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