cvmx-helper-xaui.c revision 256281
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 42 43 44 45 46/** 47 * @file 48 * 49 * Functions for XAUI initialization, configuration, 50 * and monitoring. 51 * 52 * <hr>$Revision: 70030 $<hr> 53 */ 54#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 55#include <asm/octeon/cvmx.h> 56#include <asm/octeon/cvmx-config.h> 57#ifdef CVMX_ENABLE_PKO_FUNCTIONS 58#include <asm/octeon/cvmx-qlm.h> 59#include <asm/octeon/cvmx-helper.h> 60#include <asm/octeon/cvmx-helper-cfg.h> 61#endif 62#include <asm/octeon/cvmx-gmxx-defs.h> 63#include <asm/octeon/cvmx-pko-defs.h> 64#include <asm/octeon/cvmx-pcsx-defs.h> 65#include <asm/octeon/cvmx-pcsxx-defs.h> 66#include <asm/octeon/cvmx-ciu-defs.h> 67#else 68#if !defined(__FreeBSD__) || !defined(_KERNEL) 69#include "executive-config.h" 70#include "cvmx-config.h" 71 72#ifdef CVMX_ENABLE_PKO_FUNCTIONS 73 74#include "cvmx.h" 75#include "cvmx-helper.h" 76#include "cvmx-helper-cfg.h" 77#include "cvmx-qlm.h" 78#endif 79#else 80#include "cvmx.h" 81#include "cvmx-helper.h" 82#include "cvmx-qlm.h" 83#endif 84#endif 85 86#ifdef CVMX_ENABLE_PKO_FUNCTIONS 87 88int __cvmx_helper_xaui_enumerate(int interface) 89{ 90 union cvmx_gmxx_hg2_control gmx_hg2_control; 91 92 /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ 93 gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); 94 if (gmx_hg2_control.s.hg2tx_en) 95 return 16; 96 else 97 return 1; 98} 99 100/** 101 * @INTERNAL 102 * Probe a XAUI interface and determine the number of ports 103 * connected to it. The XAUI interface should still be down 104 * after this call. 105 * 106 * @param interface Interface to probe 107 * 108 * @return Number of ports on the interface. Zero to disable. 109 */ 110int __cvmx_helper_xaui_probe(int interface) 111{ 112 int i; 113 cvmx_gmxx_inf_mode_t mode; 114 115 /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ 116 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) 117 { 118 cvmx_ciu_qlm2_t ciu_qlm; 119 ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2); 120 ciu_qlm.s.txbypass = 1; 121 ciu_qlm.s.txdeemph = 0x5; 122 ciu_qlm.s.txmargin = 0x1a; 123 cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64); 124 } 125 126 /* CN63XX Pass 2.0 and 2.1 errata G-15273 requires the QLM De-emphasis be 127 programmed when using a 156.25Mhz ref clock */ 128 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) || 129 OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1)) 130 { 131 /* Read the QLM speed pins */ 132 cvmx_mio_rst_boot_t mio_rst_boot; 133 mio_rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT); 134 135 if (mio_rst_boot.cn63xx.qlm2_spd == 0xb) 136 { 137 cvmx_ciu_qlm2_t ciu_qlm; 138 ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM2); 139 ciu_qlm.s.txbypass = 1; 140 ciu_qlm.s.txdeemph = 0xa; 141 ciu_qlm.s.txmargin = 0x1f; 142 cvmx_write_csr(CVMX_CIU_QLM2, ciu_qlm.u64); 143 } 144 } 145 146 /* Check if QLM is configured correct for XAUI/RXAUI, verify the 147 speed as well as mode */ 148 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 149 { 150 int qlm, status; 151 152 qlm = cvmx_qlm_interface(interface); 153 status = cvmx_qlm_get_status(qlm); 154 if (status != 2 && status != 10) 155 return 0; 156 } 157 158 /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface 159 needs to be enabled before IPD otherwise per port backpressure 160 may not work properly */ 161 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 162 mode.s.en = 1; 163 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); 164 165 __cvmx_helper_setup_gmx(interface, 1); 166 167 if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) 168 { 169 /* Setup PKO to support 16 ports for HiGig2 virtual ports. We're pointing 170 all of the PKO packet ports for this interface to the XAUI. This allows 171 us to use HiGig2 backpressure per port */ 172 for (i=0; i<16; i++) 173 { 174 cvmx_pko_mem_port_ptrs_t pko_mem_port_ptrs; 175 pko_mem_port_ptrs.u64 = 0; 176 /* We set each PKO port to have equal priority in a round robin 177 fashion */ 178 pko_mem_port_ptrs.s.static_p = 0; 179 pko_mem_port_ptrs.s.qos_mask = 0xff; 180 /* All PKO ports map to the same XAUI hardware port */ 181 pko_mem_port_ptrs.s.eid = interface*4; 182 pko_mem_port_ptrs.s.pid = interface*16 + i; 183 cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); 184 } 185 } 186 187 return __cvmx_helper_xaui_enumerate(interface); 188} 189 190/** 191 * @INTERNAL 192 * Bringup XAUI interface. After this call packet I/O should be 193 * fully functional. 194 * 195 * @param interface Interface to bring up 196 * 197 * @return Zero on success, negative on failure 198 */ 199static int __cvmx_helper_xaui_link_init(int interface) 200{ 201 cvmx_gmxx_prtx_cfg_t gmx_cfg; 202 cvmx_pcsxx_control1_reg_t xauiCtl; 203 cvmx_pcsxx_misc_ctl_reg_t xauiMiscCtl; 204 cvmx_gmxx_tx_xaui_ctl_t gmxXauiTxCtl; 205 206 /* (1) Interface has already been enabled. */ 207 208 /* (2) Disable GMX. */ 209 xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); 210 xauiMiscCtl.s.gmxeno = 1; 211 cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); 212 213 /* (3) Disable GMX and PCSX interrupts. */ 214 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), 0x0); 215 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); 216 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); 217 218 /* (4) Bring up the PCSX and GMX reconciliation layer. */ 219 /* (4)a Set polarity and lane swapping. */ 220 /* (4)b */ 221 gmxXauiTxCtl.u64 = cvmx_read_csr (CVMX_GMXX_TX_XAUI_CTL(interface)); 222 gmxXauiTxCtl.s.dic_en = 1; /* Enable better IFG packing and improves performance */ 223 gmxXauiTxCtl.s.uni_en = 0; 224 cvmx_write_csr (CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64); 225 226 /* (4)c Aply reset sequence */ 227 xauiCtl.u64 = cvmx_read_csr (CVMX_PCSXX_CONTROL1_REG(interface)); 228 xauiCtl.s.lo_pwr = 0; 229 230 /* Errata G-15618 requires disabling PCS soft reset in some OCTEON II models. */ 231 if (!OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) 232 && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0) 233 && !OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_1) 234 && !OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) 235 && !OCTEON_IS_MODEL(OCTEON_CN68XX)) 236 xauiCtl.s.reset = 1; 237 cvmx_write_csr (CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); 238 239 /* Wait for PCS to come out of reset */ 240 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_CONTROL1_REG(interface), cvmx_pcsxx_control1_reg_t, reset, ==, 0, 10000)) 241 return -1; 242 /* Wait for PCS to be aligned */ 243 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_10GBX_STATUS_REG(interface), cvmx_pcsxx_10gbx_status_reg_t, alignd, ==, 1, 10000)) 244 return -1; 245 /* Wait for RX to be ready */ 246 if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_RX_XAUI_CTL(interface), cvmx_gmxx_rx_xaui_ctl_t, status, ==, 0, 10000)) 247 return -1; 248 249 /* (6) Configure GMX */ 250 251 /* Wait for GMX RX to be idle */ 252 if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000)) 253 return -1; 254 /* Wait for GMX TX to be idle */ 255 if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000)) 256 return -1; 257 258 /* GMX configure */ 259 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 260 gmx_cfg.s.speed = 1; 261 gmx_cfg.s.speed_msb = 0; 262 gmx_cfg.s.slottime = 1; 263 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1); 264 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512); 265 cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192); 266 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); 267 268 /* Wait for receive link */ 269 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS1_REG(interface), cvmx_pcsxx_status1_reg_t, rcv_lnk, ==, 1, 10000)) 270 return -1; 271 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, xmtflt, ==, 0, 10000)) 272 return -1; 273 if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, rcvflt, ==, 0, 10000)) 274 return -1; 275 276 /* (8) Enable packet reception */ 277 xauiMiscCtl.s.gmxeno = 0; 278 cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); 279 280 /* Clear all error interrupts before enabling the interface. */ 281 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0,interface), ~0x0ull); 282 cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), ~0x0ull); 283 cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), ~0x0ull); 284 285 /* Enable GMX */ 286 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 287 gmx_cfg.s.en = 1; 288 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); 289 290 return 0; 291} 292 293/** 294 * @INTERNAL 295 * Bringup and enable a XAUI interface. After this call packet 296 * I/O should be fully functional. This is called with IPD 297 * enabled but PKO disabled. 298 * 299 * @param interface Interface to bring up 300 * 301 * @return Zero on success, negative on failure 302 */ 303int __cvmx_helper_xaui_enable(int interface) 304{ 305 /* Setup PKND and BPID */ 306 if (octeon_has_feature(OCTEON_FEATURE_PKND)) 307 { 308 cvmx_gmxx_bpid_msk_t bpid_msk; 309 cvmx_gmxx_bpid_mapx_t bpid_map; 310 cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg; 311 cvmx_gmxx_txx_append_t gmxx_txx_append_cfg; 312 313 /* Setup PKIND */ 314 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); 315 gmxx_prtx_cfg.s.pknd = cvmx_helper_get_pknd(interface, 0); 316 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmxx_prtx_cfg.u64); 317 318 /* Setup BPID */ 319 bpid_map.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MAPX(0, interface)); 320 bpid_map.s.val = 1; 321 bpid_map.s.bpid = cvmx_helper_get_bpid(interface, 0); 322 cvmx_write_csr(CVMX_GMXX_BPID_MAPX(0, interface), bpid_map.u64); 323 324 bpid_msk.u64 = cvmx_read_csr(CVMX_GMXX_BPID_MSK(interface)); 325 bpid_msk.s.msk_or |= 1; 326 bpid_msk.s.msk_and &= ~1; 327 cvmx_write_csr(CVMX_GMXX_BPID_MSK(interface), bpid_msk.u64); 328 329 /* CN68XX adds the padding and FCS in PKO, not GMX */ 330 gmxx_txx_append_cfg.u64 = cvmx_read_csr(CVMX_GMXX_TXX_APPEND(0, interface)); 331 gmxx_txx_append_cfg.s.fcs = 0; 332 gmxx_txx_append_cfg.s.pad = 0; 333 cvmx_write_csr(CVMX_GMXX_TXX_APPEND(0, interface), gmxx_txx_append_cfg.u64); 334 } 335 336 __cvmx_helper_xaui_link_init(interface); 337 338 return 0; 339} 340 341/** 342 * @INTERNAL 343 * Return the link state of an IPD/PKO port as returned by 344 * auto negotiation. The result of this function may not match 345 * Octeon's link config if auto negotiation has changed since 346 * the last call to cvmx_helper_link_set(). 347 * 348 * @param ipd_port IPD/PKO port to query 349 * 350 * @return Link state 351 */ 352cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) 353{ 354 int interface = cvmx_helper_get_interface_num(ipd_port); 355 cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl; 356 cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl; 357 cvmx_pcsxx_status1_reg_t pcsxx_status1_reg; 358 cvmx_helper_link_info_t result; 359 360 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); 361 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); 362 pcsxx_status1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface)); 363 result.u64 = 0; 364 365 /* Only return a link if both RX and TX are happy */ 366 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) && 367 (pcsxx_status1_reg.s.rcv_lnk == 1)) 368 { 369 cvmx_pcsxx_misc_ctl_reg_t misc_ctl; 370 result.s.link_up = 1; 371 result.s.full_duplex = 1; 372 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 373 { 374 cvmx_mio_qlmx_cfg_t qlm_cfg; 375 int lanes; 376 int qlm = (interface == 1) ? 0 : interface; 377 378 qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(qlm)); 379 result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10; 380 lanes = (qlm_cfg.s.qlm_cfg == 7) ? 2 : 4; 381 result.s.speed *= lanes; 382 } 383 else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 384 { 385 int qlm = cvmx_qlm_interface(interface); 386 result.s.speed = cvmx_qlm_get_gbaud_mhz(qlm) * 8 / 10; 387 result.s.speed *= 4; 388 } 389 else 390 result.s.speed = 10000; 391 misc_ctl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); 392 if (misc_ctl.s.gmxeno) 393 __cvmx_helper_xaui_link_init(interface); 394 } 395 else 396 { 397 /* Disable GMX and PCSX interrupts. */ 398 cvmx_write_csr (CVMX_GMXX_RXX_INT_EN(0,interface), 0x0); 399 cvmx_write_csr (CVMX_GMXX_TX_INT_EN(interface), 0x0); 400 cvmx_write_csr (CVMX_PCSXX_INT_EN_REG(interface), 0x0); 401 } 402 return result; 403} 404 405 406/** 407 * @INTERNAL 408 * Configure an IPD/PKO port for the specified link state. This 409 * function does not influence auto negotiation at the PHY level. 410 * The passed link state must always match the link state returned 411 * by cvmx_helper_link_get(). It is normally best to use 412 * cvmx_helper_link_autoconf() instead. 413 * 414 * @param ipd_port IPD/PKO port to configure 415 * @param link_info The new link state 416 * 417 * @return Zero on success, negative on failure 418 */ 419int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 420{ 421 int interface = cvmx_helper_get_interface_num(ipd_port); 422 cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl; 423 cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl; 424 425 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); 426 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); 427 428 /* If the link shouldn't be up, then just return */ 429 if (!link_info.s.link_up) 430 return 0; 431 432 /* Do nothing if both RX and TX are happy */ 433 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0)) 434 return 0; 435 436 /* Bring the link up */ 437 return __cvmx_helper_xaui_link_init(interface); 438} 439 440 441/** 442 * @INTERNAL 443 * Configure a port for internal and/or external loopback. Internal loopback 444 * causes packets sent by the port to be received by Octeon. External loopback 445 * causes packets received from the wire to sent out again. 446 * 447 * @param ipd_port IPD/PKO port to loopback. 448 * @param enable_internal 449 * Non zero if you want internal loopback 450 * @param enable_external 451 * Non zero if you want external loopback 452 * 453 * @return Zero on success, negative on failure. 454 */ 455extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, int enable_internal, int enable_external) 456{ 457 int interface = cvmx_helper_get_interface_num(ipd_port); 458 cvmx_pcsxx_control1_reg_t pcsxx_control1_reg; 459 cvmx_gmxx_xaui_ext_loopback_t gmxx_xaui_ext_loopback; 460 461 /* Set the internal loop */ 462 pcsxx_control1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); 463 pcsxx_control1_reg.s.loopbck1 = enable_internal; 464 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), pcsxx_control1_reg.u64); 465 466 /* Set the external loop */ 467 gmxx_xaui_ext_loopback.u64 = cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface)); 468 gmxx_xaui_ext_loopback.s.en = enable_external; 469 cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), gmxx_xaui_ext_loopback.u64); 470 471 /* Take the link through a reset */ 472 return __cvmx_helper_xaui_link_init(interface); 473} 474 475#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 476 477