cvmx-helper.c revision 212844
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 * Helper functions for common, but complicated tasks.
48 *
49 * <hr>$Revision: 42150 $<hr>
50 */
51#include "cvmx.h"
52#include "cvmx-bootmem.h"
53#include "cvmx-fpa.h"
54#include "cvmx-pip.h"
55#include "cvmx-pko.h"
56#include "cvmx-ipd.h"
57#include "cvmx-asx.h"
58#include "cvmx-gmx.h"
59#include "cvmx-spi.h"
60#include "cvmx-sysinfo.h"
61#include "cvmx-helper.h"
62#include "cvmx-version.h"
63#include "cvmx-helper-check-defines.h"
64#include "cvmx-helper-board.h"
65#include "cvmx-helper-errata.h"
66
67#ifdef CVMX_ENABLE_PKO_FUNCTIONS
68
69/**
70 * cvmx_override_pko_queue_priority(int ipd_port, uint64_t
71 * priorities[16]) is a function pointer. It is meant to allow
72 * customization of the PKO queue priorities based on the port
73 * number. Users should set this pointer to a function before
74 * calling any cvmx-helper operations.
75 */
76CVMX_SHARED void (*cvmx_override_pko_queue_priority)(int pko_port, uint64_t priorities[16]) = NULL;
77
78/**
79 * cvmx_override_ipd_port_setup(int ipd_port) is a function
80 * pointer. It is meant to allow customization of the IPD port
81 * setup before packet input/output comes online. It is called
82 * after cvmx-helper does the default IPD configuration, but
83 * before IPD is enabled. Users should set this pointer to a
84 * function before calling any cvmx-helper operations.
85 */
86CVMX_SHARED void (*cvmx_override_ipd_port_setup)(int ipd_port) = NULL;
87
88/* Port count per interface */
89static CVMX_SHARED int interface_port_count[4] = {0,0,0,0};
90/* Port last configured link info index by IPD/PKO port */
91static CVMX_SHARED cvmx_helper_link_info_t port_link_info[CVMX_PIP_NUM_INPUT_PORTS];
92
93
94/**
95 * Return the number of interfaces the chip has. Each interface
96 * may have multiple ports. Most chips support two interfaces,
97 * but the CNX0XX and CNX1XX are exceptions. These only support
98 * one interface.
99 *
100 * @return Number of interfaces on chip
101 */
102int cvmx_helper_get_number_of_interfaces(void)
103{
104    switch (cvmx_sysinfo_get()->board_type) {
105#if defined(OCTEON_VENDOR_LANNER)
106	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
107	    return 2;
108#endif
109	default:
110	    break;
111    }
112
113    if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
114        return 4;
115    else
116        return 3;
117}
118
119
120/**
121 * Return the number of ports on an interface. Depending on the
122 * chip and configuration, this can be 1-16. A value of 0
123 * specifies that the interface doesn't exist or isn't usable.
124 *
125 * @param interface Interface to get the port count for
126 *
127 * @return Number of ports on interface. Can be Zero.
128 */
129int cvmx_helper_ports_on_interface(int interface)
130{
131    return interface_port_count[interface];
132}
133
134
135/**
136 * Get the operating mode of an interface. Depending on the Octeon
137 * chip and configuration, this function returns an enumeration
138 * of the type of packet I/O supported by an interface.
139 *
140 * @param interface Interface to probe
141 *
142 * @return Mode of the interface. Unknown or unsupported interfaces return
143 *         DISABLED.
144 */
145cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
146{
147    cvmx_gmxx_inf_mode_t mode;
148    if (interface == 2)
149        return CVMX_HELPER_INTERFACE_MODE_NPI;
150
151    if (interface == 3)
152    {
153        if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
154            return CVMX_HELPER_INTERFACE_MODE_LOOP;
155        else
156            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
157    }
158
159    if (interface == 0 && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 && cvmx_sysinfo_get()->board_rev_major == 1)
160    {
161        /* Lie about interface type of CN3005 board.  This board has a switch on port 1 like
162        ** the other evaluation boards, but it is connected over RGMII instead of GMII.  Report
163        ** GMII mode so that the speed is forced to 1 Gbit full duplex.  Other than some initial configuration
164        ** (which does not use the output of this function) there is no difference in setup between GMII and RGMII modes.
165        */
166        return CVMX_HELPER_INTERFACE_MODE_GMII;
167    }
168
169    /* Interface 1 is always disabled on CN31XX and CN30XX */
170    if ((interface == 1) && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)))
171        return CVMX_HELPER_INTERFACE_MODE_DISABLED;
172
173    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
174
175    if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
176    {
177        switch(mode.cn56xx.mode)
178        {
179            case 0: return CVMX_HELPER_INTERFACE_MODE_DISABLED;
180            case 1: return CVMX_HELPER_INTERFACE_MODE_XAUI;
181            case 2: return CVMX_HELPER_INTERFACE_MODE_SGMII;
182            case 3: return CVMX_HELPER_INTERFACE_MODE_PICMG;
183            default:return CVMX_HELPER_INTERFACE_MODE_DISABLED;
184        }
185    }
186    else
187    {
188        if (!mode.s.en)
189            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
190
191        if (mode.s.type)
192        {
193            if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
194                return CVMX_HELPER_INTERFACE_MODE_SPI;
195            else
196                return CVMX_HELPER_INTERFACE_MODE_GMII;
197        }
198        else
199            return CVMX_HELPER_INTERFACE_MODE_RGMII;
200    }
201}
202
203
204/**
205 * @INTERNAL
206 * Configure the IPD/PIP tagging and QoS options for a specific
207 * port. This function determines the POW work queue entry
208 * contents for a port. The setup performed here is controlled by
209 * the defines in executive-config.h.
210 *
211 * @param ipd_port Port to configure. This follows the IPD numbering, not the
212 *                 per interface numbering
213 *
214 * @return Zero on success, negative on failure
215 */
216static int __cvmx_helper_port_setup_ipd(int ipd_port)
217{
218    cvmx_pip_port_cfg_t port_config;
219    cvmx_pip_port_tag_cfg_t tag_config;
220
221    port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
222    tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port));
223
224    /* Have each port go to a different POW queue */
225    port_config.s.qos = ipd_port & 0x7;
226
227    /* Process the headers and place the IP header in the work queue */
228    port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE;
229
230    tag_config.s.ip6_src_flag  = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP;
231    tag_config.s.ip6_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP;
232    tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT;
233    tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT;
234    tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER;
235    tag_config.s.ip4_src_flag  = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP;
236    tag_config.s.ip4_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP;
237    tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT;
238    tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT;
239    tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL;
240    tag_config.s.inc_prt_flag  = CVMX_HELPER_INPUT_TAG_INPUT_PORT;
241    tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
242    tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
243    tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
244    tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
245    tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
246    /* Put all packets in group 0. Other groups can be used by the app */
247    tag_config.s.grp = 0;
248
249    cvmx_pip_config_port(ipd_port, port_config, tag_config);
250
251    /* Give the user a chance to override our setting for each port */
252    if (cvmx_override_ipd_port_setup)
253        cvmx_override_ipd_port_setup(ipd_port);
254
255    return 0;
256}
257
258
259/**
260 * This function probes an interface to determine the actual
261 * number of hardware ports connected to it. It doesn't setup the
262 * ports or enable them. The main goal here is to set the global
263 * interface_port_count[interface] correctly. Hardware setup of the
264 * ports will be performed later.
265 *
266 * @param interface Interface to probe
267 *
268 * @return Zero on success, negative on failure
269 */
270int cvmx_helper_interface_probe(int interface)
271{
272    /* At this stage in the game we don't want packets to be moving yet.
273        The following probe calls should perform hardware setup
274        needed to determine port counts. Receive must still be disabled */
275    switch (cvmx_helper_interface_get_mode(interface))
276    {
277        /* These types don't support ports to IPD/PKO */
278        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
279        case CVMX_HELPER_INTERFACE_MODE_PCIE:
280            interface_port_count[interface] = 0;
281            break;
282        /* XAUI is a single high speed port */
283        case CVMX_HELPER_INTERFACE_MODE_XAUI:
284            interface_port_count[interface] = __cvmx_helper_xaui_probe(interface);
285            break;
286        /* RGMII/GMII/MII are all treated about the same. Most functions
287            refer to these ports as RGMII */
288        case CVMX_HELPER_INTERFACE_MODE_RGMII:
289        case CVMX_HELPER_INTERFACE_MODE_GMII:
290            interface_port_count[interface] = __cvmx_helper_rgmii_probe(interface);
291            break;
292        /* SPI4 can have 1-16 ports depending on the device at the other end */
293        case CVMX_HELPER_INTERFACE_MODE_SPI:
294            interface_port_count[interface] = __cvmx_helper_spi_probe(interface);
295            break;
296        /* SGMII can have 1-4 ports depending on how many are hooked up */
297        case CVMX_HELPER_INTERFACE_MODE_SGMII:
298        case CVMX_HELPER_INTERFACE_MODE_PICMG:
299            interface_port_count[interface] = __cvmx_helper_sgmii_probe(interface);
300            break;
301        /* PCI target Network Packet Interface */
302        case CVMX_HELPER_INTERFACE_MODE_NPI:
303            interface_port_count[interface] = __cvmx_helper_npi_probe(interface);
304            break;
305        /* Special loopback only ports. These are not the same as other ports
306            in loopback mode */
307        case CVMX_HELPER_INTERFACE_MODE_LOOP:
308            interface_port_count[interface] = __cvmx_helper_loop_probe(interface);
309            break;
310    }
311
312    interface_port_count[interface] = __cvmx_helper_board_interface_probe(interface, interface_port_count[interface]);
313
314    /* Make sure all global variables propagate to other cores */
315    CVMX_SYNCWS;
316
317    return 0;
318}
319
320
321/**
322 * @INTERNAL
323 * Setup the IPD/PIP for the ports on an interface. Packet
324 * classification and tagging are set for every port on the
325 * interface. The number of ports on the interface must already
326 * have been probed.
327 *
328 * @param interface Interface to setup IPD/PIP for
329 *
330 * @return Zero on success, negative on failure
331 */
332static int __cvmx_helper_interface_setup_ipd(int interface)
333{
334    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
335    int num_ports = interface_port_count[interface];
336
337    while (num_ports--)
338    {
339        __cvmx_helper_port_setup_ipd(ipd_port);
340        ipd_port++;
341    }
342    return 0;
343}
344
345
346/**
347 * @INTERNAL
348 * Setup global setting for IPD/PIP not related to a specific
349 * interface or port. This must be called before IPD is enabled.
350 *
351 * @return Zero on success, negative on failure.
352 */
353static int __cvmx_helper_global_setup_ipd(void)
354{
355    /* Setup the global packet input options */
356    cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE/8,
357                    CVMX_HELPER_FIRST_MBUFF_SKIP/8,
358                    CVMX_HELPER_NOT_FIRST_MBUFF_SKIP/8,
359                    (CVMX_HELPER_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
360                    (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
361                    CVMX_FPA_WQE_POOL,
362                    CVMX_IPD_OPC_MODE_STT,
363                    CVMX_HELPER_ENABLE_BACK_PRESSURE);
364    return 0;
365}
366
367
368/**
369 * @INTERNAL
370 * Setup the PKO for the ports on an interface. The number of
371 * queues per port and the priority of each PKO output queue
372 * is set here. PKO must be disabled when this function is called.
373 *
374 * @param interface Interface to setup PKO for
375 *
376 * @return Zero on success, negative on failure
377 */
378static int __cvmx_helper_interface_setup_pko(int interface)
379{
380    /* Each packet output queue has an associated priority. The higher the
381        priority, the more often it can send a packet. A priority of 8 means
382        it can send in all 8 rounds of contention. We're going to make each
383        queue one less than the last.
384        The vector of priorities has been extended to support CN5xxx CPUs,
385        where up to 16 queues can be associated to a port.
386        To keep backward compatibility we don't change the initial 8
387        priorities and replicate them in the second half.
388        With per-core PKO queues (PKO lockless operation) all queues have
389        the same priority. */
390    uint64_t priorities[16] = {8,7,6,5,4,3,2,1,8,7,6,5,4,3,2,1};
391
392    /* Setup the IPD/PIP and PKO for the ports discovered above. Here packet
393        classification, tagging and output priorities are set */
394    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
395    int num_ports = interface_port_count[interface];
396    while (num_ports--)
397    {
398        /* Give the user a chance to override the per queue priorities */
399        if (cvmx_override_pko_queue_priority)
400            cvmx_override_pko_queue_priority(ipd_port, priorities);
401
402        cvmx_pko_config_port(ipd_port, cvmx_pko_get_base_queue_per_core(ipd_port, 0),
403                             cvmx_pko_get_num_queues(ipd_port), priorities);
404        ipd_port++;
405    }
406    return 0;
407}
408
409
410/**
411 * @INTERNAL
412 * Setup global setting for PKO not related to a specific
413 * interface or port. This must be called before PKO is enabled.
414 *
415 * @return Zero on success, negative on failure.
416 */
417static int __cvmx_helper_global_setup_pko(void)
418{
419    /* Disable tagwait FAU timeout. This needs to be done before anyone might
420        start packet output using tags */
421    cvmx_iob_fau_timeout_t fau_to;
422    fau_to.u64 = 0;
423    fau_to.s.tout_val = 0xfff;
424    fau_to.s.tout_enb = 0;
425    cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
426    return 0;
427}
428
429
430/**
431 * @INTERNAL
432 * Setup global backpressure setting.
433 *
434 * @return Zero on success, negative on failure
435 */
436static int __cvmx_helper_global_setup_backpressure(void)
437{
438#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
439    /* Disable backpressure if configured to do so */
440    /* Disable backpressure (pause frame) generation */
441    int num_interfaces = cvmx_helper_get_number_of_interfaces();
442    int interface;
443    for (interface=0; interface<num_interfaces; interface++)
444    {
445        switch (cvmx_helper_interface_get_mode(interface))
446        {
447            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
448            case CVMX_HELPER_INTERFACE_MODE_PCIE:
449            case CVMX_HELPER_INTERFACE_MODE_NPI:
450            case CVMX_HELPER_INTERFACE_MODE_LOOP:
451            case CVMX_HELPER_INTERFACE_MODE_XAUI:
452                break;
453            case CVMX_HELPER_INTERFACE_MODE_RGMII:
454            case CVMX_HELPER_INTERFACE_MODE_GMII:
455            case CVMX_HELPER_INTERFACE_MODE_SPI:
456            case CVMX_HELPER_INTERFACE_MODE_SGMII:
457            case CVMX_HELPER_INTERFACE_MODE_PICMG:
458                cvmx_gmx_set_backpressure_override(interface, 0xf);
459                break;
460        }
461    }
462    //cvmx_dprintf("Disabling backpressure\n");
463#endif
464
465    return 0;
466}
467
468
469/**
470 * @INTERNAL
471 * Enable packet input/output from the hardware. This function is
472 * called after all internal setup is complete and IPD is enabled.
473 * After this function completes, packets will be accepted from the
474 * hardware ports. PKO should still be disabled to make sure packets
475 * aren't sent out partially setup hardware.
476 *
477 * @param interface Interface to enable
478 *
479 * @return Zero on success, negative on failure
480 */
481static int __cvmx_helper_packet_hardware_enable(int interface)
482{
483    int result = 0;
484    switch (cvmx_helper_interface_get_mode(interface))
485    {
486        /* These types don't support ports to IPD/PKO */
487        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
488        case CVMX_HELPER_INTERFACE_MODE_PCIE:
489            /* Nothing to do */
490            break;
491        /* XAUI is a single high speed port */
492        case CVMX_HELPER_INTERFACE_MODE_XAUI:
493            result = __cvmx_helper_xaui_enable(interface);
494            break;
495        /* RGMII/GMII/MII are all treated about the same. Most functions
496            refer to these ports as RGMII */
497        case CVMX_HELPER_INTERFACE_MODE_RGMII:
498        case CVMX_HELPER_INTERFACE_MODE_GMII:
499            result = __cvmx_helper_rgmii_enable(interface);
500            break;
501        /* SPI4 can have 1-16 ports depending on the device at the other end */
502        case CVMX_HELPER_INTERFACE_MODE_SPI:
503            result = __cvmx_helper_spi_enable(interface);
504            break;
505        /* SGMII can have 1-4 ports depending on how many are hooked up */
506        case CVMX_HELPER_INTERFACE_MODE_SGMII:
507        case CVMX_HELPER_INTERFACE_MODE_PICMG:
508            result = __cvmx_helper_sgmii_enable(interface);
509            break;
510        /* PCI target Network Packet Interface */
511        case CVMX_HELPER_INTERFACE_MODE_NPI:
512            result = __cvmx_helper_npi_enable(interface);
513            break;
514        /* Special loopback only ports. These are not the same as other ports
515            in loopback mode */
516        case CVMX_HELPER_INTERFACE_MODE_LOOP:
517            result = __cvmx_helper_loop_enable(interface);
518            break;
519    }
520    result |= __cvmx_helper_board_hardware_enable(interface);
521    return result;
522}
523
524
525/**
526 * Called after all internal packet IO paths are setup. This
527 * function enables IPD/PIP and begins packet input and output.
528 *
529 * @return Zero on success, negative on failure
530 */
531int cvmx_helper_ipd_and_packet_input_enable(void)
532{
533    int num_interfaces;
534    int interface;
535
536    /* Enable IPD */
537    cvmx_ipd_enable();
538
539    /* Time to enable hardware ports packet input and output. Note that at this
540        point IPD/PIP must be fully functional and PKO must be disabled */
541    num_interfaces = cvmx_helper_get_number_of_interfaces();
542    for (interface=0; interface<num_interfaces; interface++)
543    {
544        if (cvmx_helper_ports_on_interface(interface) > 0)
545        {
546            //cvmx_dprintf("Enabling packet I/O on interface %d\n", interface);
547            __cvmx_helper_packet_hardware_enable(interface);
548        }
549    }
550
551    /* Finally enable PKO now that the entire path is up and running */
552    cvmx_pko_enable();
553
554    if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) &&
555        (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
556        __cvmx_helper_errata_fix_ipd_ptr_alignment();
557    return 0;
558}
559
560
561/**
562 * Initialize the PIP, IPD, and PKO hardware to support
563 * simple priority based queues for the ethernet ports. Each
564 * port is configured with a number of priority queues based
565 * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
566 * priority than the previous.
567 *
568 * @return Zero on success, non-zero on failure
569 */
570int cvmx_helper_initialize_packet_io_global(void)
571{
572    int result = 0;
573    int interface;
574    cvmx_l2c_cfg_t l2c_cfg;
575    cvmx_smix_en_t smix_en;
576    const int num_interfaces = cvmx_helper_get_number_of_interfaces();
577
578    /* CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to be disabled */
579    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
580        __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
581
582    /* Tell L2 to give the IOB statically higher priority compared to the
583        cores. This avoids conditions where IO blocks might be starved under
584        very high L2 loads */
585    l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
586    l2c_cfg.s.lrf_arb_mode = 0;
587    l2c_cfg.s.rfb_arb_mode = 0;
588    cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
589
590    /* Make sure SMI/MDIO is enabled so we can query PHYs */
591    smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
592    if (!smix_en.s.en)
593    {
594        smix_en.s.en = 1;
595        cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
596    }
597
598    /* Newer chips actually have two SMI/MDIO interfaces */
599    if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
600        !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
601        !OCTEON_IS_MODEL(OCTEON_CN50XX))
602    {
603        smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
604        if (!smix_en.s.en)
605        {
606            smix_en.s.en = 1;
607            cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
608        }
609    }
610
611    cvmx_pko_initialize_global();
612    for (interface=0; interface<num_interfaces; interface++)
613    {
614        result |= cvmx_helper_interface_probe(interface);
615        if (cvmx_helper_ports_on_interface(interface) > 0)
616            cvmx_dprintf("Interface %d has %d ports (%s)\n",
617                     interface, cvmx_helper_ports_on_interface(interface),
618                     cvmx_helper_interface_mode_to_string(cvmx_helper_interface_get_mode(interface)));
619        result |= __cvmx_helper_interface_setup_ipd(interface);
620        result |= __cvmx_helper_interface_setup_pko(interface);
621    }
622
623    result |= __cvmx_helper_global_setup_ipd();
624    result |= __cvmx_helper_global_setup_pko();
625
626    /* Enable any flow control and backpressure */
627    result |= __cvmx_helper_global_setup_backpressure();
628
629#if CVMX_HELPER_ENABLE_IPD
630    result |= cvmx_helper_ipd_and_packet_input_enable();
631#endif
632    return result;
633}
634
635
636/**
637 * Does core local initialization for packet io
638 *
639 * @return Zero on success, non-zero on failure
640 */
641int cvmx_helper_initialize_packet_io_local(void)
642{
643    return cvmx_pko_initialize_local();
644}
645
646
647/**
648 * Auto configure an IPD/PKO port link state and speed. This
649 * function basically does the equivalent of:
650 * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
651 *
652 * @param ipd_port IPD/PKO port to auto configure
653 *
654 * @return Link state after configure
655 */
656cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
657{
658    cvmx_helper_link_info_t link_info;
659    int interface = cvmx_helper_get_interface_num(ipd_port);
660    int index = cvmx_helper_get_interface_index_num(ipd_port);
661
662    if (index >= cvmx_helper_ports_on_interface(interface))
663    {
664        link_info.u64 = 0;
665        return link_info;
666    }
667
668    link_info = cvmx_helper_link_get(ipd_port);
669    if (link_info.u64 ==  port_link_info[ipd_port].u64)
670        return link_info;
671
672    /* If we fail to set the link speed, port_link_info will not change */
673    cvmx_helper_link_set(ipd_port, link_info);
674
675    /* port_link_info should be the current value, which will be different
676        than expect if cvmx_helper_link_set() failed */
677    return port_link_info[ipd_port];
678}
679
680
681/**
682 * Return the link state of an IPD/PKO port as returned by
683 * auto negotiation. The result of this function may not match
684 * Octeon's link config if auto negotiation has changed since
685 * the last call to cvmx_helper_link_set().
686 *
687 * @param ipd_port IPD/PKO port to query
688 *
689 * @return Link state
690 */
691cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
692{
693    cvmx_helper_link_info_t result;
694    int interface = cvmx_helper_get_interface_num(ipd_port);
695    int index = cvmx_helper_get_interface_index_num(ipd_port);
696
697    /* The default result will be a down link unless the code below
698        changes it */
699    result.u64 = 0;
700
701    if (index >= cvmx_helper_ports_on_interface(interface))
702        return result;
703
704    switch (cvmx_helper_interface_get_mode(interface))
705    {
706        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
707        case CVMX_HELPER_INTERFACE_MODE_PCIE:
708            /* Network links are not supported */
709            break;
710        case CVMX_HELPER_INTERFACE_MODE_XAUI:
711            result = __cvmx_helper_xaui_link_get(ipd_port);
712            break;
713        case CVMX_HELPER_INTERFACE_MODE_GMII:
714            if (index == 0)
715                result = __cvmx_helper_rgmii_link_get(ipd_port);
716            else
717            {
718                result.s.full_duplex = 1;
719                result.s.link_up = 1;
720                result.s.speed = 1000;
721            }
722            break;
723        case CVMX_HELPER_INTERFACE_MODE_RGMII:
724            result = __cvmx_helper_rgmii_link_get(ipd_port);
725            break;
726        case CVMX_HELPER_INTERFACE_MODE_SPI:
727            result = __cvmx_helper_spi_link_get(ipd_port);
728            break;
729        case CVMX_HELPER_INTERFACE_MODE_SGMII:
730        case CVMX_HELPER_INTERFACE_MODE_PICMG:
731            result = __cvmx_helper_sgmii_link_get(ipd_port);
732            break;
733        case CVMX_HELPER_INTERFACE_MODE_NPI:
734        case CVMX_HELPER_INTERFACE_MODE_LOOP:
735            /* Network links are not supported */
736            break;
737    }
738    return result;
739}
740
741
742/**
743 * Configure an IPD/PKO port for the specified link state. This
744 * function does not influence auto negotiation at the PHY level.
745 * The passed link state must always match the link state returned
746 * by cvmx_helper_link_get(). It is normally best to use
747 * cvmx_helper_link_autoconf() instead.
748 *
749 * @param ipd_port  IPD/PKO port to configure
750 * @param link_info The new link state
751 *
752 * @return Zero on success, negative on failure
753 */
754int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
755{
756    int result = -1;
757    int interface = cvmx_helper_get_interface_num(ipd_port);
758    int index = cvmx_helper_get_interface_index_num(ipd_port);
759
760    if (index >= cvmx_helper_ports_on_interface(interface))
761        return -1;
762
763    switch (cvmx_helper_interface_get_mode(interface))
764    {
765        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
766        case CVMX_HELPER_INTERFACE_MODE_PCIE:
767            break;
768        case CVMX_HELPER_INTERFACE_MODE_XAUI:
769            result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
770            break;
771        /* RGMII/GMII/MII are all treated about the same. Most functions
772            refer to these ports as RGMII */
773        case CVMX_HELPER_INTERFACE_MODE_RGMII:
774        case CVMX_HELPER_INTERFACE_MODE_GMII:
775            result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
776            break;
777        case CVMX_HELPER_INTERFACE_MODE_SPI:
778            result = __cvmx_helper_spi_link_set(ipd_port, link_info);
779            break;
780        case CVMX_HELPER_INTERFACE_MODE_SGMII:
781        case CVMX_HELPER_INTERFACE_MODE_PICMG:
782            result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
783            break;
784        case CVMX_HELPER_INTERFACE_MODE_NPI:
785        case CVMX_HELPER_INTERFACE_MODE_LOOP:
786            break;
787    }
788    /* Set the port_link_info here so that the link status is updated
789       no matter how cvmx_helper_link_set is called. We don't change
790       the value if link_set failed */
791    if (result == 0)
792        port_link_info[ipd_port].u64 = link_info.u64;
793    return result;
794}
795
796
797/**
798 * Configure a port for internal and/or external loopback. Internal loopback
799 * causes packets sent by the port to be received by Octeon. External loopback
800 * causes packets received from the wire to sent out again.
801 *
802 * @param ipd_port IPD/PKO port to loopback.
803 * @param enable_internal
804 *                 Non zero if you want internal loopback
805 * @param enable_external
806 *                 Non zero if you want external loopback
807 *
808 * @return Zero on success, negative on failure.
809 */
810int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, int enable_external)
811{
812    int result = -1;
813    int interface = cvmx_helper_get_interface_num(ipd_port);
814    int index = cvmx_helper_get_interface_index_num(ipd_port);
815
816    if (index >= cvmx_helper_ports_on_interface(interface))
817        return -1;
818
819    switch (cvmx_helper_interface_get_mode(interface))
820    {
821        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
822        case CVMX_HELPER_INTERFACE_MODE_PCIE:
823        case CVMX_HELPER_INTERFACE_MODE_SPI:
824        case CVMX_HELPER_INTERFACE_MODE_NPI:
825        case CVMX_HELPER_INTERFACE_MODE_LOOP:
826            break;
827        case CVMX_HELPER_INTERFACE_MODE_XAUI:
828            result = __cvmx_helper_xaui_configure_loopback(ipd_port, enable_internal, enable_external);
829            break;
830        case CVMX_HELPER_INTERFACE_MODE_RGMII:
831        case CVMX_HELPER_INTERFACE_MODE_GMII:
832            result = __cvmx_helper_rgmii_configure_loopback(ipd_port, enable_internal, enable_external);
833            break;
834        case CVMX_HELPER_INTERFACE_MODE_SGMII:
835        case CVMX_HELPER_INTERFACE_MODE_PICMG:
836            result = __cvmx_helper_sgmii_configure_loopback(ipd_port, enable_internal, enable_external);
837            break;
838    }
839    return result;
840}
841
842#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
843