1/***********************license start*************** 2 * Copyright (c) 2003-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 * Support library for the ILK 44 * 45 * <hr>$Revision: 49448 $<hr> 46 */ 47#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 48#include <linux/module.h> 49#include <asm/octeon/cvmx.h> 50#include <asm/octeon/cvmx-config.h> 51#include <asm/octeon/cvmx-sysinfo.h> 52#include <asm/octeon/cvmx-pko.h> 53#include <asm/octeon/cvmx-ilk.h> 54#include <asm/octeon/cvmx-ilk-defs.h> 55#include <asm/octeon/cvmx-helper-util.h> 56#include <asm/octeon/cvmx-helper-ilk.h> 57#else 58#include "cvmx.h" 59#if !defined(__FreeBSD__) || !defined(_KERNEL) 60#include "cvmx-config.h" 61#endif 62#include "cvmx-sysinfo.h" 63#include "cvmx-pko.h" 64#include "cvmx-ilk.h" 65#include "cvmx-helper-util.h" 66#include "cvmx-helper-ilk.h" 67#endif 68 69#ifdef CVMX_ENABLE_HELPER_FUNCTIONS 70 71/* 72 * global configurations. to disable the 2nd ILK, set 73 * cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xff, 0x0} and 74 * cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 0} 75 */ 76unsigned char cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xf, 0xf0}; 77//#define SINGLE_PORT_SIM_ILK 78#ifdef SINGLE_PORT_SIM_ILK 79unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {1, 1}; 80unsigned char cvmx_ilk_chan_map[CVMX_NUM_ILK_INTF][CVMX_MAX_ILK_CHANS] = 81{{0}, 82 {0}}; 83#else /* sample case */ 84unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 8}; 85unsigned char cvmx_ilk_chan_map[CVMX_NUM_ILK_INTF][CVMX_MAX_ILK_CHANS] = 86{{0, 1, 2, 3, 4, 5, 6, 7}, 87 {0, 1, 2, 3, 4, 5, 6, 7}}; 88#endif 89 90/* Default callbacks, can be overridden 91 * using cvmx_ilk_get_callbacks/cvmx_ilk_set_callbacks 92 */ 93static cvmx_ilk_callbacks_t cvmx_ilk_callbacks = { 94 .calendar_setup_rx = cvmx_ilk_cal_setup_rx, 95}; 96 97static cvmx_ilk_intf_t cvmx_ilk_intf_cfg[CVMX_NUM_ILK_INTF]; 98 99/** 100 * Get current ILK initialization callbacks 101 * 102 * @param callbacks Pointer to the callbacks structure.to fill 103 * 104 * @return Pointer to cvmx_ilk_callbacks_t structure. 105 */ 106void cvmx_ilk_get_callbacks(cvmx_ilk_callbacks_t * callbacks) 107{ 108 memcpy(callbacks, &cvmx_ilk_callbacks, sizeof(cvmx_ilk_callbacks)); 109} 110 111/** 112 * Set new ILK initialization callbacks 113 * 114 * @param new_callbacks Pointer to an updated callbacks structure. 115 */ 116void cvmx_ilk_set_callbacks(cvmx_ilk_callbacks_t * new_callbacks) 117{ 118 memcpy(&cvmx_ilk_callbacks, new_callbacks, sizeof(cvmx_ilk_callbacks)); 119} 120 121/** 122 * Initialize and start the ILK interface. 123 * 124 * @param interface The identifier of the packet interface to configure and 125 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 126 * ilk1. 127 * 128 * @param lane_mask the lane group for this interface 129 * 130 * @return Zero on success, negative of failure. 131 */ 132int cvmx_ilk_start_interface (int interface, unsigned char lane_mask) 133{ 134 int res = -1; 135 int other_intf, this_qlm, other_qlm; 136 unsigned char uni_mask; 137 cvmx_mio_qlmx_cfg_t mio_qlmx_cfg, other_mio_qlmx_cfg; 138 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 139 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 140 cvmx_ilk_ser_cfg_t ilk_ser_cfg; 141 142 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 143 return res; 144 145 if (interface >= CVMX_NUM_ILK_INTF) 146 return res; 147 148 if (lane_mask == 0) 149 return res; 150 151 /* check conflicts between 2 ilk interfaces. 1 lane can be assigned to 1 152 * interface only */ 153 other_intf = !interface; 154 this_qlm = interface + CVMX_ILK_QLM_BASE; 155 other_qlm = other_intf + CVMX_ILK_QLM_BASE; 156 if (cvmx_ilk_intf_cfg[other_intf].lane_en_mask & lane_mask) 157 { 158 cvmx_dprintf ("ILK%d: %s: lane assignment conflict\n", interface, 159 __FUNCTION__); 160 return res; 161 } 162 163 /* check the legality of the lane mask. interface 0 can have 8 lanes, 164 * while interface 1 can have 4 lanes at most */ 165 uni_mask = lane_mask >> (interface * 4); 166 if ((uni_mask != 0x1 && uni_mask != 0x3 && uni_mask != 0xf && 167 uni_mask != 0xff) || (interface == 1 && lane_mask > 0xf0)) 168 { 169#if CVMX_ENABLE_DEBUG_PRINTS 170 cvmx_dprintf ("ILK%d: %s: incorrect lane mask: 0x%x \n", interface, 171 __FUNCTION__, uni_mask); 172#endif 173 return res; 174 } 175 176 /* check the availability of qlms. qlm_cfg = 001 means the chip is fused 177 * to give this qlm to ilk */ 178 mio_qlmx_cfg.u64 = cvmx_read_csr (CVMX_MIO_QLMX_CFG(this_qlm)); 179 other_mio_qlmx_cfg.u64 = cvmx_read_csr (CVMX_MIO_QLMX_CFG(other_qlm)); 180 if (mio_qlmx_cfg.s.qlm_cfg != 1 || 181 (uni_mask == 0xff && other_mio_qlmx_cfg.s.qlm_cfg != 1)) 182 { 183#if CVMX_ENABLE_DEBUG_PRINTS 184 cvmx_dprintf ("ILK%d: %s: qlm unavailable\n", interface, __FUNCTION__); 185#endif 186 return res; 187 } 188 189 /* power up the serdes */ 190 ilk_ser_cfg.u64 = cvmx_read_csr (CVMX_ILK_SER_CFG); 191 if (ilk_ser_cfg.s.ser_pwrup == 0) 192 { 193 ilk_ser_cfg.s.ser_rxpol_auto = 1; 194 ilk_ser_cfg.s.ser_rxpol = 0; 195 ilk_ser_cfg.s.ser_txpol = 0; 196 ilk_ser_cfg.s.ser_reset_n = 0xff; 197 ilk_ser_cfg.s.ser_haul = 0; 198 } 199 ilk_ser_cfg.s.ser_pwrup |= ((interface ==0) && (lane_mask > 0xf)) ? 200 0x3 : (1 << interface); 201 cvmx_write_csr (CVMX_ILK_SER_CFG, ilk_ser_cfg.u64); 202 203 /* configure the lane enable of the interface */ 204 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 205 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 206 ilk_txx_cfg0.s.lane_ena = ilk_rxx_cfg0.s.lane_ena = lane_mask; 207 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 208 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 209 210 /* write to local cache. for lane speed, if interface 0 has 8 lanes, 211 * assume both qlms have the same speed */ 212 cvmx_ilk_intf_cfg[interface].intf_en = 1; 213 cvmx_ilk_intf_cfg[interface].lane_en_mask = lane_mask; 214 res = 0; 215 216 return res; 217} 218 219/** 220 * set pipe group base and length for the interface 221 * 222 * @param interface The identifier of the packet interface to configure and 223 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 224 * ilk1. 225 * 226 * @param pipe_base the base of the pipe group 227 * @param pipe_len the length of the pipe group 228 * 229 * @return Zero on success, negative of failure. 230 */ 231int cvmx_ilk_set_pipe (int interface, int pipe_base, unsigned int pipe_len) 232{ 233 int res = -1; 234 cvmx_ilk_txx_pipe_t ilk_txx_pipe; 235 236 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 237 return res; 238 239 if (interface >= CVMX_NUM_ILK_INTF) 240 return res; 241 242 /* base should be between 0 and 127. base + length should be <127 */ 243 if (!(pipe_base >= 0 && pipe_base <= 127) || (pipe_base + pipe_len > 127)) 244 { 245#if CVMX_ENABLE_DEBUG_PRINTS 246 cvmx_dprintf ("ILK%d: %s: pipe base/length out of bounds\n", interface, 247 __FUNCTION__); 248#endif 249 return res; 250 } 251 252 /* set them in ilk tx section */ 253 ilk_txx_pipe.u64 = cvmx_read_csr (CVMX_ILK_TXX_PIPE(interface)); 254 ilk_txx_pipe.s.base = pipe_base; 255 ilk_txx_pipe.s.nump = pipe_len; 256 cvmx_write_csr (CVMX_ILK_TXX_PIPE(interface), ilk_txx_pipe.u64); 257 res = 0; 258 259 return res; 260} 261 262/** 263 * set logical channels for tx 264 * 265 * @param interface The identifier of the packet interface to configure and 266 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 267 * ilk1. 268 * 269 * @param pch pointer to an array of pipe-channel pair 270 * @param num_chs the number of entries in the pipe-channel array 271 * 272 * @return Zero on success, negative of failure. 273 */ 274int cvmx_ilk_tx_set_channel (int interface, cvmx_ilk_pipe_chan_t *pch, 275 unsigned int num_chs) 276{ 277 int res = -1; 278 cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap; 279 unsigned int i; 280 281 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 282 return res; 283 284 if (interface >= CVMX_NUM_ILK_INTF) 285 return res; 286 287 if (pch == NULL || num_chs > CVMX_MAX_ILK_PIPES) 288 return res; 289 290 /* write the pair to ilk tx */ 291 for (i = 0; i < num_chs; i++) 292 { 293 ilk_txx_idx_pmap.u64 = 0; 294 ilk_txx_idx_pmap.s.index = pch->pipe; 295 cvmx_write_csr(CVMX_ILK_TXX_IDX_PMAP(interface), ilk_txx_idx_pmap.u64); 296 cvmx_write_csr(CVMX_ILK_TXX_MEM_PMAP(interface), pch->chan); 297 pch++; 298 } 299 res = 0; 300 301 return res; 302} 303 304/** 305 * set pkind for rx 306 * 307 * @param interface The identifier of the packet interface to configure and 308 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 309 * ilk1. 310 * 311 * @param chpknd pointer to an array of channel-pkind pair 312 * @param num_pknd the number of entries in the channel-pkind array 313 * 314 * @return Zero on success, negative of failure. 315 */ 316int cvmx_ilk_rx_set_pknd (int interface, cvmx_ilk_chan_pknd_t *chpknd, 317 unsigned int num_pknd) 318{ 319 int res = -1; 320 cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap; 321 unsigned int i; 322 323 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 324 return res; 325 326 if (interface >= CVMX_NUM_ILK_INTF) 327 return res; 328 329 if (chpknd == NULL || num_pknd > CVMX_MAX_ILK_PKNDS) 330 return res; 331 332 /* write the pair to ilk rx. note the channels for different interfaces 333 * are given in *chpknd and interface is not used as a param */ 334 for (i = 0; i < num_pknd; i++) 335 { 336 ilk_rxf_idx_pmap.u64 = 0; 337 ilk_rxf_idx_pmap.s.index = interface * 256 + chpknd->chan; 338 cvmx_write_csr (CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64); 339 cvmx_write_csr (CVMX_ILK_RXF_MEM_PMAP, chpknd->pknd); 340 chpknd++; 341 } 342 res = 0; 343 344 return res; 345} 346 347/** 348 * configure calendar for rx 349 * 350 * @param interface The identifier of the packet interface to configure and 351 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 352 * ilk1. 353 * 354 * @param cal_depth the number of calendar entries 355 * @param pent pointer to calendar entries 356 * 357 * @return Zero on success, negative of failure. 358 */ 359static int cvmx_ilk_rx_cal_conf (int interface, int cal_depth, 360 cvmx_ilk_cal_entry_t *pent) 361{ 362 int res = -1, num_grp, num_rest, i, j; 363 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 364 cvmx_ilk_rxx_idx_cal_t ilk_rxx_idx_cal; 365 cvmx_ilk_rxx_mem_cal0_t ilk_rxx_mem_cal0; 366 cvmx_ilk_rxx_mem_cal1_t ilk_rxx_mem_cal1; 367 unsigned long int tmp; 368 369 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 370 return res; 371 372 if (interface >= CVMX_NUM_ILK_INTF) 373 return res; 374 375 if (cal_depth < CVMX_ILK_RX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL 376 || pent == NULL) 377 return res; 378 379 /* mandatory link-level fc as workarounds for ILK-15397 and ILK-15479 */ 380 /* TODO: test effectiveness */ 381#if 0 382 if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_0) && pent->ent_ctrl == PIPE_BPID) 383 for (i = 0; i < cal_depth; i++) 384 pent->ent_ctrl = LINK; 385#endif 386 387 /* set the depth */ 388 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 389 ilk_rxx_cfg0.s.cal_depth = cal_depth; 390 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 391 392 /* set the calendar index */ 393 num_grp = cal_depth / CVMX_ILK_CAL_GRP_SZ; 394 num_rest = cal_depth % CVMX_ILK_CAL_GRP_SZ; 395 ilk_rxx_idx_cal.u64 = 0; 396 ilk_rxx_idx_cal.s.inc = 1; 397 cvmx_write_csr (CVMX_ILK_RXX_IDX_CAL(interface), ilk_rxx_idx_cal.u64); 398 399 /* set the calendar entries. each group has both cal0 and cal1 registers */ 400 for (i = 0; i < num_grp; i++) 401 { 402 ilk_rxx_mem_cal0.u64 = 0; 403 for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++) 404 { 405 tmp = 0; 406 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 407 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j; 408 ilk_rxx_mem_cal0.u64 |= tmp; 409 410 tmp = 0; 411 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 412 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j + 413 CVMX_ILK_PIPE_BPID_SZ; 414 ilk_rxx_mem_cal0.u64 |= tmp; 415 pent++; 416 } 417 cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL0(interface), ilk_rxx_mem_cal0.u64); 418 419 ilk_rxx_mem_cal1.u64 = 0; 420 for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++) 421 { 422 tmp = 0; 423 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 424 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j; 425 ilk_rxx_mem_cal1.u64 |= tmp; 426 427 tmp = 0; 428 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 429 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j + 430 CVMX_ILK_PIPE_BPID_SZ; 431 ilk_rxx_mem_cal1.u64 |= tmp; 432 pent++; 433 } 434 cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL1(interface), ilk_rxx_mem_cal1.u64); 435 } 436 437 /* set the calendar entries, the fraction of a group. but both cal0 and 438 * cal1 must be written */ 439 ilk_rxx_mem_cal0.u64 = 0; 440 ilk_rxx_mem_cal1.u64 = 0; 441 for (i = 0; i < num_rest; i++) 442 { 443 if (i < CVMX_ILK_CAL_GRP_SZ/2) 444 { 445 tmp = 0; 446 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 447 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * i; 448 ilk_rxx_mem_cal0.u64 |= tmp; 449 450 tmp = 0; 451 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 452 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * i + 453 CVMX_ILK_PIPE_BPID_SZ; 454 ilk_rxx_mem_cal0.u64 |= tmp; 455 pent++; 456 } 457 458 if (i >= CVMX_ILK_CAL_GRP_SZ/2) 459 { 460 tmp = 0; 461 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 462 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * 463 (i - CVMX_ILK_CAL_GRP_SZ/2); 464 ilk_rxx_mem_cal1.u64 |= tmp; 465 466 tmp = 0; 467 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 468 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * 469 (i - CVMX_ILK_CAL_GRP_SZ/2) + CVMX_ILK_PIPE_BPID_SZ; 470 ilk_rxx_mem_cal1.u64 |= tmp; 471 pent++; 472 } 473 } 474 cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL0(interface), ilk_rxx_mem_cal0.u64); 475 cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL1(interface), ilk_rxx_mem_cal1.u64); 476 cvmx_read_csr (CVMX_ILK_RXX_MEM_CAL1(interface)); 477 478 return 0; 479} 480 481/** 482 * set high water mark for rx 483 * 484 * @param interface The identifier of the packet interface to configure and 485 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 486 * ilk1. 487 * 488 * @param hi_wm high water mark for this interface 489 * 490 * @return Zero on success, negative of failure. 491 */ 492static int cvmx_ilk_rx_set_hwm (int interface, int hi_wm) 493{ 494 int res = -1; 495 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 496 497 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 498 return res; 499 500 if (interface >= CVMX_NUM_ILK_INTF) 501 return res; 502 503 if (hi_wm <= 0) 504 return res; 505 506 /* set the hwm */ 507 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 508 ilk_rxx_cfg1.s.rx_fifo_hwm = hi_wm; 509 cvmx_write_csr (CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 510 res = 0; 511 512 return res; 513} 514 515/** 516 * enable calendar for rx 517 * 518 * @param interface The identifier of the packet interface to configure and 519 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 520 * ilk1. 521 * 522 * @param cal_ena enable or disable calendar 523 * 524 * @return Zero on success, negative of failure. 525 */ 526static int cvmx_ilk_rx_cal_ena (int interface, unsigned char cal_ena) 527{ 528 int res = -1; 529 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 530 531 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 532 return res; 533 534 if (interface >= CVMX_NUM_ILK_INTF) 535 return res; 536 537 /* set the enable */ 538 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 539 ilk_rxx_cfg0.s.cal_ena = cal_ena; 540 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 541 cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 542 res = 0; 543 544 return res; 545} 546 547/** 548 * set up calendar for rx 549 * 550 * @param interface The identifier of the packet interface to configure and 551 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 552 * ilk1. 553 * 554 * @param cal_depth the number of calendar entries 555 * @param pent pointer to calendar entries 556 * @param hi_wm high water mark for this interface 557 * @param cal_ena enable or disable calendar 558 * 559 * @return Zero on success, negative of failure. 560 */ 561int cvmx_ilk_cal_setup_rx (int interface, int cal_depth, 562 cvmx_ilk_cal_entry_t *pent, int hi_wm, 563 unsigned char cal_ena) 564{ 565 int res = -1; 566 567 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 568 return res; 569 570 if (interface >= CVMX_NUM_ILK_INTF) 571 return res; 572 573 res = cvmx_ilk_rx_cal_conf (interface, cal_depth, pent); 574 if (res < 0) 575 return res; 576 577 res = cvmx_ilk_rx_set_hwm (interface, hi_wm); 578 if (res < 0) 579 return res; 580 581 res = cvmx_ilk_rx_cal_ena (interface, cal_ena); 582 return res; 583} 584#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 585EXPORT_SYMBOL(cvmx_ilk_cal_setup_rx); 586#endif 587 588/** 589 * configure calendar for tx 590 * 591 * @param interface The identifier of the packet interface to configure and 592 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 593 * ilk1. 594 * 595 * @param cal_depth the number of calendar entries 596 * @param pent pointer to calendar entries 597 * 598 * @return Zero on success, negative of failure. 599 */ 600static int cvmx_ilk_tx_cal_conf (int interface, int cal_depth, 601 cvmx_ilk_cal_entry_t *pent) 602{ 603 int res = -1, num_grp, num_rest, i, j; 604 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 605 cvmx_ilk_txx_idx_cal_t ilk_txx_idx_cal; 606 cvmx_ilk_txx_mem_cal0_t ilk_txx_mem_cal0; 607 cvmx_ilk_txx_mem_cal1_t ilk_txx_mem_cal1; 608 unsigned long int tmp; 609 cvmx_ilk_cal_entry_t *ent_tmp; 610 611 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 612 return res; 613 614 if (interface >= CVMX_NUM_ILK_INTF) 615 return res; 616 617 if (cal_depth < CVMX_ILK_TX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL 618 || pent == NULL) 619 return res; 620 621 /* mandatory link-level fc as workarounds for ILK-15397 and ILK-15479 */ 622 /* TODO: test effectiveness */ 623#if 0 624 if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_0) && pent->ent_ctrl == PIPE_BPID) 625 for (i = 0; i < cal_depth; i++) 626 pent->ent_ctrl = LINK; 627#endif 628 629 /* tx calendar depth must be a multiple of 8 */ 630 num_grp = (cal_depth - 1) / CVMX_ILK_CAL_GRP_SZ + 1; 631 num_rest = cal_depth % CVMX_ILK_CAL_GRP_SZ; 632 if (num_rest != 0) 633 { 634 ent_tmp = pent + cal_depth; 635 for (i = num_rest; i < 8; i++, ent_tmp++) 636 { 637 ent_tmp->pipe_bpid = 0; 638 ent_tmp->ent_ctrl = XOFF; 639 } 640 } 641 cal_depth = num_grp * 8; 642 643 /* set the depth */ 644 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 645 ilk_txx_cfg0.s.cal_depth = cal_depth; 646 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 647 648 /* set the calendar index */ 649 ilk_txx_idx_cal.u64 = 0; 650 ilk_txx_idx_cal.s.inc = 1; 651 cvmx_write_csr (CVMX_ILK_TXX_IDX_CAL(interface), ilk_txx_idx_cal.u64); 652 653 /* set the calendar entries. each group has both cal0 and cal1 registers */ 654 for (i = 0; i < num_grp; i++) 655 { 656 ilk_txx_mem_cal0.u64 = 0; 657 for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++) 658 { 659 tmp = 0; 660 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 661 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j; 662 ilk_txx_mem_cal0.u64 |= tmp; 663 664 tmp = 0; 665 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 666 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j + 667 CVMX_ILK_PIPE_BPID_SZ; 668 ilk_txx_mem_cal0.u64 |= tmp; 669 pent++; 670 } 671 cvmx_write_csr(CVMX_ILK_TXX_MEM_CAL0(interface), ilk_txx_mem_cal0.u64); 672 673 ilk_txx_mem_cal1.u64 = 0; 674 for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++) 675 { 676 tmp = 0; 677 tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ); 678 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j; 679 ilk_txx_mem_cal1.u64 |= tmp; 680 681 tmp = 0; 682 tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ); 683 tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j + 684 CVMX_ILK_PIPE_BPID_SZ; 685 ilk_txx_mem_cal1.u64 |= tmp; 686 pent++; 687 } 688 cvmx_write_csr(CVMX_ILK_TXX_MEM_CAL1(interface), ilk_txx_mem_cal1.u64); 689 } 690 cvmx_read_csr (CVMX_ILK_TXX_MEM_CAL1(interface)); 691 692 return 0; 693} 694 695#ifdef CVMX_ILK_BP_CONF_ENA 696/** 697 * configure backpressure for tx 698 * 699 * @param interface The identifier of the packet interface to configure and 700 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 701 * ilk1. 702 * 703 * @param cal_depth the number of calendar entries 704 * @param pent pointer to calendar entries 705 * 706 * @return Zero on success, negative of failure. 707 */ 708static int cvmx_ilk_bp_conf (int interface, int cal_depth, cvmx_ilk_cal_entry_t *pent) 709{ 710 int res = -1, i; 711 cvmx_ipd_ctl_status_t ipd_ctl_status; 712 cvmx_ilk_cal_entry_t *tmp; 713 unsigned char bpid; 714 cvmx_ipd_bpidx_mbuf_th_t ipd_bpidx_mbuf_th; 715 716 /* enable bp for the interface */ 717 ipd_ctl_status.u64 = cvmx_read_csr (CVMX_IPD_CTL_STATUS); 718 ipd_ctl_status.s.pbp_en = 1; 719 cvmx_write_csr (CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64); 720 721 /* enable bp for each id */ 722 for (i = 0, tmp = pent; i < cal_depth; i++, tmp++) 723 { 724 bpid = tmp->pipe_bpid; 725 ipd_bpidx_mbuf_th.u64 = 726 cvmx_read_csr (CVMX_IPD_BPIDX_MBUF_TH(bpid)); 727 ipd_bpidx_mbuf_th.s.page_cnt = 1; /* 256 buffers */ 728 ipd_bpidx_mbuf_th.s.bp_enb = 1; 729 cvmx_write_csr (CVMX_IPD_BPIDX_MBUF_TH(bpid), ipd_bpidx_mbuf_th.u64); 730 } 731 res = 0; 732 733 return res; 734} 735#endif 736 737/** 738 * enable calendar for tx 739 * 740 * @param interface The identifier of the packet interface to configure and 741 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 742 * ilk1. 743 * 744 * @param cal_ena enable or disable calendar 745 * 746 * @return Zero on success, negative of failure. 747 */ 748static int cvmx_ilk_tx_cal_ena (int interface, unsigned char cal_ena) 749{ 750 int res = -1; 751 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 752 753 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 754 return res; 755 756 if (interface >= CVMX_NUM_ILK_INTF) 757 return res; 758 759 /* set the enable */ 760 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 761 ilk_txx_cfg0.s.cal_ena = cal_ena; 762 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 763 cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 764 res = 0; 765 766 return res; 767} 768 769/** 770 * set up calendar for tx 771 * 772 * @param interface The identifier of the packet interface to configure and 773 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and 774 * ilk1. 775 * 776 * @param cal_depth the number of calendar entries 777 * @param pent pointer to calendar entries 778 * @param cal_ena enable or disable calendar 779 * 780 * @return Zero on success, negative of failure. 781 */ 782int cvmx_ilk_cal_setup_tx (int interface, int cal_depth, 783 cvmx_ilk_cal_entry_t *pent, unsigned char cal_ena) 784{ 785 int res = -1; 786 787 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 788 return res; 789 790 if (interface >= CVMX_NUM_ILK_INTF) 791 return res; 792 793 res = cvmx_ilk_tx_cal_conf (interface, cal_depth, pent); 794 if (res < 0) 795 return res; 796 797#ifdef CVMX_ILK_BP_CONF_ENA 798 res = cvmx_ilk_bp_conf (interface, cal_depth, pent); 799 if (res < 0) 800 return res; 801#endif 802 803 res = cvmx_ilk_tx_cal_ena (interface, cal_ena); 804 return res; 805} 806#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 807EXPORT_SYMBOL(cvmx_ilk_cal_setup_tx); 808#endif 809 810#ifdef CVMX_ILK_STATS_ENA 811static void cvmx_ilk_reg_dump_rx (int interface) 812{ 813 int i; 814 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 815 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 816 cvmx_ilk_rxx_int_t ilk_rxx_int; 817 cvmx_ilk_rxx_jabber_t ilk_rxx_jabber; 818 cvmx_ilk_rx_lnex_cfg_t ilk_rx_lnex_cfg; 819 cvmx_ilk_rx_lnex_int_t ilk_rx_lnex_int; 820 cvmx_ilk_gbl_cfg_t ilk_gbl_cfg; 821 cvmx_ilk_ser_cfg_t ilk_ser_cfg; 822 cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap; 823 cvmx_ilk_rxf_mem_pmap_t ilk_rxf_mem_pmap; 824 cvmx_ilk_rxx_idx_cal_t ilk_rxx_idx_cal; 825 cvmx_ilk_rxx_mem_cal0_t ilk_rxx_mem_cal0; 826 cvmx_ilk_rxx_mem_cal1_t ilk_rxx_mem_cal1; 827 828 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 829 cvmx_dprintf ("ilk rxx cfg0: 0x%16lx\n", ilk_rxx_cfg0.u64); 830 831 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 832 cvmx_dprintf ("ilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64); 833 834 ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface)); 835 cvmx_dprintf ("ilk rxx int: 0x%16lx\n", ilk_rxx_int.u64); 836 cvmx_write_csr (CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64); 837 838 ilk_rxx_jabber.u64 = cvmx_read_csr (CVMX_ILK_RXX_JABBER(interface)); 839 cvmx_dprintf ("ilk rxx jabber: 0x%16lx\n", ilk_rxx_jabber.u64); 840 841#define LNE_NUM_DBG 4 842 for (i = 0; i < LNE_NUM_DBG; i++) 843 { 844 ilk_rx_lnex_cfg.u64 = cvmx_read_csr (CVMX_ILK_RX_LNEX_CFG(i)); 845 cvmx_dprintf ("ilk rx lnex cfg lane: %d 0x%16lx\n", i, 846 ilk_rx_lnex_cfg.u64); 847 } 848 849 for (i = 0; i < LNE_NUM_DBG; i++) 850 { 851 ilk_rx_lnex_int.u64 = cvmx_read_csr (CVMX_ILK_RX_LNEX_INT(i)); 852 cvmx_dprintf ("ilk rx lnex int lane: %d 0x%16lx\n", i, 853 ilk_rx_lnex_int.u64); 854 cvmx_write_csr (CVMX_ILK_RX_LNEX_INT(i), ilk_rx_lnex_int.u64); 855 } 856 857 ilk_gbl_cfg.u64 = cvmx_read_csr (CVMX_ILK_GBL_CFG); 858 cvmx_dprintf ("ilk gbl cfg: 0x%16lx\n", ilk_gbl_cfg.u64); 859 860 ilk_ser_cfg.u64 = cvmx_read_csr (CVMX_ILK_SER_CFG); 861 cvmx_dprintf ("ilk ser cfg: 0x%16lx\n", ilk_ser_cfg.u64); 862 863#define CHAN_NUM_DBG 8 864 ilk_rxf_idx_pmap.u64 = 0; 865 ilk_rxf_idx_pmap.s.index = interface * 256; 866 ilk_rxf_idx_pmap.s.inc = 1; 867 cvmx_write_csr (CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64); 868 for (i = 0; i < CHAN_NUM_DBG; i++) 869 { 870 ilk_rxf_mem_pmap.u64 = cvmx_read_csr (CVMX_ILK_RXF_MEM_PMAP); 871 cvmx_dprintf ("ilk rxf mem pmap chan: %3d 0x%16lx\n", i, 872 ilk_rxf_mem_pmap.u64); 873 } 874 875#define CAL_NUM_DBG 2 876 ilk_rxx_idx_cal.u64 = 0; 877 ilk_rxx_idx_cal.s.inc = 1; 878 cvmx_write_csr (CVMX_ILK_RXX_IDX_CAL(interface), ilk_rxx_idx_cal.u64); 879 for (i = 0; i < CAL_NUM_DBG; i++) 880 { 881 ilk_rxx_idx_cal.u64 = cvmx_read_csr(CVMX_ILK_RXX_IDX_CAL(interface)); 882 cvmx_dprintf ("ilk rxx idx cal: 0x%16lx\n", ilk_rxx_idx_cal.u64); 883 884 ilk_rxx_mem_cal0.u64 = cvmx_read_csr(CVMX_ILK_RXX_MEM_CAL0(interface)); 885 cvmx_dprintf ("ilk rxx mem cal0: 0x%16lx\n", ilk_rxx_mem_cal0.u64); 886 ilk_rxx_mem_cal1.u64 = cvmx_read_csr(CVMX_ILK_RXX_MEM_CAL1(interface)); 887 cvmx_dprintf ("ilk rxx mem cal1: 0x%16lx\n", ilk_rxx_mem_cal1.u64); 888 } 889} 890 891static void cvmx_ilk_reg_dump_tx (int interface) 892{ 893 int i; 894 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 895 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 896 cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap; 897 cvmx_ilk_txx_mem_pmap_t ilk_txx_mem_pmap; 898 cvmx_ilk_txx_int_t ilk_txx_int; 899 cvmx_ilk_txx_pipe_t ilk_txx_pipe; 900 cvmx_ilk_txx_idx_cal_t ilk_txx_idx_cal; 901 cvmx_ilk_txx_mem_cal0_t ilk_txx_mem_cal0; 902 cvmx_ilk_txx_mem_cal1_t ilk_txx_mem_cal1; 903 904 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 905 cvmx_dprintf ("ilk txx cfg0: 0x%16lx\n", ilk_txx_cfg0.u64); 906 907 ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface)); 908 cvmx_dprintf ("ilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64); 909 910 ilk_txx_pipe.u64 = cvmx_read_csr (CVMX_ILK_TXX_PIPE(interface)); 911 cvmx_dprintf ("ilk txx pipe: 0x%16lx\n", ilk_txx_pipe.u64); 912 913 ilk_txx_idx_pmap.u64 = 0; 914 ilk_txx_idx_pmap.s.index = ilk_txx_pipe.s.base; 915 ilk_txx_idx_pmap.s.inc = 1; 916 cvmx_write_csr (CVMX_ILK_TXX_IDX_PMAP(interface), ilk_txx_idx_pmap.u64); 917 for (i = 0; i < CHAN_NUM_DBG; i++) 918 { 919 ilk_txx_mem_pmap.u64 = cvmx_read_csr (CVMX_ILK_TXX_MEM_PMAP(interface)); 920 cvmx_dprintf ("ilk txx mem pmap pipe: %3d 0x%16lx\n", 921 ilk_txx_pipe.s.base + i, ilk_txx_mem_pmap.u64); 922 } 923 924 ilk_txx_int.u64 = cvmx_read_csr (CVMX_ILK_TXX_INT(interface)); 925 cvmx_dprintf ("ilk txx int: 0x%16lx\n", ilk_txx_int.u64); 926 927 ilk_txx_idx_cal.u64 = 0; 928 ilk_txx_idx_cal.s.inc = 1; 929 cvmx_write_csr (CVMX_ILK_TXX_IDX_CAL(interface), ilk_txx_idx_cal.u64); 930 for (i = 0; i < CAL_NUM_DBG; i++) 931 { 932 ilk_txx_idx_cal.u64 = cvmx_read_csr(CVMX_ILK_TXX_IDX_CAL(interface)); 933 cvmx_dprintf ("ilk txx idx cal: 0x%16lx\n", ilk_txx_idx_cal.u64); 934 935 ilk_txx_mem_cal0.u64 = cvmx_read_csr(CVMX_ILK_TXX_MEM_CAL0(interface)); 936 cvmx_dprintf ("ilk txx mem cal0: 0x%16lx\n", ilk_txx_mem_cal0.u64); 937 ilk_txx_mem_cal1.u64 = cvmx_read_csr(CVMX_ILK_TXX_MEM_CAL1(interface)); 938 cvmx_dprintf ("ilk txx mem cal1: 0x%16lx\n", ilk_txx_mem_cal1.u64); 939 } 940} 941#endif 942 943/** 944 * show run time status 945 * 946 * @param interface The identifier of the packet interface to enable. cn68xx 947 * has 2 interfaces: ilk0 and ilk1. 948 * 949 * @return nothing 950 */ 951#ifdef CVMX_ILK_RUNTIME_DBG 952void cvmx_ilk_runtime_status (int interface) 953{ 954 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 955 cvmx_ilk_txx_flow_ctl0_t ilk_txx_flow_ctl0; 956 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 957 cvmx_ilk_rxx_int_t ilk_rxx_int; 958 cvmx_ilk_rxx_flow_ctl0_t ilk_rxx_flow_ctl0; 959 cvmx_ilk_rxx_flow_ctl1_t ilk_rxx_flow_ctl1; 960 cvmx_ilk_gbl_int_t ilk_gbl_int; 961 962 cvmx_dprintf ("\nilk run-time status: interface: %d\n", interface); 963 964 ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface)); 965 cvmx_dprintf ("\nilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64); 966 if (ilk_txx_cfg1.s.rx_link_fc) 967 cvmx_dprintf ("link flow control received\n"); 968 if (ilk_txx_cfg1.s.tx_link_fc) 969 cvmx_dprintf ("link flow control sent\n"); 970 971 ilk_txx_flow_ctl0.u64 = cvmx_read_csr (CVMX_ILK_TXX_FLOW_CTL0(interface)); 972 cvmx_dprintf ("\nilk txx flow ctl0: 0x%16lx\n", ilk_txx_flow_ctl0.u64); 973 974 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 975 cvmx_dprintf ("\nilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64); 976 cvmx_dprintf ("rx fifo count: %d\n", ilk_rxx_cfg1.s.rx_fifo_cnt); 977 978 ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface)); 979 cvmx_dprintf ("\nilk rxx int: 0x%16lx\n", ilk_rxx_int.u64); 980 if (ilk_rxx_int.s.pkt_drop_rxf) 981 cvmx_dprintf ("rx fifo packet drop\n"); 982 if (ilk_rxx_int.u64) 983 cvmx_write_csr (CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64); 984 985 ilk_rxx_flow_ctl0.u64 = cvmx_read_csr (CVMX_ILK_RXX_FLOW_CTL0(interface)); 986 cvmx_dprintf ("\nilk rxx flow ctl0: 0x%16lx\n", ilk_rxx_flow_ctl0.u64); 987 988 ilk_rxx_flow_ctl1.u64 = cvmx_read_csr (CVMX_ILK_RXX_FLOW_CTL1(interface)); 989 cvmx_dprintf ("\nilk rxx flow ctl1: 0x%16lx\n", ilk_rxx_flow_ctl1.u64); 990 991 ilk_gbl_int.u64 = cvmx_read_csr (CVMX_ILK_GBL_INT); 992 cvmx_dprintf ("\nilk gbl int: 0x%16lx\n", ilk_gbl_int.u64); 993 if (ilk_gbl_int.s.rxf_push_full) 994 cvmx_dprintf ("rx fifo overflow\n"); 995 if (ilk_gbl_int.u64) 996 cvmx_write_csr (CVMX_ILK_GBL_INT, ilk_gbl_int.u64); 997} 998#endif 999 1000/** 1001 * enable interface 1002 * 1003 * @param interface The identifier of the packet interface to enable. cn68xx 1004 * has 2 interfaces: ilk0 and ilk1. 1005 * 1006 * @return Zero on success, negative of failure. 1007 */ 1008//#define CVMX_ILK_STATS_ENA 1 1009int cvmx_ilk_enable (int interface) 1010{ 1011 int res = -1; 1012 int retry_count = 0; 1013 cvmx_helper_link_info_t result; 1014 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 1015 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 1016#ifdef CVMX_ILK_STATS_ENA 1017 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 1018 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 1019#endif 1020 1021 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 1022 return res; 1023 1024 if (interface >= CVMX_NUM_ILK_INTF) 1025 return res; 1026 1027 result.u64 = 0; 1028 1029#ifdef CVMX_ILK_STATS_ENA 1030 cvmx_dprintf ("\n"); 1031 cvmx_dprintf ("<<<< ILK%d: Before enabling ilk\n", interface); 1032 cvmx_ilk_reg_dump_rx (interface); 1033 cvmx_ilk_reg_dump_tx (interface); 1034#endif 1035 1036 /* RX packet will be enabled only if link is up */ 1037 1038 /* TX side */ 1039 ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface)); 1040 ilk_txx_cfg1.s.pkt_ena = 1; 1041 ilk_txx_cfg1.s.rx_link_fc_ign = 1; /* cannot use link fc workaround */ 1042 cvmx_write_csr (CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64); 1043 cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface)); 1044 1045#ifdef CVMX_ILK_STATS_ENA 1046 /* RX side stats */ 1047 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 1048 ilk_rxx_cfg0.s.lnk_stats_ena = 1; 1049 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 1050 1051 /* TX side stats */ 1052 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1053 ilk_txx_cfg0.s.lnk_stats_ena = 1; 1054 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1055#endif 1056 1057retry: 1058 retry_count++; 1059 if (retry_count > 10) 1060 goto out; 1061 1062 /* Make sure the link is up, so that packets can be sent. */ 1063 result = __cvmx_helper_ilk_link_get(cvmx_helper_get_ipd_port(interface + CVMX_ILK_GBL_BASE, 0)); 1064 1065 /* Small delay before another retry. */ 1066 cvmx_wait_usec(100); 1067 1068 ilk_rxx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_RXX_CFG1(interface)); 1069 if (ilk_rxx_cfg1.s.pkt_ena == 0) 1070 goto retry; 1071 1072out: 1073 1074#ifdef CVMX_ILK_STATS_ENA 1075 cvmx_dprintf (">>>> ILK%d: After ILK is enabled\n", interface); 1076 cvmx_ilk_reg_dump_rx (interface); 1077 cvmx_ilk_reg_dump_tx (interface); 1078#endif 1079 1080 if (result.s.link_up) 1081 return 0; 1082 1083 return -1; 1084} 1085 1086/** 1087 * Disable interface 1088 * 1089 * @param interface The identifier of the packet interface to disable. cn68xx 1090 * has 2 interfaces: ilk0 and ilk1. 1091 * 1092 * @return Zero on success, negative of failure. 1093 */ 1094int cvmx_ilk_disable (int interface) 1095{ 1096 int res = -1; 1097 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 1098 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 1099#ifdef CVMX_ILK_STATS_ENA 1100 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 1101 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 1102#endif 1103 1104 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 1105 return res; 1106 1107 if (interface >= CVMX_NUM_ILK_INTF) 1108 return res; 1109 1110 /* TX side */ 1111 ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface)); 1112 ilk_txx_cfg1.s.pkt_ena = 0; 1113 cvmx_write_csr (CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64); 1114 1115 /* RX side */ 1116 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 1117 ilk_rxx_cfg1.s.pkt_ena = 0; 1118 cvmx_write_csr (CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 1119 1120#ifdef CVMX_ILK_STATS_ENA 1121 /* RX side stats */ 1122 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 1123 ilk_rxx_cfg0.s.lnk_stats_ena = 0; 1124 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 1125 1126 /* RX side stats */ 1127 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1128 ilk_txx_cfg0.s.lnk_stats_ena = 0; 1129 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1130#endif 1131 1132 return 0; 1133} 1134 1135/** 1136 * Provide interface enable status 1137 * 1138 * @param interface The identifier of the packet interface to disable. cn68xx 1139 * has 2 interfaces: ilk0 and ilk1. 1140 * 1141 * @return Zero, not enabled; One, enabled. 1142 */ 1143int cvmx_ilk_get_intf_ena (int interface) 1144{ 1145 return cvmx_ilk_intf_cfg[interface].intf_en; 1146} 1147 1148/** 1149 * bit counter 1150 * 1151 * @param uc the byte to be counted 1152 * 1153 * @return number of bits set 1154 */ 1155unsigned char cvmx_ilk_bit_count (unsigned char uc) 1156{ 1157 unsigned char count; 1158 1159 for (count = 0; uc > 0; uc &= uc-1) 1160 count++; 1161 1162 return count; 1163} 1164 1165/** 1166 * Provide interface lane mask 1167 * 1168 * @param interface The identifier of the packet interface to disable. cn68xx 1169 * has 2 interfaces: ilk0 and ilk1. 1170 * 1171 * @return lane mask 1172 */ 1173unsigned char cvmx_ilk_get_intf_ln_msk (int interface) 1174{ 1175 return cvmx_ilk_intf_cfg[interface].lane_en_mask; 1176} 1177 1178/** 1179 * Provide channel info 1180 * 1181 * @param interface The identifier of the packet interface to disable. cn68xx 1182 * has 2 interfaces: ilk0 and ilk1. 1183 * @param chans A pointer to a channel array 1184 * @param num_chan A pointer to the number of channels 1185 * 1186 * @return Zero on success, negative of failure. 1187 */ 1188int cvmx_ilk_get_chan_info (int interface, unsigned char **chans, 1189 unsigned char *num_chan) 1190{ 1191 *chans = cvmx_ilk_chan_map[interface]; 1192 *num_chan = cvmx_ilk_chans[interface]; 1193 1194 return 0; 1195} 1196 1197/** 1198 * Show channel statistics 1199 * 1200 * @param interface The identifier of the packet interface to disable. cn68xx 1201 * has 2 interfaces: ilk0 and ilk1. 1202 * @param pstats A pointer to cvmx_ilk_stats_ctrl_t that specifies which 1203 * logical channels to access 1204 * 1205 * @return nothing 1206 */ 1207void cvmx_ilk_show_stats (int interface, cvmx_ilk_stats_ctrl_t *pstats) 1208{ 1209 unsigned int i; 1210 cvmx_ilk_rxx_idx_stat0_t ilk_rxx_idx_stat0; 1211 cvmx_ilk_rxx_idx_stat1_t ilk_rxx_idx_stat1; 1212 cvmx_ilk_rxx_mem_stat0_t ilk_rxx_mem_stat0; 1213 cvmx_ilk_rxx_mem_stat1_t ilk_rxx_mem_stat1; 1214 1215 cvmx_ilk_txx_idx_stat0_t ilk_txx_idx_stat0; 1216 cvmx_ilk_txx_idx_stat1_t ilk_txx_idx_stat1; 1217 cvmx_ilk_txx_mem_stat0_t ilk_txx_mem_stat0; 1218 cvmx_ilk_txx_mem_stat1_t ilk_txx_mem_stat1; 1219 1220 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 1221 return; 1222 1223 if (interface >= CVMX_NUM_ILK_INTF) 1224 return; 1225 1226 if (pstats == NULL) 1227 return; 1228 1229 /* discrete channels */ 1230 if (pstats->chan_list != NULL) 1231 { 1232 for (i = 0; i < pstats->num_chans; i++) 1233 { 1234 1235 /* get the number of rx packets */ 1236 ilk_rxx_idx_stat0.u64 = 0; 1237 ilk_rxx_idx_stat0.s.index = *pstats->chan_list; 1238 ilk_rxx_idx_stat0.s.clr = pstats->clr_on_rd; 1239 cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT0(interface), 1240 ilk_rxx_idx_stat0.u64); 1241 ilk_rxx_mem_stat0.u64 = cvmx_read_csr 1242 (CVMX_ILK_RXX_MEM_STAT0(interface)); 1243 1244 /* get the number of rx bytes */ 1245 ilk_rxx_idx_stat1.u64 = 0; 1246 ilk_rxx_idx_stat1.s.index = *pstats->chan_list; 1247 ilk_rxx_idx_stat1.s.clr = pstats->clr_on_rd; 1248 cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT1(interface), 1249 ilk_rxx_idx_stat1.u64); 1250 ilk_rxx_mem_stat1.u64 = cvmx_read_csr 1251 (CVMX_ILK_RXX_MEM_STAT1(interface)); 1252 1253 cvmx_dprintf ("ILK%d Channel%d Rx: %d packets %d bytes\n", interface, 1254 *pstats->chan_list, ilk_rxx_mem_stat0.s.rx_pkt, 1255 (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes); 1256 1257 /* get the number of tx packets */ 1258 ilk_txx_idx_stat0.u64 = 0; 1259 ilk_txx_idx_stat0.s.index = *pstats->chan_list; 1260 ilk_txx_idx_stat0.s.clr = pstats->clr_on_rd; 1261 cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT0(interface), 1262 ilk_txx_idx_stat0.u64); 1263 ilk_txx_mem_stat0.u64 = cvmx_read_csr 1264 (CVMX_ILK_TXX_MEM_STAT0(interface)); 1265 1266 /* get the number of tx bytes */ 1267 ilk_txx_idx_stat1.u64 = 0; 1268 ilk_txx_idx_stat1.s.index = *pstats->chan_list; 1269 ilk_txx_idx_stat1.s.clr = pstats->clr_on_rd; 1270 cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT1(interface), 1271 ilk_txx_idx_stat1.u64); 1272 ilk_txx_mem_stat1.u64 = cvmx_read_csr 1273 (CVMX_ILK_TXX_MEM_STAT1(interface)); 1274 1275 cvmx_dprintf ("ILK%d Channel%d Tx: %d packets %d bytes\n", interface, 1276 *pstats->chan_list, ilk_txx_mem_stat0.s.tx_pkt, 1277 (unsigned int) ilk_txx_mem_stat1.s.tx_bytes); 1278 1279 pstats++; 1280 } 1281 return; 1282 } 1283 1284 /* continuous channels */ 1285 ilk_rxx_idx_stat0.u64 = 0; 1286 ilk_rxx_idx_stat0.s.index = pstats->chan_start; 1287 ilk_rxx_idx_stat0.s.inc = pstats->chan_step; 1288 ilk_rxx_idx_stat0.s.clr = pstats->clr_on_rd; 1289 cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT0(interface), ilk_rxx_idx_stat0.u64); 1290 1291 ilk_rxx_idx_stat1.u64 = 0; 1292 ilk_rxx_idx_stat1.s.index = pstats->chan_start; 1293 ilk_rxx_idx_stat1.s.inc = pstats->chan_step; 1294 ilk_rxx_idx_stat1.s.clr = pstats->clr_on_rd; 1295 cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT1(interface), ilk_rxx_idx_stat1.u64); 1296 1297 ilk_txx_idx_stat0.u64 = 0; 1298 ilk_txx_idx_stat0.s.index = pstats->chan_start; 1299 ilk_txx_idx_stat0.s.inc = pstats->chan_step; 1300 ilk_txx_idx_stat0.s.clr = pstats->clr_on_rd; 1301 cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT0(interface), ilk_txx_idx_stat0.u64); 1302 1303 ilk_txx_idx_stat1.u64 = 0; 1304 ilk_txx_idx_stat1.s.index = pstats->chan_start; 1305 ilk_txx_idx_stat1.s.inc = pstats->chan_step; 1306 ilk_txx_idx_stat1.s.clr = pstats->clr_on_rd; 1307 cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT1(interface), ilk_txx_idx_stat1.u64); 1308 1309 for (i = pstats->chan_start; i <= pstats->chan_end; i += pstats->chan_step) 1310 { 1311 ilk_rxx_mem_stat0.u64 = cvmx_read_csr 1312 (CVMX_ILK_RXX_MEM_STAT0(interface)); 1313 ilk_rxx_mem_stat1.u64 = cvmx_read_csr 1314 (CVMX_ILK_RXX_MEM_STAT1(interface)); 1315 cvmx_dprintf ("ILK%d Channel%d Rx: %d packets %d bytes\n", interface, i, 1316 ilk_rxx_mem_stat0.s.rx_pkt, 1317 (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes); 1318 1319 ilk_txx_mem_stat0.u64 = cvmx_read_csr 1320 (CVMX_ILK_TXX_MEM_STAT0(interface)); 1321 ilk_txx_mem_stat1.u64 = cvmx_read_csr 1322 (CVMX_ILK_TXX_MEM_STAT1(interface)); 1323 cvmx_dprintf ("ILK%d Channel%d Tx: %d packets %d bytes\n", interface, i, 1324 ilk_rxx_mem_stat0.s.rx_pkt, 1325 (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes); 1326 } 1327 1328 return; 1329} 1330 1331/** 1332 * enable or disable loopbacks 1333 * 1334 * @param interface The identifier of the packet interface to disable. cn68xx 1335 * has 2 interfaces: ilk0 and ilk1. 1336 * @param enable Enable or disable loopback 1337 * @param mode Internal or external loopback 1338 * 1339 * @return Zero on success, negative of failure. 1340 */ 1341int cvmx_ilk_lpbk (int interface, cvmx_ilk_lpbk_ena_t enable, 1342 cvmx_ilk_lpbk_mode_t mode) 1343{ 1344 int res = -1; 1345 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0; 1346 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0; 1347 1348 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX))) 1349 return res; 1350 1351 if (interface >= CVMX_NUM_ILK_INTF) 1352 return res; 1353 1354 /* internal loopback. only 1 type of loopback can be on at 1 time */ 1355 if (mode == CVMX_ILK_LPBK_INT) 1356 { 1357 if (enable == CVMX_ILK_LPBK_ENA) 1358 { 1359 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1360 ilk_txx_cfg0.s.ext_lpbk = CVMX_ILK_LPBK_DISA; 1361 ilk_txx_cfg0.s.ext_lpbk_fc = CVMX_ILK_LPBK_DISA; 1362 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1363 1364 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 1365 ilk_rxx_cfg0.s.ext_lpbk = CVMX_ILK_LPBK_DISA; 1366 ilk_rxx_cfg0.s.ext_lpbk_fc = CVMX_ILK_LPBK_DISA; 1367 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 1368 } 1369 1370 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1371 ilk_txx_cfg0.s.int_lpbk = enable; 1372 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1373 1374 res = 0; 1375 return res; 1376 } 1377 1378 /* external loopback. only 1 type of loopback can be on at 1 time */ 1379 if (enable == CVMX_ILK_LPBK_ENA) 1380 { 1381 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1382 ilk_txx_cfg0.s.int_lpbk = CVMX_ILK_LPBK_DISA; 1383 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1384 } 1385 1386 ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface)); 1387 ilk_txx_cfg0.s.ext_lpbk = enable; 1388 ilk_txx_cfg0.s.ext_lpbk_fc = enable; 1389 cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64); 1390 1391 ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface)); 1392 ilk_rxx_cfg0.s.ext_lpbk = enable; 1393 ilk_rxx_cfg0.s.ext_lpbk_fc = enable; 1394 cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64); 1395 1396 res = 0; 1397 return res; 1398} 1399 1400#endif /* CVMX_ENABLE_HELPER_FUNCTIONS */ 1401