1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Helper functions for common, but complicated tasks.
50210284Sjmallett *
51232812Sjmallett * <hr>$Revision: 70030 $<hr>
52210284Sjmallett */
53215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54215990Sjmallett#include <linux/module.h>
55215990Sjmallett#include <asm/octeon/cvmx.h>
56215990Sjmallett#include <asm/octeon/cvmx-config.h>
57215990Sjmallett#include <asm/octeon/cvmx-bootmem.h>
58215990Sjmallett#include <asm/octeon/cvmx-sriox-defs.h>
59215990Sjmallett#include <asm/octeon/cvmx-npi-defs.h>
60232812Sjmallett#include <asm/octeon/cvmx-mio-defs.h>
61215990Sjmallett#include <asm/octeon/cvmx-pexp-defs.h>
62215990Sjmallett#include <asm/octeon/cvmx-pip-defs.h>
63215990Sjmallett#include <asm/octeon/cvmx-asxx-defs.h>
64215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
65215990Sjmallett#include <asm/octeon/cvmx-smix-defs.h>
66215990Sjmallett#include <asm/octeon/cvmx-dbg-defs.h>
67232812Sjmallett#include <asm/octeon/cvmx-sso-defs.h>
68215990Sjmallett
69215990Sjmallett#include <asm/octeon/cvmx-gmx.h>
70215990Sjmallett#include <asm/octeon/cvmx-fpa.h>
71215990Sjmallett#include <asm/octeon/cvmx-pip.h>
72215990Sjmallett#include <asm/octeon/cvmx-pko.h>
73215990Sjmallett#include <asm/octeon/cvmx-ipd.h>
74215990Sjmallett#include <asm/octeon/cvmx-spi.h>
75215990Sjmallett#include <asm/octeon/cvmx-clock.h>
76215990Sjmallett#include <asm/octeon/cvmx-helper.h>
77215990Sjmallett#include <asm/octeon/cvmx-helper-board.h>
78215990Sjmallett#include <asm/octeon/cvmx-helper-errata.h>
79232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h>
80215990Sjmallett#else
81215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
82215990Sjmallett#include "executive-config.h"
83215990Sjmallett#endif
84210284Sjmallett#include "cvmx.h"
85215990Sjmallett#include "cvmx-sysinfo.h"
86210284Sjmallett#include "cvmx-bootmem.h"
87215990Sjmallett#include "cvmx-version.h"
88215990Sjmallett#include "cvmx-helper-check-defines.h"
89215990Sjmallett#include "cvmx-gmx.h"
90232816Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
91215990Sjmallett#include "cvmx-error.h"
92215990Sjmallett#include "cvmx-config.h"
93215990Sjmallett#endif
94215990Sjmallett
95210284Sjmallett#include "cvmx-fpa.h"
96210284Sjmallett#include "cvmx-pip.h"
97210284Sjmallett#include "cvmx-pko.h"
98210284Sjmallett#include "cvmx-ipd.h"
99210284Sjmallett#include "cvmx-spi.h"
100210284Sjmallett#include "cvmx-helper.h"
101210284Sjmallett#include "cvmx-helper-board.h"
102210284Sjmallett#include "cvmx-helper-errata.h"
103232812Sjmallett#include "cvmx-helper-cfg.h"
104215990Sjmallett#endif
105210284Sjmallett
106215990Sjmallett
107210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
108210284Sjmallett
109210284Sjmallett/**
110232812Sjmallett * cvmx_override_pko_queue_priority(int pko_port, uint64_t
111210284Sjmallett * priorities[16]) is a function pointer. It is meant to allow
112210284Sjmallett * customization of the PKO queue priorities based on the port
113210284Sjmallett * number. Users should set this pointer to a function before
114210284Sjmallett * calling any cvmx-helper operations.
115210284Sjmallett */
116232812SjmallettCVMX_SHARED void (*cvmx_override_pko_queue_priority)(int ipd_port,
117232812Sjmallett    uint64_t *priorities) = NULL;
118215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
119215990SjmallettEXPORT_SYMBOL(cvmx_override_pko_queue_priority);
120215990Sjmallett#endif
121210284Sjmallett
122210284Sjmallett/**
123210284Sjmallett * cvmx_override_ipd_port_setup(int ipd_port) is a function
124232812Sjmallett * pointer. It is meant to allow customization of the IPD
125232812Sjmallett * port/port kind setup before packet input/output comes online.
126232812Sjmallett * It is called after cvmx-helper does the default IPD configuration,
127232812Sjmallett * but before IPD is enabled. Users should set this pointer to a
128210284Sjmallett * function before calling any cvmx-helper operations.
129210284Sjmallett */
130210284SjmallettCVMX_SHARED void (*cvmx_override_ipd_port_setup)(int ipd_port) = NULL;
131210284Sjmallett
132210284Sjmallett/**
133210284Sjmallett * Return the number of interfaces the chip has. Each interface
134210284Sjmallett * may have multiple ports. Most chips support two interfaces,
135210284Sjmallett * but the CNX0XX and CNX1XX are exceptions. These only support
136210284Sjmallett * one interface.
137210284Sjmallett *
138210284Sjmallett * @return Number of interfaces on chip
139210284Sjmallett */
140210284Sjmallettint cvmx_helper_get_number_of_interfaces(void)
141210284Sjmallett{
142212844Sjmallett    switch (cvmx_sysinfo_get()->board_type) {
143212844Sjmallett#if defined(OCTEON_VENDOR_LANNER)
144212844Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
145212844Sjmallett	    return 2;
146215014Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR730:
147215014Sjmallett	    return 1;
148212844Sjmallett#endif
149242104Sjmallett#if defined(OCTEON_VENDOR_RADISYS)
150242104Sjmallett	case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE:
151242104Sjmallett	    return 2;
152242104Sjmallett#endif
153212844Sjmallett	default:
154212844Sjmallett	    break;
155212844Sjmallett    }
156212844Sjmallett
157232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
158232812Sjmallett        return 9;
159232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
160232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_0))
161232812Sjmallett            return 7;
162232812Sjmallett        else
163232812Sjmallett            return 8;
164232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
165232812Sjmallett        return 6;
166232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN61XX))
167210284Sjmallett        return 4;
168210284Sjmallett    else
169210284Sjmallett        return 3;
170210284Sjmallett}
171215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
172215990SjmallettEXPORT_SYMBOL(cvmx_helper_get_number_of_interfaces);
173215990Sjmallett#endif
174210284Sjmallett
175210284Sjmallett
176210284Sjmallett/**
177210284Sjmallett * Return the number of ports on an interface. Depending on the
178210284Sjmallett * chip and configuration, this can be 1-16. A value of 0
179210284Sjmallett * specifies that the interface doesn't exist or isn't usable.
180210284Sjmallett *
181210284Sjmallett * @param interface Interface to get the port count for
182210284Sjmallett *
183210284Sjmallett * @return Number of ports on interface. Can be Zero.
184210284Sjmallett */
185210284Sjmallettint cvmx_helper_ports_on_interface(int interface)
186210284Sjmallett{
187232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
188232812Sjmallett        return cvmx_helper_interface_enumerate(interface);
189232812Sjmallett    else
190232812Sjmallett        return __cvmx_helper_get_num_ipd_ports(interface);
191210284Sjmallett}
192215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
193215990SjmallettEXPORT_SYMBOL(cvmx_helper_ports_on_interface);
194215990Sjmallett#endif
195210284Sjmallett
196210284Sjmallett
197210284Sjmallett/**
198210284Sjmallett * Get the operating mode of an interface. Depending on the Octeon
199210284Sjmallett * chip and configuration, this function returns an enumeration
200210284Sjmallett * of the type of packet I/O supported by an interface.
201210284Sjmallett *
202210284Sjmallett * @param interface Interface to probe
203210284Sjmallett *
204210284Sjmallett * @return Mode of the interface. Unknown or unsupported interfaces return
205210284Sjmallett *         DISABLED.
206210284Sjmallett */
207210284Sjmallettcvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
208210284Sjmallett{
209210284Sjmallett    cvmx_gmxx_inf_mode_t mode;
210232812Sjmallett
211232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
212232812Sjmallett    {
213232812Sjmallett        cvmx_mio_qlmx_cfg_t qlm_cfg;
214232812Sjmallett        switch(interface)
215232812Sjmallett        {
216232812Sjmallett            case 0:
217232812Sjmallett                qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0));
218232812Sjmallett                /* QLM is disabled when QLM SPD is 15. */
219232812Sjmallett                if (qlm_cfg.s.qlm_spd == 15)
220232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
221232812Sjmallett
222232812Sjmallett                if (qlm_cfg.s.qlm_cfg == 7)
223232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_RXAUI;
224232812Sjmallett                else if (qlm_cfg.s.qlm_cfg == 2)
225232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_SGMII;
226232812Sjmallett                else if (qlm_cfg.s.qlm_cfg == 3)
227232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_XAUI;
228232812Sjmallett                else
229232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
230232812Sjmallett                break;
231232812Sjmallett            case 1:
232232812Sjmallett                qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0));
233232812Sjmallett                /* QLM is disabled when QLM SPD is 15. */
234232812Sjmallett                if (qlm_cfg.s.qlm_spd == 15)
235232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
236232812Sjmallett
237232812Sjmallett                if (qlm_cfg.s.qlm_cfg == 7)
238232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_RXAUI;
239232812Sjmallett                else
240232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
241232812Sjmallett                break;
242232812Sjmallett            case 2:
243232812Sjmallett            case 3:
244232812Sjmallett            case 4:
245232812Sjmallett                qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(interface));
246232812Sjmallett                /* QLM is disabled when QLM SPD is 15. */
247232812Sjmallett                if (qlm_cfg.s.qlm_spd == 15)
248232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
249232812Sjmallett
250232812Sjmallett                if (qlm_cfg.s.qlm_cfg == 2)
251232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_SGMII;
252232812Sjmallett                else if (qlm_cfg.s.qlm_cfg == 3)
253232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_XAUI;
254232812Sjmallett                else
255232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
256232812Sjmallett                break;
257232812Sjmallett            case 5:
258232812Sjmallett            case 6:
259232812Sjmallett                qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(interface - 4));
260232812Sjmallett                /* QLM is disabled when QLM SPD is 15. */
261232812Sjmallett                if (qlm_cfg.s.qlm_spd == 15)
262232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
263232812Sjmallett
264232812Sjmallett                if (qlm_cfg.s.qlm_cfg == 1)
265232812Sjmallett		{
266232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_ILK;
267232812Sjmallett		}
268232812Sjmallett                else
269232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
270232812Sjmallett                break;
271232812Sjmallett            case 7:
272232812Sjmallett                qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(3));
273232812Sjmallett                /* QLM is disabled when QLM SPD is 15. */
274232812Sjmallett                if (qlm_cfg.s.qlm_spd == 15)
275232812Sjmallett                    return CVMX_HELPER_INTERFACE_MODE_DISABLED;
276232812Sjmallett                else if (qlm_cfg.s.qlm_cfg != 0)
277232812Sjmallett                {
278232812Sjmallett                    qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1));
279232812Sjmallett                    if (qlm_cfg.s.qlm_cfg != 0)
280232812Sjmallett                        return CVMX_HELPER_INTERFACE_MODE_DISABLED;
281232812Sjmallett                }
282232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_NPI;
283232812Sjmallett                break;
284232812Sjmallett            case 8:
285232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_LOOP;
286232812Sjmallett                break;
287232812Sjmallett            default:
288232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_DISABLED;
289232812Sjmallett                break;
290232812Sjmallett        }
291232812Sjmallett    }
292232812Sjmallett
293210284Sjmallett    if (interface == 2)
294210284Sjmallett        return CVMX_HELPER_INTERFACE_MODE_NPI;
295210284Sjmallett
296210284Sjmallett    if (interface == 3)
297210284Sjmallett    {
298232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN56XX)
299232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN52XX)
300232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN6XXX)
301232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
302210284Sjmallett            return CVMX_HELPER_INTERFACE_MODE_LOOP;
303210284Sjmallett        else
304210284Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
305210284Sjmallett    }
306210284Sjmallett
307232812Sjmallett    /* Only present in CN63XX & CN66XX Octeon model */
308232812Sjmallett    if ((OCTEON_IS_MODEL(OCTEON_CN63XX) && (interface == 4 || interface == 5))
309232812Sjmallett        || (OCTEON_IS_MODEL(OCTEON_CN66XX) && interface >= 4 && interface <= 7))
310215990Sjmallett    {
311215990Sjmallett        cvmx_sriox_status_reg_t sriox_status_reg;
312232812Sjmallett
313232812Sjmallett        /* cn66xx pass1.0 has only 2 SRIO interfaces. */
314232812Sjmallett        if ((interface == 5 || interface == 7) && OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_0))
315232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
316232812Sjmallett
317215990Sjmallett        sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(interface-4));
318215990Sjmallett        if (sriox_status_reg.s.srio)
319215990Sjmallett            return CVMX_HELPER_INTERFACE_MODE_SRIO;
320215990Sjmallett        else
321215990Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
322215990Sjmallett    }
323215990Sjmallett
324232812Sjmallett    /* Interface 5 always disabled in CN66XX */
325232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN66XX))
326232812Sjmallett    {
327232812Sjmallett        cvmx_mio_qlmx_cfg_t mio_qlm_cfg;
328232812Sjmallett
329232812Sjmallett        /* QLM2 is SGMII0 and QLM1 is SGMII1 */
330232812Sjmallett        if (interface == 0)
331232812Sjmallett            mio_qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(2));
332232812Sjmallett        else if (interface == 1)
333232812Sjmallett            mio_qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1));
334232812Sjmallett        else
335232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
336232812Sjmallett
337232812Sjmallett        if (mio_qlm_cfg.s.qlm_spd == 15)
338232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
339232812Sjmallett
340232812Sjmallett        if (mio_qlm_cfg.s.qlm_cfg == 9)
341232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_SGMII;
342232812Sjmallett        else if (mio_qlm_cfg.s.qlm_cfg == 11)
343232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_XAUI;
344232812Sjmallett        else
345232812Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
346232812Sjmallett    }
347232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
348232812Sjmallett    {
349232812Sjmallett        cvmx_mio_qlmx_cfg_t qlm_cfg;
350232812Sjmallett
351232812Sjmallett        if (interface == 0)
352232812Sjmallett        {
353232812Sjmallett            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(2));
354232812Sjmallett            if (qlm_cfg.s.qlm_cfg == 2)
355232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_SGMII;
356232812Sjmallett            else if (qlm_cfg.s.qlm_cfg == 3)
357232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_XAUI;
358232812Sjmallett            else
359232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_DISABLED;
360232812Sjmallett        }
361232812Sjmallett        else if (interface == 1)
362232812Sjmallett        {
363232812Sjmallett            /* If QLM 1 is PEV0/PEM1 mode, them QLM0 cannot be SGMII/XAUI */
364232812Sjmallett            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(1));
365232812Sjmallett            if (qlm_cfg.s.qlm_cfg == 1)
366232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_DISABLED;
367232812Sjmallett
368232812Sjmallett            qlm_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(0));
369232812Sjmallett            if (qlm_cfg.s.qlm_cfg == 2)
370232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_SGMII;
371232812Sjmallett            else if (qlm_cfg.s.qlm_cfg == 3)
372232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_XAUI;
373232812Sjmallett            else
374232812Sjmallett                return CVMX_HELPER_INTERFACE_MODE_DISABLED;
375232812Sjmallett        }
376232812Sjmallett    }
377232812Sjmallett
378210284Sjmallett    if (interface == 0 && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 && cvmx_sysinfo_get()->board_rev_major == 1)
379210284Sjmallett    {
380210284Sjmallett        /* Lie about interface type of CN3005 board.  This board has a switch on port 1 like
381210284Sjmallett        ** the other evaluation boards, but it is connected over RGMII instead of GMII.  Report
382210284Sjmallett        ** GMII mode so that the speed is forced to 1 Gbit full duplex.  Other than some initial configuration
383210284Sjmallett        ** (which does not use the output of this function) there is no difference in setup between GMII and RGMII modes.
384210284Sjmallett        */
385210284Sjmallett        return CVMX_HELPER_INTERFACE_MODE_GMII;
386210284Sjmallett    }
387210284Sjmallett
388210284Sjmallett    /* Interface 1 is always disabled on CN31XX and CN30XX */
389232812Sjmallett    if ((interface == 1)
390232812Sjmallett        && (OCTEON_IS_MODEL(OCTEON_CN31XX)
391232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN30XX)
392232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN50XX)
393232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN52XX)
394232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CN63XX)
395232812Sjmallett            || OCTEON_IS_MODEL(OCTEON_CNF71XX)))
396210284Sjmallett        return CVMX_HELPER_INTERFACE_MODE_DISABLED;
397210284Sjmallett
398210284Sjmallett    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
399210284Sjmallett
400210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
401210284Sjmallett    {
402210284Sjmallett        switch(mode.cn56xx.mode)
403210284Sjmallett        {
404210284Sjmallett            case 0: return CVMX_HELPER_INTERFACE_MODE_DISABLED;
405210284Sjmallett            case 1: return CVMX_HELPER_INTERFACE_MODE_XAUI;
406210284Sjmallett            case 2: return CVMX_HELPER_INTERFACE_MODE_SGMII;
407210284Sjmallett            case 3: return CVMX_HELPER_INTERFACE_MODE_PICMG;
408210284Sjmallett            default:return CVMX_HELPER_INTERFACE_MODE_DISABLED;
409210284Sjmallett        }
410210284Sjmallett    }
411232812Sjmallett    else if (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))
412215990Sjmallett    {
413232812Sjmallett        switch(mode.cn63xx.mode)
414232812Sjmallett        {
415232812Sjmallett            case 0: return CVMX_HELPER_INTERFACE_MODE_SGMII;
416232812Sjmallett            case 1: return CVMX_HELPER_INTERFACE_MODE_XAUI;
417232812Sjmallett            default: return CVMX_HELPER_INTERFACE_MODE_DISABLED;
418232812Sjmallett        }
419215990Sjmallett    }
420210284Sjmallett    else
421210284Sjmallett    {
422210284Sjmallett        if (!mode.s.en)
423210284Sjmallett            return CVMX_HELPER_INTERFACE_MODE_DISABLED;
424210284Sjmallett
425210284Sjmallett        if (mode.s.type)
426210284Sjmallett        {
427210284Sjmallett            if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
428210284Sjmallett                return CVMX_HELPER_INTERFACE_MODE_SPI;
429210284Sjmallett            else
430210284Sjmallett                return CVMX_HELPER_INTERFACE_MODE_GMII;
431210284Sjmallett        }
432210284Sjmallett        else
433210284Sjmallett            return CVMX_HELPER_INTERFACE_MODE_RGMII;
434210284Sjmallett    }
435210284Sjmallett}
436215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
437215990SjmallettEXPORT_SYMBOL(cvmx_helper_interface_get_mode);
438215990Sjmallett#endif
439210284Sjmallett
440210284Sjmallett/**
441210284Sjmallett * @INTERNAL
442210284Sjmallett * Configure the IPD/PIP tagging and QoS options for a specific
443210284Sjmallett * port. This function determines the POW work queue entry
444210284Sjmallett * contents for a port. The setup performed here is controlled by
445210284Sjmallett * the defines in executive-config.h.
446210284Sjmallett *
447232812Sjmallett * @param ipd_port Port/Port kind to configure. This follows the IPD numbering,
448232812Sjmallett *                 not the per interface numbering
449210284Sjmallett *
450210284Sjmallett * @return Zero on success, negative on failure
451210284Sjmallett */
452210284Sjmallettstatic int __cvmx_helper_port_setup_ipd(int ipd_port)
453210284Sjmallett{
454215990Sjmallett    cvmx_pip_prt_cfgx_t port_config;
455215990Sjmallett    cvmx_pip_prt_tagx_t tag_config;
456210284Sjmallett
457232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
458232812Sjmallett    {
459232812Sjmallett        int interface, index, pknd;
460232812Sjmallett        cvmx_pip_prt_cfgbx_t prt_cfgbx;
461210284Sjmallett
462232812Sjmallett        interface = cvmx_helper_get_interface_num(ipd_port);
463232812Sjmallett        index = cvmx_helper_get_interface_index_num(ipd_port);
464232812Sjmallett        pknd = cvmx_helper_get_pknd(interface, index);
465210284Sjmallett
466232812Sjmallett        port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(pknd));
467232812Sjmallett        tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(pknd));
468232812Sjmallett
469232812Sjmallett        port_config.s.qos = pknd & 0x7;
470232812Sjmallett
471232812Sjmallett        /* Default BPID to use for packets on this port-kind */
472232812Sjmallett        prt_cfgbx.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGBX(pknd));
473232812Sjmallett        prt_cfgbx.s.bpid = pknd;
474232812Sjmallett        cvmx_write_csr(CVMX_PIP_PRT_CFGBX(pknd), prt_cfgbx.u64);
475232812Sjmallett    }
476232812Sjmallett    else
477232812Sjmallett    {
478232812Sjmallett        port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
479232812Sjmallett        tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port));
480232812Sjmallett
481232812Sjmallett        /* Have each port go to a different POW queue */
482232812Sjmallett        port_config.s.qos = ipd_port & 0x7;
483232812Sjmallett    }
484232812Sjmallett
485210284Sjmallett    /* Process the headers and place the IP header in the work queue */
486210284Sjmallett    port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE;
487210284Sjmallett
488210284Sjmallett    tag_config.s.ip6_src_flag  = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP;
489210284Sjmallett    tag_config.s.ip6_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP;
490210284Sjmallett    tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT;
491210284Sjmallett    tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT;
492210284Sjmallett    tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER;
493210284Sjmallett    tag_config.s.ip4_src_flag  = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP;
494210284Sjmallett    tag_config.s.ip4_dst_flag  = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP;
495210284Sjmallett    tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT;
496210284Sjmallett    tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT;
497210284Sjmallett    tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL;
498210284Sjmallett    tag_config.s.inc_prt_flag  = CVMX_HELPER_INPUT_TAG_INPUT_PORT;
499210284Sjmallett    tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
500210284Sjmallett    tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
501210284Sjmallett    tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
502210284Sjmallett    tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
503210284Sjmallett    tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
504210284Sjmallett    /* Put all packets in group 0. Other groups can be used by the app */
505210284Sjmallett    tag_config.s.grp = 0;
506210284Sjmallett
507210284Sjmallett    cvmx_pip_config_port(ipd_port, port_config, tag_config);
508210284Sjmallett
509210284Sjmallett    /* Give the user a chance to override our setting for each port */
510210284Sjmallett    if (cvmx_override_ipd_port_setup)
511210284Sjmallett        cvmx_override_ipd_port_setup(ipd_port);
512210284Sjmallett
513210284Sjmallett    return 0;
514210284Sjmallett}
515210284Sjmallett
516232812Sjmallett/**
517232812Sjmallett * Enable or disable FCS stripping for all the ports on an interface.
518232812Sjmallett *
519232812Sjmallett * @param interface
520232812Sjmallett * @param nports number of ports
521232812Sjmallett * @param has_fcs 0 for disable and !0 for enable
522232812Sjmallett */
523232812Sjmallettstatic int cvmx_helper_fcs_op(int interface, int nports, int has_fcs)
524232812Sjmallett{
525232812Sjmallett    uint64_t port_bit;
526232812Sjmallett    int index;
527232812Sjmallett    int pknd;
528232812Sjmallett    cvmx_pip_sub_pkind_fcsx_t pkind_fcsx;
529232812Sjmallett    cvmx_pip_prt_cfgx_t port_cfg;
530232812Sjmallett
531232812Sjmallett    if (!octeon_has_feature(OCTEON_FEATURE_PKND))
532232812Sjmallett        return 0;
533210284Sjmallett
534232812Sjmallett    port_bit = 0;
535232812Sjmallett    for (index = 0; index < nports; index++)
536232812Sjmallett        port_bit |= ((uint64_t)1 << cvmx_helper_get_pknd(interface, index));
537232812Sjmallett
538232812Sjmallett    pkind_fcsx.u64 = cvmx_read_csr(CVMX_PIP_SUB_PKIND_FCSX(0));
539232812Sjmallett    if (has_fcs)
540232812Sjmallett        pkind_fcsx.s.port_bit |= port_bit;
541232812Sjmallett    else
542232812Sjmallett        pkind_fcsx.s.port_bit &= ~port_bit;
543232812Sjmallett    cvmx_write_csr(CVMX_PIP_SUB_PKIND_FCSX(0), pkind_fcsx.u64);
544232812Sjmallett
545232812Sjmallett    for (pknd = 0; pknd < 64; pknd++)
546232812Sjmallett    {
547232812Sjmallett	if ((1ull << pknd) & port_bit)
548232812Sjmallett	{
549232812Sjmallett            port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(pknd));
550232812Sjmallett            port_cfg.s.crc_en = (has_fcs) ? 1 : 0;
551232812Sjmallett	    cvmx_write_csr(CVMX_PIP_PRT_CFGX(pknd), port_cfg.u64);
552232812Sjmallett	}
553232812Sjmallett    }
554232812Sjmallett
555232812Sjmallett    return 0;
556232812Sjmallett}
557232812Sjmallett
558210284Sjmallett/**
559232812Sjmallett * Determine the actual number of hardware ports connected to an
560232812Sjmallett * interface. It doesn't setup the ports or enable them.
561210284Sjmallett *
562232812Sjmallett * @param interface Interface to enumerate
563232812Sjmallett *
564232812Sjmallett * @return The number of ports on the interface, negative on failure
565232812Sjmallett */
566232812Sjmallettint cvmx_helper_interface_enumerate(int interface)
567232812Sjmallett{
568232812Sjmallett	switch (cvmx_helper_interface_get_mode(interface)) {
569232812Sjmallett		/* XAUI is a single high speed port */
570232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
571232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
572232812Sjmallett		return __cvmx_helper_xaui_enumerate(interface);
573232812Sjmallett		/* RGMII/GMII/MII are all treated about the same. Most functions
574232812Sjmallett		   refer to these ports as RGMII */
575232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
576232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
577232812Sjmallett		return  __cvmx_helper_rgmii_enumerate(interface);
578232812Sjmallett		/* SPI4 can have 1-16 ports depending on the device at the other end */
579232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
580232812Sjmallett		return __cvmx_helper_spi_enumerate(interface);
581232812Sjmallett		/* SGMII can have 1-4 ports depending on how many are hooked up */
582232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
583232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
584232812Sjmallett		return __cvmx_helper_sgmii_enumerate(interface);
585232812Sjmallett		/* PCI target Network Packet Interface */
586232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
587232812Sjmallett		return __cvmx_helper_npi_enumerate(interface);
588232812Sjmallett		/* Special loopback only ports. These are not the same
589232812Sjmallett		 * as other ports in loopback mode */
590232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
591232812Sjmallett		return __cvmx_helper_loop_enumerate(interface);
592232812Sjmallett		/* SRIO has 2^N ports, where N is number of interfaces */
593232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
594232812Sjmallett		return __cvmx_helper_srio_enumerate(interface);
595232812Sjmallett
596232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
597232812Sjmallett		return __cvmx_helper_ilk_enumerate(interface);
598232812Sjmallett		/* These types don't support ports to IPD/PKO */
599232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
600232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
601232812Sjmallett	default:
602232812Sjmallett		return 0;
603232812Sjmallett    }
604232812Sjmallett}
605232812Sjmallett
606232812Sjmallett/**
607232812Sjmallett * This function probes an interface to determine the actual number of
608232812Sjmallett * hardware ports connected to it. It does some setup the ports but
609232812Sjmallett * doesn't enable them. The main goal here is to set the global
610232812Sjmallett * interface_port_count[interface] correctly. Final hardware setup of
611232812Sjmallett * the ports will be performed later.
612232812Sjmallett *
613210284Sjmallett * @param interface Interface to probe
614210284Sjmallett *
615210284Sjmallett * @return Zero on success, negative on failure
616210284Sjmallett */
617210284Sjmallettint cvmx_helper_interface_probe(int interface)
618210284Sjmallett{
619210284Sjmallett    /* At this stage in the game we don't want packets to be moving yet.
620210284Sjmallett        The following probe calls should perform hardware setup
621210284Sjmallett        needed to determine port counts. Receive must still be disabled */
622232812Sjmallett    int nports;
623232812Sjmallett    int has_fcs;
624232812Sjmallett    enum cvmx_pko_padding padding = CVMX_PKO_PADDING_NONE;
625232812Sjmallett
626232812Sjmallett    nports = -1;
627232812Sjmallett    has_fcs = 0;
628210284Sjmallett    switch (cvmx_helper_interface_get_mode(interface))
629210284Sjmallett    {
630210284Sjmallett        /* These types don't support ports to IPD/PKO */
631210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
632210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
633232812Sjmallett            nports = 0;
634210284Sjmallett            break;
635210284Sjmallett        /* XAUI is a single high speed port */
636210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
637232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
638232812Sjmallett            nports = __cvmx_helper_xaui_probe(interface);
639232812Sjmallett            has_fcs = 1;
640232812Sjmallett            padding = CVMX_PKO_PADDING_60;
641210284Sjmallett            break;
642210284Sjmallett        /* RGMII/GMII/MII are all treated about the same. Most functions
643210284Sjmallett            refer to these ports as RGMII */
644210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
645210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
646232812Sjmallett            nports = __cvmx_helper_rgmii_probe(interface);
647232812Sjmallett            padding = CVMX_PKO_PADDING_60;
648210284Sjmallett            break;
649210284Sjmallett        /* SPI4 can have 1-16 ports depending on the device at the other end */
650210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
651232812Sjmallett            nports = __cvmx_helper_spi_probe(interface);
652232812Sjmallett            padding = CVMX_PKO_PADDING_60;
653210284Sjmallett            break;
654210284Sjmallett        /* SGMII can have 1-4 ports depending on how many are hooked up */
655210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
656232812Sjmallett            padding = CVMX_PKO_PADDING_60;
657210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
658232812Sjmallett            nports = __cvmx_helper_sgmii_probe(interface);
659232812Sjmallett            has_fcs = 1;
660210284Sjmallett            break;
661210284Sjmallett        /* PCI target Network Packet Interface */
662210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
663232812Sjmallett            nports = __cvmx_helper_npi_probe(interface);
664210284Sjmallett            break;
665210284Sjmallett        /* Special loopback only ports. These are not the same as other ports
666210284Sjmallett            in loopback mode */
667210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
668232812Sjmallett            nports = __cvmx_helper_loop_probe(interface);
669210284Sjmallett            break;
670232812Sjmallett        /* SRIO has 2^N ports, where N is number of interfaces */
671232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
672232812Sjmallett            nports = __cvmx_helper_srio_probe(interface);
673232812Sjmallett            break;
674232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
675232812Sjmallett            nports = __cvmx_helper_ilk_probe(interface);
676232812Sjmallett            has_fcs = 1;
677232812Sjmallett            padding = CVMX_PKO_PADDING_60;
678232812Sjmallett            break;
679210284Sjmallett    }
680210284Sjmallett
681232812Sjmallett    if (nports == -1)
682232812Sjmallett        return -1;
683210284Sjmallett
684232812Sjmallett    if (!octeon_has_feature(OCTEON_FEATURE_PKND))
685232812Sjmallett        has_fcs = 0;
686232812Sjmallett
687232812Sjmallett    nports = __cvmx_helper_board_interface_probe(interface, nports);
688232812Sjmallett    __cvmx_helper_init_interface(interface, nports, has_fcs, padding);
689232812Sjmallett    cvmx_helper_fcs_op(interface, nports, has_fcs);
690232812Sjmallett
691210284Sjmallett    /* Make sure all global variables propagate to other cores */
692210284Sjmallett    CVMX_SYNCWS;
693210284Sjmallett
694210284Sjmallett    return 0;
695210284Sjmallett}
696210284Sjmallett
697210284Sjmallett
698210284Sjmallett/**
699210284Sjmallett * @INTERNAL
700210284Sjmallett * Setup the IPD/PIP for the ports on an interface. Packet
701210284Sjmallett * classification and tagging are set for every port on the
702210284Sjmallett * interface. The number of ports on the interface must already
703210284Sjmallett * have been probed.
704210284Sjmallett *
705210284Sjmallett * @param interface Interface to setup IPD/PIP for
706210284Sjmallett *
707210284Sjmallett * @return Zero on success, negative on failure
708210284Sjmallett */
709210284Sjmallettstatic int __cvmx_helper_interface_setup_ipd(int interface)
710210284Sjmallett{
711232812Sjmallett
712232812Sjmallett    cvmx_helper_interface_mode_t mode;
713210284Sjmallett    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
714232812Sjmallett    int num_ports = cvmx_helper_ports_on_interface(interface);
715232812Sjmallett    int delta;
716210284Sjmallett
717232812Sjmallett    if (num_ports == CVMX_HELPER_CFG_INVALID_VALUE)
718232812Sjmallett        return 0;
719232812Sjmallett
720232812Sjmallett    mode = cvmx_helper_interface_get_mode(interface);
721232812Sjmallett
722232812Sjmallett    if (mode == CVMX_HELPER_INTERFACE_MODE_LOOP)
723232812Sjmallett	__cvmx_helper_loop_enable(interface);
724232812Sjmallett
725232812Sjmallett    delta = 1;
726232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
727232812Sjmallett    {
728232812Sjmallett        if (mode == CVMX_HELPER_INTERFACE_MODE_SGMII)
729232812Sjmallett	    delta = 16;
730232812Sjmallett    }
731232812Sjmallett
732210284Sjmallett    while (num_ports--)
733210284Sjmallett    {
734210284Sjmallett        __cvmx_helper_port_setup_ipd(ipd_port);
735232812Sjmallett        ipd_port += delta;
736210284Sjmallett    }
737232812Sjmallett
738210284Sjmallett    return 0;
739210284Sjmallett}
740210284Sjmallett
741210284Sjmallett
742210284Sjmallett/**
743210284Sjmallett * @INTERNAL
744210284Sjmallett * Setup global setting for IPD/PIP not related to a specific
745210284Sjmallett * interface or port. This must be called before IPD is enabled.
746210284Sjmallett *
747210284Sjmallett * @return Zero on success, negative on failure.
748210284Sjmallett */
749210284Sjmallettstatic int __cvmx_helper_global_setup_ipd(void)
750210284Sjmallett{
751215990Sjmallett#ifndef CVMX_HELPER_IPD_DRAM_MODE
752215990Sjmallett#define CVMX_HELPER_IPD_DRAM_MODE   CVMX_IPD_OPC_MODE_STT
753215990Sjmallett#endif
754210284Sjmallett    /* Setup the global packet input options */
755210284Sjmallett    cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE/8,
756210284Sjmallett                    CVMX_HELPER_FIRST_MBUFF_SKIP/8,
757210284Sjmallett                    CVMX_HELPER_NOT_FIRST_MBUFF_SKIP/8,
758210284Sjmallett                    (CVMX_HELPER_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
759210284Sjmallett                    (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP+8) / 128, /* The +8 is to account for the next ptr */
760210284Sjmallett                    CVMX_FPA_WQE_POOL,
761215990Sjmallett                    CVMX_HELPER_IPD_DRAM_MODE,
762215990Sjmallett                    1);
763210284Sjmallett    return 0;
764210284Sjmallett}
765210284Sjmallett
766210284Sjmallett
767210284Sjmallett/**
768210284Sjmallett * @INTERNAL
769210284Sjmallett * Setup the PKO for the ports on an interface. The number of
770210284Sjmallett * queues per port and the priority of each PKO output queue
771210284Sjmallett * is set here. PKO must be disabled when this function is called.
772210284Sjmallett *
773210284Sjmallett * @param interface Interface to setup PKO for
774210284Sjmallett *
775210284Sjmallett * @return Zero on success, negative on failure
776210284Sjmallett */
777210284Sjmallettstatic int __cvmx_helper_interface_setup_pko(int interface)
778210284Sjmallett{
779210284Sjmallett    /* Each packet output queue has an associated priority. The higher the
780210284Sjmallett        priority, the more often it can send a packet. A priority of 8 means
781210284Sjmallett        it can send in all 8 rounds of contention. We're going to make each
782210284Sjmallett        queue one less than the last.
783210284Sjmallett        The vector of priorities has been extended to support CN5xxx CPUs,
784210284Sjmallett        where up to 16 queues can be associated to a port.
785210284Sjmallett        To keep backward compatibility we don't change the initial 8
786210284Sjmallett        priorities and replicate them in the second half.
787210284Sjmallett        With per-core PKO queues (PKO lockless operation) all queues have
788210284Sjmallett        the same priority. */
789232812Sjmallett    /* uint64_t priorities[16] = {8,7,6,5,4,3,2,1,8,7,6,5,4,3,2,1}; */
790232812Sjmallett    uint64_t priorities[16] = {[0 ... 15] = 8};
791210284Sjmallett
792210284Sjmallett    /* Setup the IPD/PIP and PKO for the ports discovered above. Here packet
793210284Sjmallett        classification, tagging and output priorities are set */
794210284Sjmallett    int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
795232812Sjmallett    int num_ports = cvmx_helper_ports_on_interface(interface);
796210284Sjmallett    while (num_ports--)
797210284Sjmallett    {
798210284Sjmallett        /* Give the user a chance to override the per queue priorities */
799210284Sjmallett        if (cvmx_override_pko_queue_priority)
800210284Sjmallett            cvmx_override_pko_queue_priority(ipd_port, priorities);
801210284Sjmallett
802210284Sjmallett        cvmx_pko_config_port(ipd_port, cvmx_pko_get_base_queue_per_core(ipd_port, 0),
803210284Sjmallett                             cvmx_pko_get_num_queues(ipd_port), priorities);
804210284Sjmallett        ipd_port++;
805210284Sjmallett    }
806210284Sjmallett    return 0;
807210284Sjmallett}
808210284Sjmallett
809210284Sjmallett
810210284Sjmallett/**
811210284Sjmallett * @INTERNAL
812210284Sjmallett * Setup global setting for PKO not related to a specific
813210284Sjmallett * interface or port. This must be called before PKO is enabled.
814210284Sjmallett *
815210284Sjmallett * @return Zero on success, negative on failure.
816210284Sjmallett */
817210284Sjmallettstatic int __cvmx_helper_global_setup_pko(void)
818210284Sjmallett{
819210284Sjmallett    /* Disable tagwait FAU timeout. This needs to be done before anyone might
820210284Sjmallett        start packet output using tags */
821210284Sjmallett    cvmx_iob_fau_timeout_t fau_to;
822210284Sjmallett    fau_to.u64 = 0;
823210284Sjmallett    fau_to.s.tout_val = 0xfff;
824210284Sjmallett    fau_to.s.tout_enb = 0;
825210284Sjmallett    cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
826232812Sjmallett
827232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
828232812Sjmallett	    cvmx_pko_reg_min_pkt_t min_pkt;
829232812Sjmallett
830232812Sjmallett	    min_pkt.u64 = 0;
831232812Sjmallett	    min_pkt.s.size1 = 59;
832232812Sjmallett	    min_pkt.s.size2 = 59;
833232812Sjmallett	    min_pkt.s.size3 = 59;
834232812Sjmallett	    min_pkt.s.size4 = 59;
835232812Sjmallett	    min_pkt.s.size5 = 59;
836232812Sjmallett	    min_pkt.s.size6 = 59;
837232812Sjmallett	    min_pkt.s.size7 = 59;
838232812Sjmallett	    cvmx_write_csr(CVMX_PKO_REG_MIN_PKT, min_pkt.u64);
839232812Sjmallett    }
840232812Sjmallett
841210284Sjmallett    return 0;
842210284Sjmallett}
843210284Sjmallett
844210284Sjmallett
845210284Sjmallett/**
846210284Sjmallett * @INTERNAL
847210284Sjmallett * Setup global backpressure setting.
848210284Sjmallett *
849210284Sjmallett * @return Zero on success, negative on failure
850210284Sjmallett */
851210284Sjmallettstatic int __cvmx_helper_global_setup_backpressure(void)
852210284Sjmallett{
853210284Sjmallett#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
854210284Sjmallett    /* Disable backpressure if configured to do so */
855210284Sjmallett    /* Disable backpressure (pause frame) generation */
856210284Sjmallett    int num_interfaces = cvmx_helper_get_number_of_interfaces();
857210284Sjmallett    int interface;
858210284Sjmallett    for (interface=0; interface<num_interfaces; interface++)
859210284Sjmallett    {
860210284Sjmallett        switch (cvmx_helper_interface_get_mode(interface))
861210284Sjmallett        {
862210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
863210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PCIE:
864215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SRIO:
865232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_ILK:
866210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_NPI:
867210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_LOOP:
868210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_XAUI:
869232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RXAUI:
870210284Sjmallett                break;
871210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RGMII:
872210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_GMII:
873210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SPI:
874210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SGMII:
875210284Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PICMG:
876210284Sjmallett                cvmx_gmx_set_backpressure_override(interface, 0xf);
877210284Sjmallett                break;
878210284Sjmallett        }
879210284Sjmallett    }
880210284Sjmallett    //cvmx_dprintf("Disabling backpressure\n");
881210284Sjmallett#endif
882210284Sjmallett
883210284Sjmallett    return 0;
884210284Sjmallett}
885210284Sjmallett
886215990Sjmallett/**
887215990Sjmallett * @INTERNAL
888215990Sjmallett * Verify the per port IPD backpressure is aligned properly.
889215990Sjmallett * @return Zero if working, non zero if misaligned
890215990Sjmallett */
891215990Sjmallettstatic int __cvmx_helper_backpressure_is_misaligned(void)
892215990Sjmallett{
893215990Sjmallett    uint64_t ipd_int_enb;
894215990Sjmallett    cvmx_ipd_ctl_status_t ipd_reg;
895215990Sjmallett    uint64_t bp_status0;
896215990Sjmallett    uint64_t bp_status1;
897215990Sjmallett    const int port0 = 0;
898215990Sjmallett    const int port1 = 16;
899215990Sjmallett    cvmx_helper_interface_mode_t mode0 = cvmx_helper_interface_get_mode(0);
900215990Sjmallett    cvmx_helper_interface_mode_t mode1 = cvmx_helper_interface_get_mode(1);
901210284Sjmallett
902215990Sjmallett    /* Disable error interrupts while we check backpressure */
903215990Sjmallett    ipd_int_enb = cvmx_read_csr(CVMX_IPD_INT_ENB);
904215990Sjmallett    cvmx_write_csr(CVMX_IPD_INT_ENB, 0);
905215990Sjmallett
906215990Sjmallett    /* Enable per port backpressure */
907215990Sjmallett    ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
908215990Sjmallett    ipd_reg.s.pbp_en = 1;
909215990Sjmallett    cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64);
910215990Sjmallett
911215990Sjmallett    if (mode0 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
912215990Sjmallett    {
913215990Sjmallett        /* Enable backpressure for port with a zero threshold */
914215990Sjmallett        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port0), 1<<17);
915215990Sjmallett        /* Add 1000 to the page count to simulate packets coming in */
916215990Sjmallett        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port0<<25) | 1000);
917215990Sjmallett    }
918215990Sjmallett
919215990Sjmallett    if (mode1 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
920215990Sjmallett    {
921215990Sjmallett        /* Enable backpressure for port with a zero threshold */
922215990Sjmallett        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port1), 1<<17);
923215990Sjmallett        /* Add 1000 to the page count to simulate packets coming in */
924215990Sjmallett        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port1<<25) | 1000);
925215990Sjmallett    }
926215990Sjmallett
927215990Sjmallett    /* Wait 500 cycles for the BP to update */
928215990Sjmallett    cvmx_wait(500);
929215990Sjmallett
930215990Sjmallett    /* Read the BP state from the debug select register */
931215990Sjmallett    switch (mode0)
932215990Sjmallett    {
933215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
934215990Sjmallett            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x9004);
935215990Sjmallett            bp_status0 = cvmx_read_csr(CVMX_DBG_DATA);
936215990Sjmallett            bp_status0 = 0xffff & ~bp_status0;
937215990Sjmallett            break;
938215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
939215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
940215990Sjmallett            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x0e00);
941215990Sjmallett            bp_status0 = 0xffff & cvmx_read_csr(CVMX_DBG_DATA);
942215990Sjmallett            break;
943215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
944215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
945215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
946215990Sjmallett            cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, 0x0e00);
947215990Sjmallett            bp_status0 = 0xffff & cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
948215990Sjmallett            break;
949215990Sjmallett        default:
950215990Sjmallett            bp_status0 = 1<<port0;
951215990Sjmallett            break;
952215990Sjmallett    }
953215990Sjmallett
954215990Sjmallett    /* Read the BP state from the debug select register */
955215990Sjmallett    switch (mode1)
956215990Sjmallett    {
957215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
958215990Sjmallett            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x9804);
959215990Sjmallett            bp_status1 = cvmx_read_csr(CVMX_DBG_DATA);
960215990Sjmallett            bp_status1 = 0xffff & ~bp_status1;
961215990Sjmallett            break;
962215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
963215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
964215990Sjmallett            cvmx_write_csr(CVMX_NPI_DBG_SELECT, 0x1600);
965215990Sjmallett            bp_status1 = 0xffff & cvmx_read_csr(CVMX_DBG_DATA);
966215990Sjmallett            break;
967215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
968215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
969215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
970215990Sjmallett            cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, 0x1600);
971215990Sjmallett            bp_status1 = 0xffff & cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
972215990Sjmallett            break;
973215990Sjmallett        default:
974215990Sjmallett            bp_status1 = 1<<(port1-16);
975215990Sjmallett            break;
976215990Sjmallett    }
977215990Sjmallett
978215990Sjmallett    if (mode0 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
979215990Sjmallett    {
980215990Sjmallett        /* Shutdown BP */
981215990Sjmallett        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port0<<25) | (0x1ffffff & -1000));
982215990Sjmallett        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port0), 0);
983215990Sjmallett    }
984215990Sjmallett
985215990Sjmallett    if (mode1 != CVMX_HELPER_INTERFACE_MODE_DISABLED)
986215990Sjmallett    {
987215990Sjmallett        /* Shutdown BP */
988215990Sjmallett        cvmx_write_csr(CVMX_IPD_SUB_PORT_BP_PAGE_CNT, (port1<<25) | (0x1ffffff & -1000));
989215990Sjmallett        cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port1), 0);
990215990Sjmallett    }
991215990Sjmallett
992215990Sjmallett    /* Clear any error interrupts that might have been set */
993215990Sjmallett    cvmx_write_csr(CVMX_IPD_INT_SUM, 0x1f);
994215990Sjmallett    cvmx_write_csr(CVMX_IPD_INT_ENB, ipd_int_enb);
995215990Sjmallett
996215990Sjmallett    return ((bp_status0 != 1ull<<port0) || (bp_status1 != 1ull<<(port1-16)));
997215990Sjmallett}
998215990Sjmallett
999215990Sjmallett
1000210284Sjmallett/**
1001210284Sjmallett * @INTERNAL
1002210284Sjmallett * Enable packet input/output from the hardware. This function is
1003210284Sjmallett * called after all internal setup is complete and IPD is enabled.
1004210284Sjmallett * After this function completes, packets will be accepted from the
1005210284Sjmallett * hardware ports. PKO should still be disabled to make sure packets
1006210284Sjmallett * aren't sent out partially setup hardware.
1007210284Sjmallett *
1008210284Sjmallett * @param interface Interface to enable
1009210284Sjmallett *
1010210284Sjmallett * @return Zero on success, negative on failure
1011210284Sjmallett */
1012210284Sjmallettstatic int __cvmx_helper_packet_hardware_enable(int interface)
1013210284Sjmallett{
1014210284Sjmallett    int result = 0;
1015210284Sjmallett    switch (cvmx_helper_interface_get_mode(interface))
1016210284Sjmallett    {
1017210284Sjmallett        /* These types don't support ports to IPD/PKO */
1018210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1019210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1020232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1021210284Sjmallett            /* Nothing to do */
1022210284Sjmallett            break;
1023210284Sjmallett        /* XAUI is a single high speed port */
1024210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1025232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1026210284Sjmallett            result = __cvmx_helper_xaui_enable(interface);
1027210284Sjmallett            break;
1028210284Sjmallett        /* RGMII/GMII/MII are all treated about the same. Most functions
1029210284Sjmallett            refer to these ports as RGMII */
1030210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1031210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
1032210284Sjmallett            result = __cvmx_helper_rgmii_enable(interface);
1033210284Sjmallett            break;
1034210284Sjmallett        /* SPI4 can have 1-16 ports depending on the device at the other end */
1035210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
1036210284Sjmallett            result = __cvmx_helper_spi_enable(interface);
1037210284Sjmallett            break;
1038210284Sjmallett        /* SGMII can have 1-4 ports depending on how many are hooked up */
1039210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1040210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1041210284Sjmallett            result = __cvmx_helper_sgmii_enable(interface);
1042210284Sjmallett            break;
1043210284Sjmallett        /* PCI target Network Packet Interface */
1044210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
1045210284Sjmallett            result = __cvmx_helper_npi_enable(interface);
1046210284Sjmallett            break;
1047232812Sjmallett        /* SRIO has 2^N ports, where N is number of interfaces */
1048232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1049232812Sjmallett            result = __cvmx_helper_srio_enable(interface);
1050210284Sjmallett            break;
1051232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
1052232812Sjmallett            result = __cvmx_helper_ilk_enable(interface);
1053232812Sjmallett            break;
1054210284Sjmallett    }
1055210284Sjmallett    result |= __cvmx_helper_board_hardware_enable(interface);
1056210284Sjmallett    return result;
1057210284Sjmallett}
1058210284Sjmallett
1059210284Sjmallett
1060210284Sjmallett/**
1061210284Sjmallett * Called after all internal packet IO paths are setup. This
1062210284Sjmallett * function enables IPD/PIP and begins packet input and output.
1063210284Sjmallett *
1064210284Sjmallett * @return Zero on success, negative on failure
1065210284Sjmallett */
1066210284Sjmallettint cvmx_helper_ipd_and_packet_input_enable(void)
1067210284Sjmallett{
1068210284Sjmallett    int num_interfaces;
1069210284Sjmallett    int interface;
1070210284Sjmallett
1071210284Sjmallett    /* Enable IPD */
1072210284Sjmallett    cvmx_ipd_enable();
1073210284Sjmallett
1074210284Sjmallett    /* Time to enable hardware ports packet input and output. Note that at this
1075210284Sjmallett        point IPD/PIP must be fully functional and PKO must be disabled */
1076210284Sjmallett    num_interfaces = cvmx_helper_get_number_of_interfaces();
1077210284Sjmallett    for (interface=0; interface<num_interfaces; interface++)
1078210284Sjmallett    {
1079210284Sjmallett        if (cvmx_helper_ports_on_interface(interface) > 0)
1080210284Sjmallett        {
1081210284Sjmallett            //cvmx_dprintf("Enabling packet I/O on interface %d\n", interface);
1082210284Sjmallett            __cvmx_helper_packet_hardware_enable(interface);
1083210284Sjmallett        }
1084210284Sjmallett    }
1085210284Sjmallett
1086210284Sjmallett    /* Finally enable PKO now that the entire path is up and running */
1087210284Sjmallett    cvmx_pko_enable();
1088210284Sjmallett
1089210284Sjmallett    if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) &&
1090210284Sjmallett        (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
1091210284Sjmallett        __cvmx_helper_errata_fix_ipd_ptr_alignment();
1092210284Sjmallett    return 0;
1093210284Sjmallett}
1094215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1095215990SjmallettEXPORT_SYMBOL(cvmx_helper_ipd_and_packet_input_enable);
1096215990Sjmallett#endif
1097210284Sjmallett
1098232812Sjmallett#define __CVMX_SSO_RWQ_SIZE 256
1099232812Sjmallett
1100232812Sjmallettint cvmx_helper_initialize_sso(int wqe_entries)
1101232812Sjmallett{
1102232812Sjmallett    int cvm_oct_sso_number_rwq_bufs;
1103232812Sjmallett    char *mem;
1104232812Sjmallett    int i;
1105232812Sjmallett    cvmx_sso_cfg_t sso_cfg;
1106232812Sjmallett    cvmx_fpa_fpfx_marks_t fpa_marks;
1107232812Sjmallett
1108232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
1109232812Sjmallett        return 0;
1110232812Sjmallett
1111232812Sjmallett    /*
1112232812Sjmallett     * CN68XX-P1 may reset with the wrong values, put in
1113232812Sjmallett     * the correct values.
1114232812Sjmallett     */
1115232812Sjmallett    fpa_marks.u64 = 0;
1116232812Sjmallett    fpa_marks.s.fpf_wr = 0xa4;
1117232812Sjmallett    fpa_marks.s.fpf_rd = 0x40;
1118232812Sjmallett    cvmx_write_csr(CVMX_FPA_FPF8_MARKS, fpa_marks.u64);
1119232812Sjmallett
1120232812Sjmallett    cvm_oct_sso_number_rwq_bufs = ((wqe_entries - 1) / 26) + 1 + 48 + 8;
1121232812Sjmallett
1122232812Sjmallett    mem = cvmx_bootmem_alloc(__CVMX_SSO_RWQ_SIZE * cvm_oct_sso_number_rwq_bufs, CVMX_CACHE_LINE_SIZE);
1123232812Sjmallett    if (mem == NULL) {
1124232812Sjmallett        cvmx_dprintf("Out of memory initializing sso pool\n");
1125232812Sjmallett        return -1;
1126232812Sjmallett    }
1127232812Sjmallett    /* Make sure RWI/RWO is disabled. */
1128232812Sjmallett    sso_cfg.u64 = cvmx_read_csr(CVMX_SSO_CFG);
1129232812Sjmallett    sso_cfg.s.rwen = 0;
1130232812Sjmallett    cvmx_write_csr(CVMX_SSO_CFG, sso_cfg.u64);
1131232812Sjmallett
1132232812Sjmallett    for (i = cvm_oct_sso_number_rwq_bufs - 8; i > 0; i--) {
1133232812Sjmallett        cvmx_sso_rwq_psh_fptr_t fptr;
1134232812Sjmallett
1135232812Sjmallett        for (;;) {
1136232812Sjmallett            fptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_PSH_FPTR);
1137232812Sjmallett            if (!fptr.s.full)
1138232812Sjmallett                break;
1139232812Sjmallett            cvmx_wait(1000);
1140232812Sjmallett        }
1141232812Sjmallett        fptr.s.fptr = cvmx_ptr_to_phys(mem) >> 7;
1142232812Sjmallett        cvmx_write_csr(CVMX_SSO_RWQ_PSH_FPTR, fptr.u64);
1143232812Sjmallett        mem = mem + __CVMX_SSO_RWQ_SIZE;
1144232812Sjmallett    }
1145232812Sjmallett
1146232812Sjmallett    for (i = 0; i < 8; i++) {
1147232812Sjmallett        cvmx_sso_rwq_head_ptrx_t head_ptr;
1148232812Sjmallett        cvmx_sso_rwq_tail_ptrx_t tail_ptr;
1149232812Sjmallett
1150232812Sjmallett        head_ptr.u64 = 0;
1151232812Sjmallett        tail_ptr.u64 = 0;
1152232812Sjmallett        head_ptr.s.ptr = cvmx_ptr_to_phys(mem) >> 7;
1153232812Sjmallett        tail_ptr.s.ptr = head_ptr.s.ptr;
1154232812Sjmallett        cvmx_write_csr(CVMX_SSO_RWQ_HEAD_PTRX(i), head_ptr.u64);
1155232812Sjmallett        cvmx_write_csr(CVMX_SSO_RWQ_TAIL_PTRX(i), tail_ptr.u64);
1156232812Sjmallett        mem = mem + __CVMX_SSO_RWQ_SIZE;
1157232812Sjmallett    }
1158232812Sjmallett
1159232812Sjmallett    sso_cfg.u64 = cvmx_read_csr(CVMX_SSO_CFG);
1160232812Sjmallett    sso_cfg.s.rwen = 1;
1161232812Sjmallett    sso_cfg.s.dwb = cvmx_helper_cfg_opt_get(CVMX_HELPER_CFG_OPT_USE_DWB);
1162232812Sjmallett    sso_cfg.s.rwq_byp_dis = 0;
1163232812Sjmallett    sso_cfg.s.rwio_byp_dis = 0;
1164232812Sjmallett    cvmx_write_csr(CVMX_SSO_CFG, sso_cfg.u64);
1165232812Sjmallett
1166232812Sjmallett    return 0;
1167232812Sjmallett}
1168232812Sjmallett
1169232812Sjmallettint cvmx_helper_uninitialize_sso(void)
1170232812Sjmallett{
1171232812Sjmallett    cvmx_fpa_quex_available_t queue_available;
1172232812Sjmallett    cvmx_sso_cfg_t sso_cfg;
1173232812Sjmallett    cvmx_sso_rwq_pop_fptr_t pop_fptr;
1174232812Sjmallett    cvmx_sso_rwq_psh_fptr_t fptr;
1175232812Sjmallett    cvmx_sso_fpage_cnt_t fpage_cnt;
1176232812Sjmallett    int num_to_transfer, i;
1177232812Sjmallett    char *mem;
1178232812Sjmallett
1179232812Sjmallett    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
1180232812Sjmallett        return 0;
1181232812Sjmallett
1182232812Sjmallett    sso_cfg.u64 = cvmx_read_csr(CVMX_SSO_CFG);
1183232812Sjmallett    sso_cfg.s.rwen = 0;
1184232812Sjmallett    sso_cfg.s.rwq_byp_dis = 1;
1185232812Sjmallett    cvmx_write_csr(CVMX_SSO_CFG, sso_cfg.u64);
1186232812Sjmallett    cvmx_read_csr(CVMX_SSO_CFG);
1187232812Sjmallett    queue_available.u64 = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(8));
1188232812Sjmallett
1189232812Sjmallett    /* Make CVMX_FPA_QUEX_AVAILABLE(8) % 16 == 0*/
1190232812Sjmallett    for (num_to_transfer = (16 - queue_available.s.que_siz) % 16;
1191232812Sjmallett         num_to_transfer > 0; num_to_transfer--) {
1192232812Sjmallett        do {
1193232812Sjmallett            pop_fptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_POP_FPTR);
1194232812Sjmallett        } while (!pop_fptr.s.val);
1195232812Sjmallett        for (;;) {
1196232812Sjmallett            fptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_PSH_FPTR);
1197232812Sjmallett            if (!fptr.s.full)
1198232812Sjmallett                break;
1199232812Sjmallett            cvmx_wait(1000);
1200232812Sjmallett        }
1201232812Sjmallett        fptr.s.fptr = pop_fptr.s.fptr;
1202232812Sjmallett        cvmx_write_csr(CVMX_SSO_RWQ_PSH_FPTR, fptr.u64);
1203232812Sjmallett    }
1204232812Sjmallett    cvmx_read_csr(CVMX_SSO_CFG);
1205232812Sjmallett
1206232812Sjmallett    do {
1207232812Sjmallett        queue_available.u64 = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(8));
1208232812Sjmallett    } while (queue_available.s.que_siz % 16);
1209232812Sjmallett
1210232812Sjmallett    sso_cfg.s.rwen = 1;
1211232812Sjmallett    sso_cfg.s.rwq_byp_dis = 0;
1212232812Sjmallett    cvmx_write_csr(CVMX_SSO_CFG, sso_cfg.u64);
1213232812Sjmallett
1214232812Sjmallett    for (i = 0; i < 8; i++) {
1215232812Sjmallett        cvmx_sso_rwq_head_ptrx_t head_ptr;
1216232812Sjmallett        cvmx_sso_rwq_tail_ptrx_t tail_ptr;
1217232812Sjmallett
1218232812Sjmallett        head_ptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_HEAD_PTRX(i));
1219232812Sjmallett        tail_ptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_TAIL_PTRX(i));
1220232812Sjmallett        if (head_ptr.s.ptr != tail_ptr.s.ptr) {
1221232812Sjmallett            cvmx_dprintf("head_ptr.s.ptr != tail_ptr.s.ptr, idx: %d\n", i);
1222232812Sjmallett        }
1223232812Sjmallett
1224232812Sjmallett        mem = cvmx_phys_to_ptr(((uint64_t)head_ptr.s.ptr) << 7);
1225232812Sjmallett        /* Leak the memory */
1226232812Sjmallett    }
1227232812Sjmallett
1228232812Sjmallett    do {
1229232812Sjmallett        do {
1230232812Sjmallett            pop_fptr.u64 = cvmx_read_csr(CVMX_SSO_RWQ_POP_FPTR);
1231232812Sjmallett            if (pop_fptr.s.val) {
1232232812Sjmallett                mem = cvmx_phys_to_ptr(((uint64_t)pop_fptr.s.fptr) << 7);
1233232812Sjmallett                /* Leak the memory */
1234232812Sjmallett            }
1235232812Sjmallett        } while (pop_fptr.s.val);
1236232812Sjmallett        fpage_cnt.u64 = cvmx_read_csr(CVMX_SSO_FPAGE_CNT);
1237232812Sjmallett    } while (fpage_cnt.s.fpage_cnt);
1238232812Sjmallett
1239232812Sjmallett    sso_cfg.s.rwen = 0;
1240232812Sjmallett    sso_cfg.s.rwq_byp_dis = 0;
1241232812Sjmallett    cvmx_write_csr(CVMX_SSO_CFG, sso_cfg.u64);
1242232812Sjmallett
1243232812Sjmallett    return 0;
1244232812Sjmallett}
1245232812Sjmallett
1246210284Sjmallett/**
1247210284Sjmallett * Initialize the PIP, IPD, and PKO hardware to support
1248210284Sjmallett * simple priority based queues for the ethernet ports. Each
1249210284Sjmallett * port is configured with a number of priority queues based
1250210284Sjmallett * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
1251210284Sjmallett * priority than the previous.
1252210284Sjmallett *
1253210284Sjmallett * @return Zero on success, non-zero on failure
1254210284Sjmallett */
1255210284Sjmallettint cvmx_helper_initialize_packet_io_global(void)
1256210284Sjmallett{
1257210284Sjmallett    int result = 0;
1258210284Sjmallett    int interface;
1259210284Sjmallett    cvmx_l2c_cfg_t l2c_cfg;
1260210284Sjmallett    cvmx_smix_en_t smix_en;
1261210284Sjmallett    const int num_interfaces = cvmx_helper_get_number_of_interfaces();
1262210284Sjmallett
1263210284Sjmallett    /* CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to be disabled */
1264210284Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
1265210284Sjmallett        __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
1266210284Sjmallett
1267210284Sjmallett    /* Tell L2 to give the IOB statically higher priority compared to the
1268210284Sjmallett        cores. This avoids conditions where IO blocks might be starved under
1269210284Sjmallett        very high L2 loads */
1270232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
1271210284Sjmallett    {
1272215990Sjmallett        cvmx_l2c_ctl_t l2c_ctl;
1273215990Sjmallett        l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL);
1274215990Sjmallett        l2c_ctl.s.rsp_arb_mode = 1;
1275215990Sjmallett        l2c_ctl.s.xmc_arb_mode = 0;
1276215990Sjmallett        cvmx_write_csr(CVMX_L2C_CTL, l2c_ctl.u64);
1277210284Sjmallett    }
1278215990Sjmallett    else
1279215990Sjmallett    {
1280215990Sjmallett        l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
1281215990Sjmallett        l2c_cfg.s.lrf_arb_mode = 0;
1282215990Sjmallett        l2c_cfg.s.rfb_arb_mode = 0;
1283215990Sjmallett        cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
1284215990Sjmallett    }
1285210284Sjmallett
1286215990Sjmallett    if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
1287210284Sjmallett    {
1288232812Sjmallett        int smi_inf = 1;
1289232812Sjmallett        int i;
1290215990Sjmallett
1291232812Sjmallett        /* Newer chips have more than one SMI/MDIO interface */
1292232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
1293232812Sjmallett            smi_inf = 4;
1294232812Sjmallett        else if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)
1295232812Sjmallett                 && !OCTEON_IS_MODEL(OCTEON_CN58XX)
1296232812Sjmallett                 && !OCTEON_IS_MODEL(OCTEON_CN50XX))
1297232812Sjmallett            smi_inf = 2;
1298232812Sjmallett
1299232812Sjmallett        for (i = 0; i < smi_inf; i++)
1300215990Sjmallett        {
1301232812Sjmallett            /* Make sure SMI/MDIO is enabled so we can query PHYs */
1302232812Sjmallett            smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(i));
1303215990Sjmallett            if (!smix_en.s.en)
1304215990Sjmallett            {
1305215990Sjmallett                smix_en.s.en = 1;
1306232812Sjmallett                cvmx_write_csr(CVMX_SMIX_EN(i), smix_en.u64);
1307215990Sjmallett            }
1308215990Sjmallett        }
1309210284Sjmallett    }
1310210284Sjmallett
1311232812Sjmallett    __cvmx_helper_cfg_init();
1312232812Sjmallett
1313215990Sjmallett    for (interface=0; interface<num_interfaces; interface++)
1314215990Sjmallett        result |= cvmx_helper_interface_probe(interface);
1315215990Sjmallett
1316210284Sjmallett    cvmx_pko_initialize_global();
1317210284Sjmallett    for (interface=0; interface<num_interfaces; interface++)
1318210284Sjmallett    {
1319210284Sjmallett        if (cvmx_helper_ports_on_interface(interface) > 0)
1320210284Sjmallett            cvmx_dprintf("Interface %d has %d ports (%s)\n",
1321210284Sjmallett                     interface, cvmx_helper_ports_on_interface(interface),
1322210284Sjmallett                     cvmx_helper_interface_mode_to_string(cvmx_helper_interface_get_mode(interface)));
1323210284Sjmallett        result |= __cvmx_helper_interface_setup_ipd(interface);
1324232812Sjmallett        if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
1325232812Sjmallett            result |= __cvmx_helper_interface_setup_pko(interface);
1326210284Sjmallett    }
1327210284Sjmallett
1328210284Sjmallett    result |= __cvmx_helper_global_setup_ipd();
1329210284Sjmallett    result |= __cvmx_helper_global_setup_pko();
1330210284Sjmallett
1331210284Sjmallett    /* Enable any flow control and backpressure */
1332210284Sjmallett    result |= __cvmx_helper_global_setup_backpressure();
1333210284Sjmallett
1334210284Sjmallett#if CVMX_HELPER_ENABLE_IPD
1335210284Sjmallett    result |= cvmx_helper_ipd_and_packet_input_enable();
1336210284Sjmallett#endif
1337210284Sjmallett    return result;
1338210284Sjmallett}
1339215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1340215990SjmallettEXPORT_SYMBOL(cvmx_helper_initialize_packet_io_global);
1341215990Sjmallett#endif
1342210284Sjmallett
1343210284Sjmallett
1344210284Sjmallett/**
1345210284Sjmallett * Does core local initialization for packet io
1346210284Sjmallett *
1347210284Sjmallett * @return Zero on success, non-zero on failure
1348210284Sjmallett */
1349210284Sjmallettint cvmx_helper_initialize_packet_io_local(void)
1350210284Sjmallett{
1351210284Sjmallett    return cvmx_pko_initialize_local();
1352210284Sjmallett}
1353210284Sjmallett
1354232812Sjmallett/**
1355232812Sjmallett * wait for the pko queue to drain
1356232812Sjmallett *
1357232812Sjmallett * @param queue a valid pko queue
1358232812Sjmallett * @return count is the length of the queue after calling this
1359232812Sjmallett * function
1360232812Sjmallett */
1361232812Sjmallettstatic int cvmx_helper_wait_pko_queue_drain(int queue)
1362232812Sjmallett{
1363232812Sjmallett    const int timeout = 5; /* Wait up to 5 seconds for timeouts */
1364232812Sjmallett    int count;
1365232812Sjmallett    uint64_t start_cycle, stop_cycle;
1366210284Sjmallett
1367232812Sjmallett    count = cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue));
1368232812Sjmallett    start_cycle = cvmx_get_cycle();
1369232812Sjmallett    stop_cycle = start_cycle + cvmx_clock_get_rate(CVMX_CLOCK_CORE) * timeout;
1370232812Sjmallett    while (count && (cvmx_get_cycle() < stop_cycle))
1371232812Sjmallett    {
1372232812Sjmallett        cvmx_wait(10000);
1373232812Sjmallett        count = cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue));
1374232812Sjmallett    }
1375232812Sjmallett
1376232812Sjmallett    return count;
1377232812Sjmallett}
1378232812Sjmallett
1379232812Sjmallettstruct cvmx_buffer_list {
1380232812Sjmallett    struct cvmx_buffer_list *next;
1381232812Sjmallett};
1382232812Sjmallett
1383210284Sjmallett/**
1384215990Sjmallett * Undo the initialization performed in
1385215990Sjmallett * cvmx_helper_initialize_packet_io_global(). After calling this routine and the
1386215990Sjmallett * local version on each core, packet IO for Octeon will be disabled and placed
1387215990Sjmallett * in the initial reset state. It will then be safe to call the initialize
1388215990Sjmallett * later on. Note that this routine does not empty the FPA pools. It frees all
1389215990Sjmallett * buffers used by the packet IO hardware to the FPA so a function emptying the
1390215990Sjmallett * FPA after shutdown should find all packet buffers in the FPA.
1391215990Sjmallett *
1392215990Sjmallett * @return Zero on success, negative on failure.
1393215990Sjmallett */
1394215990Sjmallettint cvmx_helper_shutdown_packet_io_global(void)
1395215990Sjmallett{
1396215990Sjmallett    const int timeout = 5; /* Wait up to 5 seconds for timeouts */
1397215990Sjmallett    int result = 0;
1398215990Sjmallett    int num_interfaces;
1399215990Sjmallett    int interface;
1400215990Sjmallett    int num_ports;
1401215990Sjmallett    int index;
1402232812Sjmallett    struct cvmx_buffer_list *pool0_buffers;
1403232812Sjmallett    struct cvmx_buffer_list *pool0_buffers_tail;
1404215990Sjmallett    cvmx_wqe_t *work;
1405215990Sjmallett
1406215990Sjmallett    /* Step 1: Disable all backpressure */
1407232812Sjmallett    for (interface=0; interface<CVMX_HELPER_MAX_GMX; interface++)
1408215990Sjmallett        if (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_DISABLED)
1409215990Sjmallett            cvmx_gmx_set_backpressure_override(interface, 0xf);
1410215990Sjmallett
1411215990Sjmallettstep2:
1412215990Sjmallett    /* Step 2: Wait for the PKO queues to drain */
1413232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
1414215990Sjmallett    {
1415232812Sjmallett        int queue, max_queue;
1416232812Sjmallett
1417232812Sjmallett	max_queue = __cvmx_helper_cfg_pko_max_queue();
1418232812Sjmallett	for (queue = 0; queue < max_queue; queue++)
1419232812Sjmallett	{
1420232812Sjmallett	    if (cvmx_helper_wait_pko_queue_drain(queue))
1421232812Sjmallett	    {
1422232812Sjmallett	        result = -1;
1423232812Sjmallett		goto step3;
1424232812Sjmallett            }
1425232812Sjmallett        }
1426232812Sjmallett    }
1427232812Sjmallett    else
1428232812Sjmallett    {
1429232812Sjmallett        num_interfaces = cvmx_helper_get_number_of_interfaces();
1430232812Sjmallett        for (interface=0; interface<num_interfaces; interface++)
1431215990Sjmallett        {
1432232812Sjmallett            num_ports = cvmx_helper_ports_on_interface(interface);
1433232812Sjmallett            for (index=0; index<num_ports; index++)
1434215990Sjmallett            {
1435232812Sjmallett                int pko_port = cvmx_helper_get_ipd_port(interface, index);
1436232812Sjmallett                int queue = cvmx_pko_get_base_queue(pko_port);
1437232812Sjmallett                int max_queue = queue + cvmx_pko_get_num_queues(pko_port);
1438232812Sjmallett                while (queue < max_queue)
1439215990Sjmallett                {
1440232812Sjmallett	            if (cvmx_helper_wait_pko_queue_drain(queue))
1441232812Sjmallett		    {
1442232812Sjmallett		        result = -1;
1443232812Sjmallett			goto step3;
1444232812Sjmallett		    }
1445232812Sjmallett                    queue++;
1446215990Sjmallett                }
1447215990Sjmallett            }
1448215990Sjmallett        }
1449215990Sjmallett    }
1450215990Sjmallett
1451232812Sjmallettstep3:
1452215990Sjmallett    /* Step 3: Disable TX and RX on all ports */
1453232812Sjmallett    for (interface=0; interface<CVMX_HELPER_MAX_GMX; interface++)
1454215990Sjmallett    {
1455215990Sjmallett        switch (cvmx_helper_interface_get_mode(interface))
1456215990Sjmallett        {
1457215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1458215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PCIE:
1459215990Sjmallett                /* Not a packet interface */
1460215990Sjmallett                break;
1461215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_NPI:
1462215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SRIO:
1463232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_ILK:
1464215990Sjmallett                /* We don't handle the NPI/NPEI/SRIO packet engines. The caller
1465215990Sjmallett                    must know these are idle */
1466215990Sjmallett                break;
1467215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_LOOP:
1468215990Sjmallett                /* Nothing needed. Once PKO is idle, the loopback devices
1469215990Sjmallett                    must be idle */
1470215990Sjmallett                break;
1471215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SPI:
1472215990Sjmallett                /* SPI cannot be disabled from Octeon. It is the responsibility
1473215990Sjmallett                    of the caller to make sure SPI is idle before doing
1474215990Sjmallett                    shutdown */
1475215990Sjmallett                /* Fall through and do the same processing as RGMII/GMII */
1476215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_GMII:
1477215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RGMII:
1478215990Sjmallett                /* Disable outermost RX at the ASX block */
1479215990Sjmallett                cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), 0);
1480215990Sjmallett                num_ports = cvmx_helper_ports_on_interface(interface);
1481215990Sjmallett                if (num_ports > 4)
1482215990Sjmallett                    num_ports = 4;
1483215990Sjmallett                for (index=0; index<num_ports; index++)
1484215990Sjmallett                {
1485215990Sjmallett                    cvmx_gmxx_prtx_cfg_t gmx_cfg;
1486215990Sjmallett                    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
1487215990Sjmallett                    gmx_cfg.s.en = 0;
1488215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
1489215990Sjmallett                    /* Poll the GMX state machine waiting for it to become idle */
1490215990Sjmallett                    cvmx_write_csr(CVMX_NPI_DBG_SELECT, interface*0x800 + index*0x100 + 0x880);
1491215990Sjmallett                    if (CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&7, ==, 0, timeout*1000000))
1492215990Sjmallett                    {
1493215990Sjmallett                        cvmx_dprintf("GMX RX path timeout waiting for idle\n");
1494215990Sjmallett                        result = -1;
1495215990Sjmallett                    }
1496215990Sjmallett                    if (CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, cvmx_dbg_data_t, data&0xf, ==, 0, timeout*1000000))
1497215990Sjmallett                    {
1498215990Sjmallett                        cvmx_dprintf("GMX TX path timeout waiting for idle\n");
1499215990Sjmallett                        result = -1;
1500215990Sjmallett                    }
1501215990Sjmallett                }
1502215990Sjmallett                /* Disable outermost TX at the ASX block */
1503215990Sjmallett                cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), 0);
1504215990Sjmallett                /* Disable interrupts for interface */
1505215990Sjmallett                cvmx_write_csr(CVMX_ASXX_INT_EN(interface), 0);
1506215990Sjmallett                cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0);
1507215990Sjmallett                break;
1508215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_XAUI:
1509232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1510215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SGMII:
1511215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PICMG:
1512215990Sjmallett                num_ports = cvmx_helper_ports_on_interface(interface);
1513215990Sjmallett                if (num_ports > 4)
1514215990Sjmallett                    num_ports = 4;
1515215990Sjmallett                for (index=0; index<num_ports; index++)
1516215990Sjmallett                {
1517215990Sjmallett                    cvmx_gmxx_prtx_cfg_t gmx_cfg;
1518215990Sjmallett                    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
1519215990Sjmallett                    gmx_cfg.s.en = 0;
1520215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
1521215990Sjmallett                    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, timeout*1000000))
1522215990Sjmallett                    {
1523215990Sjmallett                        cvmx_dprintf("GMX RX path timeout waiting for idle\n");
1524215990Sjmallett                        result = -1;
1525215990Sjmallett                    }
1526215990Sjmallett                    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, timeout*1000000))
1527215990Sjmallett                    {
1528215990Sjmallett                        cvmx_dprintf("GMX TX path timeout waiting for idle\n");
1529215990Sjmallett                        result = -1;
1530215990Sjmallett                    }
1531215990Sjmallett                }
1532215990Sjmallett                break;
1533215990Sjmallett        }
1534215990Sjmallett    }
1535215990Sjmallett
1536215990Sjmallett    /* Step 4: Retrieve all packets from the POW and free them */
1537215990Sjmallett    while ((work = cvmx_pow_work_request_sync(CVMX_POW_WAIT)))
1538215990Sjmallett    {
1539215990Sjmallett        cvmx_helper_free_packet_data(work);
1540215990Sjmallett        cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 0);
1541215990Sjmallett    }
1542215990Sjmallett
1543215990Sjmallett    /* Step 4b: Special workaround for pass 2 errata */
1544215990Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
1545215990Sjmallett    {
1546215990Sjmallett        cvmx_ipd_ptr_count_t ipd_cnt;
1547215990Sjmallett        int to_add;
1548215990Sjmallett        ipd_cnt.u64 = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
1549215990Sjmallett        to_add = (ipd_cnt.s.wqev_cnt + ipd_cnt.s.wqe_pcnt) & 0x7;
1550215990Sjmallett        if (to_add)
1551215990Sjmallett        {
1552215990Sjmallett            int port = -1;
1553215990Sjmallett            cvmx_dprintf("Aligning CN38XX pass 2 IPD counters\n");
1554215990Sjmallett            if (cvmx_helper_interface_get_mode(0) == CVMX_HELPER_INTERFACE_MODE_RGMII)
1555215990Sjmallett                port = 0;
1556215990Sjmallett            else if (cvmx_helper_interface_get_mode(1) == CVMX_HELPER_INTERFACE_MODE_RGMII)
1557215990Sjmallett                port = 16;
1558215990Sjmallett
1559215990Sjmallett            if (port != -1)
1560215990Sjmallett            {
1561215990Sjmallett                char *buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL);
1562215990Sjmallett                if (buffer)
1563215990Sjmallett                {
1564215990Sjmallett                    int queue = cvmx_pko_get_base_queue(port);
1565215990Sjmallett                    cvmx_pko_command_word0_t pko_command;
1566215990Sjmallett                    cvmx_buf_ptr_t packet;
1567215990Sjmallett                    uint64_t start_cycle;
1568215990Sjmallett                    uint64_t stop_cycle;
1569215990Sjmallett
1570215990Sjmallett                    /* Populate a minimal packet */
1571215990Sjmallett                    memset(buffer, 0xff, 6);
1572215990Sjmallett                    memset(buffer+6, 0, 54);
1573215990Sjmallett                    pko_command.u64 = 0;
1574215990Sjmallett                    pko_command.s.dontfree = 1;
1575215990Sjmallett                    pko_command.s.total_bytes = 60;
1576215990Sjmallett                    pko_command.s.segs = 1;
1577215990Sjmallett                    packet.u64 = 0;
1578215990Sjmallett                    packet.s.addr = cvmx_ptr_to_phys(buffer);
1579215990Sjmallett                    packet.s.size = CVMX_FPA_PACKET_POOL_SIZE;
1580215990Sjmallett                    __cvmx_helper_rgmii_configure_loopback(port, 1, 0);
1581215990Sjmallett                    while (to_add--)
1582215990Sjmallett                    {
1583215990Sjmallett                        cvmx_pko_send_packet_prepare(port, queue, CVMX_PKO_LOCK_CMD_QUEUE);
1584215990Sjmallett                        if (cvmx_pko_send_packet_finish(port, queue, pko_command, packet, CVMX_PKO_LOCK_CMD_QUEUE))
1585215990Sjmallett                        {
1586215990Sjmallett                            cvmx_dprintf("ERROR: Unable to align IPD counters (PKO failed)\n");
1587215990Sjmallett                            break;
1588215990Sjmallett                        }
1589215990Sjmallett                    }
1590215990Sjmallett                    cvmx_fpa_free(buffer, CVMX_FPA_PACKET_POOL, 0);
1591215990Sjmallett
1592215990Sjmallett                    /* Wait for the packets to loop back */
1593215990Sjmallett                    start_cycle = cvmx_get_cycle();
1594215990Sjmallett                    stop_cycle = start_cycle + cvmx_clock_get_rate(CVMX_CLOCK_CORE) * timeout;
1595215990Sjmallett                    while (cvmx_cmd_queue_length(CVMX_CMD_QUEUE_PKO(queue)) &&
1596215990Sjmallett                           (cvmx_get_cycle() < stop_cycle))
1597215990Sjmallett                    {
1598215990Sjmallett                        cvmx_wait(1000);
1599215990Sjmallett                    }
1600215990Sjmallett                    cvmx_wait(1000);
1601215990Sjmallett                    __cvmx_helper_rgmii_configure_loopback(port, 0, 0);
1602215990Sjmallett                    if (to_add == -1)
1603215990Sjmallett                        goto step2;
1604215990Sjmallett                }
1605215990Sjmallett                else
1606215990Sjmallett                    cvmx_dprintf("ERROR: Unable to align IPD counters (Packet pool empty)\n");
1607215990Sjmallett            }
1608215990Sjmallett            else
1609215990Sjmallett                cvmx_dprintf("ERROR: Unable to align IPD counters\n");
1610215990Sjmallett        }
1611215990Sjmallett    }
1612215990Sjmallett
1613232812Sjmallett    /* Step 5 */
1614215990Sjmallett    cvmx_ipd_disable();
1615215990Sjmallett
1616215990Sjmallett    /* Step 6: Drain all prefetched buffers from IPD/PIP. Note that IPD/PIP
1617215990Sjmallett        have not been reset yet */
1618215990Sjmallett    __cvmx_ipd_free_ptr();
1619215990Sjmallett
1620215990Sjmallett    /* Step 7: Free the PKO command buffers and put PKO in reset */
1621215990Sjmallett    cvmx_pko_shutdown();
1622215990Sjmallett
1623215990Sjmallett    /* Step 8: Disable MAC address filtering */
1624232812Sjmallett    for (interface=0; interface<CVMX_HELPER_MAX_GMX; interface++)
1625215990Sjmallett    {
1626215990Sjmallett        switch (cvmx_helper_interface_get_mode(interface))
1627215990Sjmallett        {
1628215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1629215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PCIE:
1630215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SRIO:
1631232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_ILK:
1632215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_NPI:
1633215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_LOOP:
1634215990Sjmallett                break;
1635215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_XAUI:
1636232812Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1637215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_GMII:
1638215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_RGMII:
1639215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SPI:
1640215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_SGMII:
1641215990Sjmallett            case CVMX_HELPER_INTERFACE_MODE_PICMG:
1642215990Sjmallett                num_ports = cvmx_helper_ports_on_interface(interface);
1643215990Sjmallett                if (num_ports > 4)
1644215990Sjmallett                    num_ports = 4;
1645215990Sjmallett                for (index=0; index<num_ports; index++)
1646215990Sjmallett                {
1647215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), 1);
1648215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
1649215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), 0);
1650215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), 0);
1651215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), 0);
1652215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), 0);
1653215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), 0);
1654215990Sjmallett                    cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), 0);
1655215990Sjmallett                }
1656215990Sjmallett                break;
1657215990Sjmallett        }
1658215990Sjmallett    }
1659215990Sjmallett
1660232812Sjmallett    /* Step 9: Drain all FPA buffers out of pool 0 before we reset
1661232812Sjmallett     * IPD/PIP.  This is needed to keep IPD_QUE0_FREE_PAGE_CNT in
1662232812Sjmallett     * sync. We temporarily keep the buffers in the pool0_buffers
1663232812Sjmallett     * list.
1664232812Sjmallett     */
1665232812Sjmallett    pool0_buffers = NULL;
1666232812Sjmallett    pool0_buffers_tail = NULL;
1667215990Sjmallett    while (1)
1668215990Sjmallett    {
1669232812Sjmallett        struct cvmx_buffer_list *buffer = cvmx_fpa_alloc(0);
1670232812Sjmallett        if (buffer) {
1671232812Sjmallett            buffer->next = NULL;
1672232812Sjmallett
1673232812Sjmallett            if (pool0_buffers == NULL)
1674232812Sjmallett                pool0_buffers = buffer;
1675232812Sjmallett            else
1676232812Sjmallett                pool0_buffers_tail->next = buffer;
1677232812Sjmallett
1678232812Sjmallett            pool0_buffers_tail = buffer;
1679215990Sjmallett        }
1680215990Sjmallett        else
1681215990Sjmallett            break;
1682215990Sjmallett    }
1683215990Sjmallett
1684215990Sjmallett    /* Step 10: Reset IPD and PIP */
1685215990Sjmallett    {
1686215990Sjmallett        cvmx_ipd_ctl_status_t ipd_ctl_status;
1687215990Sjmallett        ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
1688215990Sjmallett        ipd_ctl_status.s.reset = 1;
1689215990Sjmallett        cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
1690215990Sjmallett
1691215990Sjmallett        if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
1692215990Sjmallett            (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)))
1693215990Sjmallett        {
1694215990Sjmallett            /* only try 1000 times.  Normally if this works it will happen in
1695215990Sjmallett            ** the first 50 loops. */
1696215990Sjmallett            int max_loops = 1000;
1697215990Sjmallett            int loop = 0;
1698215990Sjmallett            /* Per port backpressure counters can get misaligned after an
1699215990Sjmallett               IPD reset. This code realigns them by performing repeated
1700215990Sjmallett               resets. See IPD-13473 */
1701215990Sjmallett            cvmx_wait(100);
1702215990Sjmallett            if (__cvmx_helper_backpressure_is_misaligned())
1703215990Sjmallett            {
1704215990Sjmallett                cvmx_dprintf("Starting to align per port backpressure counters.\n");
1705215990Sjmallett                while (__cvmx_helper_backpressure_is_misaligned() && (loop++ < max_loops))
1706215990Sjmallett                {
1707215990Sjmallett                    cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
1708215990Sjmallett                    cvmx_wait(123);
1709215990Sjmallett                }
1710215990Sjmallett                if (loop < max_loops)
1711215990Sjmallett                    cvmx_dprintf("Completed aligning per port backpressure counters (%d loops).\n", loop);
1712215990Sjmallett                else
1713215990Sjmallett                {
1714215990Sjmallett                    cvmx_dprintf("ERROR: unable to align per port backpressure counters.\n");
1715215990Sjmallett                    /* For now, don't hang.... */
1716215990Sjmallett                }
1717215990Sjmallett            }
1718215990Sjmallett        }
1719215990Sjmallett
1720215990Sjmallett        /* PIP_SFT_RST not present in CN38XXp{1,2} */
1721215990Sjmallett        if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
1722215990Sjmallett        {
1723215990Sjmallett            cvmx_pip_sft_rst_t pip_sft_rst;
1724215990Sjmallett            pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST);
1725215990Sjmallett            pip_sft_rst.s.rst = 1;
1726215990Sjmallett            cvmx_write_csr(CVMX_PIP_SFT_RST, pip_sft_rst.u64);
1727215990Sjmallett        }
1728232812Sjmallett
1729232812Sjmallett        /* Make sure IPD has finished reset. */
1730232812Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN6XXX))
1731232812Sjmallett        {
1732232812Sjmallett            if (CVMX_WAIT_FOR_FIELD64(CVMX_IPD_CTL_STATUS, cvmx_ipd_ctl_status_t, rst_done, ==, 0, 1000))
1733232812Sjmallett            {
1734232812Sjmallett                cvmx_dprintf("IPD reset timeout waiting for idle\n");
1735232812Sjmallett                result = -1;
1736232812Sjmallett            }
1737232812Sjmallett        }
1738215990Sjmallett    }
1739215990Sjmallett
1740215990Sjmallett    /* Step 11: Restore the FPA buffers into pool 0 */
1741232812Sjmallett    while (pool0_buffers) {
1742232812Sjmallett        struct cvmx_buffer_list *n = pool0_buffers->next;
1743232812Sjmallett        cvmx_fpa_free(pool0_buffers, 0, 0);
1744232812Sjmallett        pool0_buffers = n;
1745232812Sjmallett    }
1746215990Sjmallett
1747232812Sjmallett    /* Step 12: Release interface structures */
1748232812Sjmallett    __cvmx_helper_shutdown_interfaces();
1749232812Sjmallett
1750215990Sjmallett    return result;
1751215990Sjmallett}
1752215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1753215990SjmallettEXPORT_SYMBOL(cvmx_helper_shutdown_packet_io_global);
1754215990Sjmallett#endif
1755215990Sjmallett
1756215990Sjmallett
1757215990Sjmallett/**
1758215990Sjmallett * Does core local shutdown of packet io
1759215990Sjmallett *
1760215990Sjmallett * @return Zero on success, non-zero on failure
1761215990Sjmallett */
1762215990Sjmallettint cvmx_helper_shutdown_packet_io_local(void)
1763215990Sjmallett{
1764215990Sjmallett    /* Currently there is nothing to do per core. This may change in
1765215990Sjmallett        the future */
1766215990Sjmallett    return 0;
1767215990Sjmallett}
1768215990Sjmallett
1769215990Sjmallett
1770215990Sjmallett
1771215990Sjmallett/**
1772210284Sjmallett * Auto configure an IPD/PKO port link state and speed. This
1773210284Sjmallett * function basically does the equivalent of:
1774210284Sjmallett * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
1775210284Sjmallett *
1776210284Sjmallett * @param ipd_port IPD/PKO port to auto configure
1777210284Sjmallett *
1778210284Sjmallett * @return Link state after configure
1779210284Sjmallett */
1780210284Sjmallettcvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
1781210284Sjmallett{
1782210284Sjmallett    cvmx_helper_link_info_t link_info;
1783210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
1784210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
1785210284Sjmallett
1786210284Sjmallett    if (index >= cvmx_helper_ports_on_interface(interface))
1787210284Sjmallett    {
1788210284Sjmallett        link_info.u64 = 0;
1789210284Sjmallett        return link_info;
1790210284Sjmallett    }
1791210284Sjmallett
1792210284Sjmallett    link_info = cvmx_helper_link_get(ipd_port);
1793232812Sjmallett    if (link_info.u64 == (__cvmx_helper_get_link_info(interface, index)).u64)
1794210284Sjmallett        return link_info;
1795210284Sjmallett
1796215990Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
1797215990Sjmallett    if (!link_info.s.link_up)
1798215990Sjmallett        cvmx_error_disable_group(CVMX_ERROR_GROUP_ETHERNET, ipd_port);
1799215990Sjmallett#endif
1800215990Sjmallett
1801210284Sjmallett    /* If we fail to set the link speed, port_link_info will not change */
1802210284Sjmallett    cvmx_helper_link_set(ipd_port, link_info);
1803210284Sjmallett
1804215990Sjmallett#if !defined(CVMX_BUILD_FOR_LINUX_KERNEL) && !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL)
1805215990Sjmallett    if (link_info.s.link_up)
1806215990Sjmallett        cvmx_error_enable_group(CVMX_ERROR_GROUP_ETHERNET, ipd_port);
1807215990Sjmallett#endif
1808215990Sjmallett
1809232812Sjmallett    return link_info;
1810210284Sjmallett}
1811215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1812215990SjmallettEXPORT_SYMBOL(cvmx_helper_link_autoconf);
1813215990Sjmallett#endif
1814210284Sjmallett
1815210284Sjmallett/**
1816210284Sjmallett * Return the link state of an IPD/PKO port as returned by
1817210284Sjmallett * auto negotiation. The result of this function may not match
1818210284Sjmallett * Octeon's link config if auto negotiation has changed since
1819210284Sjmallett * the last call to cvmx_helper_link_set().
1820210284Sjmallett *
1821210284Sjmallett * @param ipd_port IPD/PKO port to query
1822210284Sjmallett *
1823210284Sjmallett * @return Link state
1824210284Sjmallett */
1825210284Sjmallettcvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
1826210284Sjmallett{
1827210284Sjmallett    cvmx_helper_link_info_t result;
1828210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
1829210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
1830210284Sjmallett
1831210284Sjmallett    /* The default result will be a down link unless the code below
1832210284Sjmallett        changes it */
1833210284Sjmallett    result.u64 = 0;
1834210284Sjmallett
1835210284Sjmallett    if (index >= cvmx_helper_ports_on_interface(interface))
1836210284Sjmallett        return result;
1837210284Sjmallett
1838210284Sjmallett    switch (cvmx_helper_interface_get_mode(interface))
1839210284Sjmallett    {
1840210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1841210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1842210284Sjmallett            /* Network links are not supported */
1843210284Sjmallett            break;
1844210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1845232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1846210284Sjmallett            result = __cvmx_helper_xaui_link_get(ipd_port);
1847210284Sjmallett            break;
1848210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
1849210284Sjmallett            if (index == 0)
1850210284Sjmallett                result = __cvmx_helper_rgmii_link_get(ipd_port);
1851210284Sjmallett            else
1852210284Sjmallett            {
1853210284Sjmallett                result.s.full_duplex = 1;
1854210284Sjmallett                result.s.link_up = 1;
1855210284Sjmallett                result.s.speed = 1000;
1856210284Sjmallett            }
1857210284Sjmallett            break;
1858210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1859210284Sjmallett            result = __cvmx_helper_rgmii_link_get(ipd_port);
1860210284Sjmallett            break;
1861210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
1862210284Sjmallett            result = __cvmx_helper_spi_link_get(ipd_port);
1863210284Sjmallett            break;
1864210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1865210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1866210284Sjmallett            result = __cvmx_helper_sgmii_link_get(ipd_port);
1867210284Sjmallett            break;
1868215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1869215990Sjmallett            result = __cvmx_helper_srio_link_get(ipd_port);
1870215990Sjmallett            break;
1871232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
1872232812Sjmallett            result = __cvmx_helper_ilk_link_get(ipd_port);
1873232812Sjmallett            break;
1874210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
1875210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1876210284Sjmallett            /* Network links are not supported */
1877210284Sjmallett            break;
1878210284Sjmallett    }
1879210284Sjmallett    return result;
1880210284Sjmallett}
1881215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1882215990SjmallettEXPORT_SYMBOL(cvmx_helper_link_get);
1883215990Sjmallett#endif
1884210284Sjmallett
1885210284Sjmallett
1886210284Sjmallett/**
1887210284Sjmallett * Configure an IPD/PKO port for the specified link state. This
1888210284Sjmallett * function does not influence auto negotiation at the PHY level.
1889210284Sjmallett * The passed link state must always match the link state returned
1890210284Sjmallett * by cvmx_helper_link_get(). It is normally best to use
1891210284Sjmallett * cvmx_helper_link_autoconf() instead.
1892210284Sjmallett *
1893210284Sjmallett * @param ipd_port  IPD/PKO port to configure
1894210284Sjmallett * @param link_info The new link state
1895210284Sjmallett *
1896210284Sjmallett * @return Zero on success, negative on failure
1897210284Sjmallett */
1898210284Sjmallettint cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
1899210284Sjmallett{
1900210284Sjmallett    int result = -1;
1901210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
1902210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
1903210284Sjmallett
1904210284Sjmallett    if (index >= cvmx_helper_ports_on_interface(interface))
1905210284Sjmallett        return -1;
1906210284Sjmallett
1907210284Sjmallett    switch (cvmx_helper_interface_get_mode(interface))
1908210284Sjmallett    {
1909210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1910210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1911210284Sjmallett            break;
1912210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1913232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1914210284Sjmallett            result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
1915210284Sjmallett            break;
1916210284Sjmallett        /* RGMII/GMII/MII are all treated about the same. Most functions
1917210284Sjmallett            refer to these ports as RGMII */
1918210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1919210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
1920210284Sjmallett            result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
1921210284Sjmallett            break;
1922210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
1923210284Sjmallett            result = __cvmx_helper_spi_link_set(ipd_port, link_info);
1924210284Sjmallett            break;
1925210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1926210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1927210284Sjmallett            result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
1928210284Sjmallett            break;
1929215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1930215990Sjmallett            result = __cvmx_helper_srio_link_set(ipd_port, link_info);
1931215990Sjmallett            break;
1932232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
1933232812Sjmallett            result = __cvmx_helper_ilk_link_set(ipd_port, link_info);
1934232812Sjmallett            break;
1935210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
1936210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1937210284Sjmallett            break;
1938210284Sjmallett    }
1939210284Sjmallett    /* Set the port_link_info here so that the link status is updated
1940210284Sjmallett       no matter how cvmx_helper_link_set is called. We don't change
1941210284Sjmallett       the value if link_set failed */
1942210284Sjmallett    if (result == 0)
1943232812Sjmallett        __cvmx_helper_set_link_info(interface, index, link_info);
1944210284Sjmallett    return result;
1945210284Sjmallett}
1946215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
1947215990SjmallettEXPORT_SYMBOL(cvmx_helper_link_set);
1948215990Sjmallett#endif
1949210284Sjmallett
1950210284Sjmallett
1951210284Sjmallett/**
1952210284Sjmallett * Configure a port for internal and/or external loopback. Internal loopback
1953210284Sjmallett * causes packets sent by the port to be received by Octeon. External loopback
1954210284Sjmallett * causes packets received from the wire to sent out again.
1955210284Sjmallett *
1956210284Sjmallett * @param ipd_port IPD/PKO port to loopback.
1957210284Sjmallett * @param enable_internal
1958210284Sjmallett *                 Non zero if you want internal loopback
1959210284Sjmallett * @param enable_external
1960210284Sjmallett *                 Non zero if you want external loopback
1961210284Sjmallett *
1962210284Sjmallett * @return Zero on success, negative on failure.
1963210284Sjmallett */
1964210284Sjmallettint cvmx_helper_configure_loopback(int ipd_port, int enable_internal, int enable_external)
1965210284Sjmallett{
1966210284Sjmallett    int result = -1;
1967210284Sjmallett    int interface = cvmx_helper_get_interface_num(ipd_port);
1968210284Sjmallett    int index = cvmx_helper_get_interface_index_num(ipd_port);
1969210284Sjmallett
1970210284Sjmallett    if (index >= cvmx_helper_ports_on_interface(interface))
1971210284Sjmallett        return -1;
1972210284Sjmallett
1973210284Sjmallett    switch (cvmx_helper_interface_get_mode(interface))
1974210284Sjmallett    {
1975210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1976210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PCIE:
1977215990Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SRIO:
1978232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_ILK:
1979210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SPI:
1980210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_NPI:
1981210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_LOOP:
1982210284Sjmallett            break;
1983210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1984232812Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1985210284Sjmallett            result = __cvmx_helper_xaui_configure_loopback(ipd_port, enable_internal, enable_external);
1986210284Sjmallett            break;
1987210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1988210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_GMII:
1989210284Sjmallett            result = __cvmx_helper_rgmii_configure_loopback(ipd_port, enable_internal, enable_external);
1990210284Sjmallett            break;
1991210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1992210284Sjmallett        case CVMX_HELPER_INTERFACE_MODE_PICMG:
1993210284Sjmallett            result = __cvmx_helper_sgmii_configure_loopback(ipd_port, enable_internal, enable_external);
1994210284Sjmallett            break;
1995210284Sjmallett    }
1996210284Sjmallett    return result;
1997210284Sjmallett}
1998210284Sjmallett
1999210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
2000