cvmx-helper-ilk.c revision 256281
1/***********************license start*************** 2 * Copyright (c) 2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40/** 41 * @file 42 * 43 * Functions for ILK initialization, configuration, 44 * and monitoring. 45 * 46 * <hr>$Revision: 41586 $<hr> 47 */ 48 49#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 50#include <linux/module.h> 51 52#include <asm/octeon/cvmx.h> 53#include <asm/octeon/cvmx-config.h> 54#include <asm/octeon/cvmx-helper.h> 55#include <asm/octeon/cvmx-helper-cfg.h> 56#include <asm/octeon/cvmx-ilk.h> 57#include <asm/octeon/cvmx-bootmem.h> 58#include <asm/octeon/cvmx-pko.h> 59#include <asm/octeon/cvmx-qlm.h> 60#include <asm/octeon/cvmx-ilk-defs.h> 61#else 62#if !defined(__FreeBSD__) || !defined(_KERNEL) 63#include "executive-config.h" 64#include "cvmx-config.h" 65#endif 66#include "cvmx.h" 67#include "cvmx-helper.h" 68#include "cvmx-helper-cfg.h" 69#include "cvmx-ilk.h" 70#include "cvmx-bootmem.h" 71#include "cvmx-pko.h" 72#include "cvmx-qlm.h" 73#endif 74 75#ifdef CVMX_ENABLE_PKO_FUNCTIONS 76 77int __cvmx_helper_ilk_enumerate(int interface) 78{ 79 interface -= CVMX_ILK_GBL_BASE; 80 return cvmx_ilk_chans[interface]; 81} 82 83/** 84 * @INTERNAL 85 * Probe a ILK interface and determine the number of ports 86 * connected to it. The ILK interface should still be down 87 * after this call. 88 * 89 * @param interface Interface to probe 90 * 91 * @return Number of ports on the interface. Zero to disable. 92 */ 93int __cvmx_helper_ilk_probe(int interface) 94{ 95 int i, j, res = -1; 96 static int pipe_base = 0, pknd_base = 0; 97 static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp; 98 static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1; 99 static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2; 100 101 if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) 102 return 0; 103 104 interface -= CVMX_ILK_GBL_BASE; 105 if (interface >= CVMX_NUM_ILK_INTF) 106 return 0; 107 108 /* the configuration should be done only once */ 109 if (cvmx_ilk_get_intf_ena (interface)) 110 return cvmx_ilk_chans[interface]; 111 112 /* configure lanes and enable the link */ 113 res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]); 114 if (res < 0) 115 return 0; 116 117 /* set up the group of pipes available to ilk */ 118 if (pipe_base == 0) 119 pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0); 120 121 if (pipe_base == -1) 122 { 123 pipe_base = 0; 124 return 0; 125 } 126 127 res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]); 128 if (res < 0) 129 return 0; 130 131 /* set up pipe to channel mapping */ 132 i = pipe_base; 133 if (pch == NULL) 134 { 135 pch = (cvmx_ilk_pipe_chan_t *) 136#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 137 kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL); 138#else 139 cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), 140 sizeof(cvmx_ilk_pipe_chan_t)); 141#endif 142 if (pch == NULL) 143 return 0; 144 } 145 146 memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t)); 147 tmp = pch; 148 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 149 { 150 tmp->pipe = i++; 151 tmp->chan = cvmx_ilk_chan_map[interface][j]; 152 tmp++; 153 } 154 res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]); 155 if (res < 0) 156 { 157 res = 0; 158 goto err_free_pch; 159 } 160 pipe_base += cvmx_ilk_chans[interface]; 161 162 /* set up channel to pkind mapping */ 163 if (pknd_base == 0) 164 pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0); 165 166 i = pknd_base; 167 if (chpknd == NULL) 168 { 169 chpknd = (cvmx_ilk_chan_pknd_t *) 170#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 171 kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL); 172#else 173 cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), 174 sizeof(cvmx_ilk_chan_pknd_t)); 175#endif 176 if (chpknd == NULL) 177 { 178 pipe_base -= cvmx_ilk_chans[interface]; 179 res = 0; 180 goto err_free_pch; 181 } 182 } 183 184 memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t)); 185 tmp1 = chpknd; 186 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 187 { 188 tmp1->chan = cvmx_ilk_chan_map[interface][j]; 189 tmp1->pknd = i++; 190 tmp1++; 191 } 192 res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]); 193 if (res < 0) 194 { 195 pipe_base -= cvmx_ilk_chans[interface]; 196 res = 0; 197 goto err_free_chpknd; 198 } 199 pknd_base += cvmx_ilk_chans[interface]; 200 201 /* Set up tx calendar */ 202 if (calent == NULL) 203 { 204 calent = (cvmx_ilk_cal_entry_t *) 205#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 206 kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL); 207#else 208 cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), 209 sizeof(cvmx_ilk_cal_entry_t)); 210#endif 211 if (calent == NULL) 212 { 213 pipe_base -= cvmx_ilk_chans[interface]; 214 pknd_base -= cvmx_ilk_chans[interface]; 215 res = 0; 216 goto err_free_chpknd; 217 } 218 } 219 220 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); 221 tmp1 = chpknd; 222 tmp2 = calent; 223 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 224 { 225 tmp2->pipe_bpid = tmp1->pknd; 226 tmp2->ent_ctrl = PIPE_BPID; 227 tmp1++; 228 tmp2++; 229 } 230 res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface], 231 calent, 1); 232 if (res < 0) 233 { 234 pipe_base -= cvmx_ilk_chans[interface]; 235 pknd_base -= cvmx_ilk_chans[interface]; 236 res = 0; 237 goto err_free_calent; 238 } 239 240 /* set up rx calendar. allocated memory can be reused. 241 * this is because max pkind is always less than max pipe */ 242 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); 243 tmp = pch; 244 tmp2 = calent; 245 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 246 { 247 tmp2->pipe_bpid = tmp->pipe; 248 tmp2->ent_ctrl = PIPE_BPID; 249 tmp++; 250 tmp2++; 251 } 252 res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface], 253 calent, CVMX_ILK_RX_FIFO_WM, 1); 254 if (res < 0) 255 { 256 pipe_base -= cvmx_ilk_chans[interface]; 257 pknd_base -= cvmx_ilk_chans[interface]; 258 res = 0; 259 goto err_free_calent; 260 } 261 res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE); 262 263 goto out; 264 265err_free_calent: 266#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 267 kfree (calent); 268#else 269 /* no free() for cvmx_bootmem_alloc() */ 270#endif 271 272err_free_chpknd: 273#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 274 kfree (chpknd); 275#else 276 /* no free() for cvmx_bootmem_alloc() */ 277#endif 278 279err_free_pch: 280#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 281 kfree (pch); 282#else 283 /* no free() for cvmx_bootmem_alloc() */ 284#endif 285out: 286 return res; 287} 288 289/** 290 * @INTERNAL 291 * Bringup and enable ILK interface. After this call packet 292 * I/O should be fully functional. This is called with IPD 293 * enabled but PKO disabled. 294 * 295 * @param interface Interface to bring up 296 * 297 * @return Zero on success, negative on failure 298 */ 299int __cvmx_helper_ilk_enable(int interface) 300{ 301 interface -= CVMX_ILK_GBL_BASE; 302 return cvmx_ilk_enable(interface); 303} 304 305/** 306 * @INTERNAL 307 * Return the link state of an IPD/PKO port as returned by ILK link status. 308 * 309 * @param ipd_port IPD/PKO port to query 310 * 311 * @return Link state 312 */ 313cvmx_helper_link_info_t __cvmx_helper_ilk_link_get(int ipd_port) 314{ 315 cvmx_helper_link_info_t result; 316 int interface = cvmx_helper_get_interface_num(ipd_port); 317 int retry_count = 0; 318 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 319 cvmx_ilk_rxx_int_t ilk_rxx_int; 320 int lanes = 0; 321 322 result.u64 = 0; 323 interface -= CVMX_ILK_GBL_BASE; 324 325retry: 326 retry_count++; 327 if (retry_count > 10) 328 goto out; 329 330 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 331 ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface)); 332 333 /* Clear all RX status bits */ 334 if (ilk_rxx_int.u64) 335 cvmx_write_csr(CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64); 336 337 if (ilk_rxx_cfg1.s.rx_bdry_lock_ena == 0) 338 { 339 /* We need to start looking for work boundary lock */ 340 ilk_rxx_cfg1.s.rx_bdry_lock_ena = cvmx_ilk_get_intf_ln_msk(interface); 341 ilk_rxx_cfg1.s.rx_align_ena = 0; 342 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 343 //cvmx_dprintf("ILK%d: Looking for word boundary lock\n", interface); 344 goto retry; 345 } 346 347 if (ilk_rxx_cfg1.s.rx_align_ena == 0) 348 { 349 if (ilk_rxx_int.s.word_sync_done) 350 { 351 ilk_rxx_cfg1.s.rx_align_ena = 1; 352 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 353 //printf("ILK%d: Looking for lane alignment\n", interface); 354 goto retry; 355 } 356 goto out; 357 } 358 359 if (ilk_rxx_int.s.lane_align_fail) 360 { 361 ilk_rxx_cfg1.s.rx_bdry_lock_ena = 0; 362 ilk_rxx_cfg1.s.rx_align_ena = 0; 363 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 364 cvmx_dprintf("ILK%d: Lane alignment failed\n", interface); 365 goto out; 366 } 367 368 if (ilk_rxx_int.s.lane_align_done) 369 { 370 //cvmx_dprintf("ILK%d: Lane alignment complete\n", interface); 371 } 372 373 lanes = cvmx_pop(ilk_rxx_cfg1.s.rx_bdry_lock_ena); 374 375 result.s.link_up = 1; 376 result.s.full_duplex = 1; 377 result.s.speed = cvmx_qlm_get_gbaud_mhz(1+interface) * 64 / 67; 378 result.s.speed *= lanes; 379 380out: 381 /* If the link is down we will force disable the RX path. If it up, we'll 382 set it to match the TX state set by the if_enable call */ 383 if (result.s.link_up) 384 { 385 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 386 ilk_txx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_TXX_CFG1(interface)); 387 ilk_rxx_cfg1.s.pkt_ena = ilk_txx_cfg1.s.pkt_ena; 388 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 389 //cvmx_dprintf("ILK%d: link up, %d Mbps, Full duplex mode, %d lanes\n", interface, result.s.speed, lanes); 390 } 391 else 392 { 393 ilk_rxx_cfg1.s.pkt_ena = 0; 394 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 395 //cvmx_dprintf("ILK link down\n"); 396 } 397 return result; 398} 399 400/** 401 * @INTERNAL 402 * Set the link state of an IPD/PKO port. 403 * 404 * @param ipd_port IPD/PKO port to configure 405 * @param link_info The new link state 406 * 407 * @return Zero on success, negative on failure 408 */ 409int __cvmx_helper_ilk_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 410{ 411 /* nothing to do */ 412 413 return 0; 414} 415 416/** 417 * Display ilk interface statistics. 418 * 419 */ 420void __cvmx_helper_ilk_show_stats (void) 421{ 422 int i, j; 423 unsigned char *pchans, num_chans; 424 unsigned int chan_tmp[CVMX_MAX_ILK_CHANS]; 425 cvmx_ilk_stats_ctrl_t ilk_stats_ctrl; 426 427 for (i = 0; i < CVMX_NUM_ILK_INTF; i++) 428 { 429 cvmx_ilk_get_chan_info (i, &pchans, &num_chans); 430 431 memset (chan_tmp, 0, CVMX_MAX_ILK_CHANS * sizeof (int)); 432 for (j = 0; j < num_chans; j++) 433 chan_tmp[j] = pchans[j]; 434 435 ilk_stats_ctrl.chan_list = chan_tmp; 436 ilk_stats_ctrl.num_chans = num_chans; 437 ilk_stats_ctrl.clr_on_rd = 0; 438 cvmx_ilk_show_stats (i, &ilk_stats_ctrl); 439 } 440} 441 442#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 443