1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018-2022 Marvell International Ltd. 4 * 5 * Functions to configure the BGX MAC. 6 */ 7 8#include <log.h> 9#include <linux/delay.h> 10 11#include <mach/cvmx-regs.h> 12#include <mach/cvmx-csr.h> 13#include <mach/cvmx-bootmem.h> 14#include <mach/octeon-model.h> 15#include <mach/cvmx-fuse.h> 16#include <mach/octeon-feature.h> 17#include <mach/cvmx-qlm.h> 18#include <mach/octeon_qlm.h> 19#include <mach/cvmx-pcie.h> 20#include <mach/cvmx-coremask.h> 21 22#include <mach/cvmx-agl-defs.h> 23#include <mach/cvmx-bgxx-defs.h> 24#include <mach/cvmx-gmxx-defs.h> 25#include <mach/cvmx-ipd-defs.h> 26#include <mach/cvmx-pki-defs.h> 27#include <mach/cvmx-xcv-defs.h> 28 29#include <mach/cvmx-helper.h> 30#include <mach/cvmx-helper-board.h> 31#include <mach/cvmx-helper-fdt.h> 32#include <mach/cvmx-helper-bgx.h> 33#include <mach/cvmx-helper-cfg.h> 34#include <mach/cvmx-helper-util.h> 35#include <mach/cvmx-helper-pki.h> 36 37#include <mach/cvmx-global-resources.h> 38#include <mach/cvmx-pko-internal-ports-range.h> 39#include <mach/cvmx-ilk.h> 40#include <mach/cvmx-pip.h> 41 42/* Enable this define to see BGX error messages */ 43/*#define DEBUG_BGX */ 44 45/* Enable this variable to trace functions called for initializing BGX */ 46static const int debug; 47 48/** 49 * cvmx_helper_bgx_override_autoneg(int xiface, int index) is a function pointer 50 * to override enabling/disabling of autonegotiation for SGMII, 10G-KR or 40G-KR4 51 * interfaces. This function is called when interface is initialized. 52 */ 53int (*cvmx_helper_bgx_override_autoneg)(int xiface, int index) = NULL; 54 55/* 56 * cvmx_helper_bgx_override_fec(int xiface) is a function pointer 57 * to override enabling/disabling of FEC for 10G interfaces. This function 58 * is called when interface is initialized. 59 */ 60int (*cvmx_helper_bgx_override_fec)(int xiface, int index) = NULL; 61 62/** 63 * Delay after enabling an interface based on the mode. Different modes take 64 * different amounts of time. 65 */ 66static void 67__cvmx_helper_bgx_interface_enable_delay(cvmx_helper_interface_mode_t mode) 68{ 69 switch (mode) { 70 case CVMX_HELPER_INTERFACE_MODE_10G_KR: 71 case CVMX_HELPER_INTERFACE_MODE_40G_KR4: 72 case CVMX_HELPER_INTERFACE_MODE_XLAUI: 73 case CVMX_HELPER_INTERFACE_MODE_XFI: 74 mdelay(250); 75 break; 76 case CVMX_HELPER_INTERFACE_MODE_RXAUI: 77 case CVMX_HELPER_INTERFACE_MODE_XAUI: 78 mdelay(100); 79 break; 80 case CVMX_HELPER_INTERFACE_MODE_SGMII: 81 mdelay(50); 82 break; 83 default: 84 mdelay(50); 85 break; 86 } 87} 88 89/** 90 * @INTERNAL 91 * 92 * Returns number of ports based on interface 93 * @param xiface Which xiface 94 * @return Number of ports based on xiface 95 */ 96int __cvmx_helper_bgx_enumerate(int xiface) 97{ 98 cvmx_bgxx_cmr_tx_lmacs_t lmacs; 99 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 100 101 lmacs.u64 = csr_rd_node(xi.node, CVMX_BGXX_CMR_TX_LMACS(xi.interface)); 102 return lmacs.s.lmacs; 103} 104 105/** 106 * @INTERNAL 107 * 108 * Returns mode of each BGX LMAC (port). 109 * This is different than 'cvmx_helper_interface_get_mode()' which 110 * provides mode of an entire interface, but when BGX is in "mixed" 111 * mode this function should be called instead to get the protocol 112 * for each port (BGX LMAC) individually. 113 * Both function return the same enumerated mode. 114 * 115 * @param xiface is the global interface identifier 116 * @param index is the interface port index 117 * @returns mode of the individual port 118 */ 119cvmx_helper_interface_mode_t cvmx_helper_bgx_get_mode(int xiface, int index) 120{ 121 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 122 cvmx_bgxx_cmrx_config_t cmr_config; 123 cvmx_bgxx_spux_br_pmd_control_t pmd_control; 124 125 cmr_config.u64 = csr_rd_node( 126 xi.node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 127 128 switch (cmr_config.s.lmac_type) { 129 case 0: 130 return CVMX_HELPER_INTERFACE_MODE_SGMII; 131 case 1: 132 return CVMX_HELPER_INTERFACE_MODE_XAUI; 133 case 2: 134 return CVMX_HELPER_INTERFACE_MODE_RXAUI; 135 case 3: 136 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) 137 return cvmx_helper_interface_get_mode(xiface); 138 pmd_control.u64 = csr_rd_node( 139 xi.node, 140 CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, xi.interface)); 141 if (pmd_control.s.train_en) 142 return CVMX_HELPER_INTERFACE_MODE_10G_KR; 143 else 144 return CVMX_HELPER_INTERFACE_MODE_XFI; 145 break; 146 case 4: 147 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) 148 return cvmx_helper_interface_get_mode(xiface); 149 pmd_control.u64 = csr_rd_node( 150 xi.node, 151 CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, xi.interface)); 152 if (pmd_control.s.train_en) 153 return CVMX_HELPER_INTERFACE_MODE_40G_KR4; 154 else 155 return CVMX_HELPER_INTERFACE_MODE_XLAUI; 156 break; 157 case 5: 158 return CVMX_HELPER_INTERFACE_MODE_RGMII; 159 default: 160 return CVMX_HELPER_INTERFACE_MODE_DISABLED; 161 } 162} 163 164static int __cvmx_helper_bgx_rgmii_speed(cvmx_helper_link_info_t link_info) 165{ 166 cvmx_xcv_reset_t xcv_reset; 167 cvmx_xcv_ctl_t xcv_ctl; 168 cvmx_xcv_batch_crd_ret_t crd_ret; 169 cvmx_xcv_dll_ctl_t dll_ctl; 170 cvmx_xcv_comp_ctl_t comp_ctl; 171 int speed; 172 int up = link_info.s.link_up; 173 int do_credits; 174 175 if (link_info.s.speed == 100) 176 speed = 1; 177 else if (link_info.s.speed == 10) 178 speed = 0; 179 else 180 speed = 2; 181 182 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 183 xcv_ctl.u64 = csr_rd(CVMX_XCV_CTL); 184 do_credits = up && !xcv_reset.s.enable; 185 186 if (xcv_ctl.s.lpbk_int) { 187 xcv_reset.s.clkrst = 0; 188 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 189 } 190 191 if (up && (!xcv_reset.s.enable || xcv_ctl.s.speed != speed)) { 192 if (debug) 193 debug("%s: *** Enabling XCV block\n", __func__); 194 /* Enable the XCV block */ 195 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 196 xcv_reset.s.enable = 1; 197 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 198 199 /* Set operating mode */ 200 xcv_ctl.u64 = csr_rd(CVMX_XCV_CTL); 201 xcv_ctl.s.speed = speed; 202 csr_wr(CVMX_XCV_CTL, xcv_ctl.u64); 203 204 /* Configure DLL - enable or bypass */ 205 /* TX no bypass, RX bypass */ 206 dll_ctl.u64 = csr_rd(CVMX_XCV_DLL_CTL); 207 dll_ctl.s.clkrx_set = 0; 208 dll_ctl.s.clkrx_byp = 1; 209 dll_ctl.s.clktx_byp = 0; 210 csr_wr(CVMX_XCV_DLL_CTL, dll_ctl.u64); 211 212 /* Enable */ 213 dll_ctl.u64 = csr_rd(CVMX_XCV_DLL_CTL); 214 dll_ctl.s.refclk_sel = 0; 215 csr_wr(CVMX_XCV_DLL_CTL, dll_ctl.u64); 216 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 217 xcv_reset.s.dllrst = 0; 218 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 219 220 /* Delay deems to be need so XCV_DLL_CTL[CLK_SET] works */ 221 udelay(10); 222 223 comp_ctl.u64 = csr_rd(CVMX_XCV_COMP_CTL); 224 //comp_ctl.s.drv_pctl = 0; 225 //comp_ctl.s.drv_nctl = 0; 226 comp_ctl.s.drv_byp = 0; 227 csr_wr(CVMX_XCV_COMP_CTL, comp_ctl.u64); 228 229 /* enable */ 230 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 231 xcv_reset.s.comp = 1; 232 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 233 234 /* setup the RXC */ 235 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 236 xcv_reset.s.clkrst = !xcv_ctl.s.lpbk_int; 237 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 238 239 /* datapaths come out of the reset 240 * - the datapath resets will disengage BGX from the RGMII 241 * interface 242 * - XCV will continue to return TX credits for each tick that 243 * is sent on the TX data path 244 */ 245 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 246 xcv_reset.s.tx_dat_rst_n = 1; 247 xcv_reset.s.rx_dat_rst_n = 1; 248 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 249 } else if (debug) { 250 debug("%s: *** Not enabling XCV\n", __func__); 251 debug(" up: %s, xcv_reset.s.enable: %d, xcv_ctl.s.speed: %d, speed: %d\n", 252 up ? "true" : "false", (unsigned int)xcv_reset.s.enable, 253 (unsigned int)xcv_ctl.s.speed, speed); 254 } 255 256 /* enable the packet flow 257 * - The packet resets will be only disengage on packet boundaries 258 * - XCV will continue to return TX credits for each tick that is 259 * sent on the TX datapath 260 */ 261 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 262 xcv_reset.s.tx_pkt_rst_n = up; 263 xcv_reset.s.rx_pkt_rst_n = up; 264 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 265 266 /* Full reset when link is down */ 267 if (!up) { 268 if (debug) 269 debug("%s: *** Disabling XCV reset\n", __func__); 270 /* wait 2*MTU in time */ 271 mdelay(10); 272 /* reset the world */ 273 csr_wr(CVMX_XCV_RESET, 0); 274 } 275 276 /* grant PKO TX credits */ 277 if (do_credits) { 278 crd_ret.u64 = csr_rd(CVMX_XCV_BATCH_CRD_RET); 279 crd_ret.s.crd_ret = 1; 280 csr_wr(CVMX_XCV_BATCH_CRD_RET, crd_ret.u64); 281 } 282 283 return 0; 284} 285 286static void __cvmx_bgx_common_init_pknd(int xiface, int index) 287{ 288 int num_ports; 289 int num_chl = 16; 290 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 291 int node = xi.node; 292 int pknd; 293 cvmx_bgxx_cmrx_rx_bp_on_t bgx_rx_bp_on; 294 cvmx_bgxx_cmrx_rx_id_map_t cmr_rx_id_map; 295 cvmx_bgxx_cmr_chan_msk_and_t chan_msk_and; 296 cvmx_bgxx_cmr_chan_msk_or_t chan_msk_or; 297 298 if (debug) 299 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 300 xi.interface, index); 301 302 num_ports = cvmx_helper_ports_on_interface(xiface); 303 /* Modify bp_on mark, depending on number of LMACS on that interface 304 * and write it for every port 305 */ 306 bgx_rx_bp_on.u64 = 0; 307 bgx_rx_bp_on.s.mark = (CVMX_BGX_RX_FIFO_SIZE / (num_ports * 4 * 16)); 308 309 /* Setup pkind */ 310 pknd = cvmx_helper_get_pknd(xiface, index); 311 cmr_rx_id_map.u64 = csr_rd_node( 312 node, CVMX_BGXX_CMRX_RX_ID_MAP(index, xi.interface)); 313 cmr_rx_id_map.s.pknd = pknd; 314 /* Change the default reassembly id (RID), as max 14 RIDs allowed */ 315 if (OCTEON_IS_MODEL(OCTEON_CN73XX)) 316 cmr_rx_id_map.s.rid = ((4 * xi.interface) + 2 + index); 317 csr_wr_node(node, CVMX_BGXX_CMRX_RX_ID_MAP(index, xi.interface), 318 cmr_rx_id_map.u64); 319 /* Set backpressure channel mask AND/OR registers */ 320 chan_msk_and.u64 = 321 csr_rd_node(node, CVMX_BGXX_CMR_CHAN_MSK_AND(xi.interface)); 322 chan_msk_or.u64 = 323 csr_rd_node(node, CVMX_BGXX_CMR_CHAN_MSK_OR(xi.interface)); 324 chan_msk_and.s.msk_and |= ((1 << num_chl) - 1) << (16 * index); 325 chan_msk_or.s.msk_or |= ((1 << num_chl) - 1) << (16 * index); 326 csr_wr_node(node, CVMX_BGXX_CMR_CHAN_MSK_AND(xi.interface), 327 chan_msk_and.u64); 328 csr_wr_node(node, CVMX_BGXX_CMR_CHAN_MSK_OR(xi.interface), 329 chan_msk_or.u64); 330 /* set rx back pressure (bp_on) on value */ 331 csr_wr_node(node, CVMX_BGXX_CMRX_RX_BP_ON(index, xi.interface), 332 bgx_rx_bp_on.u64); 333} 334 335/** 336 * @INTERNAL 337 * Probe a SGMII interface and determine the number of ports 338 * connected to it. The SGMII interface should still be down after 339 * this call. This is used by interfaces using the bgx mac. 340 * 341 * @param xiface Interface to probe 342 * 343 * @return Number of ports on the interface. Zero to disable. 344 */ 345int __cvmx_helper_bgx_probe(int xiface) 346{ 347 return __cvmx_helper_bgx_enumerate(xiface); 348} 349 350/** 351 * @INTERNAL 352 * Return the size of the BGX TX_FIFO for a given LMAC, 353 * or 0 if the requested LMAC is inactive. 354 * 355 * TBD: Need also to add a "__cvmx_helper_bgx_speed()" function to 356 * return the speed of each LMAC. 357 */ 358int __cvmx_helper_bgx_fifo_size(int xiface, unsigned int lmac) 359{ 360 cvmx_bgxx_cmr_tx_lmacs_t lmacs; 361 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 362 unsigned int tx_fifo_size = CVMX_BGX_TX_FIFO_SIZE; 363 364 /* FIXME: Add validation for interface# < BGX_count */ 365 lmacs.u64 = csr_rd_node(xi.node, CVMX_BGXX_CMR_TX_LMACS(xi.interface)); 366 367 switch (lmacs.s.lmacs) { 368 case 1: 369 if (lmac > 0) 370 return 0; 371 else 372 return tx_fifo_size; 373 case 2: 374 if (lmac > 1) 375 return 0; 376 else 377 return tx_fifo_size >> 1; 378 case 3: 379 if (lmac > 2) 380 return 0; 381 else 382 return tx_fifo_size >> 2; 383 case 4: 384 if (lmac > 3) 385 return 0; 386 else 387 return tx_fifo_size >> 2; 388 default: 389 return 0; 390 } 391} 392 393/** 394 * @INTERNAL 395 * Perform initialization required only once for an SGMII port. 396 * 397 * @param xiface Interface to init 398 * @param index Index of prot on the interface 399 * 400 * @return Zero on success, negative on failure 401 */ 402static int __cvmx_helper_bgx_sgmii_hardware_init_one_time(int xiface, int index) 403{ 404 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 405 int node = xi.node; 406 const u64 clock_mhz = 1200; /* todo: fixme */ 407 cvmx_bgxx_gmp_pcs_miscx_ctl_t gmp_misc_ctl; 408 cvmx_bgxx_gmp_pcs_linkx_timer_t gmp_timer; 409 410 if (!cvmx_helper_is_port_valid(xi.interface, index)) 411 return 0; 412 413 if (debug) 414 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 415 xi.interface, index); 416 417 /* 418 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the 419 * appropriate value. 1000BASE-X specifies a 10ms 420 * interval. SGMII specifies a 1.6ms interval. 421 */ 422 gmp_misc_ctl.u64 = csr_rd_node( 423 node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface)); 424 /* Adjust the MAC mode if requested by device tree */ 425 gmp_misc_ctl.s.mac_phy = cvmx_helper_get_mac_phy_mode(xiface, index); 426 gmp_misc_ctl.s.mode = cvmx_helper_get_1000x_mode(xiface, index); 427 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface), 428 gmp_misc_ctl.u64); 429 430 gmp_timer.u64 = csr_rd_node( 431 node, CVMX_BGXX_GMP_PCS_LINKX_TIMER(index, xi.interface)); 432 if (gmp_misc_ctl.s.mode) 433 /* 1000BASE-X */ 434 gmp_timer.s.count = (10000ull * clock_mhz) >> 10; 435 else 436 /* SGMII */ 437 gmp_timer.s.count = (1600ull * clock_mhz) >> 10; 438 439 csr_wr_node(node, CVMX_BGXX_GMP_PCS_LINKX_TIMER(index, xi.interface), 440 gmp_timer.u64); 441 442 /* 443 * Write the advertisement register to be used as the 444 * tx_Config_Reg<D15:D0> of the autonegotiation. In 445 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG. 446 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is 447 * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode, 448 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this 449 * step can be skipped. 450 */ 451 if (gmp_misc_ctl.s.mode) { 452 /* 1000BASE-X */ 453 cvmx_bgxx_gmp_pcs_anx_adv_t gmp_an_adv; 454 455 gmp_an_adv.u64 = csr_rd_node( 456 node, CVMX_BGXX_GMP_PCS_ANX_ADV(index, xi.interface)); 457 gmp_an_adv.s.rem_flt = 0; 458 gmp_an_adv.s.pause = 3; 459 gmp_an_adv.s.hfd = 1; 460 gmp_an_adv.s.fd = 1; 461 csr_wr_node(node, 462 CVMX_BGXX_GMP_PCS_ANX_ADV(index, xi.interface), 463 gmp_an_adv.u64); 464 } else { 465 if (gmp_misc_ctl.s.mac_phy) { 466 /* PHY Mode */ 467 cvmx_bgxx_gmp_pcs_sgmx_an_adv_t gmp_sgmx_an_adv; 468 469 gmp_sgmx_an_adv.u64 = 470 csr_rd_node(node, CVMX_BGXX_GMP_PCS_SGMX_AN_ADV( 471 index, xi.interface)); 472 gmp_sgmx_an_adv.s.dup = 1; 473 gmp_sgmx_an_adv.s.speed = 2; 474 csr_wr_node(node, 475 CVMX_BGXX_GMP_PCS_SGMX_AN_ADV(index, 476 xi.interface), 477 gmp_sgmx_an_adv.u64); 478 } else { 479 /* MAC Mode - Nothing to do */ 480 } 481 } 482 return 0; 483} 484 485/** 486 * @INTERNAL 487 * Bring up the SGMII interface to be ready for packet I/O but 488 * leave I/O disabled using the GMX override. This function 489 * follows the bringup documented in 10.6.3 of the manual. 490 * 491 * @param xiface Interface to bringup 492 * @param num_ports Number of ports on the interface 493 * 494 * @return Zero on success, negative on failure 495 */ 496static int __cvmx_helper_bgx_sgmii_hardware_init(int xiface, int num_ports) 497{ 498 int index; 499 int do_link_set = 1; 500 501 for (index = 0; index < num_ports; index++) { 502 int xipd_port = cvmx_helper_get_ipd_port(xiface, index); 503 cvmx_helper_interface_mode_t mode; 504 505 if (!cvmx_helper_is_port_valid(xiface, index)) 506 continue; 507 508 __cvmx_helper_bgx_port_init(xipd_port, 0); 509 510 mode = cvmx_helper_bgx_get_mode(xiface, index); 511 if (mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 512 continue; 513 514 if (do_link_set) 515 __cvmx_helper_bgx_sgmii_link_set( 516 xipd_port, 517 __cvmx_helper_bgx_sgmii_link_get(xipd_port)); 518 } 519 520 return 0; 521} 522 523/** 524 * @INTERNAL 525 * Bringup and enable a SGMII interface. After this call packet 526 * I/O should be fully functional. This is called with IPD 527 * enabled but PKO disabled. This is used by interfaces using 528 * the bgx mac. 529 * 530 * @param xiface Interface to bring up 531 * 532 * @return Zero on success, negative on failure 533 */ 534int __cvmx_helper_bgx_sgmii_enable(int xiface) 535{ 536 int num_ports; 537 538 num_ports = cvmx_helper_ports_on_interface(xiface); 539 __cvmx_helper_bgx_sgmii_hardware_init(xiface, num_ports); 540 541 return 0; 542} 543 544/** 545 * @INTERNAL 546 * Initialize the SERDES link for the first time or after a loss 547 * of link. 548 * 549 * @param xiface Interface to init 550 * @param index Index of prot on the interface 551 * 552 * @return Zero on success, negative on failure 553 */ 554static int __cvmx_helper_bgx_sgmii_hardware_init_link(int xiface, int index) 555{ 556 cvmx_bgxx_gmp_pcs_mrx_control_t gmp_control; 557 cvmx_bgxx_gmp_pcs_miscx_ctl_t gmp_misc_ctl; 558 cvmx_bgxx_cmrx_config_t cmr_config; 559 int phy_mode, mode_1000x; 560 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 561 int interface = xi.interface; 562 int node = xi.node; 563 int autoneg = 0; 564 565 if (!cvmx_helper_is_port_valid(xiface, index)) 566 return 0; 567 568 if (debug) 569 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 570 xi.interface, index); 571 572 gmp_control.u64 = csr_rd_node( 573 node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface)); 574 /* Take PCS through a reset sequence */ 575 gmp_control.s.reset = 1; 576 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface), 577 gmp_control.u64); 578 579 /* Wait until GMP_PCS_MRX_CONTROL[reset] comes out of reset */ 580 if (CVMX_WAIT_FOR_FIELD64_NODE( 581 node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface), 582 cvmx_bgxx_gmp_pcs_mrx_control_t, reset, ==, 0, 10000)) { 583 debug("SGMII%d: Timeout waiting for port %d to finish reset\n", 584 interface, index); 585 return -1; 586 } 587 588 cmr_config.u64 = 589 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 590 591 gmp_control.u64 = csr_rd_node( 592 node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface)); 593 if (cvmx_helper_get_port_phy_present(xiface, index)) { 594 gmp_control.s.pwr_dn = 0; 595 } else { 596 gmp_control.s.spdmsb = 1; 597 gmp_control.s.spdlsb = 0; 598 gmp_control.s.pwr_dn = 0; 599 } 600 /* Write GMP_PCS_MR*_CONTROL[RST_AN]=1 to ensure a fresh SGMII 601 * negotiation starts. 602 */ 603 autoneg = cvmx_helper_get_port_autonegotiation(xiface, index); 604 gmp_control.s.rst_an = 1; 605 gmp_control.s.an_en = (cmr_config.s.lmac_type != 5) && autoneg; 606 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface), 607 gmp_control.u64); 608 609 phy_mode = cvmx_helper_get_mac_phy_mode(xiface, index); 610 mode_1000x = cvmx_helper_get_1000x_mode(xiface, index); 611 612 gmp_misc_ctl.u64 = csr_rd_node( 613 node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface)); 614 gmp_misc_ctl.s.mac_phy = phy_mode; 615 gmp_misc_ctl.s.mode = mode_1000x; 616 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface), 617 gmp_misc_ctl.u64); 618 619 if (phy_mode || !autoneg) 620 /* In PHY mode we can't query the link status so we just 621 * assume that the link is up 622 */ 623 return 0; 624 625 /* Wait for GMP_PCS_MRX_CONTROL[an_cpt] to be set, indicating that 626 * SGMII autonegotiation is complete. In MAC mode this isn't an 627 * ethernet link, but a link between OCTEON and PHY. 628 */ 629 if (cmr_config.s.lmac_type != 5 && 630 CVMX_WAIT_FOR_FIELD64_NODE( 631 node, CVMX_BGXX_GMP_PCS_MRX_STATUS(index, xi.interface), 632 cvmx_bgxx_gmp_pcs_mrx_status_t, an_cpt, ==, 1, 10000)) { 633 debug("SGMII%d: Port %d link timeout\n", interface, index); 634 return -1; 635 } 636 637 return 0; 638} 639 640/** 641 * @INTERNAL 642 * Configure an SGMII link to the specified speed after the SERDES 643 * link is up. 644 * 645 * @param xiface Interface to init 646 * @param index Index of prot on the interface 647 * @param link_info Link state to configure 648 * 649 * @return Zero on success, negative on failure 650 */ 651static int __cvmx_helper_bgx_sgmii_hardware_init_link_speed( 652 int xiface, int index, cvmx_helper_link_info_t link_info) 653{ 654 cvmx_bgxx_cmrx_config_t cmr_config; 655 cvmx_bgxx_gmp_pcs_miscx_ctl_t gmp_miscx_ctl; 656 cvmx_bgxx_gmp_gmi_prtx_cfg_t gmp_prtx_cfg; 657 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 658 int node = xi.node; 659 660 if (!cvmx_helper_is_port_valid(xiface, index)) 661 return 0; 662 663 if (debug) 664 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 665 xi.interface, index); 666 667 /* Disable GMX before we make any changes. */ 668 cmr_config.u64 = 669 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 670 cmr_config.s.data_pkt_tx_en = 0; 671 cmr_config.s.data_pkt_rx_en = 0; 672 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 673 cmr_config.u64); 674 675 /* Wait for GMX to be idle */ 676 if (CVMX_WAIT_FOR_FIELD64_NODE( 677 node, CVMX_BGXX_GMP_GMI_PRTX_CFG(index, xi.interface), 678 cvmx_bgxx_gmp_gmi_prtx_cfg_t, rx_idle, ==, 1, 10000) || 679 CVMX_WAIT_FOR_FIELD64_NODE( 680 node, CVMX_BGXX_GMP_GMI_PRTX_CFG(index, xi.interface), 681 cvmx_bgxx_gmp_gmi_prtx_cfg_t, tx_idle, ==, 1, 10000)) { 682 debug("SGMII%d:%d: Timeout waiting for port %d to be idle\n", 683 node, xi.interface, index); 684 return -1; 685 } 686 687 /* Read GMX CFG again to make sure the disable completed */ 688 gmp_prtx_cfg.u64 = csr_rd_node( 689 node, CVMX_BGXX_GMP_GMI_PRTX_CFG(index, xi.interface)); 690 691 /* 692 * Get the misc control for PCS. We will need to set the 693 * duplication amount. 694 */ 695 gmp_miscx_ctl.u64 = csr_rd_node( 696 node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface)); 697 698 /* 699 * Use GMXENO to force the link down if the status we get says 700 * it should be down. 701 */ 702 gmp_miscx_ctl.s.gmxeno = !link_info.s.link_up; 703 704 /* Only change the duplex setting if the link is up */ 705 if (link_info.s.link_up) 706 gmp_prtx_cfg.s.duplex = link_info.s.full_duplex; 707 708 /* Do speed based setting for GMX */ 709 switch (link_info.s.speed) { 710 case 10: 711 gmp_prtx_cfg.s.speed = 0; 712 gmp_prtx_cfg.s.speed_msb = 1; 713 gmp_prtx_cfg.s.slottime = 0; 714 /* Setting from GMX-603 */ 715 gmp_miscx_ctl.s.samp_pt = 25; 716 csr_wr_node(node, 717 CVMX_BGXX_GMP_GMI_TXX_SLOT(index, xi.interface), 718 64); 719 csr_wr_node(node, 720 CVMX_BGXX_GMP_GMI_TXX_BURST(index, xi.interface), 721 0); 722 break; 723 case 100: 724 gmp_prtx_cfg.s.speed = 0; 725 gmp_prtx_cfg.s.speed_msb = 0; 726 gmp_prtx_cfg.s.slottime = 0; 727 gmp_miscx_ctl.s.samp_pt = 0x5; 728 csr_wr_node(node, 729 CVMX_BGXX_GMP_GMI_TXX_SLOT(index, xi.interface), 730 64); 731 csr_wr_node(node, 732 CVMX_BGXX_GMP_GMI_TXX_BURST(index, xi.interface), 733 0); 734 break; 735 case 1000: 736 gmp_prtx_cfg.s.speed = 1; 737 gmp_prtx_cfg.s.speed_msb = 0; 738 gmp_prtx_cfg.s.slottime = 1; 739 gmp_miscx_ctl.s.samp_pt = 1; 740 csr_wr_node(node, 741 CVMX_BGXX_GMP_GMI_TXX_SLOT(index, xi.interface), 742 512); 743 if (gmp_prtx_cfg.s.duplex) 744 /* full duplex */ 745 csr_wr_node(node, 746 CVMX_BGXX_GMP_GMI_TXX_BURST(index, 747 xi.interface), 748 0); 749 else 750 /* half duplex */ 751 csr_wr_node(node, 752 CVMX_BGXX_GMP_GMI_TXX_BURST(index, 753 xi.interface), 754 8192); 755 break; 756 default: 757 break; 758 } 759 760 /* Write the new misc control for PCS */ 761 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface), 762 gmp_miscx_ctl.u64); 763 764 /* Write the new GMX settings with the port still disabled */ 765 csr_wr_node(node, CVMX_BGXX_GMP_GMI_PRTX_CFG(index, xi.interface), 766 gmp_prtx_cfg.u64); 767 768 /* Read GMX CFG again to make sure the config completed */ 769 csr_rd_node(node, CVMX_BGXX_GMP_GMI_PRTX_CFG(index, xi.interface)); 770 771 /* Enable back BGX. */ 772 cmr_config.u64 = 773 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 774 if (debug) 775 debug("%s: Enabling tx and rx packets on %d:%d\n", __func__, 776 xi.interface, index); 777 cmr_config.s.data_pkt_tx_en = 1; 778 cmr_config.s.data_pkt_rx_en = 1; 779 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 780 cmr_config.u64); 781 782 return 0; 783} 784 785/** 786 * @INTERNAL 787 * Return the link state of an IPD/PKO port as returned by 788 * auto negotiation. The result of this function may not match 789 * Octeon's link config if auto negotiation has changed since 790 * the last call to cvmx_helper_link_set(). This is used by 791 * interfaces using the bgx mac. 792 * 793 * @param xipd_port IPD/PKO port to query 794 * 795 * @return Link state 796 */ 797cvmx_helper_link_info_t __cvmx_helper_bgx_sgmii_link_get(int xipd_port) 798{ 799 cvmx_helper_link_info_t result; 800 cvmx_bgxx_gmp_pcs_mrx_control_t gmp_control; 801 cvmx_bgxx_gmp_pcs_miscx_ctl_t gmp_misc_ctl; 802 int xiface = cvmx_helper_get_interface_num(xipd_port); 803 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 804 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 805 int node = xi.node; 806 int index = cvmx_helper_get_interface_index_num(xp.port); 807 808 result.u64 = 0; 809 810 if (!cvmx_helper_is_port_valid(xiface, index)) 811 return result; 812 813 if (debug) 814 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 815 xi.interface, index); 816 817 gmp_control.u64 = csr_rd_node( 818 node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface)); 819 if (gmp_control.s.loopbck1) { 820 int qlm = cvmx_qlm_lmac(xiface, index); 821 int speed; 822 823 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 824 speed = cvmx_qlm_get_gbaud_mhz_node(node, qlm); 825 else 826 speed = cvmx_qlm_get_gbaud_mhz(qlm); 827 /* Force 1Gbps full duplex link for internal loopback */ 828 result.s.link_up = 1; 829 result.s.full_duplex = 1; 830 result.s.speed = speed * 8 / 10; 831 return result; 832 } 833 834 gmp_misc_ctl.u64 = csr_rd_node( 835 node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface)); 836 if (gmp_misc_ctl.s.mac_phy || 837 cvmx_helper_get_port_force_link_up(xiface, index)) { 838 int qlm = cvmx_qlm_lmac(xiface, index); 839 int speed; 840 841 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 842 speed = cvmx_qlm_get_gbaud_mhz_node(node, qlm); 843 else 844 speed = cvmx_qlm_get_gbaud_mhz(qlm); 845 /* PHY Mode */ 846 /* Note that this also works for 1000base-X mode */ 847 848 result.s.speed = speed * 8 / 10; 849 result.s.full_duplex = 1; 850 result.s.link_up = 1; 851 return result; 852 } 853 854 /* MAC Mode */ 855 return __cvmx_helper_board_link_get(xipd_port); 856} 857 858/** 859 * This sequence brings down the link for the XCV RGMII interface 860 * 861 * @param interface Interface (BGX) number. Port index is always 0 862 */ 863static void __cvmx_helper_bgx_rgmii_link_set_down(int interface) 864{ 865 union cvmx_xcv_reset xcv_reset; 866 union cvmx_bgxx_cmrx_config cmr_config; 867 union cvmx_bgxx_gmp_pcs_mrx_control mr_control; 868 union cvmx_bgxx_cmrx_rx_fifo_len rx_fifo_len; 869 union cvmx_bgxx_cmrx_tx_fifo_len tx_fifo_len; 870 871 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 872 xcv_reset.s.rx_pkt_rst_n = 0; 873 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 874 csr_rd(CVMX_XCV_RESET); 875 mdelay(10); /* Wait for 1 MTU */ 876 877 cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(0, interface)); 878 cmr_config.s.data_pkt_rx_en = 0; 879 csr_wr(CVMX_BGXX_CMRX_CONFIG(0, interface), cmr_config.u64); 880 881 /* Wait for RX and TX to be idle */ 882 do { 883 rx_fifo_len.u64 = 884 csr_rd(CVMX_BGXX_CMRX_RX_FIFO_LEN(0, interface)); 885 tx_fifo_len.u64 = 886 csr_rd(CVMX_BGXX_CMRX_TX_FIFO_LEN(0, interface)); 887 } while (rx_fifo_len.s.fifo_len > 0 && tx_fifo_len.s.lmac_idle != 1); 888 889 cmr_config.u64 = csr_rd(CVMX_BGXX_CMRX_CONFIG(0, interface)); 890 cmr_config.s.data_pkt_tx_en = 0; 891 csr_wr(CVMX_BGXX_CMRX_CONFIG(0, interface), cmr_config.u64); 892 893 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 894 xcv_reset.s.tx_pkt_rst_n = 0; 895 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 896 mr_control.u64 = csr_rd(CVMX_BGXX_GMP_PCS_MRX_CONTROL(0, interface)); 897 mr_control.s.pwr_dn = 1; 898 csr_wr(CVMX_BGXX_GMP_PCS_MRX_CONTROL(0, interface), mr_control.u64); 899} 900 901/** 902 * Sets a BGS SGMII link down. 903 * 904 * @param node Octeon node number 905 * @param iface BGX interface number 906 * @param index BGX port index 907 */ 908static void __cvmx_helper_bgx_sgmii_link_set_down(int node, int iface, 909 int index) 910{ 911 union cvmx_bgxx_gmp_pcs_miscx_ctl gmp_misc_ctl; 912 union cvmx_bgxx_gmp_pcs_mrx_control gmp_control; 913 union cvmx_bgxx_cmrx_config cmr_config; 914 915 cmr_config.u64 = csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, iface)); 916 cmr_config.s.data_pkt_tx_en = 0; 917 cmr_config.s.data_pkt_rx_en = 0; 918 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, iface), cmr_config.u64); 919 920 gmp_misc_ctl.u64 = 921 csr_rd_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, iface)); 922 923 /* Disable autonegotiation only when in MAC mode. */ 924 if (gmp_misc_ctl.s.mac_phy == 0) { 925 gmp_control.u64 = csr_rd_node( 926 node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, iface)); 927 gmp_control.s.an_en = 0; 928 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, iface), 929 gmp_control.u64); 930 } 931 932 /* Use GMXENO to force the link down. It will get reenabled later... */ 933 gmp_misc_ctl.s.gmxeno = 1; 934 csr_wr_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, iface), 935 gmp_misc_ctl.u64); 936 csr_rd_node(node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, iface)); 937} 938 939/** 940 * @INTERNAL 941 * Configure an IPD/PKO port for the specified link state. This 942 * function does not influence auto negotiation at the PHY level. 943 * The passed link state must always match the link state returned 944 * by cvmx_helper_link_get(). It is normally best to use 945 * cvmx_helper_link_autoconf() instead. This is used by interfaces 946 * using the bgx mac. 947 * 948 * @param xipd_port IPD/PKO port to configure 949 * @param link_info The new link state 950 * 951 * @return Zero on success, negative on failure 952 */ 953int __cvmx_helper_bgx_sgmii_link_set(int xipd_port, 954 cvmx_helper_link_info_t link_info) 955{ 956 cvmx_bgxx_cmrx_config_t cmr_config; 957 int xiface = cvmx_helper_get_interface_num(xipd_port); 958 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 959 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 960 int node = xi.node; 961 int index = cvmx_helper_get_interface_index_num(xp.port); 962 const int iface = xi.interface; 963 int rc = 0; 964 965 if (!cvmx_helper_is_port_valid(xiface, index)) 966 return 0; 967 968 if (debug) 969 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 970 xi.interface, index); 971 972 cmr_config.u64 = csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, iface)); 973 if (link_info.s.link_up) { 974 cmr_config.s.enable = 1; 975 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, iface), 976 cmr_config.u64); 977 /* Apply workaround for errata BGX-22429 */ 978 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && index) { 979 cvmx_bgxx_cmrx_config_t cmr0; 980 981 cmr0.u64 = csr_rd_node(node, 982 CVMX_BGXX_CMRX_CONFIG(0, iface)); 983 cmr0.s.enable = 1; 984 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(0, iface), 985 cmr0.u64); 986 } 987 __cvmx_helper_bgx_sgmii_hardware_init_link(xiface, index); 988 } else if (cvmx_helper_bgx_is_rgmii(xi.interface, index)) { 989 if (debug) 990 debug("%s: Bringing down XCV RGMII interface %d\n", 991 __func__, xi.interface); 992 __cvmx_helper_bgx_rgmii_link_set_down(xi.interface); 993 } else { /* Link is down, not RGMII */ 994 __cvmx_helper_bgx_sgmii_link_set_down(node, iface, index); 995 return 0; 996 } 997 rc = __cvmx_helper_bgx_sgmii_hardware_init_link_speed(xiface, index, 998 link_info); 999 if (cvmx_helper_bgx_is_rgmii(xiface, index)) 1000 rc = __cvmx_helper_bgx_rgmii_speed(link_info); 1001 1002 return rc; 1003} 1004 1005/** 1006 * @INTERNAL 1007 * Bringup XAUI interface. After this call packet I/O should be 1008 * fully functional. 1009 * 1010 * @param index port on interface to bring up 1011 * @param xiface Interface to bring up 1012 * 1013 * @return Zero on success, negative on failure 1014 */ 1015static int __cvmx_helper_bgx_xaui_init(int index, int xiface) 1016{ 1017 cvmx_bgxx_cmrx_config_t cmr_config; 1018 cvmx_bgxx_spux_br_pmd_control_t pmd_control; 1019 cvmx_bgxx_spux_misc_control_t spu_misc_control; 1020 cvmx_bgxx_spux_control1_t spu_control1; 1021 cvmx_bgxx_spux_an_control_t spu_an_control; 1022 cvmx_bgxx_spux_an_adv_t spu_an_adv; 1023 cvmx_bgxx_spux_fec_control_t spu_fec_control; 1024 cvmx_bgxx_spu_dbg_control_t spu_dbg_control; 1025 cvmx_bgxx_smux_tx_append_t smu_tx_append; 1026 cvmx_bgxx_smux_tx_ctl_t smu_tx_ctl; 1027 cvmx_helper_interface_mode_t mode; 1028 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 1029 int interface = xi.interface; 1030 int node = xi.node; 1031 int use_auto_neg = 0; 1032 int kr_mode = 0; 1033 1034 if (debug) 1035 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 1036 xi.interface, index); 1037 1038 mode = cvmx_helper_bgx_get_mode(xiface, index); 1039 1040 if (mode == CVMX_HELPER_INTERFACE_MODE_10G_KR || 1041 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4) { 1042 kr_mode = 1; 1043 if (cvmx_helper_bgx_override_autoneg) 1044 use_auto_neg = 1045 cvmx_helper_bgx_override_autoneg(xiface, index); 1046 else 1047 use_auto_neg = cvmx_helper_get_port_autonegotiation( 1048 xiface, index); 1049 } 1050 1051 /* NOTE: This code was moved first, out of order compared to the HRM 1052 * because the RESET causes all SPU registers to loose their value 1053 */ 1054 /* 4. Next, bring up the SMU/SPU and the BGX reconciliation layer 1055 * logic: 1056 */ 1057 /* 4a. Take SMU/SPU through a reset sequence. Write 1058 * BGX(0..5)_SPU(0..3)_CONTROL1[RESET] = 1. Read 1059 * BGX(0..5)_SPU(0..3)_CONTROL1[RESET] until it changes value to 0. Keep 1060 * BGX(0..5)_SPU(0..3)_MISC_CONTROL[RX_PACKET_DIS] = 1 to disable 1061 * reception. 1062 */ 1063 spu_control1.u64 = 1064 csr_rd_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 1065 spu_control1.s.reset = 1; 1066 csr_wr_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1067 spu_control1.u64); 1068 1069 /* 1. Wait for PCS to come out of reset */ 1070 if (CVMX_WAIT_FOR_FIELD64_NODE( 1071 node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1072 cvmx_bgxx_spux_control1_t, reset, ==, 0, 10000)) { 1073 debug("BGX%d:%d: SPU stuck in reset\n", node, interface); 1074 return -1; 1075 } 1076 1077 /* 2. Write BGX(0..5)_CMR(0..3)_CONFIG[ENABLE] to 0, 1078 * BGX(0..5)_SPU(0..3)_CONTROL1[LO_PWR] = 1 and 1079 * BGX(0..5)_SPU(0..3)_MISC_CONTROL[RX_PACKET_DIS] = 1. 1080 */ 1081 spu_control1.u64 = 1082 csr_rd_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 1083 spu_control1.s.lo_pwr = 1; 1084 csr_wr_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1085 spu_control1.u64); 1086 1087 spu_misc_control.u64 = csr_rd_node( 1088 node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface)); 1089 spu_misc_control.s.rx_packet_dis = 1; 1090 csr_wr_node(node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface), 1091 spu_misc_control.u64); 1092 1093 /* 3. At this point, it may be appropriate to disable all BGX and 1094 * SMU/SPU interrupts, as a number of them will occur during bring-up 1095 * of the Link. 1096 * - zero BGX(0..5)_SMU(0..3)_RX_INT 1097 * - zero BGX(0..5)_SMU(0..3)_TX_INT 1098 * - zero BGX(0..5)_SPU(0..3)_INT 1099 */ 1100 csr_wr_node(node, CVMX_BGXX_SMUX_RX_INT(index, xi.interface), 1101 csr_rd_node(node, 1102 CVMX_BGXX_SMUX_RX_INT(index, xi.interface))); 1103 csr_wr_node(node, CVMX_BGXX_SMUX_TX_INT(index, xi.interface), 1104 csr_rd_node(node, 1105 CVMX_BGXX_SMUX_TX_INT(index, xi.interface))); 1106 csr_wr_node(node, CVMX_BGXX_SPUX_INT(index, xi.interface), 1107 csr_rd_node(node, CVMX_BGXX_SPUX_INT(index, xi.interface))); 1108 1109 /* 4. Configure the BGX LMAC. */ 1110 /* 4a. Configure the LMAC type (40GBASE-R/10GBASE-R/RXAUI/XAUI) and 1111 * SerDes selection in the BGX(0..5)_CMR(0..3)_CONFIG register, but keep 1112 * the ENABLE, DATA_PKT_TX_EN and DATA_PKT_RX_EN bits clear. 1113 */ 1114 /* Already done in bgx_setup_one_time */ 1115 1116 /* 4b. Write BGX(0..5)_SPU(0..3)_CONTROL1[LO_PWR] = 1 and 1117 * BGX(0..5)_SPU(0..3)_MISC_CONTROL[RX_PACKET_DIS] = 1. 1118 */ 1119 /* 4b. Initialize the selected SerDes lane(s) in the QLM. See Section 1120 * 28.1.2.2 in the GSER chapter. 1121 */ 1122 /* Already done in QLM setup */ 1123 1124 /* 4c. For 10GBASE-KR or 40GBASE-KR, enable link training by writing 1125 * BGX(0..5)_SPU(0..3)_BR_PMD_CONTROL[TRAIN_EN] = 1. 1126 */ 1127 1128 if (kr_mode && !OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) { 1129 csr_wr_node(node, 1130 CVMX_BGXX_SPUX_BR_PMD_LP_CUP(index, interface), 0); 1131 csr_wr_node(node, 1132 CVMX_BGXX_SPUX_BR_PMD_LD_CUP(index, interface), 0); 1133 csr_wr_node(node, 1134 CVMX_BGXX_SPUX_BR_PMD_LD_REP(index, interface), 0); 1135 pmd_control.u64 = csr_rd_node( 1136 node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, interface)); 1137 pmd_control.s.train_en = 1; 1138 csr_wr_node(node, 1139 CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, interface), 1140 pmd_control.u64); 1141 } 1142 1143 /* 4d. Program all other relevant BGX configuration while 1144 * BGX(0..5)_CMR(0..3)_CONFIG[ENABLE] = 0. This includes all things 1145 * described in this chapter. 1146 */ 1147 /* Always add FCS to PAUSE frames */ 1148 smu_tx_append.u64 = csr_rd_node( 1149 node, CVMX_BGXX_SMUX_TX_APPEND(index, xi.interface)); 1150 smu_tx_append.s.fcs_c = 1; 1151 csr_wr_node(node, CVMX_BGXX_SMUX_TX_APPEND(index, xi.interface), 1152 smu_tx_append.u64); 1153 1154 /* 4e. If Forward Error Correction is desired for 10GBASE-R or 1155 * 40GBASE-R, enable it by writing 1156 * BGX(0..5)_SPU(0..3)_FEC_CONTROL[FEC_EN] = 1. 1157 */ 1158 /* FEC is optional for 10GBASE-KR, 40GBASE-KR4, and XLAUI. We're going 1159 * to disable it by default 1160 */ 1161 spu_fec_control.u64 = csr_rd_node( 1162 node, CVMX_BGXX_SPUX_FEC_CONTROL(index, xi.interface)); 1163 if (cvmx_helper_bgx_override_fec) 1164 spu_fec_control.s.fec_en = 1165 cvmx_helper_bgx_override_fec(xiface, index); 1166 else 1167 spu_fec_control.s.fec_en = 1168 cvmx_helper_get_port_fec(xiface, index); 1169 csr_wr_node(node, CVMX_BGXX_SPUX_FEC_CONTROL(index, xi.interface), 1170 spu_fec_control.u64); 1171 1172 /* 4f. If Auto-Negotiation is desired, configure and enable 1173 * Auto-Negotiation as described in Section 33.6.2. 1174 */ 1175 spu_an_control.u64 = csr_rd_node( 1176 node, CVMX_BGXX_SPUX_AN_CONTROL(index, xi.interface)); 1177 /* Disable extended next pages */ 1178 spu_an_control.s.xnp_en = 0; 1179 spu_an_control.s.an_en = use_auto_neg; 1180 csr_wr_node(node, CVMX_BGXX_SPUX_AN_CONTROL(index, xi.interface), 1181 spu_an_control.u64); 1182 1183 spu_fec_control.u64 = csr_rd_node( 1184 node, CVMX_BGXX_SPUX_FEC_CONTROL(index, xi.interface)); 1185 spu_an_adv.u64 = 1186 csr_rd_node(node, CVMX_BGXX_SPUX_AN_ADV(index, xi.interface)); 1187 spu_an_adv.s.fec_req = spu_fec_control.s.fec_en; 1188 spu_an_adv.s.fec_able = 1; 1189 spu_an_adv.s.a100g_cr10 = 0; 1190 spu_an_adv.s.a40g_cr4 = 0; 1191 spu_an_adv.s.a40g_kr4 = (mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4); 1192 spu_an_adv.s.a10g_kr = (mode == CVMX_HELPER_INTERFACE_MODE_10G_KR); 1193 spu_an_adv.s.a10g_kx4 = 0; 1194 spu_an_adv.s.a1g_kx = 0; 1195 spu_an_adv.s.xnp_able = 0; 1196 spu_an_adv.s.rf = 0; 1197 csr_wr_node(node, CVMX_BGXX_SPUX_AN_ADV(index, xi.interface), 1198 spu_an_adv.u64); 1199 1200 /* 3. Set BGX(0..5)_SPU_DBG_CONTROL[AN_ARB_LINK_CHK_EN] = 1. */ 1201 spu_dbg_control.u64 = 1202 csr_rd_node(node, CVMX_BGXX_SPU_DBG_CONTROL(xi.interface)); 1203 spu_dbg_control.s.an_nonce_match_dis = 1; /* Needed for loopback */ 1204 spu_dbg_control.s.an_arb_link_chk_en |= kr_mode; 1205 csr_wr_node(node, CVMX_BGXX_SPU_DBG_CONTROL(xi.interface), 1206 spu_dbg_control.u64); 1207 1208 /* 4. Execute the link bring-up sequence in Section 33.6.3. */ 1209 1210 /* 5. If the auto-negotiation protocol is successful, 1211 * BGX(0..5)_SPU(0..3)_AN_ADV[AN_COMPLETE] is set along with 1212 * BGX(0..5)_SPU(0..3)_INT[AN_COMPLETE] when the link is up. 1213 */ 1214 1215 /* 3h. Set BGX(0..5)_CMR(0..3)_CONFIG[ENABLE] = 1 and 1216 * BGX(0..5)_SPU(0..3)_CONTROL1[LO_PWR] = 0 to enable the LMAC. 1217 */ 1218 cmr_config.u64 = 1219 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 1220 cmr_config.s.enable = 1; 1221 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 1222 cmr_config.u64); 1223 /* Apply workaround for errata BGX-22429 */ 1224 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && index) { 1225 cvmx_bgxx_cmrx_config_t cmr0; 1226 1227 cmr0.u64 = csr_rd_node(node, 1228 CVMX_BGXX_CMRX_CONFIG(0, xi.interface)); 1229 cmr0.s.enable = 1; 1230 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(0, xi.interface), 1231 cmr0.u64); 1232 } 1233 1234 spu_control1.u64 = 1235 csr_rd_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 1236 spu_control1.s.lo_pwr = 0; 1237 csr_wr_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1238 spu_control1.u64); 1239 1240 /* 4g. Set the polarity and lane swapping of the QLM SerDes. Refer to 1241 * Section 33.4.1, BGX(0..5)_SPU(0..3)_MISC_CONTROL[XOR_TXPLRT,XOR_RXPLRT] 1242 * and BGX(0..5)_SPU(0..3)_MISC_CONTROL[TXPLRT,RXPLRT]. 1243 */ 1244 1245 /* 4c. Write BGX(0..5)_SPU(0..3)_CONTROL1[LO_PWR] = 0. */ 1246 spu_control1.u64 = 1247 csr_rd_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 1248 spu_control1.s.lo_pwr = 0; 1249 csr_wr_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1250 spu_control1.u64); 1251 1252 /* 4d. Select Deficit Idle Count mode and unidirectional enable/disable 1253 * via BGX(0..5)_SMU(0..3)_TX_CTL[DIC_EN,UNI_EN]. 1254 */ 1255 smu_tx_ctl.u64 = 1256 csr_rd_node(node, CVMX_BGXX_SMUX_TX_CTL(index, xi.interface)); 1257 smu_tx_ctl.s.dic_en = 1; 1258 smu_tx_ctl.s.uni_en = 0; 1259 csr_wr_node(node, CVMX_BGXX_SMUX_TX_CTL(index, xi.interface), 1260 smu_tx_ctl.u64); 1261 1262 { 1263 /* Calculate the number of s-clk cycles per usec. */ 1264 const u64 clock_mhz = 1200; /* todo: fixme */ 1265 cvmx_bgxx_spu_dbg_control_t dbg_control; 1266 1267 dbg_control.u64 = csr_rd_node( 1268 node, CVMX_BGXX_SPU_DBG_CONTROL(xi.interface)); 1269 dbg_control.s.us_clk_period = clock_mhz - 1; 1270 csr_wr_node(node, CVMX_BGXX_SPU_DBG_CONTROL(xi.interface), 1271 dbg_control.u64); 1272 } 1273 /* The PHY often takes at least 100ms to stabilize */ 1274 __cvmx_helper_bgx_interface_enable_delay(mode); 1275 return 0; 1276} 1277 1278static void __cvmx_bgx_start_training(int node, int unit, int index) 1279{ 1280 cvmx_bgxx_spux_int_t spu_int; 1281 cvmx_bgxx_spux_br_pmd_control_t pmd_control; 1282 cvmx_bgxx_spux_an_control_t an_control; 1283 1284 /* Clear the training interrupts (W1C) */ 1285 spu_int.u64 = 0; 1286 spu_int.s.training_failure = 1; 1287 spu_int.s.training_done = 1; 1288 csr_wr_node(node, CVMX_BGXX_SPUX_INT(index, unit), spu_int.u64); 1289 1290 /* These registers aren't cleared when training is restarted. Manually 1291 * clear them as per Errata BGX-20968. 1292 */ 1293 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LP_CUP(index, unit), 0); 1294 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LD_CUP(index, unit), 0); 1295 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LD_REP(index, unit), 0); 1296 1297 /* Disable autonegotiation */ 1298 an_control.u64 = 1299 csr_rd_node(node, CVMX_BGXX_SPUX_AN_CONTROL(index, unit)); 1300 an_control.s.an_en = 0; 1301 csr_wr_node(node, CVMX_BGXX_SPUX_AN_CONTROL(index, unit), 1302 an_control.u64); 1303 udelay(1); 1304 1305 /* Restart training */ 1306 pmd_control.u64 = 1307 csr_rd_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit)); 1308 pmd_control.s.train_en = 1; 1309 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit), 1310 pmd_control.u64); 1311 1312 udelay(1); 1313 pmd_control.u64 = 1314 csr_rd_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit)); 1315 pmd_control.s.train_restart = 1; 1316 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit), 1317 pmd_control.u64); 1318} 1319 1320static void __cvmx_bgx_restart_training(int node, int unit, int index) 1321{ 1322 cvmx_bgxx_spux_int_t spu_int; 1323 cvmx_bgxx_spux_br_pmd_control_t pmd_control; 1324 1325 /* Clear the training interrupts (W1C) */ 1326 spu_int.u64 = 0; 1327 spu_int.s.training_failure = 1; 1328 spu_int.s.training_done = 1; 1329 csr_wr_node(node, CVMX_BGXX_SPUX_INT(index, unit), spu_int.u64); 1330 1331 udelay(1700); /* Wait 1.7 msec */ 1332 1333 /* These registers aren't cleared when training is restarted. Manually 1334 * clear them as per Errata BGX-20968. 1335 */ 1336 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LP_CUP(index, unit), 0); 1337 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LD_CUP(index, unit), 0); 1338 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_LD_REP(index, unit), 0); 1339 1340 /* Restart training */ 1341 pmd_control.u64 = 1342 csr_rd_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit)); 1343 pmd_control.s.train_restart = 1; 1344 csr_wr_node(node, CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, unit), 1345 pmd_control.u64); 1346} 1347 1348/* 1349 * @INTERNAL 1350 * Wrapper function to configure the BGX, does not enable. 1351 * 1352 * @param xipd_port IPD/PKO port to configure. 1353 * @param phy_pres If set, enable disparity, only applies to RXAUI interface 1354 * 1355 * @return Zero on success, negative on failure. 1356 */ 1357int __cvmx_helper_bgx_port_init(int xipd_port, int phy_pres) 1358{ 1359 int xiface = cvmx_helper_get_interface_num(xipd_port); 1360 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 1361 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 1362 int index = cvmx_helper_get_interface_index_num(xp.port); 1363 cvmx_helper_interface_mode_t mode; 1364 1365 if (debug) 1366 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 1367 xi.interface, index); 1368 1369 mode = cvmx_helper_bgx_get_mode(xiface, index); 1370 1371 __cvmx_bgx_common_init_pknd(xiface, index); 1372 1373 if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII || 1374 mode == CVMX_HELPER_INTERFACE_MODE_RGMII) { 1375 cvmx_bgxx_gmp_gmi_txx_thresh_t gmi_tx_thresh; 1376 cvmx_bgxx_gmp_gmi_txx_append_t gmp_txx_append; 1377 cvmx_bgxx_gmp_gmi_txx_sgmii_ctl_t gmp_sgmii_ctl; 1378 1379 /* Set TX Threshold */ 1380 gmi_tx_thresh.u64 = 0; 1381 gmi_tx_thresh.s.cnt = 0x20; 1382 csr_wr_node(xi.node, 1383 CVMX_BGXX_GMP_GMI_TXX_THRESH(index, xi.interface), 1384 gmi_tx_thresh.u64); 1385 __cvmx_helper_bgx_sgmii_hardware_init_one_time(xiface, index); 1386 gmp_txx_append.u64 = csr_rd_node( 1387 xi.node, 1388 CVMX_BGXX_GMP_GMI_TXX_APPEND(index, xi.interface)); 1389 gmp_sgmii_ctl.u64 = csr_rd_node( 1390 xi.node, 1391 CVMX_BGXX_GMP_GMI_TXX_SGMII_CTL(index, xi.interface)); 1392 gmp_sgmii_ctl.s.align = gmp_txx_append.s.preamble ? 0 : 1; 1393 csr_wr_node(xi.node, 1394 CVMX_BGXX_GMP_GMI_TXX_SGMII_CTL(index, 1395 xi.interface), 1396 gmp_sgmii_ctl.u64); 1397 if (mode == CVMX_HELPER_INTERFACE_MODE_RGMII) { 1398 /* Disable XCV interface when initialized */ 1399 union cvmx_xcv_reset xcv_reset; 1400 1401 if (debug) 1402 debug("%s: Disabling RGMII XCV interface\n", 1403 __func__); 1404 xcv_reset.u64 = csr_rd(CVMX_XCV_RESET); 1405 xcv_reset.s.enable = 0; 1406 xcv_reset.s.tx_pkt_rst_n = 0; 1407 xcv_reset.s.rx_pkt_rst_n = 0; 1408 csr_wr(CVMX_XCV_RESET, xcv_reset.u64); 1409 } 1410 } else { 1411 int res, cred; 1412 cvmx_bgxx_smux_tx_thresh_t smu_tx_thresh; 1413 1414 res = __cvmx_helper_bgx_xaui_init(index, xiface); 1415 if (res == -1) { 1416#ifdef DEBUG_BGX 1417 debug("Failed to enable XAUI for %d:BGX(%d,%d)\n", 1418 xi.node, xi.interface, index); 1419#endif 1420 return res; 1421 } 1422 /* See BVX_SMU_TX_THRESH register descriptin */ 1423 cred = __cvmx_helper_bgx_fifo_size(xiface, index) >> 4; 1424 smu_tx_thresh.u64 = 0; 1425 smu_tx_thresh.s.cnt = cred - 10; 1426 csr_wr_node(xi.node, 1427 CVMX_BGXX_SMUX_TX_THRESH(index, xi.interface), 1428 smu_tx_thresh.u64); 1429 if (debug) 1430 debug("%s: BGX%d:%d TX-thresh=%d\n", __func__, 1431 xi.interface, index, 1432 (unsigned int)smu_tx_thresh.s.cnt); 1433 1434 /* Set disparity for RXAUI interface as described in the 1435 * Marvell RXAUI Interface specification. 1436 */ 1437 if (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI && phy_pres) { 1438 cvmx_bgxx_spux_misc_control_t misc_control; 1439 1440 misc_control.u64 = csr_rd_node( 1441 xi.node, CVMX_BGXX_SPUX_MISC_CONTROL( 1442 index, xi.interface)); 1443 misc_control.s.intlv_rdisp = 1; 1444 csr_wr_node(xi.node, 1445 CVMX_BGXX_SPUX_MISC_CONTROL(index, 1446 xi.interface), 1447 misc_control.u64); 1448 } 1449 } 1450 return 0; 1451} 1452 1453/** 1454 * @INTERNAL 1455 * Configure a port for internal and/or external loopback. Internal loopback 1456 * causes packets sent by the port to be received by Octeon. External loopback 1457 * causes packets received from the wire to sent out again. This is used by 1458 * interfaces using the bgx mac. 1459 * 1460 * @param xipd_port IPD/PKO port to loopback. 1461 * @param enable_internal 1462 * Non zero if you want internal loopback 1463 * @param enable_external 1464 * Non zero if you want external loopback 1465 * 1466 * @return Zero on success, negative on failure. 1467 */ 1468int __cvmx_helper_bgx_sgmii_configure_loopback(int xipd_port, 1469 int enable_internal, 1470 int enable_external) 1471{ 1472 int xiface = cvmx_helper_get_interface_num(xipd_port); 1473 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 1474 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 1475 int node = xi.node; 1476 int index = cvmx_helper_get_interface_index_num(xp.port); 1477 cvmx_bgxx_gmp_pcs_mrx_control_t gmp_mrx_control; 1478 cvmx_bgxx_gmp_pcs_miscx_ctl_t gmp_misc_ctl; 1479 1480 if (!cvmx_helper_is_port_valid(xiface, index)) 1481 return 0; 1482 1483 if (debug) 1484 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 1485 xi.interface, index); 1486 1487 if (cvmx_helper_bgx_is_rgmii(xi.interface, index)) { 1488 cvmx_xcv_ctl_t xcv_ctl; 1489 cvmx_helper_link_info_t link_info; 1490 1491 xcv_ctl.u64 = csr_rd(CVMX_XCV_CTL); 1492 xcv_ctl.s.lpbk_int = enable_internal; 1493 xcv_ctl.s.lpbk_ext = enable_external; 1494 csr_wr(CVMX_XCV_CTL, xcv_ctl.u64); 1495 1496 /* Initialize link and speed */ 1497 __cvmx_helper_bgx_sgmii_hardware_init_link(xiface, index); 1498 link_info = __cvmx_helper_bgx_sgmii_link_get(xipd_port); 1499 __cvmx_helper_bgx_sgmii_hardware_init_link_speed(xiface, index, 1500 link_info); 1501 __cvmx_helper_bgx_rgmii_speed(link_info); 1502 } else { 1503 gmp_mrx_control.u64 = csr_rd_node( 1504 node, 1505 CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface)); 1506 gmp_mrx_control.s.loopbck1 = enable_internal; 1507 csr_wr_node(node, 1508 CVMX_BGXX_GMP_PCS_MRX_CONTROL(index, xi.interface), 1509 gmp_mrx_control.u64); 1510 1511 gmp_misc_ctl.u64 = csr_rd_node( 1512 node, CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface)); 1513 gmp_misc_ctl.s.loopbck2 = enable_external; 1514 csr_wr_node(node, 1515 CVMX_BGXX_GMP_PCS_MISCX_CTL(index, xi.interface), 1516 gmp_misc_ctl.u64); 1517 __cvmx_helper_bgx_sgmii_hardware_init_link(xiface, index); 1518 } 1519 1520 return 0; 1521} 1522 1523static int __cvmx_helper_bgx_xaui_link_init(int index, int xiface) 1524{ 1525 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 1526 int node = xi.node; 1527 cvmx_bgxx_spux_status1_t spu_status1; 1528 cvmx_bgxx_spux_status2_t spu_status2; 1529 cvmx_bgxx_spux_br_status2_t br_status2; 1530 cvmx_bgxx_spux_int_t spu_int; 1531 cvmx_bgxx_spux_misc_control_t spu_misc_control; 1532 cvmx_bgxx_spux_an_control_t spu_an_control; 1533 cvmx_bgxx_spux_an_status_t spu_an_status; 1534 cvmx_bgxx_spux_br_pmd_control_t pmd_control; 1535 cvmx_bgxx_cmrx_config_t cmr_config; 1536 cvmx_helper_interface_mode_t mode; 1537 int use_training = 0; 1538 int rgmii_first = 0; 1539 int qlm = cvmx_qlm_lmac(xiface, index); 1540 int use_ber = 0; 1541 u64 err_blks; 1542 u64 ber_cnt; 1543 u64 error_debounce; 1544 1545 if (debug) 1546 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 1547 xi.interface, index); 1548 1549 rgmii_first = cvmx_helper_bgx_is_rgmii(xi.interface, index); 1550 1551 mode = cvmx_helper_bgx_get_mode(xiface, index); 1552 if (mode == CVMX_HELPER_INTERFACE_MODE_10G_KR || 1553 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4) 1554 use_training = 1; 1555 1556 if ((mode == CVMX_HELPER_INTERFACE_MODE_XFI || 1557 mode == CVMX_HELPER_INTERFACE_MODE_XLAUI || 1558 mode == CVMX_HELPER_INTERFACE_MODE_10G_KR || 1559 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4)) 1560 use_ber = 1; 1561 1562 /* Disable packet reception, CMR as well as SPU block */ 1563 cmr_config.u64 = 1564 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 1565 cmr_config.s.data_pkt_tx_en = 0; 1566 cmr_config.s.data_pkt_rx_en = 0; 1567 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 1568 cmr_config.u64); 1569 spu_misc_control.u64 = csr_rd_node( 1570 node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface)); 1571 spu_misc_control.s.rx_packet_dis = 1; 1572 csr_wr_node(node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface), 1573 spu_misc_control.u64); 1574 1575 spu_an_control.u64 = csr_rd_node( 1576 node, CVMX_BGXX_SPUX_AN_CONTROL(index, xi.interface)); 1577 if (spu_an_control.s.an_en) { 1578 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) { 1579 cvmx_bgxx_spux_int_t spu_int; 1580 1581 spu_int.u64 = csr_rd_node( 1582 node, CVMX_BGXX_SPUX_INT(index, xi.interface)); 1583 if (!spu_int.s.an_link_good) { 1584 static u64 restart_auto_neg[2][6][4] = { 1585 [0 ... 1][0 ... 5] = { [0 ... 3] = 0 } 1586 }; 1587 u64 now = get_timer(0); 1588 u64 next_restart = 1589 restart_auto_neg[node][xi.interface] 1590 [index] + 1591 2000; 1592 1593 if (now >= next_restart) 1594 return -1; 1595 1596 restart_auto_neg[node][xi.interface][index] = 1597 now; 1598 1599 /* Clear the auto negotiation (W1C) */ 1600 spu_int.u64 = 0; 1601 spu_int.s.an_complete = 1; 1602 spu_int.s.an_link_good = 1; 1603 spu_int.s.an_page_rx = 1; 1604 csr_wr_node(node, 1605 CVMX_BGXX_SPUX_INT(index, 1606 xi.interface), 1607 spu_int.u64); 1608 /* Restart auto negotiation */ 1609 spu_an_control.u64 = csr_rd_node( 1610 node, CVMX_BGXX_SPUX_AN_CONTROL( 1611 index, xi.interface)); 1612 spu_an_control.s.an_restart = 1; 1613 csr_wr_node(node, 1614 CVMX_BGXX_SPUX_AN_CONTROL( 1615 index, xi.interface), 1616 spu_an_control.u64); 1617 return -1; 1618 } 1619 } else { 1620 spu_an_status.u64 = csr_rd_node( 1621 node, 1622 CVMX_BGXX_SPUX_AN_STATUS(index, xi.interface)); 1623 if (!spu_an_status.s.an_complete) { 1624 static u64 restart_auto_neg[2][6][4] = { 1625 [0 ... 1][0 ... 5] = { [0 ... 3] = 0 } 1626 }; 1627 u64 now = get_timer(0); 1628 u64 next_restart = 1629 restart_auto_neg[node][xi.interface] 1630 [index] + 1631 2000; 1632 if (now >= next_restart) { 1633#ifdef DEBUG_BGX 1634 debug("WARNING: BGX%d:%d: Waiting for autoneg to complete\n", 1635 xi.interface, index); 1636#endif 1637 return -1; 1638 } 1639 1640 restart_auto_neg[node][xi.interface][index] = 1641 now; 1642 /* Restart auto negotiation */ 1643 spu_an_control.u64 = csr_rd_node( 1644 node, CVMX_BGXX_SPUX_AN_CONTROL( 1645 index, xi.interface)); 1646 spu_an_control.s.an_restart = 1; 1647 csr_wr_node(node, 1648 CVMX_BGXX_SPUX_AN_CONTROL( 1649 index, xi.interface), 1650 spu_an_control.u64); 1651 return -1; 1652 } 1653 } 1654 } 1655 1656 if (use_training) { 1657 spu_int.u64 = csr_rd_node( 1658 node, CVMX_BGXX_SPUX_INT(index, xi.interface)); 1659 pmd_control.u64 = csr_rd_node( 1660 node, 1661 CVMX_BGXX_SPUX_BR_PMD_CONTROL(index, xi.interface)); 1662 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && 1663 pmd_control.s.train_en == 0) { 1664 __cvmx_bgx_start_training(node, xi.interface, index); 1665 return -1; 1666 } 1667 cvmx_qlm_gser_errata_27882(node, qlm, index); 1668 spu_int.u64 = csr_rd_node( 1669 node, CVMX_BGXX_SPUX_INT(index, xi.interface)); 1670 1671 if (spu_int.s.training_failure && 1672 !OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) { 1673 __cvmx_bgx_restart_training(node, xi.interface, index); 1674 return -1; 1675 } 1676 if (!spu_int.s.training_done) { 1677 debug("Waiting for link training\n"); 1678 return -1; 1679 } 1680 } 1681 1682 /* (GSER-21957) GSER RX Equalization may make >= 5gbaud non-KR 1683 * channel with DXAUI, RXAUI, XFI and XLAUI, we need to perform 1684 * RX equalization when the link is receiving data the first time 1685 */ 1686 if (use_training == 0) { 1687 int lane = index; 1688 cvmx_bgxx_spux_control1_t control1; 1689 1690 cmr_config.u64 = csr_rd_node( 1691 node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 1692 control1.u64 = csr_rd_node( 1693 node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 1694 if (control1.s.loopbck) { 1695 /* Skip RX equalization when in loopback */ 1696 } else if (mode == CVMX_HELPER_INTERFACE_MODE_XLAUI || 1697 mode == CVMX_HELPER_INTERFACE_MODE_XAUI) { 1698 lane = -1; 1699 if (__cvmx_qlm_rx_equalization(node, qlm, lane)) { 1700#ifdef DEBUG_BGX 1701 debug("%d:%d:%d: Waiting for RX Equalization on QLM%d\n", 1702 node, xi.interface, index, qlm); 1703#endif 1704 return -1; 1705 } 1706 /* If BGX2 uses both dlms, then configure other dlm also. */ 1707 if (OCTEON_IS_MODEL(OCTEON_CN73XX) && 1708 xi.interface == 2) { 1709 if (__cvmx_qlm_rx_equalization(node, 6, lane)) { 1710#ifdef DEBUG_BGX 1711 debug("%d:%d:%d: Waiting for RX Equalization on QLM%d\n", 1712 node, xi.interface, index, qlm); 1713#endif 1714 return -1; 1715 } 1716 } 1717 /* RXAUI */ 1718 } else if (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI) { 1719 lane = index * 2; 1720 if (OCTEON_IS_MODEL(OCTEON_CN73XX) && index >= 2 && 1721 xi.interface == 2) { 1722 lane = 0; 1723 } 1724 if (rgmii_first) 1725 lane--; 1726 if (__cvmx_qlm_rx_equalization(node, qlm, lane) || 1727 __cvmx_qlm_rx_equalization(node, qlm, lane + 1)) { 1728#ifdef DEBUG_BGX 1729 debug("%d:%d:%d: Waiting for RX Equalization on QLM%d\n", 1730 node, xi.interface, index, qlm); 1731#endif 1732 return -1; 1733 } 1734 /* XFI */ 1735 } else if (cmr_config.s.lmac_type != 5) { 1736 if (rgmii_first) 1737 lane--; 1738 if (OCTEON_IS_MODEL(OCTEON_CN73XX) && index >= 2 && 1739 xi.interface == 2) { 1740 lane = index - 2; 1741 } else if (OCTEON_IS_MODEL(OCTEON_CNF75XX) && 1742 index >= 2) { 1743 lane = index - 2; 1744 } 1745 if (__cvmx_qlm_rx_equalization(node, qlm, lane)) { 1746#ifdef DEBUG_BGX 1747 debug("%d:%d:%d: Waiting for RX Equalization on QLM%d\n", 1748 node, xi.interface, index, qlm); 1749#endif 1750 return -1; 1751 } 1752 } 1753 } 1754 1755 if (CVMX_WAIT_FOR_FIELD64_NODE( 1756 node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 1757 cvmx_bgxx_spux_control1_t, reset, ==, 0, 10000)) { 1758#ifdef DEBUG_BGX 1759 debug("ERROR: %d:BGX%d:%d: PCS in reset", node, xi.interface, 1760 index); 1761#endif 1762 return -1; 1763 } 1764 1765 if (use_ber) { 1766 if (CVMX_WAIT_FOR_FIELD64_NODE( 1767 node, 1768 CVMX_BGXX_SPUX_BR_STATUS1(index, xi.interface), 1769 cvmx_bgxx_spux_br_status1_t, blk_lock, ==, 1, 1770 10000)) { 1771#ifdef DEBUG_BGX 1772 debug("ERROR: %d:BGX%d:%d: BASE-R PCS block not locked\n", 1773 node, xi.interface, index); 1774 1775 if (mode == CVMX_HELPER_INTERFACE_MODE_XLAUI || 1776 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4) { 1777 cvmx_bgxx_spux_br_algn_status_t bstatus; 1778 1779 bstatus.u64 = csr_rd_node( 1780 node, CVMX_BGXX_SPUX_BR_ALGN_STATUS( 1781 index, xi.interface)); 1782 debug("ERROR: %d:BGX%d:%d: LANE BLOCK_LOCK:%x LANE MARKER_LOCK:%x\n", 1783 node, xi.interface, index, 1784 bstatus.s.block_lock, 1785 bstatus.s.marker_lock); 1786 } 1787#endif 1788 return -1; 1789 } 1790 } else { 1791 /* (5) Check to make sure that the link appears up and stable. 1792 */ 1793 /* Wait for PCS to be aligned */ 1794 if (CVMX_WAIT_FOR_FIELD64_NODE( 1795 node, CVMX_BGXX_SPUX_BX_STATUS(index, xi.interface), 1796 cvmx_bgxx_spux_bx_status_t, alignd, ==, 1, 10000)) { 1797#ifdef DEBUG_BGX 1798 debug("ERROR: %d:BGX%d:%d: PCS not aligned\n", node, 1799 xi.interface, index); 1800#endif 1801 return -1; 1802 } 1803 } 1804 1805 if (use_ber) { 1806 /* Set the BGXX_SPUX_BR_STATUS2.latched_lock bit (latching low). 1807 * This will be checked prior to enabling packet tx and rx, 1808 * ensuring block lock is sustained throughout the BGX link-up 1809 * procedure 1810 */ 1811 br_status2.u64 = csr_rd_node( 1812 node, CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface)); 1813 br_status2.s.latched_lock = 1; 1814 csr_wr_node(node, 1815 CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface), 1816 br_status2.u64); 1817 } 1818 1819 /* Clear rcvflt bit (latching high) and read it back */ 1820 spu_status2.u64 = 1821 csr_rd_node(node, CVMX_BGXX_SPUX_STATUS2(index, xi.interface)); 1822 spu_status2.s.rcvflt = 1; 1823 csr_wr_node(node, CVMX_BGXX_SPUX_STATUS2(index, xi.interface), 1824 spu_status2.u64); 1825 1826 spu_status2.u64 = 1827 csr_rd_node(node, CVMX_BGXX_SPUX_STATUS2(index, xi.interface)); 1828 if (spu_status2.s.rcvflt) { 1829#ifdef DEBUG_BGX 1830 debug("ERROR: %d:BGX%d:%d: Receive fault, need to retry\n", 1831 node, xi.interface, index); 1832#endif 1833 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X) && use_training) 1834 __cvmx_bgx_restart_training(node, xi.interface, index); 1835 /* debug("training restarting\n"); */ 1836 return -1; 1837 } 1838 1839 /* Wait for MAC RX to be ready */ 1840 if (CVMX_WAIT_FOR_FIELD64_NODE( 1841 node, CVMX_BGXX_SMUX_RX_CTL(index, xi.interface), 1842 cvmx_bgxx_smux_rx_ctl_t, status, ==, 0, 10000)) { 1843#ifdef DEBUG_BGX 1844 debug("ERROR: %d:BGX%d:%d: RX not ready\n", node, xi.interface, 1845 index); 1846#endif 1847 return -1; 1848 } 1849 1850 /* Wait for BGX RX to be idle */ 1851 if (CVMX_WAIT_FOR_FIELD64_NODE( 1852 node, CVMX_BGXX_SMUX_CTRL(index, xi.interface), 1853 cvmx_bgxx_smux_ctrl_t, rx_idle, ==, 1, 10000)) { 1854#ifdef DEBUG_BGX 1855 debug("ERROR: %d:BGX%d:%d: RX not idle\n", node, xi.interface, 1856 index); 1857#endif 1858 return -1; 1859 } 1860 1861 /* Wait for GMX TX to be idle */ 1862 if (CVMX_WAIT_FOR_FIELD64_NODE( 1863 node, CVMX_BGXX_SMUX_CTRL(index, xi.interface), 1864 cvmx_bgxx_smux_ctrl_t, tx_idle, ==, 1, 10000)) { 1865#ifdef DEBUG_BGX 1866 debug("ERROR: %d:BGX%d:%d: TX not idle\n", node, xi.interface, 1867 index); 1868#endif 1869 return -1; 1870 } 1871 1872 /* rcvflt should still be 0 */ 1873 spu_status2.u64 = 1874 csr_rd_node(node, CVMX_BGXX_SPUX_STATUS2(index, xi.interface)); 1875 if (spu_status2.s.rcvflt) { 1876#ifdef DEBUG_BGX 1877 debug("ERROR: %d:BGX%d:%d: Receive fault, need to retry\n", 1878 node, xi.interface, index); 1879#endif 1880 return -1; 1881 } 1882 1883 /* Receive link is latching low. Force it high and verify it */ 1884 spu_status1.u64 = 1885 csr_rd_node(node, CVMX_BGXX_SPUX_STATUS1(index, xi.interface)); 1886 spu_status1.s.rcv_lnk = 1; 1887 csr_wr_node(node, CVMX_BGXX_SPUX_STATUS1(index, xi.interface), 1888 spu_status1.u64); 1889 1890 if (CVMX_WAIT_FOR_FIELD64_NODE( 1891 node, CVMX_BGXX_SPUX_STATUS1(index, xi.interface), 1892 cvmx_bgxx_spux_status1_t, rcv_lnk, ==, 1, 10000)) { 1893#ifdef DEBUG_BGX 1894 debug("ERROR: %d:BGX%d:%d: Receive link down\n", node, 1895 xi.interface, index); 1896#endif 1897 return -1; 1898 } 1899 1900 if (use_ber) { 1901 /* Clearing BER_CNT and ERR_BLKs */ 1902 br_status2.u64 = csr_rd_node( 1903 node, CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface)); 1904 1905 /* If set, clear the LATCHED_BER by writing it to a one. */ 1906 if (br_status2.s.latched_ber) 1907 csr_wr_node(node, 1908 CVMX_BGXX_SPUX_BR_STATUS2(index, 1909 xi.interface), 1910 br_status2.u64); 1911 1912 error_debounce = get_timer(0); 1913 1914 /* Clear error counts */ 1915 err_blks = 0; 1916 ber_cnt = 0; 1917 1918 /* Verify that the link is up and error free for 100ms */ 1919 while (get_timer(error_debounce) < 100) { 1920 spu_status1.u64 = csr_rd_node( 1921 node, 1922 CVMX_BGXX_SPUX_STATUS1(index, xi.interface)); 1923 /* Checking that Receive link is still up (rcv_lnk = 1 (up)) */ 1924 if (!spu_status1.s.rcv_lnk) { 1925#ifdef DEBUG_BGX 1926 debug("ERROR: %d:BGX%d:%d: Receive link down\n", 1927 node, xi.interface, index); 1928#endif 1929 return -1; 1930 } 1931 1932 /* Checking if latched_ber = 1 (BER >= 10e^4) */ 1933 br_status2.u64 = csr_rd_node( 1934 node, 1935 CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface)); 1936 err_blks += br_status2.s.err_blks; 1937 ber_cnt += br_status2.s.ber_cnt; 1938 1939 if (br_status2.s.latched_ber) { 1940#ifdef DEBUG_BGX 1941 debug("ERROR: %d:BGX%d:%d: BER test failed, BER >= 10e^4, need to retry\n", 1942 node, xi.interface, index); 1943#endif 1944 return -1; 1945 } 1946 /* Checking that latched BLOCK_LOCK is still set (Block Lock never lost) */ 1947 if (!br_status2.s.latched_lock) { 1948#ifdef DEBUG_BGX 1949 debug("ERROR: %d:BGX%d:%d: BASE-R PCS block lock lost, need to retry\n", 1950 node, xi.interface, index); 1951#endif 1952 return -1; 1953 } 1954 1955 /* Check error counters. Must be 0 (this error rate# 1956 * is much higher than 1E-12) 1957 */ 1958 if (err_blks > 0) { 1959#ifdef DEBUG_BGX 1960 debug("ERROR: %d:BGX%d:%d: BASE-R errored-blocks (%llu) detected, need to retry\n", 1961 node, xi.interface, index, 1962 (unsigned long long)err_blks); 1963#endif 1964 return -1; 1965 } 1966 1967 if (ber_cnt > 0) { 1968#ifdef DEBUG_BGX 1969 debug("ERROR: %d:BGX%d:%d: BASE-R bit-errors (%llu) detected, need to retry\n", 1970 node, xi.interface, index, 1971 (unsigned long long)ber_cnt); 1972#endif 1973 return -1; 1974 } 1975 1976 udelay(1000); 1977 } 1978 1979 /* Clear out the BGX error counters/bits. These errors are 1980 * expected as part of the BGX link up procedure 1981 */ 1982 /* BIP_ERR counters clear as part of this read */ 1983 csr_rd_node(node, 1984 CVMX_BGXX_SPUX_BR_BIP_ERR_CNT(index, xi.interface)); 1985 /* BER_CNT and ERR_BLKs clear as part of this read */ 1986 br_status2.u64 = csr_rd_node( 1987 node, CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface)); 1988 } 1989 1990 /* (7) Enable packet transmit and receive */ 1991 spu_misc_control.u64 = csr_rd_node( 1992 node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface)); 1993 spu_misc_control.s.rx_packet_dis = 0; 1994 csr_wr_node(node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface), 1995 spu_misc_control.u64); 1996 1997 if (debug) 1998 debug("%s: Enabling tx and rx data packets\n", __func__); 1999 cmr_config.u64 = 2000 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2001 cmr_config.s.data_pkt_tx_en = 1; 2002 cmr_config.s.data_pkt_rx_en = 1; 2003 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 2004 cmr_config.u64); 2005 return 0; 2006} 2007 2008int __cvmx_helper_bgx_xaui_enable(int xiface) 2009{ 2010 int index; 2011 cvmx_helper_interface_mode_t mode; 2012 int num_ports = cvmx_helper_ports_on_interface(xiface); 2013 2014 for (index = 0; index < num_ports; index++) { 2015 int res; 2016 int xipd_port = cvmx_helper_get_ipd_port(xiface, index); 2017 int phy_pres; 2018 struct cvmx_xiface xi = 2019 cvmx_helper_xiface_to_node_interface(xiface); 2020 static int count 2021 [CVMX_MAX_NODES][CVMX_HELPER_MAX_IFACE] 2022 [CVMX_HELPER_CFG_MAX_PORT_PER_IFACE] = { 2023 [0 ... CVMX_MAX_NODES - 2024 1][0 ... CVMX_HELPER_MAX_IFACE - 2025 1] = { [0 ... CVMX_HELPER_CFG_MAX_PORT_PER_IFACE - 2026 1] = 0 } 2027 }; 2028 2029 mode = cvmx_helper_bgx_get_mode(xiface, index); 2030 2031 /* Set disparity for RXAUI interface as described in the 2032 * Marvell RXAUI Interface specification. 2033 */ 2034 if (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI && 2035 (cvmx_helper_get_port_phy_present(xiface, index))) 2036 phy_pres = 1; 2037 else 2038 phy_pres = 0; 2039 __cvmx_helper_bgx_port_init(xipd_port, phy_pres); 2040 2041retry_link: 2042 res = __cvmx_helper_bgx_xaui_link_init(index, xiface); 2043 /* RX Equalization or autonegotiation can take little longer 2044 * retry the link maybe 5 times for now 2045 */ 2046 if (res == -1 && count[xi.node][xi.interface][index] < 5) { 2047 count[xi.node][xi.interface][index]++; 2048#ifdef DEBUG_BGX 2049 debug("%d:BGX(%d,%d): Failed to get link, retrying\n", 2050 xi.node, xi.interface, index); 2051#endif 2052 goto retry_link; 2053 } 2054 2055 if (res == -1) { 2056#ifdef DEBUG_BGX 2057 debug("%d:BGX(%d,%d): Failed to get link\n", xi.node, 2058 xi.interface, index); 2059#endif 2060 continue; 2061 } 2062 } 2063 return 0; 2064} 2065 2066cvmx_helper_link_info_t __cvmx_helper_bgx_xaui_link_get(int xipd_port) 2067{ 2068 int xiface = cvmx_helper_get_interface_num(xipd_port); 2069 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2070 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 2071 int index = cvmx_helper_get_interface_index_num(xp.port); 2072 cvmx_bgxx_spux_status1_t spu_status1; 2073 cvmx_bgxx_smux_tx_ctl_t smu_tx_ctl; 2074 cvmx_bgxx_smux_rx_ctl_t smu_rx_ctl; 2075 cvmx_bgxx_cmrx_config_t cmr_config; 2076 cvmx_helper_link_info_t result; 2077 cvmx_helper_interface_mode_t mode; 2078 cvmx_bgxx_spux_misc_control_t spu_misc_control; 2079 cvmx_bgxx_spux_br_status2_t br_status2; 2080 2081 result.u64 = 0; 2082 2083 if (debug) 2084 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 2085 xi.interface, index); 2086 2087 mode = cvmx_helper_bgx_get_mode(xiface, index); 2088 if (mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2089 return __cvmx_helper_bgx_sgmii_link_get(xipd_port); 2090 2091 /* Reading current rx/tx link status */ 2092 spu_status1.u64 = csr_rd_node( 2093 xi.node, CVMX_BGXX_SPUX_STATUS1(index, xi.interface)); 2094 smu_tx_ctl.u64 = csr_rd_node( 2095 xi.node, CVMX_BGXX_SMUX_TX_CTL(index, xi.interface)); 2096 smu_rx_ctl.u64 = csr_rd_node( 2097 xi.node, CVMX_BGXX_SMUX_RX_CTL(index, xi.interface)); 2098 /* Reading tx/rx packet enables */ 2099 cmr_config.u64 = csr_rd_node( 2100 xi.node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2101 spu_misc_control.u64 = csr_rd_node( 2102 xi.node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface)); 2103 2104 if (smu_tx_ctl.s.ls == 0 && smu_rx_ctl.s.status == 0 && 2105 cmr_config.s.data_pkt_tx_en == 1 && 2106 cmr_config.s.data_pkt_rx_en == 1 && 2107 spu_misc_control.s.rx_packet_dis == 0 && 2108 spu_status1.s.rcv_lnk) { 2109 int lanes; 2110 int qlm = cvmx_qlm_lmac(xiface, index); 2111 u64 speed; 2112 2113 result.s.link_up = 1; 2114 result.s.full_duplex = 1; 2115 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 2116 speed = cvmx_qlm_get_gbaud_mhz_node(xi.node, qlm); 2117 else 2118 speed = cvmx_qlm_get_gbaud_mhz(qlm); 2119 2120 cmr_config.u64 = csr_rd_node( 2121 xi.node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2122 switch (cmr_config.s.lmac_type) { 2123 default: 2124 case 1: // XAUI 2125 speed = (speed * 8 + 5) / 10; 2126 lanes = 4; 2127 break; 2128 case 2: // RXAUI 2129 speed = (speed * 8 + 5) / 10; 2130 lanes = 2; 2131 break; 2132 case 3: // XFI 2133 speed = (speed * 64 + 33) / 66; 2134 lanes = 1; 2135 break; 2136 case 4: // XLAUI 2137 /* Adjust the speed when XLAUI is configured at 6.250Gbps */ 2138 if (speed == 6250) 2139 speed = 6445; 2140 speed = (speed * 64 + 33) / 66; 2141 lanes = 4; 2142 break; 2143 } 2144 2145 if (debug) 2146 debug("%s: baud: %llu, lanes: %d\n", __func__, 2147 (unsigned long long)speed, lanes); 2148 speed *= lanes; 2149 result.s.speed = speed; 2150 } else { 2151 int res; 2152 u64 err_blks = 0; 2153 u64 ber_cnt = 0; 2154 2155 /* Check for err_blk and ber errors if 10G or 40G */ 2156 if ((mode == CVMX_HELPER_INTERFACE_MODE_XFI || 2157 mode == CVMX_HELPER_INTERFACE_MODE_XLAUI || 2158 mode == CVMX_HELPER_INTERFACE_MODE_10G_KR || 2159 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4)) { 2160 br_status2.u64 = csr_rd_node( 2161 xi.node, 2162 CVMX_BGXX_SPUX_BR_STATUS2(index, xi.interface)); 2163 err_blks = br_status2.s.err_blks; 2164 ber_cnt = br_status2.s.ber_cnt; 2165 } 2166 2167 /* Checking if the link is up and error-free but we are receiving remote-faults */ 2168 if (smu_tx_ctl.s.ls != 1 && smu_rx_ctl.s.status != 1 && 2169 cmr_config.s.data_pkt_tx_en == 1 && 2170 cmr_config.s.data_pkt_rx_en == 1 && 2171 spu_misc_control.s.rx_packet_dis == 0 && 2172 err_blks == 0 && ber_cnt == 0 && 2173 spu_status1.s.rcv_lnk) { 2174 result.s.init_success = 1; 2175#ifdef DEBUG_BGX 2176 debug("Receiving remote-fault ordered sets %d:BGX(%d,%d)\n", 2177 xi.node, xi.interface, index); 2178#endif 2179 2180 } else { 2181 res = __cvmx_helper_bgx_xaui_link_init(index, xiface); 2182 if (res == -1) { 2183#ifdef DEBUG_BGX 2184 debug("Failed to get %d:BGX(%d,%d) link\n", 2185 xi.node, xi.interface, index); 2186#endif 2187 } else { 2188#ifdef DEBUG_BGX 2189 debug("Link initialization successful %d:BGX(%d,%d)\n", 2190 xi.node, xi.interface, index); 2191#endif 2192 result.s.init_success = 1; 2193 } 2194 } 2195 } 2196 2197 return result; 2198} 2199 2200int __cvmx_helper_bgx_xaui_link_set(int xipd_port, 2201 cvmx_helper_link_info_t link_info) 2202{ 2203 int xiface = cvmx_helper_get_interface_num(xipd_port); 2204 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2205 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 2206 int node = xi.node; 2207 int index = cvmx_helper_get_interface_index_num(xp.port); 2208 cvmx_bgxx_smux_tx_ctl_t smu_tx_ctl; 2209 cvmx_bgxx_smux_rx_ctl_t smu_rx_ctl; 2210 cvmx_bgxx_spux_status1_t spu_status1; 2211 cvmx_helper_interface_mode_t mode; 2212 cvmx_bgxx_cmrx_config_t cmr_config; 2213 cvmx_bgxx_spux_misc_control_t spu_misc_control; 2214 2215 if (debug) 2216 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 2217 xi.interface, index); 2218 2219 mode = cvmx_helper_bgx_get_mode(xiface, index); 2220 if (mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2221 return __cvmx_helper_bgx_sgmii_link_set(xipd_port, link_info); 2222 2223 /* Reading current rx/tx link status */ 2224 smu_tx_ctl.u64 = 2225 csr_rd_node(node, CVMX_BGXX_SMUX_TX_CTL(index, xi.interface)); 2226 smu_rx_ctl.u64 = 2227 csr_rd_node(node, CVMX_BGXX_SMUX_RX_CTL(index, xi.interface)); 2228 spu_status1.u64 = 2229 csr_rd_node(node, CVMX_BGXX_SPUX_STATUS1(index, xi.interface)); 2230 /* Reading tx/rx packet enables */ 2231 cmr_config.u64 = csr_rd_node( 2232 xi.node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2233 spu_misc_control.u64 = csr_rd_node( 2234 xi.node, CVMX_BGXX_SPUX_MISC_CONTROL(index, xi.interface)); 2235 2236 /* If the link shouldn't be up, then just return */ 2237 if (!link_info.s.link_up) 2238 return 0; 2239 2240 /* Do nothing if both RX and TX are happy and packet 2241 * transmission/reception is enabled 2242 */ 2243 if (smu_tx_ctl.s.ls == 0 && smu_rx_ctl.s.status == 0 && 2244 cmr_config.s.data_pkt_tx_en == 1 && 2245 cmr_config.s.data_pkt_rx_en == 1 && 2246 spu_misc_control.s.rx_packet_dis == 0 && spu_status1.s.rcv_lnk) 2247 return 0; 2248 2249 /* Bring the link up */ 2250 return __cvmx_helper_bgx_xaui_link_init(index, xiface); 2251} 2252 2253int __cvmx_helper_bgx_xaui_configure_loopback(int xipd_port, 2254 int enable_internal, 2255 int enable_external) 2256{ 2257 int xiface = cvmx_helper_get_interface_num(xipd_port); 2258 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2259 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port); 2260 int node = xi.node; 2261 int index = cvmx_helper_get_interface_index_num(xp.port); 2262 cvmx_bgxx_spux_control1_t spu_control1; 2263 cvmx_bgxx_smux_ext_loopback_t smu_ext_loopback; 2264 2265 if (debug) 2266 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 2267 xi.interface, index); 2268 2269 /* INT_BEAT_GEN must be set for loopback if the QLMs are not clocked. 2270 * Set it whenever we use internal loopback 2271 */ 2272 if (enable_internal) { 2273 cvmx_bgxx_cmrx_config_t cmr_config; 2274 2275 cmr_config.u64 = csr_rd_node( 2276 node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2277 cmr_config.s.int_beat_gen = 1; 2278 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 2279 cmr_config.u64); 2280 } 2281 /* Set the internal loop */ 2282 spu_control1.u64 = 2283 csr_rd_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface)); 2284 spu_control1.s.loopbck = enable_internal; 2285 csr_wr_node(node, CVMX_BGXX_SPUX_CONTROL1(index, xi.interface), 2286 spu_control1.u64); 2287 /* Set the external loop */ 2288 smu_ext_loopback.u64 = csr_rd_node( 2289 node, CVMX_BGXX_SMUX_EXT_LOOPBACK(index, xi.interface)); 2290 smu_ext_loopback.s.en = enable_external; 2291 csr_wr_node(node, CVMX_BGXX_SMUX_EXT_LOOPBACK(index, xi.interface), 2292 smu_ext_loopback.u64); 2293 2294 return __cvmx_helper_bgx_xaui_link_init(index, xiface); 2295} 2296 2297int __cvmx_helper_bgx_mixed_enable(int xiface) 2298{ 2299 int index; 2300 int num_ports = cvmx_helper_ports_on_interface(xiface); 2301 cvmx_helper_interface_mode_t mode; 2302 2303 for (index = 0; index < num_ports; index++) { 2304 int xipd_port, phy_pres = 0; 2305 2306 if (!cvmx_helper_is_port_valid(xiface, index)) 2307 continue; 2308 2309 mode = cvmx_helper_bgx_get_mode(xiface, index); 2310 2311 xipd_port = cvmx_helper_get_ipd_port(xiface, index); 2312 2313 if (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI && 2314 (cvmx_helper_get_port_phy_present(xiface, index))) 2315 phy_pres = 1; 2316 2317 if (__cvmx_helper_bgx_port_init(xipd_port, phy_pres)) 2318 continue; 2319 2320 /* For RGMII interface, initialize the link after PKO is setup */ 2321 if (mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2322 continue; 2323 /* Call SGMII init code for lmac_type = 0|5 */ 2324 else if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII) { 2325 int do_link_set = 1; 2326 2327 if (do_link_set) 2328 __cvmx_helper_bgx_sgmii_link_set( 2329 xipd_port, 2330 __cvmx_helper_bgx_sgmii_link_get( 2331 xipd_port)); 2332 /* All other lmac type call XAUI init code */ 2333 } else { 2334 int res; 2335 struct cvmx_xiface xi = 2336 cvmx_helper_xiface_to_node_interface(xiface); 2337 static int count 2338 [CVMX_MAX_NODES][CVMX_HELPER_MAX_IFACE] 2339 [CVMX_HELPER_CFG_MAX_PORT_PER_IFACE] = { 2340 [0 ... CVMX_MAX_NODES - 2341 1][0 ... CVMX_HELPER_MAX_IFACE - 2342 1] = { [0 ... CVMX_HELPER_CFG_MAX_PORT_PER_IFACE - 2343 1] = 0 } 2344 }; 2345 2346retry_link: 2347 res = __cvmx_helper_bgx_xaui_link_init(index, xiface); 2348 /* RX Equalization or autonegotiation can take little 2349 * longer retry the link maybe 5 times for now 2350 */ 2351 if (res == -1 && 2352 count[xi.node][xi.interface][index] < 5) { 2353 count[xi.node][xi.interface][index]++; 2354 goto retry_link; 2355 } 2356 2357 if (res == -1) { 2358#ifdef DEBUG_BGX 2359 debug("Failed to get %d:BGX(%d,%d) link\n", 2360 xi.node, xi.interface, index); 2361#endif 2362 continue; 2363 } 2364 } 2365 } 2366 return 0; 2367} 2368 2369cvmx_helper_link_info_t __cvmx_helper_bgx_mixed_link_get(int xipd_port) 2370{ 2371 int xiface = cvmx_helper_get_interface_num(xipd_port); 2372 int index = cvmx_helper_get_interface_index_num(xipd_port); 2373 cvmx_helper_interface_mode_t mode; 2374 2375 mode = cvmx_helper_bgx_get_mode(xiface, index); 2376 if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII || 2377 mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2378 return __cvmx_helper_bgx_sgmii_link_get(xipd_port); 2379 else 2380 return __cvmx_helper_bgx_xaui_link_get(xipd_port); 2381} 2382 2383int __cvmx_helper_bgx_mixed_link_set(int xipd_port, 2384 cvmx_helper_link_info_t link_info) 2385{ 2386 int xiface = cvmx_helper_get_interface_num(xipd_port); 2387 int index = cvmx_helper_get_interface_index_num(xipd_port); 2388 cvmx_helper_interface_mode_t mode; 2389 2390 mode = cvmx_helper_bgx_get_mode(xiface, index); 2391 if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII || 2392 mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2393 return __cvmx_helper_bgx_sgmii_link_set(xipd_port, link_info); 2394 else 2395 return __cvmx_helper_bgx_xaui_link_set(xipd_port, link_info); 2396} 2397 2398int __cvmx_helper_bgx_mixed_configure_loopback(int xipd_port, 2399 int enable_internal, 2400 int enable_external) 2401{ 2402 int xiface = cvmx_helper_get_interface_num(xipd_port); 2403 int index = cvmx_helper_get_interface_index_num(xipd_port); 2404 cvmx_helper_interface_mode_t mode; 2405 2406 mode = cvmx_helper_bgx_get_mode(xiface, index); 2407 if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII || 2408 mode == CVMX_HELPER_INTERFACE_MODE_RGMII) 2409 return __cvmx_helper_bgx_sgmii_configure_loopback( 2410 xipd_port, enable_internal, enable_external); 2411 else 2412 return __cvmx_helper_bgx_xaui_configure_loopback( 2413 xipd_port, enable_internal, enable_external); 2414} 2415 2416/** 2417 * @INTERNAL 2418 * Configure Priority-Based Flow Control (a.k.a. PFC/CBFC) 2419 * on a specific BGX interface/port. 2420 */ 2421void __cvmx_helper_bgx_xaui_config_pfc(unsigned int node, 2422 unsigned int interface, 2423 unsigned int index, bool pfc_enable) 2424{ 2425 int xiface = cvmx_helper_node_interface_to_xiface(node, interface); 2426 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2427 cvmx_bgxx_smux_cbfc_ctl_t cbfc_ctl; 2428 2429 if (debug) 2430 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 2431 xi.interface, index); 2432 2433 cbfc_ctl.u64 = 2434 csr_rd_node(node, CVMX_BGXX_SMUX_CBFC_CTL(index, xi.interface)); 2435 2436 /* Enable all PFC controls if requiested */ 2437 cbfc_ctl.s.rx_en = pfc_enable; 2438 cbfc_ctl.s.tx_en = pfc_enable; 2439 if (debug) 2440 debug("%s: CVMX_BGXX_SMUX_CBFC_CTL(%d,%d)=%#llx\n", __func__, 2441 index, xi.interface, (unsigned long long)cbfc_ctl.u64); 2442 csr_wr_node(node, CVMX_BGXX_SMUX_CBFC_CTL(index, xi.interface), 2443 cbfc_ctl.u64); 2444} 2445 2446/** 2447 * Function to control the generation of FCS, padding by the BGX 2448 * 2449 */ 2450void cvmx_helper_bgx_tx_options(unsigned int node, unsigned int interface, 2451 unsigned int index, bool fcs_enable, 2452 bool pad_enable) 2453{ 2454 cvmx_bgxx_cmrx_config_t cmr_config; 2455 cvmx_bgxx_gmp_gmi_txx_append_t gmp_txx_append; 2456 cvmx_bgxx_gmp_gmi_txx_min_pkt_t gmp_min_pkt; 2457 cvmx_bgxx_smux_tx_min_pkt_t smu_min_pkt; 2458 cvmx_bgxx_smux_tx_append_t smu_tx_append; 2459 int xiface = cvmx_helper_node_interface_to_xiface(node, interface); 2460 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2461 2462 if (!cvmx_helper_is_port_valid(xiface, index)) 2463 return; 2464 2465 if (debug) 2466 debug("%s: interface %u:%d/%d, fcs: %s, pad: %s\n", __func__, 2467 xi.node, xi.interface, index, 2468 fcs_enable ? "true" : "false", 2469 pad_enable ? "true" : "false"); 2470 2471 cmr_config.u64 = 2472 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2473 2474 (void)cmr_config; /* In case we need LMAC_TYPE later */ 2475 2476 /* Setting options for both BGX subsystems, regardless of LMAC type */ 2477 2478 /* Set GMP (SGMII) Tx options */ 2479 gmp_min_pkt.u64 = 0; 2480 /* per HRM Sec 34.3.4.4 */ 2481 gmp_min_pkt.s.min_size = 59; 2482 csr_wr_node(node, CVMX_BGXX_GMP_GMI_TXX_MIN_PKT(index, xi.interface), 2483 gmp_min_pkt.u64); 2484 gmp_txx_append.u64 = csr_rd_node( 2485 node, CVMX_BGXX_GMP_GMI_TXX_APPEND(index, xi.interface)); 2486 gmp_txx_append.s.fcs = fcs_enable; 2487 gmp_txx_append.s.pad = pad_enable; 2488 csr_wr_node(node, CVMX_BGXX_GMP_GMI_TXX_APPEND(index, xi.interface), 2489 gmp_txx_append.u64); 2490 2491 /* Set SMUX (XAUI/XFI) Tx options */ 2492 /* HRM Sec 33.3.4.3 should read 64 */ 2493 smu_min_pkt.u64 = 0; 2494 smu_min_pkt.s.min_size = 0x40; 2495 csr_wr_node(node, CVMX_BGXX_SMUX_TX_MIN_PKT(index, xi.interface), 2496 smu_min_pkt.u64); 2497 smu_tx_append.u64 = csr_rd_node( 2498 node, CVMX_BGXX_SMUX_TX_APPEND(index, xi.interface)); 2499 smu_tx_append.s.fcs_d = fcs_enable; /* Set data-packet FCS */ 2500 smu_tx_append.s.pad = pad_enable; 2501 csr_wr_node(node, CVMX_BGXX_SMUX_TX_APPEND(index, xi.interface), 2502 smu_tx_append.u64); 2503} 2504 2505/** 2506 * Set mac for the ipd_port 2507 * 2508 * @param xipd_port ipd_port to set the mac 2509 * @param bcst If set, accept all broadcast packets 2510 * @param mcst Multicast mode 2511 * 0 = Force reject all multicast packets 2512 * 1 = Force accept all multicast packets 2513 * 2 = use the address filter CAM. 2514 * @param mac mac address for the ipd_port, or 0 to disable MAC filtering 2515 */ 2516void cvmx_helper_bgx_set_mac(int xipd_port, int bcst, int mcst, u64 mac) 2517{ 2518 int xiface = cvmx_helper_get_interface_num(xipd_port); 2519 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2520 int node = xi.node; 2521 int index; 2522 cvmx_bgxx_cmr_rx_adrx_cam_t adr_cam; 2523 cvmx_bgxx_cmrx_rx_adr_ctl_t adr_ctl; 2524 cvmx_bgxx_cmrx_config_t cmr_config; 2525 int saved_state_tx, saved_state_rx; 2526 2527 index = cvmx_helper_get_interface_index_num(xipd_port); 2528 2529 if (!cvmx_helper_is_port_valid(xiface, index)) 2530 return; 2531 2532 if (debug) 2533 debug("%s: interface %u:%d/%d\n", __func__, xi.node, 2534 xi.interface, index); 2535 2536 cmr_config.u64 = 2537 csr_rd_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface)); 2538 saved_state_tx = cmr_config.s.data_pkt_tx_en; 2539 saved_state_rx = cmr_config.s.data_pkt_rx_en; 2540 cmr_config.s.data_pkt_tx_en = 0; 2541 cmr_config.s.data_pkt_rx_en = 0; 2542 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 2543 cmr_config.u64); 2544 2545 /* Set the mac */ 2546 adr_cam.u64 = 0; 2547 adr_cam.s.id = index; 2548 2549 if (mac != 0ull) 2550 adr_cam.s.en = 1; 2551 adr_cam.s.adr = mac; 2552 2553 csr_wr_node(node, CVMX_BGXX_CMR_RX_ADRX_CAM(index * 8, xi.interface), 2554 adr_cam.u64); 2555 2556 adr_ctl.u64 = csr_rd_node( 2557 node, CVMX_BGXX_CMRX_RX_ADR_CTL(index, xi.interface)); 2558 if (mac != 0ull) 2559 adr_ctl.s.cam_accept = 2560 1; /* Accept the packet on DMAC CAM address */ 2561 else 2562 adr_ctl.s.cam_accept = 0; /* No filtering, promiscuous */ 2563 2564 adr_ctl.s.mcst_mode = mcst; /* Use the address filter CAM */ 2565 adr_ctl.s.bcst_accept = bcst; /* Accept all broadcast packets */ 2566 csr_wr_node(node, CVMX_BGXX_CMRX_RX_ADR_CTL(index, xi.interface), 2567 adr_ctl.u64); 2568 /* Set SMAC for PAUSE frames */ 2569 csr_wr_node(node, CVMX_BGXX_GMP_GMI_SMACX(index, xi.interface), mac); 2570 2571 /* Restore back the interface state */ 2572 cmr_config.s.data_pkt_tx_en = saved_state_tx; 2573 cmr_config.s.data_pkt_rx_en = saved_state_rx; 2574 csr_wr_node(node, CVMX_BGXX_CMRX_CONFIG(index, xi.interface), 2575 cmr_config.u64); 2576 2577 /* Wait 100ms after bringing up the link to give the PHY some time */ 2578 if (cmr_config.s.enable) { 2579 cvmx_helper_interface_mode_t mode; 2580 2581 mode = cvmx_helper_bgx_get_mode(xiface, index); 2582 __cvmx_helper_bgx_interface_enable_delay(mode); 2583 } 2584} 2585 2586/** 2587 * Disables the sending of flow control (pause) frames on the specified 2588 * BGX port(s). 2589 * 2590 * @param xiface Which xiface 2591 * @param port_mask Mask (4bits) of which ports on the interface to disable 2592 * backpressure on. 2593 * 1 => disable backpressure 2594 * 0 => enable backpressure 2595 * 2596 * @return 0 on success 2597 * -1 on error 2598 * 2599 * FIXME: Should change the API to handle a single port in every 2600 * invocation, for consistency with other API calls. 2601 */ 2602int cvmx_bgx_set_backpressure_override(int xiface, unsigned int port_mask) 2603{ 2604 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); 2605 cvmx_bgxx_cmr_rx_ovr_bp_t rx_ovr_bp; 2606 int node = xi.node; 2607 2608 if (xi.interface >= CVMX_HELPER_MAX_GMX) 2609 return 0; 2610 2611 if (debug) 2612 debug("%s: interface %u:%d port_mask=%#x\n", __func__, xi.node, 2613 xi.interface, port_mask); 2614 2615 /* Check for valid arguments */ 2616 rx_ovr_bp.u64 = 0; 2617 rx_ovr_bp.s.en = port_mask; /* Per port Enable back pressure override */ 2618 rx_ovr_bp.s.ign_fifo_bp = 2619 port_mask; /* Ignore the RX FIFO full when computing BP */ 2620 2621 csr_wr_node(node, CVMX_BGXX_CMR_RX_OVR_BP(xi.interface), rx_ovr_bp.u64); 2622 return 0; 2623} 2624 2625int cvmx_bgx_set_flowctl_mode(int xipd_port, cvmx_qos_proto_t qos, 2626 cvmx_qos_pkt_mode_t fc_mode) 2627{ 2628 int node, xiface, iface, index, mode; 2629 struct cvmx_xiface xi; 2630 const struct { 2631 int bck; 2632 int drp; 2633 } fcmode[4] = { [CVMX_QOS_PKT_MODE_HWONLY] = { 1, 1 }, 2634 [CVMX_QOS_PKT_MODE_SWONLY] = { 0, 0 }, 2635 [CVMX_QOS_PKT_MODE_HWSW] = { 1, 0 }, 2636 [CVMX_QOS_PKT_MODE_DROP] = { 0, 1 } }; 2637 2638 xiface = cvmx_helper_get_interface_num(xipd_port); 2639 xi = cvmx_helper_xiface_to_node_interface(xiface); 2640 node = xi.node; 2641 iface = xi.interface; 2642 2643 if (xi.interface >= CVMX_HELPER_MAX_GMX) 2644 return 0; 2645 2646 index = cvmx_helper_get_interface_index_num(xipd_port); 2647 mode = cvmx_helper_bgx_get_mode(xiface, index); 2648 switch (mode) { 2649 case CVMX_HELPER_INTERFACE_MODE_10G_KR: 2650 case CVMX_HELPER_INTERFACE_MODE_40G_KR4: 2651 case CVMX_HELPER_INTERFACE_MODE_XLAUI: 2652 case CVMX_HELPER_INTERFACE_MODE_XFI: 2653 case CVMX_HELPER_INTERFACE_MODE_RXAUI: 2654 case CVMX_HELPER_INTERFACE_MODE_XAUI: { 2655 cvmx_bgxx_smux_tx_ctl_t txctl; 2656 cvmx_bgxx_smux_cbfc_ctl_t cbfc; 2657 cvmx_bgxx_smux_rx_frm_ctl_t frmctl; 2658 cvmx_bgxx_smux_hg2_control_t hg2ctl; 2659 2660 txctl.u64 = 2661 csr_rd_node(node, CVMX_BGXX_SMUX_TX_CTL(index, iface)); 2662 cbfc.u64 = csr_rd_node(node, 2663 CVMX_BGXX_SMUX_CBFC_CTL(index, iface)); 2664 frmctl.u64 = csr_rd_node( 2665 node, CVMX_BGXX_SMUX_RX_FRM_CTL(index, iface)); 2666 hg2ctl.u64 = csr_rd_node( 2667 node, CVMX_BGXX_SMUX_HG2_CONTROL(index, iface)); 2668 switch (qos) { 2669 case CVMX_QOS_PROTO_PAUSE: 2670 cbfc.u64 = 0; 2671 hg2ctl.u64 = 0; 2672 frmctl.s.ctl_bck = fcmode[fc_mode].bck; 2673 frmctl.s.ctl_drp = fcmode[fc_mode].drp; 2674 frmctl.s.ctl_mcst = 1; 2675 txctl.s.l2p_bp_conv = 1; 2676 break; 2677 case CVMX_QOS_PROTO_PFC: 2678 hg2ctl.u64 = 0; 2679 hg2ctl.s.logl_en = 0xff; 2680 frmctl.s.ctl_bck = fcmode[fc_mode].bck; 2681 frmctl.s.ctl_drp = fcmode[fc_mode].drp; 2682 frmctl.s.ctl_mcst = 1; 2683 cbfc.s.bck_en = fcmode[fc_mode].bck; 2684 cbfc.s.drp_en = fcmode[fc_mode].drp; 2685 cbfc.s.phys_en = 0; 2686 cbfc.s.logl_en = 0xff; 2687 cbfc.s.tx_en = 1; 2688 cbfc.s.rx_en = 1; 2689 break; 2690 case CVMX_QOS_PROTO_NONE: 2691 cbfc.u64 = 0; 2692 hg2ctl.u64 = 0; 2693 frmctl.s.ctl_bck = fcmode[CVMX_QOS_PKT_MODE_DROP].bck; 2694 frmctl.s.ctl_drp = fcmode[CVMX_QOS_PKT_MODE_DROP].drp; 2695 txctl.s.l2p_bp_conv = 0; 2696 break; 2697 default: 2698 break; 2699 } 2700 csr_wr_node(node, CVMX_BGXX_SMUX_CBFC_CTL(index, iface), 2701 cbfc.u64); 2702 csr_wr_node(node, CVMX_BGXX_SMUX_RX_FRM_CTL(index, iface), 2703 frmctl.u64); 2704 csr_wr_node(node, CVMX_BGXX_SMUX_HG2_CONTROL(index, iface), 2705 hg2ctl.u64); 2706 csr_wr_node(node, CVMX_BGXX_SMUX_TX_CTL(index, iface), 2707 txctl.u64); 2708 break; 2709 } 2710 case CVMX_HELPER_INTERFACE_MODE_SGMII: 2711 case CVMX_HELPER_INTERFACE_MODE_RGMII: { 2712 cvmx_bgxx_gmp_gmi_rxx_frm_ctl_t gmi_frmctl; 2713 2714 gmi_frmctl.u64 = csr_rd_node( 2715 node, CVMX_BGXX_GMP_GMI_RXX_FRM_CTL(index, iface)); 2716 switch (qos) { 2717 case CVMX_QOS_PROTO_PAUSE: 2718 gmi_frmctl.s.ctl_bck = fcmode[fc_mode].bck; 2719 gmi_frmctl.s.ctl_drp = fcmode[fc_mode].drp; 2720 gmi_frmctl.s.ctl_mcst = 1; 2721 break; 2722 case CVMX_QOS_PROTO_NONE: 2723 gmi_frmctl.s.ctl_bck = 2724 fcmode[CVMX_QOS_PKT_MODE_DROP].bck; 2725 gmi_frmctl.s.ctl_drp = 2726 fcmode[CVMX_QOS_PKT_MODE_DROP].drp; 2727 break; 2728 default: 2729 break; 2730 } 2731 csr_wr_node(node, CVMX_BGXX_GMP_GMI_RXX_FRM_CTL(index, iface), 2732 gmi_frmctl.u64); 2733 } 2734 } /*switch*/ 2735 2736 return 0; 2737} 2738