diff options
Diffstat (limited to 'drivers/staging/octeon/cvmx-helper.c')
| -rw-r--r-- | drivers/staging/octeon/cvmx-helper.c | 1058 |
1 files changed, 1058 insertions, 0 deletions
diff --git a/drivers/staging/octeon/cvmx-helper.c b/drivers/staging/octeon/cvmx-helper.c new file mode 100644 index 00000000000..e9c5c836cef --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper.c | |||
| @@ -0,0 +1,1058 @@ | |||
| 1 | /***********************license start*************** | ||
| 2 | * Author: Cavium Networks | ||
| 3 | * | ||
| 4 | * Contact: support@caviumnetworks.com | ||
| 5 | * This file is part of the OCTEON SDK | ||
| 6 | * | ||
| 7 | * Copyright (c) 2003-2008 Cavium Networks | ||
| 8 | * | ||
| 9 | * This file is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License, Version 2, as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This file is distributed in the hope that it will be useful, but | ||
| 14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
| 15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
| 16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
| 17 | * details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this file; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 22 | * or visit http://www.gnu.org/licenses/. | ||
| 23 | * | ||
| 24 | * This file may also be available under a different license from Cavium. | ||
| 25 | * Contact Cavium Networks for more information | ||
| 26 | ***********************license end**************************************/ | ||
| 27 | |||
| 28 | /* | ||
| 29 | * | ||
| 30 | * Helper functions for common, but complicated tasks. | ||
| 31 | * | ||
| 32 | */ | ||
| 33 | #include <asm/octeon/octeon.h> | ||
| 34 | |||
| 35 | #include "cvmx-config.h" | ||
| 36 | |||
| 37 | #include "cvmx-fpa.h" | ||
| 38 | #include "cvmx-pip.h" | ||
| 39 | #include "cvmx-pko.h" | ||
| 40 | #include "cvmx-ipd.h" | ||
| 41 | #include "cvmx-spi.h" | ||
| 42 | #include "cvmx-helper.h" | ||
| 43 | #include "cvmx-helper-board.h" | ||
| 44 | |||
| 45 | #include "cvmx-pip-defs.h" | ||
| 46 | #include "cvmx-smix-defs.h" | ||
| 47 | #include "cvmx-asxx-defs.h" | ||
| 48 | |||
| 49 | /** | ||
| 50 | * cvmx_override_pko_queue_priority(int ipd_port, uint64_t | ||
| 51 | * priorities[16]) is a function pointer. It is meant to allow | ||
| 52 | * customization of the PKO queue priorities based on the port | ||
| 53 | * number. Users should set this pointer to a function before | ||
| 54 | * calling any cvmx-helper operations. | ||
| 55 | */ | ||
| 56 | void (*cvmx_override_pko_queue_priority) (int pko_port, | ||
| 57 | uint64_t priorities[16]); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * cvmx_override_ipd_port_setup(int ipd_port) is a function | ||
| 61 | * pointer. It is meant to allow customization of the IPD port | ||
| 62 | * setup before packet input/output comes online. It is called | ||
| 63 | * after cvmx-helper does the default IPD configuration, but | ||
| 64 | * before IPD is enabled. Users should set this pointer to a | ||
| 65 | * function before calling any cvmx-helper operations. | ||
| 66 | */ | ||
| 67 | void (*cvmx_override_ipd_port_setup) (int ipd_port); | ||
| 68 | |||
| 69 | /* Port count per interface */ | ||
| 70 | static int interface_port_count[4] = { 0, 0, 0, 0 }; | ||
| 71 | |||
| 72 | /* Port last configured link info index by IPD/PKO port */ | ||
| 73 | static cvmx_helper_link_info_t | ||
| 74 | port_link_info[CVMX_PIP_NUM_INPUT_PORTS]; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Return the number of interfaces the chip has. Each interface | ||
| 78 | * may have multiple ports. Most chips support two interfaces, | ||
| 79 | * but the CNX0XX and CNX1XX are exceptions. These only support | ||
| 80 | * one interface. | ||
| 81 | * | ||
| 82 | * Returns Number of interfaces on chip | ||
| 83 | */ | ||
| 84 | int cvmx_helper_get_number_of_interfaces(void) | ||
| 85 | { | ||
| 86 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
| 87 | return 4; | ||
| 88 | else | ||
| 89 | return 3; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Return the number of ports on an interface. Depending on the | ||
| 94 | * chip and configuration, this can be 1-16. A value of 0 | ||
| 95 | * specifies that the interface doesn't exist or isn't usable. | ||
| 96 | * | ||
| 97 | * @interface: Interface to get the port count for | ||
| 98 | * | ||
| 99 | * Returns Number of ports on interface. Can be Zero. | ||
| 100 | */ | ||
| 101 | int cvmx_helper_ports_on_interface(int interface) | ||
| 102 | { | ||
| 103 | return interface_port_count[interface]; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Get the operating mode of an interface. Depending on the Octeon | ||
| 108 | * chip and configuration, this function returns an enumeration | ||
| 109 | * of the type of packet I/O supported by an interface. | ||
| 110 | * | ||
| 111 | * @interface: Interface to probe | ||
| 112 | * | ||
| 113 | * Returns Mode of the interface. Unknown or unsupported interfaces return | ||
| 114 | * DISABLED. | ||
| 115 | */ | ||
| 116 | cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) | ||
| 117 | { | ||
| 118 | union cvmx_gmxx_inf_mode mode; | ||
| 119 | if (interface == 2) | ||
| 120 | return CVMX_HELPER_INTERFACE_MODE_NPI; | ||
| 121 | |||
| 122 | if (interface == 3) { | ||
| 123 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) | ||
| 124 | || OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
| 125 | return CVMX_HELPER_INTERFACE_MODE_LOOP; | ||
| 126 | else | ||
| 127 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (interface == 0 | ||
| 131 | && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 | ||
| 132 | && cvmx_sysinfo_get()->board_rev_major == 1) { | ||
| 133 | /* | ||
| 134 | * Lie about interface type of CN3005 board. This | ||
| 135 | * board has a switch on port 1 like the other | ||
| 136 | * evaluation boards, but it is connected over RGMII | ||
| 137 | * instead of GMII. Report GMII mode so that the | ||
| 138 | * speed is forced to 1 Gbit full duplex. Other than | ||
| 139 | * some initial configuration (which does not use the | ||
| 140 | * output of this function) there is no difference in | ||
| 141 | * setup between GMII and RGMII modes. | ||
| 142 | */ | ||
| 143 | return CVMX_HELPER_INTERFACE_MODE_GMII; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Interface 1 is always disabled on CN31XX and CN30XX */ | ||
| 147 | if ((interface == 1) | ||
| 148 | && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) | ||
| 149 | || OCTEON_IS_MODEL(OCTEON_CN50XX) | ||
| 150 | || OCTEON_IS_MODEL(OCTEON_CN52XX))) | ||
| 151 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
| 152 | |||
| 153 | mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); | ||
| 154 | |||
| 155 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { | ||
| 156 | switch (mode.cn56xx.mode) { | ||
| 157 | case 0: | ||
| 158 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
| 159 | case 1: | ||
| 160 | return CVMX_HELPER_INTERFACE_MODE_XAUI; | ||
| 161 | case 2: | ||
| 162 | return CVMX_HELPER_INTERFACE_MODE_SGMII; | ||
| 163 | case 3: | ||
| 164 | return CVMX_HELPER_INTERFACE_MODE_PICMG; | ||
| 165 | default: | ||
| 166 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
| 167 | } | ||
| 168 | } else { | ||
| 169 | if (!mode.s.en) | ||
| 170 | return CVMX_HELPER_INTERFACE_MODE_DISABLED; | ||
| 171 | |||
| 172 | if (mode.s.type) { | ||
| 173 | if (OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
| 174 | || OCTEON_IS_MODEL(OCTEON_CN58XX)) | ||
| 175 | return CVMX_HELPER_INTERFACE_MODE_SPI; | ||
| 176 | else | ||
| 177 | return CVMX_HELPER_INTERFACE_MODE_GMII; | ||
| 178 | } else | ||
| 179 | return CVMX_HELPER_INTERFACE_MODE_RGMII; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | /** | ||
| 184 | * Configure the IPD/PIP tagging and QoS options for a specific | ||
| 185 | * port. This function determines the POW work queue entry | ||
| 186 | * contents for a port. The setup performed here is controlled by | ||
| 187 | * the defines in executive-config.h. | ||
| 188 | * | ||
| 189 | * @ipd_port: Port to configure. This follows the IPD numbering, not the | ||
| 190 | * per interface numbering | ||
| 191 | * | ||
| 192 | * Returns Zero on success, negative on failure | ||
| 193 | */ | ||
| 194 | static int __cvmx_helper_port_setup_ipd(int ipd_port) | ||
| 195 | { | ||
| 196 | union cvmx_pip_prt_cfgx port_config; | ||
| 197 | union cvmx_pip_prt_tagx tag_config; | ||
| 198 | |||
| 199 | port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); | ||
| 200 | tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port)); | ||
| 201 | |||
| 202 | /* Have each port go to a different POW queue */ | ||
| 203 | port_config.s.qos = ipd_port & 0x7; | ||
| 204 | |||
| 205 | /* Process the headers and place the IP header in the work queue */ | ||
| 206 | port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE; | ||
| 207 | |||
| 208 | tag_config.s.ip6_src_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP; | ||
| 209 | tag_config.s.ip6_dst_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP; | ||
| 210 | tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT; | ||
| 211 | tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT; | ||
| 212 | tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER; | ||
| 213 | tag_config.s.ip4_src_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP; | ||
| 214 | tag_config.s.ip4_dst_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP; | ||
| 215 | tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT; | ||
| 216 | tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT; | ||
| 217 | tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL; | ||
| 218 | tag_config.s.inc_prt_flag = CVMX_HELPER_INPUT_TAG_INPUT_PORT; | ||
| 219 | tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | ||
| 220 | tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | ||
| 221 | tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | ||
| 222 | tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | ||
| 223 | tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; | ||
| 224 | /* Put all packets in group 0. Other groups can be used by the app */ | ||
| 225 | tag_config.s.grp = 0; | ||
| 226 | |||
| 227 | cvmx_pip_config_port(ipd_port, port_config, tag_config); | ||
| 228 | |||
| 229 | /* Give the user a chance to override our setting for each port */ | ||
| 230 | if (cvmx_override_ipd_port_setup) | ||
| 231 | cvmx_override_ipd_port_setup(ipd_port); | ||
| 232 | |||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * This function probes an interface to determine the actual | ||
| 238 | * number of hardware ports connected to it. It doesn't setup the | ||
| 239 | * ports or enable them. The main goal here is to set the global | ||
| 240 | * interface_port_count[interface] correctly. Hardware setup of the | ||
| 241 | * ports will be performed later. | ||
| 242 | * | ||
| 243 | * @interface: Interface to probe | ||
| 244 | * | ||
| 245 | * Returns Zero on success, negative on failure | ||
| 246 | */ | ||
| 247 | int cvmx_helper_interface_probe(int interface) | ||
| 248 | { | ||
| 249 | /* At this stage in the game we don't want packets to be moving yet. | ||
| 250 | The following probe calls should perform hardware setup | ||
| 251 | needed to determine port counts. Receive must still be disabled */ | ||
| 252 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 253 | /* These types don't support ports to IPD/PKO */ | ||
| 254 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 255 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 256 | interface_port_count[interface] = 0; | ||
| 257 | break; | ||
| 258 | /* XAUI is a single high speed port */ | ||
| 259 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 260 | interface_port_count[interface] = | ||
| 261 | __cvmx_helper_xaui_probe(interface); | ||
| 262 | break; | ||
| 263 | /* | ||
| 264 | * RGMII/GMII/MII are all treated about the same. Most | ||
| 265 | * functions refer to these ports as RGMII. | ||
| 266 | */ | ||
| 267 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 268 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 269 | interface_port_count[interface] = | ||
| 270 | __cvmx_helper_rgmii_probe(interface); | ||
| 271 | break; | ||
| 272 | /* | ||
| 273 | * SPI4 can have 1-16 ports depending on the device at | ||
| 274 | * the other end. | ||
| 275 | */ | ||
| 276 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 277 | interface_port_count[interface] = | ||
| 278 | __cvmx_helper_spi_probe(interface); | ||
| 279 | break; | ||
| 280 | /* | ||
| 281 | * SGMII can have 1-4 ports depending on how many are | ||
| 282 | * hooked up. | ||
| 283 | */ | ||
| 284 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 285 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 286 | interface_port_count[interface] = | ||
| 287 | __cvmx_helper_sgmii_probe(interface); | ||
| 288 | break; | ||
| 289 | /* PCI target Network Packet Interface */ | ||
| 290 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 291 | interface_port_count[interface] = | ||
| 292 | __cvmx_helper_npi_probe(interface); | ||
| 293 | break; | ||
| 294 | /* | ||
| 295 | * Special loopback only ports. These are not the same | ||
| 296 | * as other ports in loopback mode. | ||
| 297 | */ | ||
| 298 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 299 | interface_port_count[interface] = | ||
| 300 | __cvmx_helper_loop_probe(interface); | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | |||
| 304 | interface_port_count[interface] = | ||
| 305 | __cvmx_helper_board_interface_probe(interface, | ||
| 306 | interface_port_count | ||
| 307 | [interface]); | ||
| 308 | |||
| 309 | /* Make sure all global variables propagate to other cores */ | ||
| 310 | CVMX_SYNCWS; | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | /** | ||
| 316 | * Setup the IPD/PIP for the ports on an interface. Packet | ||
| 317 | * classification and tagging are set for every port on the | ||
| 318 | * interface. The number of ports on the interface must already | ||
| 319 | * have been probed. | ||
| 320 | * | ||
| 321 | * @interface: Interface to setup IPD/PIP for | ||
| 322 | * | ||
| 323 | * Returns Zero on success, negative on failure | ||
| 324 | */ | ||
| 325 | static int __cvmx_helper_interface_setup_ipd(int interface) | ||
| 326 | { | ||
| 327 | int ipd_port = cvmx_helper_get_ipd_port(interface, 0); | ||
| 328 | int num_ports = interface_port_count[interface]; | ||
| 329 | |||
| 330 | while (num_ports--) { | ||
| 331 | __cvmx_helper_port_setup_ipd(ipd_port); | ||
| 332 | ipd_port++; | ||
| 333 | } | ||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * Setup global setting for IPD/PIP not related to a specific | ||
| 339 | * interface or port. This must be called before IPD is enabled. | ||
| 340 | * | ||
| 341 | * Returns Zero on success, negative on failure. | ||
| 342 | */ | ||
| 343 | static int __cvmx_helper_global_setup_ipd(void) | ||
| 344 | { | ||
| 345 | /* Setup the global packet input options */ | ||
| 346 | cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8, | ||
| 347 | CVMX_HELPER_FIRST_MBUFF_SKIP / 8, | ||
| 348 | CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8, | ||
| 349 | /* The +8 is to account for the next ptr */ | ||
| 350 | (CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128, | ||
| 351 | /* The +8 is to account for the next ptr */ | ||
| 352 | (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128, | ||
| 353 | CVMX_FPA_WQE_POOL, | ||
| 354 | CVMX_IPD_OPC_MODE_STT, | ||
| 355 | CVMX_HELPER_ENABLE_BACK_PRESSURE); | ||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | /** | ||
| 360 | * Setup the PKO for the ports on an interface. The number of | ||
| 361 | * queues per port and the priority of each PKO output queue | ||
| 362 | * is set here. PKO must be disabled when this function is called. | ||
| 363 | * | ||
| 364 | * @interface: Interface to setup PKO for | ||
| 365 | * | ||
| 366 | * Returns Zero on success, negative on failure | ||
| 367 | */ | ||
| 368 | static int __cvmx_helper_interface_setup_pko(int interface) | ||
| 369 | { | ||
| 370 | /* | ||
| 371 | * Each packet output queue has an associated priority. The | ||
| 372 | * higher the priority, the more often it can send a packet. A | ||
| 373 | * priority of 8 means it can send in all 8 rounds of | ||
| 374 | * contention. We're going to make each queue one less than | ||
| 375 | * the last. The vector of priorities has been extended to | ||
| 376 | * support CN5xxx CPUs, where up to 16 queues can be | ||
| 377 | * associated to a port. To keep backward compatibility we | ||
| 378 | * don't change the initial 8 priorities and replicate them in | ||
| 379 | * the second half. With per-core PKO queues (PKO lockless | ||
| 380 | * operation) all queues have the same priority. | ||
| 381 | */ | ||
| 382 | uint64_t priorities[16] = | ||
| 383 | { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 }; | ||
| 384 | |||
| 385 | /* | ||
| 386 | * Setup the IPD/PIP and PKO for the ports discovered | ||
| 387 | * above. Here packet classification, tagging and output | ||
| 388 | * priorities are set. | ||
| 389 | */ | ||
| 390 | int ipd_port = cvmx_helper_get_ipd_port(interface, 0); | ||
| 391 | int num_ports = interface_port_count[interface]; | ||
| 392 | while (num_ports--) { | ||
| 393 | /* | ||
| 394 | * Give the user a chance to override the per queue | ||
| 395 | * priorities. | ||
| 396 | */ | ||
| 397 | if (cvmx_override_pko_queue_priority) | ||
| 398 | cvmx_override_pko_queue_priority(ipd_port, priorities); | ||
| 399 | |||
| 400 | cvmx_pko_config_port(ipd_port, | ||
| 401 | cvmx_pko_get_base_queue_per_core(ipd_port, | ||
| 402 | 0), | ||
| 403 | cvmx_pko_get_num_queues(ipd_port), | ||
| 404 | priorities); | ||
| 405 | ipd_port++; | ||
| 406 | } | ||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | /** | ||
| 411 | * Setup global setting for PKO not related to a specific | ||
| 412 | * interface or port. This must be called before PKO is enabled. | ||
| 413 | * | ||
| 414 | * Returns Zero on success, negative on failure. | ||
| 415 | */ | ||
| 416 | static int __cvmx_helper_global_setup_pko(void) | ||
| 417 | { | ||
| 418 | /* | ||
| 419 | * Disable tagwait FAU timeout. This needs to be done before | ||
| 420 | * anyone might start packet output using tags. | ||
| 421 | */ | ||
| 422 | union cvmx_iob_fau_timeout fau_to; | ||
| 423 | fau_to.u64 = 0; | ||
| 424 | fau_to.s.tout_val = 0xfff; | ||
| 425 | fau_to.s.tout_enb = 0; | ||
| 426 | cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); | ||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | /** | ||
| 431 | * Setup global backpressure setting. | ||
| 432 | * | ||
| 433 | * Returns Zero on success, negative on failure | ||
| 434 | */ | ||
| 435 | static int __cvmx_helper_global_setup_backpressure(void) | ||
| 436 | { | ||
| 437 | #if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE | ||
| 438 | /* Disable backpressure if configured to do so */ | ||
| 439 | /* Disable backpressure (pause frame) generation */ | ||
| 440 | int num_interfaces = cvmx_helper_get_number_of_interfaces(); | ||
| 441 | int interface; | ||
| 442 | for (interface = 0; interface < num_interfaces; interface++) { | ||
| 443 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 444 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 445 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 446 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 447 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 448 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 449 | break; | ||
| 450 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 451 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 452 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 453 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 454 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 455 | cvmx_gmx_set_backpressure_override(interface, 0xf); | ||
| 456 | break; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | #endif | ||
| 460 | |||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | /** | ||
| 465 | * Enable packet input/output from the hardware. This function is | ||
| 466 | * called after all internal setup is complete and IPD is enabled. | ||
| 467 | * After this function completes, packets will be accepted from the | ||
| 468 | * hardware ports. PKO should still be disabled to make sure packets | ||
| 469 | * aren't sent out partially setup hardware. | ||
| 470 | * | ||
| 471 | * @interface: Interface to enable | ||
| 472 | * | ||
| 473 | * Returns Zero on success, negative on failure | ||
| 474 | */ | ||
| 475 | static int __cvmx_helper_packet_hardware_enable(int interface) | ||
| 476 | { | ||
| 477 | int result = 0; | ||
| 478 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 479 | /* These types don't support ports to IPD/PKO */ | ||
| 480 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 481 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 482 | /* Nothing to do */ | ||
| 483 | break; | ||
| 484 | /* XAUI is a single high speed port */ | ||
| 485 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 486 | result = __cvmx_helper_xaui_enable(interface); | ||
| 487 | break; | ||
| 488 | /* | ||
| 489 | * RGMII/GMII/MII are all treated about the same. Most | ||
| 490 | * functions refer to these ports as RGMII | ||
| 491 | */ | ||
| 492 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 493 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 494 | result = __cvmx_helper_rgmii_enable(interface); | ||
| 495 | break; | ||
| 496 | /* | ||
| 497 | * SPI4 can have 1-16 ports depending on the device at | ||
| 498 | * the other end | ||
| 499 | */ | ||
| 500 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 501 | result = __cvmx_helper_spi_enable(interface); | ||
| 502 | break; | ||
| 503 | /* | ||
| 504 | * SGMII can have 1-4 ports depending on how many are | ||
| 505 | * hooked up | ||
| 506 | */ | ||
| 507 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 508 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 509 | result = __cvmx_helper_sgmii_enable(interface); | ||
| 510 | break; | ||
| 511 | /* PCI target Network Packet Interface */ | ||
| 512 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 513 | result = __cvmx_helper_npi_enable(interface); | ||
| 514 | break; | ||
| 515 | /* | ||
| 516 | * Special loopback only ports. These are not the same | ||
| 517 | * as other ports in loopback mode | ||
| 518 | */ | ||
| 519 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 520 | result = __cvmx_helper_loop_enable(interface); | ||
| 521 | break; | ||
| 522 | } | ||
| 523 | result |= __cvmx_helper_board_hardware_enable(interface); | ||
| 524 | return result; | ||
| 525 | } | ||
| 526 | |||
| 527 | /** | ||
| 528 | * Function to adjust internal IPD pointer alignments | ||
| 529 | * | ||
| 530 | * Returns 0 on success | ||
| 531 | * !0 on failure | ||
| 532 | */ | ||
| 533 | int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) | ||
| 534 | { | ||
| 535 | #define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \ | ||
| 536 | (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP) | ||
| 537 | #define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \ | ||
| 538 | (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP) | ||
| 539 | #define FIX_IPD_OUTPORT 0 | ||
| 540 | /* Ports 0-15 are interface 0, 16-31 are interface 1 */ | ||
| 541 | #define INTERFACE(port) (port >> 4) | ||
| 542 | #define INDEX(port) (port & 0xf) | ||
| 543 | uint64_t *p64; | ||
| 544 | cvmx_pko_command_word0_t pko_command; | ||
| 545 | union cvmx_buf_ptr g_buffer, pkt_buffer; | ||
| 546 | cvmx_wqe_t *work; | ||
| 547 | int size, num_segs = 0, wqe_pcnt, pkt_pcnt; | ||
| 548 | union cvmx_gmxx_prtx_cfg gmx_cfg; | ||
| 549 | int retry_cnt; | ||
| 550 | int retry_loop_cnt; | ||
| 551 | int mtu; | ||
| 552 | int i; | ||
| 553 | cvmx_helper_link_info_t link_info; | ||
| 554 | |||
| 555 | /* Save values for restore at end */ | ||
| 556 | uint64_t prtx_cfg = | ||
| 557 | cvmx_read_csr(CVMX_GMXX_PRTX_CFG | ||
| 558 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); | ||
| 559 | uint64_t tx_ptr_en = | ||
| 560 | cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); | ||
| 561 | uint64_t rx_ptr_en = | ||
| 562 | cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); | ||
| 563 | uint64_t rxx_jabber = | ||
| 564 | cvmx_read_csr(CVMX_GMXX_RXX_JABBER | ||
| 565 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); | ||
| 566 | uint64_t frame_max = | ||
| 567 | cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX | ||
| 568 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); | ||
| 569 | |||
| 570 | /* Configure port to gig FDX as required for loopback mode */ | ||
| 571 | cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT); | ||
| 572 | |||
| 573 | /* | ||
| 574 | * Disable reception on all ports so if traffic is present it | ||
| 575 | * will not interfere. | ||
| 576 | */ | ||
| 577 | cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0); | ||
| 578 | |||
| 579 | cvmx_wait(100000000ull); | ||
| 580 | |||
| 581 | for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) { | ||
| 582 | retry_cnt = 100000; | ||
| 583 | wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT); | ||
| 584 | pkt_pcnt = (wqe_pcnt >> 7) & 0x7f; | ||
| 585 | wqe_pcnt &= 0x7f; | ||
| 586 | |||
| 587 | num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3; | ||
| 588 | |||
| 589 | if (num_segs == 0) | ||
| 590 | goto fix_ipd_exit; | ||
| 591 | |||
| 592 | num_segs += 1; | ||
| 593 | |||
| 594 | size = | ||
| 595 | FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES + | ||
| 596 | ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) - | ||
| 597 | (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2); | ||
| 598 | |||
| 599 | cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), | ||
| 600 | 1 << INDEX(FIX_IPD_OUTPORT)); | ||
| 601 | CVMX_SYNC; | ||
| 602 | |||
| 603 | g_buffer.u64 = 0; | ||
| 604 | g_buffer.s.addr = | ||
| 605 | cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL)); | ||
| 606 | if (g_buffer.s.addr == 0) { | ||
| 607 | cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " | ||
| 608 | "buffer allocation failure.\n"); | ||
| 609 | goto fix_ipd_exit; | ||
| 610 | } | ||
| 611 | |||
| 612 | g_buffer.s.pool = CVMX_FPA_WQE_POOL; | ||
| 613 | g_buffer.s.size = num_segs; | ||
| 614 | |||
| 615 | pkt_buffer.u64 = 0; | ||
| 616 | pkt_buffer.s.addr = | ||
| 617 | cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL)); | ||
| 618 | if (pkt_buffer.s.addr == 0) { | ||
| 619 | cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " | ||
| 620 | "buffer allocation failure.\n"); | ||
| 621 | goto fix_ipd_exit; | ||
| 622 | } | ||
| 623 | pkt_buffer.s.i = 1; | ||
| 624 | pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL; | ||
| 625 | pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES; | ||
| 626 | |||
| 627 | p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr); | ||
| 628 | p64[0] = 0xffffffffffff0000ull; | ||
| 629 | p64[1] = 0x08004510ull; | ||
| 630 | p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull; | ||
| 631 | p64[3] = 0x3a5fc0a81073c0a8ull; | ||
| 632 | |||
| 633 | for (i = 0; i < num_segs; i++) { | ||
| 634 | if (i > 0) | ||
| 635 | pkt_buffer.s.size = | ||
| 636 | FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES; | ||
| 637 | |||
| 638 | if (i == (num_segs - 1)) | ||
| 639 | pkt_buffer.s.i = 0; | ||
| 640 | |||
| 641 | *(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr + | ||
| 642 | 8 * i) = pkt_buffer.u64; | ||
| 643 | } | ||
| 644 | |||
| 645 | /* Build the PKO command */ | ||
| 646 | pko_command.u64 = 0; | ||
| 647 | pko_command.s.segs = num_segs; | ||
| 648 | pko_command.s.total_bytes = size; | ||
| 649 | pko_command.s.dontfree = 0; | ||
| 650 | pko_command.s.gather = 1; | ||
| 651 | |||
| 652 | gmx_cfg.u64 = | ||
| 653 | cvmx_read_csr(CVMX_GMXX_PRTX_CFG | ||
| 654 | (INDEX(FIX_IPD_OUTPORT), | ||
| 655 | INTERFACE(FIX_IPD_OUTPORT))); | ||
| 656 | gmx_cfg.s.en = 1; | ||
| 657 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG | ||
| 658 | (INDEX(FIX_IPD_OUTPORT), | ||
| 659 | INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64); | ||
| 660 | cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), | ||
| 661 | 1 << INDEX(FIX_IPD_OUTPORT)); | ||
| 662 | cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), | ||
| 663 | 1 << INDEX(FIX_IPD_OUTPORT)); | ||
| 664 | |||
| 665 | mtu = | ||
| 666 | cvmx_read_csr(CVMX_GMXX_RXX_JABBER | ||
| 667 | (INDEX(FIX_IPD_OUTPORT), | ||
| 668 | INTERFACE(FIX_IPD_OUTPORT))); | ||
| 669 | cvmx_write_csr(CVMX_GMXX_RXX_JABBER | ||
| 670 | (INDEX(FIX_IPD_OUTPORT), | ||
| 671 | INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); | ||
| 672 | cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX | ||
| 673 | (INDEX(FIX_IPD_OUTPORT), | ||
| 674 | INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); | ||
| 675 | |||
| 676 | cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT, | ||
| 677 | cvmx_pko_get_base_queue | ||
| 678 | (FIX_IPD_OUTPORT), | ||
| 679 | CVMX_PKO_LOCK_CMD_QUEUE); | ||
| 680 | cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT, | ||
| 681 | cvmx_pko_get_base_queue | ||
| 682 | (FIX_IPD_OUTPORT), pko_command, | ||
| 683 | g_buffer, CVMX_PKO_LOCK_CMD_QUEUE); | ||
| 684 | |||
| 685 | CVMX_SYNC; | ||
| 686 | |||
| 687 | do { | ||
| 688 | work = cvmx_pow_work_request_sync(CVMX_POW_WAIT); | ||
| 689 | retry_cnt--; | ||
| 690 | } while ((work == NULL) && (retry_cnt > 0)); | ||
| 691 | |||
| 692 | if (!retry_cnt) | ||
| 693 | cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " | ||
| 694 | "get_work() timeout occurred.\n"); | ||
| 695 | |||
| 696 | /* Free packet */ | ||
| 697 | if (work) | ||
| 698 | cvmx_helper_free_packet_data(work); | ||
| 699 | } | ||
| 700 | |||
| 701 | fix_ipd_exit: | ||
| 702 | |||
| 703 | /* Return CSR configs to saved values */ | ||
| 704 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG | ||
| 705 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), | ||
| 706 | prtx_cfg); | ||
| 707 | cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), | ||
| 708 | tx_ptr_en); | ||
| 709 | cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), | ||
| 710 | rx_ptr_en); | ||
| 711 | cvmx_write_csr(CVMX_GMXX_RXX_JABBER | ||
| 712 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), | ||
| 713 | rxx_jabber); | ||
| 714 | cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX | ||
| 715 | (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), | ||
| 716 | frame_max); | ||
| 717 | cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0); | ||
| 718 | /* Set link to down so autonegotiation will set it up again */ | ||
| 719 | link_info.u64 = 0; | ||
| 720 | cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info); | ||
| 721 | |||
| 722 | /* | ||
| 723 | * Bring the link back up as autonegotiation is not done in | ||
| 724 | * user applications. | ||
| 725 | */ | ||
| 726 | cvmx_helper_link_autoconf(FIX_IPD_OUTPORT); | ||
| 727 | |||
| 728 | CVMX_SYNC; | ||
| 729 | if (num_segs) | ||
| 730 | cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n"); | ||
| 731 | |||
| 732 | return !!num_segs; | ||
| 733 | |||
| 734 | } | ||
| 735 | |||
| 736 | /** | ||
| 737 | * Called after all internal packet IO paths are setup. This | ||
| 738 | * function enables IPD/PIP and begins packet input and output. | ||
| 739 | * | ||
| 740 | * Returns Zero on success, negative on failure | ||
| 741 | */ | ||
| 742 | int cvmx_helper_ipd_and_packet_input_enable(void) | ||
| 743 | { | ||
| 744 | int num_interfaces; | ||
| 745 | int interface; | ||
| 746 | |||
| 747 | /* Enable IPD */ | ||
| 748 | cvmx_ipd_enable(); | ||
| 749 | |||
| 750 | /* | ||
| 751 | * Time to enable hardware ports packet input and output. Note | ||
| 752 | * that at this point IPD/PIP must be fully functional and PKO | ||
| 753 | * must be disabled | ||
| 754 | */ | ||
| 755 | num_interfaces = cvmx_helper_get_number_of_interfaces(); | ||
| 756 | for (interface = 0; interface < num_interfaces; interface++) { | ||
| 757 | if (cvmx_helper_ports_on_interface(interface) > 0) | ||
| 758 | __cvmx_helper_packet_hardware_enable(interface); | ||
| 759 | } | ||
| 760 | |||
| 761 | /* Finally enable PKO now that the entire path is up and running */ | ||
| 762 | cvmx_pko_enable(); | ||
| 763 | |||
| 764 | if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) | ||
| 765 | || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) | ||
| 766 | && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)) | ||
| 767 | __cvmx_helper_errata_fix_ipd_ptr_alignment(); | ||
| 768 | return 0; | ||
| 769 | } | ||
| 770 | |||
| 771 | /** | ||
| 772 | * Initialize the PIP, IPD, and PKO hardware to support | ||
| 773 | * simple priority based queues for the ethernet ports. Each | ||
| 774 | * port is configured with a number of priority queues based | ||
| 775 | * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower | ||
| 776 | * priority than the previous. | ||
| 777 | * | ||
| 778 | * Returns Zero on success, non-zero on failure | ||
| 779 | */ | ||
| 780 | int cvmx_helper_initialize_packet_io_global(void) | ||
| 781 | { | ||
| 782 | int result = 0; | ||
| 783 | int interface; | ||
| 784 | union cvmx_l2c_cfg l2c_cfg; | ||
| 785 | union cvmx_smix_en smix_en; | ||
| 786 | const int num_interfaces = cvmx_helper_get_number_of_interfaces(); | ||
| 787 | |||
| 788 | /* | ||
| 789 | * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to | ||
| 790 | * be disabled. | ||
| 791 | */ | ||
| 792 | if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) | ||
| 793 | __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1); | ||
| 794 | |||
| 795 | /* | ||
| 796 | * Tell L2 to give the IOB statically higher priority compared | ||
| 797 | * to the cores. This avoids conditions where IO blocks might | ||
| 798 | * be starved under very high L2 loads. | ||
| 799 | */ | ||
| 800 | l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); | ||
| 801 | l2c_cfg.s.lrf_arb_mode = 0; | ||
| 802 | l2c_cfg.s.rfb_arb_mode = 0; | ||
| 803 | cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64); | ||
| 804 | |||
| 805 | /* Make sure SMI/MDIO is enabled so we can query PHYs */ | ||
| 806 | smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0)); | ||
| 807 | if (!smix_en.s.en) { | ||
| 808 | smix_en.s.en = 1; | ||
| 809 | cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64); | ||
| 810 | } | ||
| 811 | |||
| 812 | /* Newer chips actually have two SMI/MDIO interfaces */ | ||
| 813 | if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && | ||
| 814 | !OCTEON_IS_MODEL(OCTEON_CN58XX) && | ||
| 815 | !OCTEON_IS_MODEL(OCTEON_CN50XX)) { | ||
| 816 | smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1)); | ||
| 817 | if (!smix_en.s.en) { | ||
| 818 | smix_en.s.en = 1; | ||
| 819 | cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64); | ||
| 820 | } | ||
| 821 | } | ||
| 822 | |||
| 823 | cvmx_pko_initialize_global(); | ||
| 824 | for (interface = 0; interface < num_interfaces; interface++) { | ||
| 825 | result |= cvmx_helper_interface_probe(interface); | ||
| 826 | if (cvmx_helper_ports_on_interface(interface) > 0) | ||
| 827 | cvmx_dprintf("Interface %d has %d ports (%s)\n", | ||
| 828 | interface, | ||
| 829 | cvmx_helper_ports_on_interface(interface), | ||
| 830 | cvmx_helper_interface_mode_to_string | ||
| 831 | (cvmx_helper_interface_get_mode | ||
| 832 | (interface))); | ||
| 833 | result |= __cvmx_helper_interface_setup_ipd(interface); | ||
| 834 | result |= __cvmx_helper_interface_setup_pko(interface); | ||
| 835 | } | ||
| 836 | |||
| 837 | result |= __cvmx_helper_global_setup_ipd(); | ||
| 838 | result |= __cvmx_helper_global_setup_pko(); | ||
| 839 | |||
| 840 | /* Enable any flow control and backpressure */ | ||
| 841 | result |= __cvmx_helper_global_setup_backpressure(); | ||
| 842 | |||
| 843 | #if CVMX_HELPER_ENABLE_IPD | ||
| 844 | result |= cvmx_helper_ipd_and_packet_input_enable(); | ||
| 845 | #endif | ||
| 846 | return result; | ||
| 847 | } | ||
| 848 | |||
| 849 | /** | ||
| 850 | * Does core local initialization for packet io | ||
| 851 | * | ||
| 852 | * Returns Zero on success, non-zero on failure | ||
| 853 | */ | ||
| 854 | int cvmx_helper_initialize_packet_io_local(void) | ||
| 855 | { | ||
| 856 | return cvmx_pko_initialize_local(); | ||
| 857 | } | ||
| 858 | |||
| 859 | /** | ||
| 860 | * Auto configure an IPD/PKO port link state and speed. This | ||
| 861 | * function basically does the equivalent of: | ||
| 862 | * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); | ||
| 863 | * | ||
| 864 | * @ipd_port: IPD/PKO port to auto configure | ||
| 865 | * | ||
| 866 | * Returns Link state after configure | ||
| 867 | */ | ||
| 868 | cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port) | ||
| 869 | { | ||
| 870 | cvmx_helper_link_info_t link_info; | ||
| 871 | int interface = cvmx_helper_get_interface_num(ipd_port); | ||
| 872 | int index = cvmx_helper_get_interface_index_num(ipd_port); | ||
| 873 | |||
| 874 | if (index >= cvmx_helper_ports_on_interface(interface)) { | ||
| 875 | link_info.u64 = 0; | ||
| 876 | return link_info; | ||
| 877 | } | ||
| 878 | |||
| 879 | link_info = cvmx_helper_link_get(ipd_port); | ||
| 880 | if (link_info.u64 == port_link_info[ipd_port].u64) | ||
| 881 | return link_info; | ||
| 882 | |||
| 883 | /* If we fail to set the link speed, port_link_info will not change */ | ||
| 884 | cvmx_helper_link_set(ipd_port, link_info); | ||
| 885 | |||
| 886 | /* | ||
| 887 | * port_link_info should be the current value, which will be | ||
| 888 | * different than expect if cvmx_helper_link_set() failed. | ||
| 889 | */ | ||
| 890 | return port_link_info[ipd_port]; | ||
| 891 | } | ||
| 892 | |||
| 893 | /** | ||
| 894 | * Return the link state of an IPD/PKO port as returned by | ||
| 895 | * auto negotiation. The result of this function may not match | ||
| 896 | * Octeon's link config if auto negotiation has changed since | ||
| 897 | * the last call to cvmx_helper_link_set(). | ||
| 898 | * | ||
| 899 | * @ipd_port: IPD/PKO port to query | ||
| 900 | * | ||
| 901 | * Returns Link state | ||
| 902 | */ | ||
| 903 | cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port) | ||
| 904 | { | ||
| 905 | cvmx_helper_link_info_t result; | ||
| 906 | int interface = cvmx_helper_get_interface_num(ipd_port); | ||
| 907 | int index = cvmx_helper_get_interface_index_num(ipd_port); | ||
| 908 | |||
| 909 | /* The default result will be a down link unless the code below | ||
| 910 | changes it */ | ||
| 911 | result.u64 = 0; | ||
| 912 | |||
| 913 | if (index >= cvmx_helper_ports_on_interface(interface)) | ||
| 914 | return result; | ||
| 915 | |||
| 916 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 917 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 918 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 919 | /* Network links are not supported */ | ||
| 920 | break; | ||
| 921 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 922 | result = __cvmx_helper_xaui_link_get(ipd_port); | ||
| 923 | break; | ||
| 924 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 925 | if (index == 0) | ||
| 926 | result = __cvmx_helper_rgmii_link_get(ipd_port); | ||
| 927 | else { | ||
| 928 | result.s.full_duplex = 1; | ||
| 929 | result.s.link_up = 1; | ||
| 930 | result.s.speed = 1000; | ||
| 931 | } | ||
| 932 | break; | ||
| 933 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 934 | result = __cvmx_helper_rgmii_link_get(ipd_port); | ||
| 935 | break; | ||
| 936 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 937 | result = __cvmx_helper_spi_link_get(ipd_port); | ||
| 938 | break; | ||
| 939 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 940 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 941 | result = __cvmx_helper_sgmii_link_get(ipd_port); | ||
| 942 | break; | ||
| 943 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 944 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 945 | /* Network links are not supported */ | ||
| 946 | break; | ||
| 947 | } | ||
| 948 | return result; | ||
| 949 | } | ||
| 950 | |||
| 951 | /** | ||
| 952 | * Configure an IPD/PKO port for the specified link state. This | ||
| 953 | * function does not influence auto negotiation at the PHY level. | ||
| 954 | * The passed link state must always match the link state returned | ||
| 955 | * by cvmx_helper_link_get(). It is normally best to use | ||
| 956 | * cvmx_helper_link_autoconf() instead. | ||
| 957 | * | ||
| 958 | * @ipd_port: IPD/PKO port to configure | ||
| 959 | * @link_info: The new link state | ||
| 960 | * | ||
| 961 | * Returns Zero on success, negative on failure | ||
| 962 | */ | ||
| 963 | int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info) | ||
| 964 | { | ||
| 965 | int result = -1; | ||
| 966 | int interface = cvmx_helper_get_interface_num(ipd_port); | ||
| 967 | int index = cvmx_helper_get_interface_index_num(ipd_port); | ||
| 968 | |||
| 969 | if (index >= cvmx_helper_ports_on_interface(interface)) | ||
| 970 | return -1; | ||
| 971 | |||
| 972 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 973 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 974 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 975 | break; | ||
| 976 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 977 | result = __cvmx_helper_xaui_link_set(ipd_port, link_info); | ||
| 978 | break; | ||
| 979 | /* | ||
| 980 | * RGMII/GMII/MII are all treated about the same. Most | ||
| 981 | * functions refer to these ports as RGMII. | ||
| 982 | */ | ||
| 983 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 984 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 985 | result = __cvmx_helper_rgmii_link_set(ipd_port, link_info); | ||
| 986 | break; | ||
| 987 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 988 | result = __cvmx_helper_spi_link_set(ipd_port, link_info); | ||
| 989 | break; | ||
| 990 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 991 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 992 | result = __cvmx_helper_sgmii_link_set(ipd_port, link_info); | ||
| 993 | break; | ||
| 994 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 995 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 996 | break; | ||
| 997 | } | ||
| 998 | /* Set the port_link_info here so that the link status is updated | ||
| 999 | no matter how cvmx_helper_link_set is called. We don't change | ||
| 1000 | the value if link_set failed */ | ||
| 1001 | if (result == 0) | ||
| 1002 | port_link_info[ipd_port].u64 = link_info.u64; | ||
| 1003 | return result; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | /** | ||
| 1007 | * Configure a port for internal and/or external loopback. Internal loopback | ||
| 1008 | * causes packets sent by the port to be received by Octeon. External loopback | ||
| 1009 | * causes packets received from the wire to sent out again. | ||
| 1010 | * | ||
| 1011 | * @ipd_port: IPD/PKO port to loopback. | ||
| 1012 | * @enable_internal: | ||
| 1013 | * Non zero if you want internal loopback | ||
| 1014 | * @enable_external: | ||
| 1015 | * Non zero if you want external loopback | ||
| 1016 | * | ||
| 1017 | * Returns Zero on success, negative on failure. | ||
| 1018 | */ | ||
| 1019 | int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, | ||
| 1020 | int enable_external) | ||
| 1021 | { | ||
| 1022 | int result = -1; | ||
| 1023 | int interface = cvmx_helper_get_interface_num(ipd_port); | ||
| 1024 | int index = cvmx_helper_get_interface_index_num(ipd_port); | ||
| 1025 | |||
| 1026 | if (index >= cvmx_helper_ports_on_interface(interface)) | ||
| 1027 | return -1; | ||
| 1028 | |||
| 1029 | switch (cvmx_helper_interface_get_mode(interface)) { | ||
| 1030 | case CVMX_HELPER_INTERFACE_MODE_DISABLED: | ||
| 1031 | case CVMX_HELPER_INTERFACE_MODE_PCIE: | ||
| 1032 | case CVMX_HELPER_INTERFACE_MODE_SPI: | ||
| 1033 | case CVMX_HELPER_INTERFACE_MODE_NPI: | ||
| 1034 | case CVMX_HELPER_INTERFACE_MODE_LOOP: | ||
| 1035 | break; | ||
| 1036 | case CVMX_HELPER_INTERFACE_MODE_XAUI: | ||
| 1037 | result = | ||
| 1038 | __cvmx_helper_xaui_configure_loopback(ipd_port, | ||
| 1039 | enable_internal, | ||
| 1040 | enable_external); | ||
| 1041 | break; | ||
| 1042 | case CVMX_HELPER_INTERFACE_MODE_RGMII: | ||
| 1043 | case CVMX_HELPER_INTERFACE_MODE_GMII: | ||
| 1044 | result = | ||
| 1045 | __cvmx_helper_rgmii_configure_loopback(ipd_port, | ||
| 1046 | enable_internal, | ||
| 1047 | enable_external); | ||
| 1048 | break; | ||
| 1049 | case CVMX_HELPER_INTERFACE_MODE_SGMII: | ||
| 1050 | case CVMX_HELPER_INTERFACE_MODE_PICMG: | ||
| 1051 | result = | ||
| 1052 | __cvmx_helper_sgmii_configure_loopback(ipd_port, | ||
| 1053 | enable_internal, | ||
| 1054 | enable_external); | ||
| 1055 | break; | ||
| 1056 | } | ||
| 1057 | return result; | ||
| 1058 | } | ||
