cvmx-helper.c revision 215990
1/***********************license start***************
2 * Copyright (c) 2003-2010  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 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41
42
43
44
45
46/**
47 * @file
48 *
49 * Helper functions for common, but complicated tasks.
50 *
51 * <hr>$Revision: 52004 $<hr>
52 */
53#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54#include <linux/module.h>
55#include <asm/octeon/cvmx.h>
56#include <asm/octeon/cvmx-config.h>
57#include <asm/octeon/cvmx-bootmem.h>
58#include <asm/octeon/cvmx-sriox-defs.h>
59#include <asm/octeon/cvmx-npi-defs.h>
60#include <asm/octeon/cvmx-pexp-defs.h>
61#include <asm/octeon/cvmx-pip-defs.h>
62#include <asm/octeon/cvmx-asxx-defs.h>
63#include <asm/octeon/cvmx-gmxx-defs.h>
64#include <asm/octeon/cvmx-smix-defs.h>
65#include <asm/octeon/cvmx-dbg-defs.h>
66
67#include <asm/octeon/cvmx-gmx.h>
68#include <asm/octeon/cvmx-fpa.h>
69#include <asm/octeon/cvmx-pip.h>
70#include <asm/octeon/cvmx-pko.h>
71#include <asm/octeon/cvmx-ipd.h>
72#include <asm/octeon/cvmx-spi.h>
73#include <asm/octeon/cvmx-clock.h>
74#include <asm/octeon/cvmx-helper.h>
75#include <asm/octeon/cvmx-helper-board.h>
76#include <asm/octeon/cvmx-helper-errata.h>
77#else
78#if !defined(__FreeBSD__) || !defined(_KERNEL)
79#include "executive-config.h"
80#endif
81#include "cvmx.h"
82#include "cvmx-sysinfo.h"
83#include "cvmx-bootmem.h"
84#include "cvmx-version.h"
85#include "cvmx-helper-check-defines.h"
86#include "cvmx-gmx.h"
87#include "cvmx-error.h"
88#if !defined(__FreeBSD__) || !defined(_KERNEL)
89#include "cvmx-config.h"
90#endif
91
92#include "cvmx-fpa.h"
93#include "cvmx-pip.h"
94#include "cvmx-pko.h"
95#include "cvmx-ipd.h"
96#include "cvmx-spi.h"
97#include "cvmx-helper.h"
98#include "cvmx-helper-board.h"
99#include "cvmx-helper-errata.h"
100#endif
101
102
103
104#ifdef CVMX_ENABLE_PKO_FUNCTIONS
105
106/**
107 * cvmx_override_pko_queue_priority(int ipd_port, uint64_t
108 * priorities[16]) is a function pointer. It is meant to allow
109 * customization of the PKO queue priorities based on the port
110 * number. Users should set this pointer to a function before
111 * calling any cvmx-helper operations.
112 */
113CVMX_SHARED void (*cvmx_override_pko_queue_priority)(int pko_port, uint64_t priorities[16]) = NULL;
114#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
115EXPORT_SYMBOL(cvmx_override_pko_queue_priority);
116#endif
117
118/**
119 * cvmx_override_ipd_port_setup(int ipd_port) is a function
120 * pointer. It is meant to allow customization of the IPD port
121 * setup before packet input/output comes online. It is called
122 * after cvmx-helper does the default IPD configuration, but
123 * before IPD is enabled. Users should set this pointer to a
124 * function before calling any cvmx-helper operations.
125 */
126CVMX_SHARED void (*cvmx_override_ipd_port_setup)(int ipd_port) = NULL;
127
128/* Port count per interface */
129static CVMX_SHARED int interface_port_count[6] = {0,};
130/* Port last configured link info index by IPD/PKO port */
131static CVMX_SHARED cvmx_helper_link_info_t port_link_info[CVMX_PIP_NUM_INPUT_PORTS];
132
133
134/**
135 * Return the number of interfaces the chip has. Each interface
136 * may have multiple ports. Most chips support two interfaces,
137 * but the CNX0XX and CNX1XX are exceptions. These only support
138 * one interface.
139 *
140 * @return Number of interfaces on chip
141 */
142int cvmx_helper_get_number_of_interfaces(void)
143{
144    switch (cvmx_sysinfo_get()->board_type) {
145#if defined(OCTEON_VENDOR_LANNER)
146	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
147	    return 2;
148	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
149	    return 1;
150#endif
151	default:
152	    break;
153    }
154
155    if (OCTEON_IS_MODEL(OCTEON_CN63XX))
156	return 6;
157    else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
158        return 4;
159    else
160        return 3;
161}
162#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
163EXPORT_SYMBOL(cvmx_helper_get_number_of_interfaces);
164#endif
165
166
167/**
168 * Return the number of ports on an interface. Depending on the
169 * chip and configuration, this can be 1-16. A value of 0
170 * specifies that the interface doesn't exist or isn't usable.
171 *
172 * @param interface Interface to get the port count for
173 *
174 * @return Number of ports on interface. Can be Zero.
175 */
176int cvmx_helper_ports_on_interface(int interface)
177{
178    return interface_port_count[interface];
179}
180#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
181EXPORT_SYMBOL(cvmx_helper_ports_on_interface);
182#endif
183
184
185/**
186 * Get the operating mode of an interface. Depending on the Octeon
187 * chip and configuration, this function returns an enumeration
188 * of the type of packet I/O supported by an interface.
189 *
190 * @param interface Interface to probe
191 *
192 * @return Mode of the interface. Unknown or unsupported interfaces return
193 *         DISABLED.
194 */
195cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
196{
197    cvmx_gmxx_inf_mode_t mode;
198    if (interface == 2)
199        return CVMX_HELPER_INTERFACE_MODE_NPI;
200
201    if (interface == 3)
202    {
203        if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN6XXX))
204            return CVMX_HELPER_INTERFACE_MODE_LOOP;
205        else
206            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
207    }
208
209    if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && (interface == 4 || interface == 5))
210    {
211        cvmx_sriox_status_reg_t sriox_status_reg;
212        sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(interface-4));
213        if (sriox_status_reg.s.srio)
214            return CVMX_HELPER_INTERFACE_MODE_SRIO;
215        else
216            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
217    }
218
219    if (interface == 0 && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 && cvmx_sysinfo_get()->board_rev_major == 1)
220    {
221        /* Lie about interface type of CN3005 board.  This board has a switch on port 1 like
222        ** the other evaluation boards, but it is connected over RGMII instead of GMII.  Report
223        ** GMII mode so that the speed is forced to 1 Gbit full duplex.  Other than some initial configuration
224        ** (which does not use the output of this function) there is no difference in setup between GMII and RGMII modes.
225        */
226        return CVMX_HELPER_INTERFACE_MODE_GMII;
227    }
228
229    /* Interface 1 is always disabled on CN31XX and CN30XX */
230    if ((interface == 1) && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)))
231        return CVMX_HELPER_INTERFACE_MODE_DISABLED;
232
233    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
234
235    if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
236    {
237        switch(mode.cn56xx.mode)
238        {
239            case 0: return CVMX_HELPER_INTERFACE_MODE_DISABLED;
240            case 1: return CVMX_HELPER_INTERFACE_MODE_XAUI;
241            case 2: return CVMX_HELPER_INTERFACE_MODE_SGMII;
242            case 3: return CVMX_HELPER_INTERFACE_MODE_PICMG;
243            default:return CVMX_HELPER_INTERFACE_MODE_DISABLED;
244        }
245    }
246    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
247    {
248	switch(mode.cn63xx.mode)
249	{
250	    case 0: return CVMX_HELPER_INTERFACE_MODE_SGMII;
251	    case 1: return CVMX_HELPER_INTERFACE_MODE_XAUI;
252	    default: return CVMX_HELPER_INTERFACE_MODE_DISABLED;
253	}
254    }
255    else
256    {
257        if (!mode.s.en)
258            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
259
260        if (mode.s.type)
261        {
262            if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
263                return CVMX_HELPER_INTERFACE_MODE_SPI;
264            else
265                return CVMX_HELPER_INTERFACE_MODE_GMII;
266        }
267        else
268            return CVMX_HELPER_INTERFACE_MODE_RGMII;
269    }
270}
271#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
272EXPORT_SYMBOL(cvmx_helper_interface_get_mode);
273#endif
274
275/**
276 * @INTERNAL
277 * Configure the IPD/PIP tagging and QoS options for a specific
278 * port. This function determines the POW work queue entry
279 * contents for a port. The setup performed here is controlled by
280 * the defines in executive-config.h.
281 *
282 * @param ipd_port Port to configure. This follows the IPD numbering, not the
283 *                 per interface numbering
284 *
285 * @return Zero on success, negative on failure
286 */
287static int __cvmx_helper_port_setup_ipd(int ipd_port)
288{
289    cvmx_pip_prt_cfgx_t port_config;
290    cvmx_pip_prt_tagx_t tag_config;
291
292    port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
293    tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port));
294
295    /* Have each port go to a different POW queue */
296    port_config.s.qos = ipd_port & 0x7;
297
298    /* Process the headers and place the IP header in the work queue */
299    port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE;
300
301    tag_config.s.ip6_src_flag  = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP;
302    tag_config.s.ip6_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP;
303    tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT;
304    tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT;
305    tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER;
306    tag_config.s.ip4_src_flag  = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP;
307    tag_config.s.ip4_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP;
308    tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT;
309    tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT;
310    tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL;
311    tag_config.s.inc_prt_flag  = CVMX_HELPER_INPUT_TAG_INPUT_PORT;
312    tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
313    tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
314    tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
315    tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
316    tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
317    /* Put all packets in group 0. Other groups can be used by the app */
318    tag_config.s.grp = 0;
319
320    cvmx_pip_config_port(ipd_port, port_config, tag_config);
321
322    /* Give the user a chance to override our setting for each port */
323    if (cvmx_override_ipd_port_setup)
324        cvmx_override_ipd_port_setup(ipd_port);
325
326    return 0;
327}
328
329
330/**
331 * This function probes an interface to determine the actual
332 * number of hardware ports connected to it. It doesn't setup the
333 * ports or enable them. The main goal here is to set the global
334 * interface_port_count[interface] correctly. Hardware setup of the
335 * ports will be performed later.
336 *
337 * @param interface Interface to probe
338 *
339 * @return Zero on success, negative on failure
340 */
341int cvmx_helper_interface_probe(int interface)
342{
343    /* At this stage in the game we don't want packets to be moving yet.
344        The following probe calls should perform hardware setup
345        needed to determine port counts. Receive must still be disabled */
346    switch (cvmx_helper_interface_get_mode(interface))
347    {
348        /* These types don't support ports to IPD/PKO */
349        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
350        case CVMX_HELPER_INTERFACE_MODE_PCIE:
351            interface_port_count[interface] = 0;
352            break;
353        /* XAUI is a single high speed port */
354        case CVMX_HELPER_INTERFACE_MODE_XAUI:
355            interface_port_count[interface] = __cvmx_helper_xaui_probe(interface);
356            break;
357        /* RGMII/GMII/MII are all treated about the same. Most functions
358            refer to these ports as RGMII */
359        case CVMX_HELPER_INTERFACE_MODE_RGMII:
360        case CVMX_HELPER_INTERFACE_MODE_GMII:
361            interface_port_count[interface] = __cvmx_helper_rgmii_probe(interface);
362            break;
363        /* SPI4 can have 1-16 ports depending on the device at the other end */
364        case CVMX_HELPER_INTERFACE_MODE_SPI:
365            interface_port_count[interface] = __cvmx_helper_spi_probe(interface);
366            break;
367        /* SGMII can have 1-4 ports depending on how many are hooked up */
368        case CVMX_HELPER_INTERFACE_MODE_SGMII:
369        case CVMX_HELPER_INTERFACE_MODE_PICMG:
370            interface_port_count[interface] = __cvmx_helper_sgmii_probe(interface);
371            break;
372        /* PCI target Network Packet Interface */
373        case CVMX_HELPER_INTERFACE_MODE_NPI:
374            interface_port_count[interface] = __cvmx_helper_npi_probe(interface);
375            break;
376        /* Special loopback only ports. These are not the same as other ports
377            in loopback mode */
378        case CVMX_HELPER_INTERFACE_MODE_LOOP:
379            interface_port_count[interface] = __cvmx_helper_loop_probe(interface);
380            break;
381	/* SRIO has 2^N ports, where N is number of interfaces */
382	case CVMX_HELPER_INTERFACE_MODE_SRIO:
383	    interface_port_count[interface] = __cvmx_helper_srio_probe(interface);
384	    break;
385    }
386
387    interface_port_count[interface] = __cvmx_helper_board_interface_probe(interface, interface_port_count[interface]);
388
389    /* Make sure all global variables propagate to other cores */
390    CVMX_SYNCWS;
391
392    return 0;
393}
394
395
396/**
397 * @INTERNAL
398 * Setup the IPD/PIP for the ports on an interface. Packet
399 * classification and tagging are set for every port on the
400 * interface. The number of ports on the interface must already
401 * have been probed.
402 *
403 * @param interface Interface to setup IPD/PIP for
404 *
405 * @return Zero on success, negative on failure
406 */
407static int __cvmx_helper_interface_setup_ipd(int interface)
408{
409    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
410    int num_ports = interface_port_count[interface];
411
412    while (num_ports--)
413    {
414        __cvmx_helper_port_setup_ipd(ipd_port);
415        ipd_port++;
416    }
417    return 0;
418}
419
420
421/**
422 * @INTERNAL
423 * Setup global setting for IPD/PIP not related to a specific
424 * interface or port. This must be called before IPD is enabled.
425 *
426 * @return Zero on success, negative on failure.
427 */
428static int __cvmx_helper_global_setup_ipd(void)
429{
430#ifndef CVMX_HELPER_IPD_DRAM_MODE
431#define CVMX_HELPER_IPD_DRAM_MODE   CVMX_IPD_OPC_MODE_STT
432#endif
433    /* Setup the global packet input options */
434    cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE/8,
435                    CVMX_HELPER_FIRST_MBUFF_SKIP/8,
436                    CVMX_HELPER_NOT_FIRST_MBUFF_SKIP/8,
437                    (CVMX_HELPER_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
438                    (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
439                    CVMX_FPA_WQE_POOL,
440                    CVMX_HELPER_IPD_DRAM_MODE,
441                    1);
442    return 0;
443}
444
445
446/**
447 * @INTERNAL
448 * Setup the PKO for the ports on an interface. The number of
449 * queues per port and the priority of each PKO output queue
450 * is set here. PKO must be disabled when this function is called.
451 *
452 * @param interface Interface to setup PKO for
453 *
454 * @return Zero on success, negative on failure
455 */
456static int __cvmx_helper_interface_setup_pko(int interface)
457{
458    /* Each packet output queue has an associated priority. The higher the
459        priority, the more often it can send a packet. A priority of 8 means
460        it can send in all 8 rounds of contention. We're going to make each
461        queue one less than the last.
462        The vector of priorities has been extended to support CN5xxx CPUs,
463        where up to 16 queues can be associated to a port.
464        To keep backward compatibility we don't change the initial 8
465        priorities and replicate them in the second half.
466        With per-core PKO queues (PKO lockless operation) all queues have
467        the same priority. */
468    uint64_t priorities[16] = {8,7,6,5,4,3,2,1,8,7,6,5,4,3,2,1};
469
470    /* Setup the IPD/PIP and PKO for the ports discovered above. Here packet
471        classification, tagging and output priorities are set */
472    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
473    int num_ports = interface_port_count[interface];
474    while (num_ports--)
475    {
476        /* Give the user a chance to override the per queue priorities */
477        if (cvmx_override_pko_queue_priority)
478            cvmx_override_pko_queue_priority(ipd_port, priorities);
479
480        cvmx_pko_config_port(ipd_port, cvmx_pko_get_base_queue_per_core(ipd_port, 0),
481                             cvmx_pko_get_num_queues(ipd_port), priorities);
482        ipd_port++;
483    }
484    return 0;
485}
486
487
488/**
489 * @INTERNAL
490 * Setup global setting for PKO not related to a specific
491 * interface or port. This must be called before PKO is enabled.
492 *
493 * @return Zero on success, negative on failure.
494 */
495static int __cvmx_helper_global_setup_pko(void)
496{
497    /* Disable tagwait FAU timeout. This needs to be done before anyone might
498        start packet output using tags */
499    cvmx_iob_fau_timeout_t fau_to;
500    fau_to.u64 = 0;
501    fau_to.s.tout_val = 0xfff;
502    fau_to.s.tout_enb = 0;
503    cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
504    return 0;
505}
506
507
508/**
509 * @INTERNAL
510 * Setup global backpressure setting.
511 *
512 * @return Zero on success, negative on failure
513 */
514static int __cvmx_helper_global_setup_backpressure(void)
515{
516#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
517    /* Disable backpressure if configured to do so */
518    /* Disable backpressure (pause frame) generation */
519    int num_interfaces = cvmx_helper_get_number_of_interfaces();
520    int interface;
521    for (interface=0; interface<num_interfaces; interface++)
522    {
523        switch (cvmx_helper_interface_get_mode(interface))
524        {
525            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
526            case CVMX_HELPER_INTERFACE_MODE_PCIE:
527            case CVMX_HELPER_INTERFACE_MODE_SRIO:
528            case CVMX_HELPER_INTERFACE_MODE_NPI:
529            case CVMX_HELPER_INTERFACE_MODE_LOOP:
530            case CVMX_HELPER_INTERFACE_MODE_XAUI:
531                break;
532            case CVMX_HELPER_INTERFACE_MODE_RGMII:
533            case CVMX_HELPER_INTERFACE_MODE_GMII:
534            case CVMX_HELPER_INTERFACE_MODE_SPI:
535            case CVMX_HELPER_INTERFACE_MODE_SGMII:
536            case CVMX_HELPER_INTERFACE_MODE_PICMG:
537                cvmx_gmx_set_backpressure_override(interface, 0xf);
538                break;
539        }
540    }
541    //cvmx_dprintf("Disabling backpressure\n");
542#endif
543
544    return 0;
545}
546
547/**
548 * @INTERNAL
549 * Verify the per port IPD backpressure is aligned properly.
550 * @return Zero if working, non zero if misaligned
551 */
552static int __cvmx_helper_backpressure_is_misaligned(void)
553{
554    uint64_t ipd_int_enb;
555    cvmx_ipd_ctl_status_t ipd_reg;
556    uint64_t bp_status0;
557    uint64_t bp_status1;
558    const int port0 = 0;
559    const int port1 = 16;
560    cvmx_helper_interface_mode_t mode0 = cvmx_helper_interface_get_mode(0);
561    cvmx_helper_interface_mode_t mode1 = cvmx_helper_interface_get_mode(1);
562
563    /* Disable error interrupts while we check backpressure */
564    ipd_int_enb = cvmx_read_csr(CVMX_IPD_INT_ENB);
565    cvmx_write_csr(CVMX_IPD_INT_ENB, 0);
566
567    /* Enable per port backpressure */
568    ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
569    ipd_reg.s.pbp_en = 1;
570    cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64);
571
572    if (mode0 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
573    {
574        /* Enable backpressure for port with a zero threshold */
575        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port0), 1<<17);
576        /* Add 1000 to the page count to simulate packets coming in */
577        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port0<<25) | 1000);
578    }
579
580    if (mode1 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
581    {
582        /* Enable backpressure for port with a zero threshold */
583        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port1), 1<<17);
584        /* Add 1000 to the page count to simulate packets coming in */
585        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port1<<25) | 1000);
586    }
587
588    /* Wait 500 cycles for the BP to update */
589    cvmx_wait(500);
590
591    /* Read the BP state from the debug select register */
592    switch (mode0)
593    {
594        case CVMX_HELPER_INTERFACE_MODE_SPI:
595            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x9004);
596            bp_status0 = cvmx_read_csr(CVMX_DBG_DATA);
597            bp_status0 = 0xffff & ~bp_status0;
598            break;
599        case CVMX_HELPER_INTERFACE_MODE_RGMII:
600        case CVMX_HELPER_INTERFACE_MODE_GMII:
601            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x0e00);
602            bp_status0 = 0xffff & cvmx_read_csr(CVMX_DBG_DATA);
603            break;
604        case CVMX_HELPER_INTERFACE_MODE_XAUI:
605        case CVMX_HELPER_INTERFACE_MODE_SGMII:
606        case CVMX_HELPER_INTERFACE_MODE_PICMG:
607            cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, 0x0e00);
608            bp_status0 = 0xffff & cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
609            break;
610        default:
611            bp_status0 = 1<<port0;
612            break;
613    }
614
615    /* Read the BP state from the debug select register */
616    switch (mode1)
617    {
618        case CVMX_HELPER_INTERFACE_MODE_SPI:
619            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x9804);
620            bp_status1 = cvmx_read_csr(CVMX_DBG_DATA);
621            bp_status1 = 0xffff & ~bp_status1;
622            break;
623        case CVMX_HELPER_INTERFACE_MODE_RGMII:
624        case CVMX_HELPER_INTERFACE_MODE_GMII:
625            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x1600);
626            bp_status1 = 0xffff & cvmx_read_csr(CVMX_DBG_DATA);
627            break;
628        case CVMX_HELPER_INTERFACE_MODE_XAUI:
629        case CVMX_HELPER_INTERFACE_MODE_SGMII:
630        case CVMX_HELPER_INTERFACE_MODE_PICMG:
631            cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, 0x1600);
632            bp_status1 = 0xffff & cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
633            break;
634        default:
635            bp_status1 = 1<<(port1-16);
636            break;
637    }
638
639    if (mode0 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
640    {
641        /* Shutdown BP */
642        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port0<<25) | (0x1ffffff & -1000));
643        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port0), 0);
644    }
645
646    if (mode1 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
647    {
648        /* Shutdown BP */
649        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port1<<25) | (0x1ffffff & -1000));
650        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port1), 0);
651    }
652
653    /* Clear any error interrupts that might have been set */
654    cvmx_write_csr(CVMX_IPD_INT_SUM, 0x1f);
655    cvmx_write_csr(CVMX_IPD_INT_ENB, ipd_int_enb);
656
657    return ((bp_status0 != 1ull<<port0) || (bp_status1 != 1ull<<(port1-16)));
658}
659
660
661/**
662 * @INTERNAL
663 * Enable packet input/output from the hardware. This function is
664 * called after all internal setup is complete and IPD is enabled.
665 * After this function completes, packets will be accepted from the
666 * hardware ports. PKO should still be disabled to make sure packets
667 * aren't sent out partially setup hardware.
668 *
669 * @param interface Interface to enable
670 *
671 * @return Zero on success, negative on failure
672 */
673static int __cvmx_helper_packet_hardware_enable(int interface)
674{
675    int result = 0;
676    switch (cvmx_helper_interface_get_mode(interface))
677    {
678        /* These types don't support ports to IPD/PKO */
679        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
680        case CVMX_HELPER_INTERFACE_MODE_PCIE:
681            /* Nothing to do */
682            break;
683        /* XAUI is a single high speed port */
684        case CVMX_HELPER_INTERFACE_MODE_XAUI:
685            result = __cvmx_helper_xaui_enable(interface);
686            break;
687        /* RGMII/GMII/MII are all treated about the same. Most functions
688            refer to these ports as RGMII */
689        case CVMX_HELPER_INTERFACE_MODE_RGMII:
690        case CVMX_HELPER_INTERFACE_MODE_GMII:
691            result = __cvmx_helper_rgmii_enable(interface);
692            break;
693        /* SPI4 can have 1-16 ports depending on the device at the other end */
694        case CVMX_HELPER_INTERFACE_MODE_SPI:
695            result = __cvmx_helper_spi_enable(interface);
696            break;
697        /* SGMII can have 1-4 ports depending on how many are hooked up */
698        case CVMX_HELPER_INTERFACE_MODE_SGMII:
699        case CVMX_HELPER_INTERFACE_MODE_PICMG:
700            result = __cvmx_helper_sgmii_enable(interface);
701            break;
702        /* PCI target Network Packet Interface */
703        case CVMX_HELPER_INTERFACE_MODE_NPI:
704            result = __cvmx_helper_npi_enable(interface);
705            break;
706        /* Special loopback only ports. These are not the same as other ports
707            in loopback mode */
708        case CVMX_HELPER_INTERFACE_MODE_LOOP:
709            result = __cvmx_helper_loop_enable(interface);
710            break;
711	/* SRIO has 2^N ports, where N is number of interfaces */
712        case CVMX_HELPER_INTERFACE_MODE_SRIO:
713	    result = __cvmx_helper_srio_enable(interface);
714	    break;
715    }
716    result |= __cvmx_helper_board_hardware_enable(interface);
717    return result;
718}
719
720
721/**
722 * Called after all internal packet IO paths are setup. This
723 * function enables IPD/PIP and begins packet input and output.
724 *
725 * @return Zero on success, negative on failure
726 */
727int cvmx_helper_ipd_and_packet_input_enable(void)
728{
729    int num_interfaces;
730    int interface;
731
732    /* Enable IPD */
733    cvmx_ipd_enable();
734
735    /* Time to enable hardware ports packet input and output. Note that at this
736        point IPD/PIP must be fully functional and PKO must be disabled */
737    num_interfaces = cvmx_helper_get_number_of_interfaces();
738    for (interface=0; interface<num_interfaces; interface++)
739    {
740        if (cvmx_helper_ports_on_interface(interface) > 0)
741        {
742            //cvmx_dprintf("Enabling packet I/O on interface %d\n", interface);
743            __cvmx_helper_packet_hardware_enable(interface);
744        }
745    }
746
747    /* Finally enable PKO now that the entire path is up and running */
748    cvmx_pko_enable();
749
750    if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) &&
751        (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
752        __cvmx_helper_errata_fix_ipd_ptr_alignment();
753    return 0;
754}
755#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
756EXPORT_SYMBOL(cvmx_helper_ipd_and_packet_input_enable);
757#endif
758
759/**
760 * Initialize the PIP, IPD, and PKO hardware to support
761 * simple priority based queues for the ethernet ports. Each
762 * port is configured with a number of priority queues based
763 * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
764 * priority than the previous.
765 *
766 * @return Zero on success, non-zero on failure
767 */
768int cvmx_helper_initialize_packet_io_global(void)
769{
770    int result = 0;
771    int interface;
772    cvmx_l2c_cfg_t l2c_cfg;
773    cvmx_smix_en_t smix_en;
774    const int num_interfaces = cvmx_helper_get_number_of_interfaces();
775
776    /* CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to be disabled */
777    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
778        __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
779
780    /* Tell L2 to give the IOB statically higher priority compared to the
781        cores. This avoids conditions where IO blocks might be starved under
782        very high L2 loads */
783    if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
784    {
785        cvmx_l2c_ctl_t l2c_ctl;
786        l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL);
787        l2c_ctl.s.rsp_arb_mode = 1;
788        l2c_ctl.s.xmc_arb_mode = 0;
789        cvmx_write_csr(CVMX_L2C_CTL, l2c_ctl.u64);
790    }
791    else
792    {
793        l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
794        l2c_cfg.s.lrf_arb_mode = 0;
795        l2c_cfg.s.rfb_arb_mode = 0;
796        cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
797    }
798
799    if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
800    {
801        /* Make sure SMI/MDIO is enabled so we can query PHYs */
802        smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
803        if (!smix_en.s.en)
804        {
805            smix_en.s.en = 1;
806            cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
807        }
808
809        /* Newer chips actually have two SMI/MDIO interfaces */
810        if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
811            !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
812            !OCTEON_IS_MODEL(OCTEON_CN50XX))
813        {
814            smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
815            if (!smix_en.s.en)
816            {
817                smix_en.s.en = 1;
818                cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
819            }
820        }
821    }
822
823    for (interface=0; interface<num_interfaces; interface++)
824        result |= cvmx_helper_interface_probe(interface);
825
826    cvmx_pko_initialize_global();
827    for (interface=0; interface<num_interfaces; interface++)
828    {
829        if (cvmx_helper_ports_on_interface(interface) > 0)
830            cvmx_dprintf("Interface %d has %d ports (%s)\n",
831                     interface, cvmx_helper_ports_on_interface(interface),
832                     cvmx_helper_interface_mode_to_string(cvmx_helper_interface_get_mode(interface)));
833        result |= __cvmx_helper_interface_setup_ipd(interface);
834        result |= __cvmx_helper_interface_setup_pko(interface);
835    }
836
837    result |= __cvmx_helper_global_setup_ipd();
838    result |= __cvmx_helper_global_setup_pko();
839
840    /* Enable any flow control and backpressure */
841    result |= __cvmx_helper_global_setup_backpressure();
842
843#if CVMX_HELPER_ENABLE_IPD
844    result |= cvmx_helper_ipd_and_packet_input_enable();
845#endif
846    return result;
847}
848#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
849EXPORT_SYMBOL(cvmx_helper_initialize_packet_io_global);
850#endif
851
852
853/**
854 * Does core local initialization for packet io
855 *
856 * @return Zero on success, non-zero on failure
857 */
858int cvmx_helper_initialize_packet_io_local(void)
859{
860    return cvmx_pko_initialize_local();
861}
862
863
864/**
865 * Undo the initialization performed in
866 * cvmx_helper_initialize_packet_io_global(). After calling this routine and the
867 * local version on each core, packet IO for Octeon will be disabled and placed
868 * in the initial reset state. It will then be safe to call the initialize
869 * later on. Note that this routine does not empty the FPA pools. It frees all
870 * buffers used by the packet IO hardware to the FPA so a function emptying the
871 * FPA after shutdown should find all packet buffers in the FPA.
872 *
873 * @return Zero on success, negative on failure.
874 */
875int cvmx_helper_shutdown_packet_io_global(void)
876{
877    const int timeout = 5; /* Wait up to 5 seconds for timeouts */
878    int result = 0;
879    int num_interfaces;
880    int interface;
881    int num_ports;
882    int index;
883    int pool0_count;
884    cvmx_wqe_t *work;
885
886    /* Step 1: Disable all backpressure */
887    for (interface=0; interface<2; interface++)
888        if (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_DISABLED)
889            cvmx_gmx_set_backpressure_override(interface, 0xf);
890
891step2:
892    /* Step 2: Wait for the PKO queues to drain */
893    num_interfaces = cvmx_helper_get_number_of_interfaces();
894    for (interface=0; interface<num_interfaces; interface++)
895    {
896        num_ports = cvmx_helper_ports_on_interface(interface);
897        for (index=0; index<num_ports; index++)
898        {
899            int pko_port = cvmx_helper_get_ipd_port(interface, index);
900            int queue = cvmx_pko_get_base_queue(pko_port);
901            int max_queue = queue + cvmx_pko_get_num_queues(pko_port);
902            while (queue < max_queue)
903            {
904                int count = cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue));
905                uint64_t start_cycle = cvmx_get_cycle();
906                uint64_t stop_cycle = start_cycle +
907                    cvmx_clock_get_rate(CVMX_CLOCK_CORE) * timeout;
908                while (count && (cvmx_get_cycle() < stop_cycle))
909                {
910                    cvmx_wait(10000);
911                    count = cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue));
912                }
913                if (count)
914                {
915                    cvmx_dprintf("PKO port %d, queue %d, timeout waiting for idle\n",
916                        pko_port, queue);
917                    result = -1;
918                }
919                queue++;
920            }
921        }
922    }
923
924    /* Step 3: Disable TX and RX on all ports */
925    for (interface=0; interface<2; interface++)
926    {
927        switch (cvmx_helper_interface_get_mode(interface))
928        {
929            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
930            case CVMX_HELPER_INTERFACE_MODE_PCIE:
931                /* Not a packet interface */
932                break;
933            case CVMX_HELPER_INTERFACE_MODE_NPI:
934            case CVMX_HELPER_INTERFACE_MODE_SRIO:
935                /* We don't handle the NPI/NPEI/SRIO packet engines. The caller
936                    must know these are idle */
937                break;
938            case CVMX_HELPER_INTERFACE_MODE_LOOP:
939                /* Nothing needed. Once PKO is idle, the loopback devices
940                    must be idle */
941                break;
942            case CVMX_HELPER_INTERFACE_MODE_SPI:
943                /* SPI cannot be disabled from Octeon. It is the responsibility
944                    of the caller to make sure SPI is idle before doing
945                    shutdown */
946                /* Fall through and do the same processing as RGMII/GMII */
947            case CVMX_HELPER_INTERFACE_MODE_GMII:
948            case CVMX_HELPER_INTERFACE_MODE_RGMII:
949                /* Disable outermost RX at the ASX block */
950                cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 0);
951                num_ports = cvmx_helper_ports_on_interface(interface);
952                if (num_ports > 4)
953                    num_ports = 4;
954                for (index=0; index<num_ports; index++)
955                {
956                    cvmx_gmxx_prtx_cfg_t gmx_cfg;
957                    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
958                    gmx_cfg.s.en = 0;
959                    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
960                    /* Poll the GMX state machine waiting for it to become idle */
961                    cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
962                    if (CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, timeout*1000000))
963                    {
964                        cvmx_dprintf("GMX RX path timeout waiting for idle\n");
965                        result = -1;
966                    }
967                    if (CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, timeout*1000000))
968                    {
969                        cvmx_dprintf("GMX TX path timeout waiting for idle\n");
970                        result = -1;
971                    }
972                }
973                /* Disable outermost TX at the ASX block */
974                cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), 0);
975                /* Disable interrupts for interface */
976                cvmx_write_csr(CVMX_ASXX_INT_EN(interface), 0);
977                cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0);
978                break;
979            case CVMX_HELPER_INTERFACE_MODE_XAUI:
980            case CVMX_HELPER_INTERFACE_MODE_SGMII:
981            case CVMX_HELPER_INTERFACE_MODE_PICMG:
982                num_ports = cvmx_helper_ports_on_interface(interface);
983                if (num_ports > 4)
984                    num_ports = 4;
985                for (index=0; index<num_ports; index++)
986                {
987                    cvmx_gmxx_prtx_cfg_t gmx_cfg;
988                    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
989                    gmx_cfg.s.en = 0;
990                    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
991                    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, timeout*1000000))
992                    {
993                        cvmx_dprintf("GMX RX path timeout waiting for idle\n");
994                        result = -1;
995                    }
996                    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, timeout*1000000))
997                    {
998                        cvmx_dprintf("GMX TX path timeout waiting for idle\n");
999                        result = -1;
1000                    }
1001                }
1002                break;
1003        }
1004    }
1005
1006    /* Step 4: Retrieve all packets from the POW and free them */
1007    while ((work = cvmx_pow_work_request_sync(CVMX_POW_WAIT)))
1008    {
1009        cvmx_helper_free_packet_data(work);
1010        cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 0);
1011    }
1012
1013    /* Step 4b: Special workaround for pass 2 errata */
1014    if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
1015    {
1016        cvmx_ipd_ptr_count_t ipd_cnt;
1017        int to_add;
1018        ipd_cnt.u64 = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
1019        to_add = (ipd_cnt.s.wqev_cnt + ipd_cnt.s.wqe_pcnt) & 0x7;
1020        if (to_add)
1021        {
1022            int port = -1;
1023            cvmx_dprintf("Aligning CN38XX pass 2 IPD counters\n");
1024            if (cvmx_helper_interface_get_mode(0) == CVMX_HELPER_INTERFACE_MODE_RGMII)
1025                port = 0;
1026            else if (cvmx_helper_interface_get_mode(1) == CVMX_HELPER_INTERFACE_MODE_RGMII)
1027                port = 16;
1028
1029            if (port != -1)
1030            {
1031                char *buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL);
1032                if (buffer)
1033                {
1034                    int queue = cvmx_pko_get_base_queue(port);
1035                    cvmx_pko_command_word0_t pko_command;
1036                    cvmx_buf_ptr_t packet;
1037                    uint64_t start_cycle;
1038                    uint64_t stop_cycle;
1039
1040                    /* Populate a minimal packet */
1041                    memset(buffer, 0xff, 6);
1042                    memset(buffer+6, 0, 54);
1043                    pko_command.u64 = 0;
1044                    pko_command.s.dontfree = 1;
1045                    pko_command.s.total_bytes = 60;
1046                    pko_command.s.segs = 1;
1047                    packet.u64 = 0;
1048                    packet.s.addr = cvmx_ptr_to_phys(buffer);
1049                    packet.s.size = CVMX_FPA_PACKET_POOL_SIZE;
1050                    __cvmx_helper_rgmii_configure_loopback(port, 1, 0);
1051                    while (to_add--)
1052                    {
1053                        cvmx_pko_send_packet_prepare(port, queue, CVMX_PKO_LOCK_CMD_QUEUE);
1054                        if (cvmx_pko_send_packet_finish(port, queue, pko_command, packet, CVMX_PKO_LOCK_CMD_QUEUE))
1055                        {
1056                            cvmx_dprintf("ERROR: Unable to align IPD counters (PKO failed)\n");
1057                            break;
1058                        }
1059                    }
1060                    cvmx_fpa_free(buffer, CVMX_FPA_PACKET_POOL, 0);
1061
1062                    /* Wait for the packets to loop back */
1063                    start_cycle = cvmx_get_cycle();
1064                    stop_cycle = start_cycle + cvmx_clock_get_rate(CVMX_CLOCK_CORE) * timeout;
1065                    while (cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue)) &&
1066                           (cvmx_get_cycle() < stop_cycle))
1067                    {
1068                        cvmx_wait(1000);
1069                    }
1070                    cvmx_wait(1000);
1071                    __cvmx_helper_rgmii_configure_loopback(port, 0, 0);
1072                    if (to_add == -1)
1073                        goto step2;
1074                }
1075                else
1076                    cvmx_dprintf("ERROR: Unable to align IPD counters (Packet pool empty)\n");
1077            }
1078            else
1079                cvmx_dprintf("ERROR: Unable to align IPD counters\n");
1080        }
1081    }
1082
1083    /* Step 5: Disable IPD and PKO. PIP is taken care of in the next step */
1084    cvmx_ipd_disable();
1085    cvmx_pko_disable();
1086
1087    /* Step 6: Drain all prefetched buffers from IPD/PIP. Note that IPD/PIP
1088        have not been reset yet */
1089    __cvmx_ipd_free_ptr();
1090
1091    /* Step 7: Free the PKO command buffers and put PKO in reset */
1092    cvmx_pko_shutdown();
1093
1094    /* Step 8: Disable MAC address filtering */
1095    for (interface=0; interface<2; interface++)
1096    {
1097        switch (cvmx_helper_interface_get_mode(interface))
1098        {
1099            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1100            case CVMX_HELPER_INTERFACE_MODE_PCIE:
1101            case CVMX_HELPER_INTERFACE_MODE_SRIO:
1102            case CVMX_HELPER_INTERFACE_MODE_NPI:
1103            case CVMX_HELPER_INTERFACE_MODE_LOOP:
1104                break;
1105            case CVMX_HELPER_INTERFACE_MODE_XAUI:
1106            case CVMX_HELPER_INTERFACE_MODE_GMII:
1107            case CVMX_HELPER_INTERFACE_MODE_RGMII:
1108            case CVMX_HELPER_INTERFACE_MODE_SPI:
1109            case CVMX_HELPER_INTERFACE_MODE_SGMII:
1110            case CVMX_HELPER_INTERFACE_MODE_PICMG:
1111                num_ports = cvmx_helper_ports_on_interface(interface);
1112                if (num_ports > 4)
1113                    num_ports = 4;
1114                for (index=0; index<num_ports; index++)
1115                {
1116                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), 1);
1117                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
1118                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), 0);
1119                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), 0);
1120                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), 0);
1121                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), 0);
1122                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), 0);
1123                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), 0);
1124                }
1125                break;
1126        }
1127    }
1128
1129    /* Step 9: Drain all FPA buffers out of pool 0 before we reset IPD/PIP.
1130        This is needed to keep IPD_QUE0_FREE_PAGE_CNT in sync. We use pool 1
1131        for temporary storage */
1132    pool0_count = 0;
1133    while (1)
1134    {
1135        void *buffer = cvmx_fpa_alloc(0);
1136        if (buffer)
1137        {
1138            cvmx_fpa_free(buffer, 1, 0);
1139            pool0_count++;
1140        }
1141        else
1142            break;
1143    }
1144
1145
1146    /* Step 10: Reset IPD and PIP */
1147    {
1148        cvmx_ipd_ctl_status_t ipd_ctl_status;
1149        ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
1150        ipd_ctl_status.s.reset = 1;
1151        cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
1152
1153        if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
1154            (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)))
1155        {
1156            /* only try 1000 times.  Normally if this works it will happen in
1157            ** the first 50 loops. */
1158            int max_loops = 1000;
1159            int loop = 0;
1160            /* Per port backpressure counters can get misaligned after an
1161               IPD reset. This code realigns them by performing repeated
1162               resets. See IPD-13473 */
1163            cvmx_wait(100);
1164            if (__cvmx_helper_backpressure_is_misaligned())
1165            {
1166                cvmx_dprintf("Starting to align per port backpressure counters.\n");
1167                while (__cvmx_helper_backpressure_is_misaligned() && (loop++ < max_loops))
1168                {
1169                    cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
1170                    cvmx_wait(123);
1171                }
1172                if (loop < max_loops)
1173                    cvmx_dprintf("Completed aligning per port backpressure counters (%d loops).\n", loop);
1174                else
1175                {
1176                    cvmx_dprintf("ERROR: unable to align per port backpressure counters.\n");
1177                    /* For now, don't hang.... */
1178                }
1179            }
1180        }
1181
1182        /* PIP_SFT_RST not present in CN38XXp{1,2} */
1183        if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
1184        {
1185            cvmx_pip_sft_rst_t pip_sft_rst;
1186            pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
1187            pip_sft_rst.s.rst = 1;
1188            cvmx_write_csr(CVMX_PIP_SFT_RST, pip_sft_rst.u64);
1189        }
1190    }
1191
1192    /* Step 11: Restore the FPA buffers into pool 0 */
1193    while (pool0_count--)
1194        cvmx_fpa_free(cvmx_fpa_alloc(1), 0, 0);
1195
1196    return result;
1197}
1198#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1199EXPORT_SYMBOL(cvmx_helper_shutdown_packet_io_global);
1200#endif
1201
1202
1203/**
1204 * Does core local shutdown of packet io
1205 *
1206 * @return Zero on success, non-zero on failure
1207 */
1208int cvmx_helper_shutdown_packet_io_local(void)
1209{
1210    /* Currently there is nothing to do per core. This may change in
1211        the future */
1212    return 0;
1213}
1214
1215
1216
1217/**
1218 * Auto configure an IPD/PKO port link state and speed. This
1219 * function basically does the equivalent of:
1220 * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
1221 *
1222 * @param ipd_port IPD/PKO port to auto configure
1223 *
1224 * @return Link state after configure
1225 */
1226cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
1227{
1228    cvmx_helper_link_info_t link_info;
1229    int interface = cvmx_helper_get_interface_num(ipd_port);
1230    int index = cvmx_helper_get_interface_index_num(ipd_port);
1231
1232    if (index >= cvmx_helper_ports_on_interface(interface))
1233    {
1234        link_info.u64 = 0;
1235        return link_info;
1236    }
1237
1238    link_info = cvmx_helper_link_get(ipd_port);
1239    if (link_info.u64 ==  port_link_info[ipd_port].u64)
1240        return link_info;
1241
1242#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
1243    if (!link_info.s.link_up)
1244        cvmx_error_disable_group(CVMX_ERROR_GROUP_ETHERNET, ipd_port);
1245#endif
1246
1247    /* If we fail to set the link speed, port_link_info will not change */
1248    cvmx_helper_link_set(ipd_port, link_info);
1249
1250#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
1251    if (link_info.s.link_up)
1252        cvmx_error_enable_group(CVMX_ERROR_GROUP_ETHERNET, ipd_port);
1253#endif
1254
1255    /* port_link_info should be the current value, which will be different
1256        than expect if cvmx_helper_link_set() failed */
1257    return port_link_info[ipd_port];
1258}
1259#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1260EXPORT_SYMBOL(cvmx_helper_link_autoconf);
1261#endif
1262
1263/**
1264 * Return the link state of an IPD/PKO port as returned by
1265 * auto negotiation. The result of this function may not match
1266 * Octeon's link config if auto negotiation has changed since
1267 * the last call to cvmx_helper_link_set().
1268 *
1269 * @param ipd_port IPD/PKO port to query
1270 *
1271 * @return Link state
1272 */
1273cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
1274{
1275    cvmx_helper_link_info_t result;
1276    int interface = cvmx_helper_get_interface_num(ipd_port);
1277    int index = cvmx_helper_get_interface_index_num(ipd_port);
1278
1279    /* The default result will be a down link unless the code below
1280        changes it */
1281    result.u64 = 0;
1282
1283    if (index >= cvmx_helper_ports_on_interface(interface))
1284        return result;
1285
1286    switch (cvmx_helper_interface_get_mode(interface))
1287    {
1288        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1289        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1290            /* Network links are not supported */
1291            break;
1292        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1293            result = __cvmx_helper_xaui_link_get(ipd_port);
1294            break;
1295        case CVMX_HELPER_INTERFACE_MODE_GMII:
1296            if (index == 0)
1297                result = __cvmx_helper_rgmii_link_get(ipd_port);
1298            else
1299            {
1300                result.s.full_duplex = 1;
1301                result.s.link_up = 1;
1302                result.s.speed = 1000;
1303            }
1304            break;
1305        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1306            result = __cvmx_helper_rgmii_link_get(ipd_port);
1307            break;
1308        case CVMX_HELPER_INTERFACE_MODE_SPI:
1309            result = __cvmx_helper_spi_link_get(ipd_port);
1310            break;
1311        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1312        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1313            result = __cvmx_helper_sgmii_link_get(ipd_port);
1314            break;
1315        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1316            result = __cvmx_helper_srio_link_get(ipd_port);
1317            break;
1318        case CVMX_HELPER_INTERFACE_MODE_NPI:
1319        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1320            /* Network links are not supported */
1321            break;
1322    }
1323    return result;
1324}
1325#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1326EXPORT_SYMBOL(cvmx_helper_link_get);
1327#endif
1328
1329
1330/**
1331 * Configure an IPD/PKO port for the specified link state. This
1332 * function does not influence auto negotiation at the PHY level.
1333 * The passed link state must always match the link state returned
1334 * by cvmx_helper_link_get(). It is normally best to use
1335 * cvmx_helper_link_autoconf() instead.
1336 *
1337 * @param ipd_port  IPD/PKO port to configure
1338 * @param link_info The new link state
1339 *
1340 * @return Zero on success, negative on failure
1341 */
1342int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
1343{
1344    int result = -1;
1345    int interface = cvmx_helper_get_interface_num(ipd_port);
1346    int index = cvmx_helper_get_interface_index_num(ipd_port);
1347
1348    if (index >= cvmx_helper_ports_on_interface(interface))
1349        return -1;
1350
1351    switch (cvmx_helper_interface_get_mode(interface))
1352    {
1353        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1354        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1355            break;
1356        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1357            result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
1358            break;
1359        /* RGMII/GMII/MII are all treated about the same. Most functions
1360            refer to these ports as RGMII */
1361        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1362        case CVMX_HELPER_INTERFACE_MODE_GMII:
1363            result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
1364            break;
1365        case CVMX_HELPER_INTERFACE_MODE_SPI:
1366            result = __cvmx_helper_spi_link_set(ipd_port, link_info);
1367            break;
1368        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1369        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1370            result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
1371            break;
1372        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1373            result = __cvmx_helper_srio_link_set(ipd_port, link_info);
1374            break;
1375        case CVMX_HELPER_INTERFACE_MODE_NPI:
1376        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1377            break;
1378    }
1379    /* Set the port_link_info here so that the link status is updated
1380       no matter how cvmx_helper_link_set is called. We don't change
1381       the value if link_set failed */
1382    if (result == 0)
1383        port_link_info[ipd_port].u64 = link_info.u64;
1384    return result;
1385}
1386#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1387EXPORT_SYMBOL(cvmx_helper_link_set);
1388#endif
1389
1390
1391/**
1392 * Configure a port for internal and/or external loopback. Internal loopback
1393 * causes packets sent by the port to be received by Octeon. External loopback
1394 * causes packets received from the wire to sent out again.
1395 *
1396 * @param ipd_port IPD/PKO port to loopback.
1397 * @param enable_internal
1398 *                 Non zero if you want internal loopback
1399 * @param enable_external
1400 *                 Non zero if you want external loopback
1401 *
1402 * @return Zero on success, negative on failure.
1403 */
1404int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, int enable_external)
1405{
1406    int result = -1;
1407    int interface = cvmx_helper_get_interface_num(ipd_port);
1408    int index = cvmx_helper_get_interface_index_num(ipd_port);
1409
1410    if (index >= cvmx_helper_ports_on_interface(interface))
1411        return -1;
1412
1413    switch (cvmx_helper_interface_get_mode(interface))
1414    {
1415        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1416        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1417        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1418        case CVMX_HELPER_INTERFACE_MODE_SPI:
1419        case CVMX_HELPER_INTERFACE_MODE_NPI:
1420        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1421            break;
1422        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1423            result = __cvmx_helper_xaui_configure_loopback(ipd_port, enable_internal, enable_external);
1424            break;
1425        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1426        case CVMX_HELPER_INTERFACE_MODE_GMII:
1427            result = __cvmx_helper_rgmii_configure_loopback(ipd_port, enable_internal, enable_external);
1428            break;
1429        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1430        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1431            result = __cvmx_helper_sgmii_configure_loopback(ipd_port, enable_internal, enable_external);
1432            break;
1433    }
1434    return result;
1435}
1436
1437#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
1438