cvmx-helper-xaui.c revision 210284
1/***********************license start***************
2 *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3 *  reserved.
4 *
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions are
8 *  met:
9 *
10 *      * Redistributions of source code must retain the above copyright
11 *        notice, this list of conditions and the following disclaimer.
12 *
13 *      * Redistributions in binary form must reproduce the above
14 *        copyright notice, this list of conditions and the following
15 *        disclaimer in the documentation and/or other materials provided
16 *        with the distribution.
17 *
18 *      * Neither the name of Cavium Networks nor the names of
19 *        its contributors may be used to endorse or promote products
20 *        derived from this software without specific prior written
21 *        permission.
22 *
23 *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32 *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33 *
34 *
35 *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36 *
37 ***********************license end**************************************/
38
39
40
41
42
43
44/**
45 * @file
46 *
47 * Functions for XAUI initialization, configuration,
48 * and monitoring.
49 *
50 * <hr>$Revision: 42417 $<hr>
51 */
52#include "executive-config.h"
53#include "cvmx-config.h"
54#ifdef CVMX_ENABLE_PKO_FUNCTIONS
55
56#include "cvmx.h"
57#include "cvmx-helper.h"
58
59
60/**
61 * @INTERNAL
62 * Probe a XAUI interface and determine the number of ports
63 * connected to it. The XAUI interface should still be down
64 * after this call.
65 *
66 * @param interface Interface to probe
67 *
68 * @return Number of ports on the interface. Zero to disable.
69 */
70int __cvmx_helper_xaui_probe(int interface)
71{
72    int i;
73    cvmx_gmxx_hg2_control_t gmx_hg2_control;
74    cvmx_gmxx_inf_mode_t mode;
75
76    /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
77        needs to be enabled before IPD otherwise per port backpressure
78        may not work properly */
79    mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
80    mode.s.en = 1;
81    cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
82
83    __cvmx_helper_setup_gmx(interface, 1);
84
85    /* Setup PKO to support 16 ports for HiGig2 virtual ports. We're pointing
86        all of the PKO packet ports for this interface to the XAUI. This allows
87        us to use HiGig2 backpressure per port */
88    for (i=0; i<16; i++)
89    {
90        cvmx_pko_mem_port_ptrs_t pko_mem_port_ptrs;
91        pko_mem_port_ptrs.u64 = 0;
92        /* We set each PKO port to have equal priority in a round robin
93            fashion */
94        pko_mem_port_ptrs.s.static_p = 0;
95        pko_mem_port_ptrs.s.qos_mask = 0xff;
96        /* All PKO ports map to the same XAUI hardware port */
97        pko_mem_port_ptrs.s.eid = interface*4;
98        pko_mem_port_ptrs.s.pid = interface*16 + i;
99        cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
100    }
101
102    /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
103    gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
104    if (gmx_hg2_control.s.hg2tx_en)
105        return 16;
106    else
107        return 1;
108}
109
110
111/**
112 * @INTERNAL
113 * Bringup and enable a XAUI interface. After this call packet
114 * I/O should be fully functional. This is called with IPD
115 * enabled but PKO disabled.
116 *
117 * @param interface Interface to bring up
118 *
119 * @return Zero on success, negative on failure
120 */
121int __cvmx_helper_xaui_enable(int interface)
122{
123    cvmx_gmxx_prtx_cfg_t          gmx_cfg;
124    cvmx_pcsxx_control1_reg_t     xauiCtl;
125    cvmx_pcsxx_misc_ctl_reg_t     xauiMiscCtl;
126    cvmx_gmxx_tx_xaui_ctl_t       gmxXauiTxCtl;
127    cvmx_gmxx_rxx_int_en_t        gmx_rx_int_en;
128    cvmx_gmxx_tx_int_en_t         gmx_tx_int_en;
129    cvmx_pcsxx_int_en_reg_t       pcsx_int_en_reg;
130
131    /* (1) Interface has already been enabled. */
132
133    /* (2) Disable GMX. */
134    xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
135    xauiMiscCtl.s.gmxeno = 1;
136    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
137
138    /* (3) Disable GMX and PCSX interrupts. */
139    gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0,interface));
140    cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
141    gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
142    cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
143    pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
144    cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
145
146    /* (4) Bring up the PCSX and GMX reconciliation layer. */
147    /* (4)a Set polarity and lane swapping. */
148    /* (4)b */
149    gmxXauiTxCtl.u64 = cvmx_read_csr (CVMX_GMXX_TX_XAUI_CTL(interface));
150    gmxXauiTxCtl.s.dic_en = 1; /* Enable better IFG packing and improves performance */
151    gmxXauiTxCtl.s.uni_en = 0;
152    cvmx_write_csr (CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
153
154    /* (4)c Aply reset sequence */
155    xauiCtl.u64 = cvmx_read_csr (CVMX_PCSXX_CONTROL1_REG(interface));
156    xauiCtl.s.lo_pwr = 0;
157    xauiCtl.s.reset  = 1;
158    cvmx_write_csr (CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
159
160    /* Wait for PCS to come out of reset */
161    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_CONTROL1_REG(interface), cvmx_pcsxx_control1_reg_t, reset, ==, 0, 10000))
162        return -1;
163    /* Wait for PCS to be aligned */
164    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_10GBX_STATUS_REG(interface), cvmx_pcsxx_10gbx_status_reg_t, alignd, ==, 1, 10000))
165        return -1;
166    /* Wait for RX to be ready */
167    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_RX_XAUI_CTL(interface), cvmx_gmxx_rx_xaui_ctl_t, status, ==, 0, 10000))
168        return -1;
169
170    /* (6) Configure GMX */
171    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
172    gmx_cfg.s.en = 0;
173    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
174
175    /* Wait for GMX RX to be idle */
176    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000))
177        return -1;
178    /* Wait for GMX TX to be idle */
179    if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(0, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
180        return -1;
181
182    /* GMX configure */
183    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
184    gmx_cfg.s.speed = 1;
185    gmx_cfg.s.speed_msb = 0;
186    gmx_cfg.s.slottime = 1;
187    cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
188    cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
189    cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
190    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
191
192    /* (7) Clear out any error state */
193    cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0,interface), cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0,interface)));
194    cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
195    cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
196
197    /* Wait for receive link */
198    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS1_REG(interface), cvmx_pcsxx_status1_reg_t, rcv_lnk, ==, 1, 10000))
199        return -1;
200    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, xmtflt, ==, 0, 10000))
201        return -1;
202    if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSXX_STATUS2_REG(interface), cvmx_pcsxx_status2_reg_t, rcvflt, ==, 0, 10000))
203        return -1;
204
205    cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0,interface), gmx_rx_int_en.u64);
206    cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
207    cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
208
209    cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0));
210
211    /* (8) Enable packet reception */
212    xauiMiscCtl.s.gmxeno = 0;
213    cvmx_write_csr (CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
214
215    gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
216    gmx_cfg.s.en = 1;
217    cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
218    return 0;
219}
220
221/**
222 * @INTERNAL
223 * Return the link state of an IPD/PKO port as returned by
224 * auto negotiation. The result of this function may not match
225 * Octeon's link config if auto negotiation has changed since
226 * the last call to cvmx_helper_link_set().
227 *
228 * @param ipd_port IPD/PKO port to query
229 *
230 * @return Link state
231 */
232cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
233{
234    int interface = cvmx_helper_get_interface_num(ipd_port);
235    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
236    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
237    cvmx_pcsxx_status1_reg_t pcsxx_status1_reg;
238    cvmx_helper_link_info_t result;
239
240    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
241    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
242    pcsxx_status1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
243    result.u64 = 0;
244
245    /* Only return a link if both RX and TX are happy */
246    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
247        (pcsxx_status1_reg.s.rcv_lnk == 1))
248    {
249        result.s.link_up = 1;
250        result.s.full_duplex = 1;
251        result.s.speed = 10000;
252    }
253    else
254    {
255        /* Disable GMX and PCSX interrupts. */
256        cvmx_write_csr (CVMX_GMXX_RXX_INT_EN(0,interface), 0x0);
257        cvmx_write_csr (CVMX_GMXX_TX_INT_EN(interface), 0x0);
258        cvmx_write_csr (CVMX_PCSXX_INT_EN_REG(interface), 0x0);
259    }
260    return result;
261}
262
263
264/**
265 * @INTERNAL
266 * Configure an IPD/PKO port for the specified link state. This
267 * function does not influence auto negotiation at the PHY level.
268 * The passed link state must always match the link state returned
269 * by cvmx_helper_link_get(). It is normally best to use
270 * cvmx_helper_link_autoconf() instead.
271 *
272 * @param ipd_port  IPD/PKO port to configure
273 * @param link_info The new link state
274 *
275 * @return Zero on success, negative on failure
276 */
277int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
278{
279    int interface = cvmx_helper_get_interface_num(ipd_port);
280    cvmx_gmxx_tx_xaui_ctl_t gmxx_tx_xaui_ctl;
281    cvmx_gmxx_rx_xaui_ctl_t gmxx_rx_xaui_ctl;
282
283    gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
284    gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
285
286    /* If the link shouldn't be up, then just return */
287    if (!link_info.s.link_up)
288        return 0;
289
290    /* Do nothing if both RX and TX are happy */
291    if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
292        return 0;
293
294    /* Bring the link up */
295    return __cvmx_helper_xaui_enable(interface);
296}
297
298
299/**
300 * @INTERNAL
301 * Configure a port for internal and/or external loopback. Internal loopback
302 * causes packets sent by the port to be received by Octeon. External loopback
303 * causes packets received from the wire to sent out again.
304 *
305 * @param ipd_port IPD/PKO port to loopback.
306 * @param enable_internal
307 *                 Non zero if you want internal loopback
308 * @param enable_external
309 *                 Non zero if you want external loopback
310 *
311 * @return Zero on success, negative on failure.
312 */
313extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, int enable_internal, int enable_external)
314{
315    int interface = cvmx_helper_get_interface_num(ipd_port);
316    cvmx_pcsxx_control1_reg_t pcsxx_control1_reg;
317    cvmx_gmxx_xaui_ext_loopback_t gmxx_xaui_ext_loopback;
318
319    /* Set the internal loop */
320    pcsxx_control1_reg.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
321    pcsxx_control1_reg.s.loopbck1 = enable_internal;
322    cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), pcsxx_control1_reg.u64);
323
324    /* Set the external loop */
325    gmxx_xaui_ext_loopback.u64 = cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
326    gmxx_xaui_ext_loopback.s.en = enable_external;
327    cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), gmxx_xaui_ext_loopback.u64);
328
329    /* Take the link through a reset */
330    return __cvmx_helper_xaui_enable(interface);
331}
332
333#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
334
335