cvmx-helper-rgmii.c revision 210311
1/***********************license start*************** 2 * Copyright (c) 2003-2008 Cavium Networks (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 Networks 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 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33 * 34 * 35 * For any questions regarding licensing please contact marketing@caviumnetworks.com 36 * 37 ***********************license end**************************************/ 38 39 40 41 42 43 44/** 45 * @file 46 * 47 * Functions for RGMII/GMII/MII initialization, configuration, 48 * and monitoring. 49 * 50 * <hr>$Revision: 42417 $<hr> 51 */ 52#include "cvmx.h" 53#include "cvmx-sysinfo.h" 54#include "cvmx-mdio.h" 55#include "cvmx-pko.h" 56#include "cvmx-helper.h" 57#include "cvmx-helper-board.h" 58 59#ifdef CVMX_ENABLE_PKO_FUNCTIONS 60/** 61 * @INTERNAL 62 * Probe RGMII ports and determine the number present 63 * 64 * @param interface Interface to probe 65 * 66 * @return Number of RGMII/GMII/MII ports (0-4). 67 */ 68int __cvmx_helper_rgmii_probe(int interface) 69{ 70 int num_ports = 0; 71 cvmx_gmxx_inf_mode_t mode; 72 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 73 74 if (mode.s.type) 75 { 76 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 77 { 78 cvmx_dprintf("ERROR: RGMII initialize called in SPI interface\n"); 79 } 80 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 81 { 82 /* On these chips "type" says we're in GMII/MII mode. This 83 limits us to 2 ports */ 84 num_ports = 2; 85 } 86 else 87 { 88 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 89 } 90 } 91 else 92 { 93 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 94 { 95 num_ports = 4; 96 } 97 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 98 { 99 num_ports = 3; 100 } 101 else 102 { 103 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", __FUNCTION__); 104 } 105 } 106 return num_ports; 107} 108 109 110/** 111 * Put an RGMII interface in loopback mode. Internal packets sent 112 * out will be received back again on the same port. Externally 113 * received packets will echo back out. 114 * 115 * @param port IPD port number to loop. 116 */ 117void cvmx_helper_rgmii_internal_loopback(int port) 118{ 119 int interface = (port >> 4) & 1; 120 int index = port & 0xf; 121 uint64_t tmp; 122 123 cvmx_gmxx_prtx_cfg_t gmx_cfg; 124 gmx_cfg.u64 = 0; 125 gmx_cfg.s.duplex = 1; 126 gmx_cfg.s.slottime = 1; 127 gmx_cfg.s.speed = 1; 128 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 129 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 130 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 131 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 132 tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 133 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp); 134 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 135 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 136 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 137 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 138 gmx_cfg.s.en = 1; 139 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 140} 141 142 143/** 144 * @INTERNAL 145 * Configure all of the ASX, GMX, and PKO regsiters required 146 * to get RGMII to function on the supplied interface. 147 * 148 * @param interface PKO Interface to configure (0 or 1) 149 * 150 * @return Zero on success 151 */ 152int __cvmx_helper_rgmii_enable(int interface) 153{ 154 int num_ports = cvmx_helper_ports_on_interface(interface); 155 int port; 156 cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 157 cvmx_gmxx_inf_mode_t mode; 158 cvmx_asxx_tx_prt_en_t asx_tx; 159 cvmx_asxx_rx_prt_en_t asx_rx; 160 161 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 162 163 if (mode.s.en == 0) 164 return -1; 165 if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) /* Ignore SPI interfaces */ 166 return -1; 167 168 /* Configure the ASX registers needed to use the RGMII ports */ 169 asx_tx.u64 = 0; 170 asx_tx.s.prt_en = cvmx_build_mask(num_ports); 171 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64); 172 173 asx_rx.u64 = 0; 174 asx_rx.s.prt_en = cvmx_build_mask(num_ports); 175 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64); 176 177 /* Configure the GMX registers needed to use the RGMII ports */ 178 for (port=0; port<num_ports; port++) 179 { 180 /* Setting of CVMX_GMXX_TXX_THRESH has been moved to 181 __cvmx_helper_setup_gmx() */ 182 183 if (cvmx_octeon_is_pass1()) 184 __cvmx_helper_errata_asx_pass1(interface, port, sys_info_ptr->cpu_clock_hz); 185 else 186 { 187 /* Configure more flexible RGMII preamble checking. Pass 1 doesn't 188 support this feature. */ 189 cvmx_gmxx_rxx_frm_ctl_t frm_ctl; 190 frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface)); 191 frm_ctl.s.pre_free = 1; /* New field, so must be compile time */ 192 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), frm_ctl.u64); 193 } 194 195 /* Each pause frame transmitted will ask for about 10M bit times 196 before resume. If buffer space comes available before that time 197 has expired, an XON pause frame (0 time) will be transmitted to 198 restart the flow. */ 199 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), 20000); 200 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(port, interface), 19000); 201 202 /* 203 * Board types we have to know at compile-time. 204 */ 205#if defined(OCTEON_BOARD_CAPK_0100ND) 206 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 26); 207 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 26); 208#else 209 /* 210 * Vendor-defined board types. 211 */ 212#if defined(OCTEON_VENDOR_LANNER) 213 switch (cvmx_sysinfo_get()->board_type) { 214 case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 215 if (port == 0) { 216 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 4); 217 } else { 218 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 7); 219 } 220 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 0); 221 break; 222 } 223#else 224 /* 225 * For board types we can determine at runtime. 226 */ 227 if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 228 { 229 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 16); 230 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 16); 231 } 232 else 233 { 234 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), 24); 235 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), 24); 236 } 237#endif 238#endif 239 } 240 241 __cvmx_helper_setup_gmx(interface, num_ports); 242 243 /* enable the ports now */ 244 for (port=0; port<num_ports; port++) 245 { 246 cvmx_gmxx_prtx_cfg_t gmx_cfg; 247 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, port)); 248 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); 249 gmx_cfg.s.en = 1; 250 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), gmx_cfg.u64); 251 } 252 253 return 0; 254} 255 256 257/** 258 * @INTERNAL 259 * Return the link state of an IPD/PKO port as returned by 260 * auto negotiation. The result of this function may not match 261 * Octeon's link config if auto negotiation has changed since 262 * the last call to cvmx_helper_link_set(). 263 * 264 * @param ipd_port IPD/PKO port to query 265 * 266 * @return Link state 267 */ 268cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) 269{ 270 int interface = cvmx_helper_get_interface_num(ipd_port); 271 int index = cvmx_helper_get_interface_index_num(ipd_port); 272 cvmx_asxx_prt_loop_t asxx_prt_loop; 273 274 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 275 if (asxx_prt_loop.s.int_loop & (1<<index)) 276 { 277 /* Force 1Gbps full duplex on internal loopback */ 278 cvmx_helper_link_info_t result; 279 result.u64 = 0; 280 result.s.full_duplex = 1; 281 result.s.link_up = 1; 282 result.s.speed = 1000; 283 return result; 284 } 285 else 286 return __cvmx_helper_board_link_get(ipd_port); 287} 288 289 290/** 291 * @INTERNAL 292 * Configure an IPD/PKO port for the specified link state. This 293 * function does not influence auto negotiation at the PHY level. 294 * The passed link state must always match the link state returned 295 * by cvmx_helper_link_get(). It is normally best to use 296 * cvmx_helper_link_autoconf() instead. 297 * 298 * @param ipd_port IPD/PKO port to configure 299 * @param link_info The new link state 300 * 301 * @return Zero on success, negative on failure 302 */ 303int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 304{ 305 int result = 0; 306 int interface = cvmx_helper_get_interface_num(ipd_port); 307 int index = cvmx_helper_get_interface_index_num(ipd_port); 308 cvmx_gmxx_prtx_cfg_t original_gmx_cfg; 309 cvmx_gmxx_prtx_cfg_t new_gmx_cfg; 310 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos; 311 cvmx_pko_mem_queue_qos_t pko_mem_queue_qos_save[16]; 312 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp; 313 cvmx_gmxx_tx_ovr_bp_t gmx_tx_ovr_bp_save; 314 int i; 315 316 /* Ignore speed sets in the simulator */ 317 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) 318 return 0; 319 320 /* Read the current settings so we know the current enable state */ 321 original_gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 322 new_gmx_cfg = original_gmx_cfg; 323 324 /* Disable the lowest level RX */ 325 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 326 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1<<index)); 327 328 /* Disable all queues so that TX should become idle */ 329 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 330 { 331 int queue = cvmx_pko_get_base_queue(ipd_port) + i; 332 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 333 pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS); 334 pko_mem_queue_qos.s.pid = ipd_port; 335 pko_mem_queue_qos.s.qid = queue; 336 pko_mem_queue_qos_save[i] = pko_mem_queue_qos; 337 pko_mem_queue_qos.s.qos_mask = 0; 338 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64); 339 } 340 341 /* Disable backpressure */ 342 gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 343 gmx_tx_ovr_bp_save = gmx_tx_ovr_bp; 344 gmx_tx_ovr_bp.s.bp &= ~(1<<index); 345 gmx_tx_ovr_bp.s.en |= 1<<index; 346 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64); 347 cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); 348 349 /* Poll the GMX state machine waiting for it to become idle. Preferably we 350 should only change speed when it is idle. If it doesn't become idle we 351 will still do the speed change, but there is a slight chance that GMX 352 will lockup */ 353 cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880); 354 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, 10000); 355 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, 10000); 356 357 /* Disable the port before we make any changes */ 358 new_gmx_cfg.s.en = 0; 359 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 360 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 361 362 /* Set full/half duplex */ 363 if (cvmx_octeon_is_pass1()) 364 new_gmx_cfg.s.duplex = 1; /* Half duplex is broken for 38XX Pass 1 */ 365 else if (!link_info.s.link_up) 366 new_gmx_cfg.s.duplex = 1; /* Force full duplex on down links */ 367 else 368 new_gmx_cfg.s.duplex = link_info.s.full_duplex; 369 370 /* Set the link speed. Anything unknown is set to 1Gbps */ 371 if (link_info.s.speed == 10) 372 { 373 new_gmx_cfg.s.slottime = 0; 374 new_gmx_cfg.s.speed = 0; 375 } 376 else if (link_info.s.speed == 100) 377 { 378 new_gmx_cfg.s.slottime = 0; 379 new_gmx_cfg.s.speed = 0; 380 } 381 else 382 { 383 new_gmx_cfg.s.slottime = 1; 384 new_gmx_cfg.s.speed = 1; 385 } 386 387 /* Adjust the clocks */ 388 if (link_info.s.speed == 10) 389 { 390 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50); 391 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 392 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 393 } 394 else if (link_info.s.speed == 100) 395 { 396 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5); 397 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); 398 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); 399 } 400 else 401 { 402 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 403 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 404 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 405 } 406 407 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 408 { 409 if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) 410 { 411 cvmx_gmxx_inf_mode_t mode; 412 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); 413 414 /* 415 ** Port .en .type .p0mii Configuration 416 ** ---- --- ----- ------ ----------------------------------------- 417 ** X 0 X X All links are disabled. 418 ** 0 1 X 0 Port 0 is RGMII 419 ** 0 1 X 1 Port 0 is MII 420 ** 1 1 0 X Ports 1 and 2 are configured as RGMII ports. 421 ** 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or 422 ** MII port is selected by GMX_PRT1_CFG[SPEED]. 423 */ 424 425 /* In MII mode, CLK_CNT = 1. */ 426 if (((index == 0) && (mode.s.p0mii == 1)) || ((index != 0) && (mode.s.type == 1))) 427 { 428 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 429 } 430 } 431 } 432 433 /* Do a read to make sure all setup stuff is complete */ 434 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 435 436 /* Save the new GMX setting without enabling the port */ 437 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 438 439 /* Enable the lowest level RX */ 440 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 441 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1<<index)); 442 443 /* Re-enable the TX path */ 444 for (i=0; i<cvmx_pko_get_num_queues(ipd_port); i++) 445 { 446 int queue = cvmx_pko_get_base_queue(ipd_port) + i; 447 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); 448 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos_save[i].u64); 449 } 450 451 /* Restore backpressure */ 452 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64); 453 454 /* Restore the GMX enable state. Port config is complete */ 455 new_gmx_cfg.s.en = original_gmx_cfg.s.en; 456 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); 457 458 return result; 459} 460 461 462/** 463 * @INTERNAL 464 * Configure a port for internal and/or external loopback. Internal loopback 465 * causes packets sent by the port to be received by Octeon. External loopback 466 * causes packets received from the wire to sent out again. 467 * 468 * @param ipd_port IPD/PKO port to loopback. 469 * @param enable_internal 470 * Non zero if you want internal loopback 471 * @param enable_external 472 * Non zero if you want external loopback 473 * 474 * @return Zero on success, negative on failure. 475 */ 476int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external) 477{ 478 int interface = cvmx_helper_get_interface_num(ipd_port); 479 int index = cvmx_helper_get_interface_index_num(ipd_port); 480 int original_enable; 481 cvmx_gmxx_prtx_cfg_t gmx_cfg; 482 cvmx_asxx_prt_loop_t asxx_prt_loop; 483 484 /* Read the current enable state and save it */ 485 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 486 original_enable = gmx_cfg.s.en; 487 /* Force port to be disabled */ 488 gmx_cfg.s.en = 0; 489 if (enable_internal) 490 { 491 /* Force speed if we're doing internal loopback */ 492 gmx_cfg.s.duplex = 1; 493 gmx_cfg.s.slottime = 1; 494 gmx_cfg.s.speed = 1; 495 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); 496 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); 497 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); 498 } 499 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 500 501 /* Set the loopback bits */ 502 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); 503 if (enable_internal) 504 asxx_prt_loop.s.int_loop |= 1<<index; 505 else 506 asxx_prt_loop.s.int_loop &= ~(1<<index); 507 if (enable_external) 508 asxx_prt_loop.s.ext_loop |= 1<<index; 509 else 510 asxx_prt_loop.s.ext_loop &= ~(1<<index); 511 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64); 512 513 /* Force enables in internal loopback */ 514 if (enable_internal) 515 { 516 uint64_t tmp; 517 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); 518 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); 519 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); 520 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); 521 original_enable = 1; 522 } 523 524 /* Restore the enable state */ 525 gmx_cfg.s.en = original_enable; 526 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); 527 return 0; 528} 529 530#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 531 532