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