]>
Commit | Line | Data |
---|---|---|
80ff0fd3 DD |
1 | /***********************license start*************** |
2 | * Author: Cavium Networks | |
3 | * | |
4 | * Contact: support@caviumnetworks.com | |
5 | * This file is part of the OCTEON SDK | |
6 | * | |
7 | * Copyright (c) 2003-2008 Cavium Networks | |
8 | * | |
9 | * This file is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, Version 2, as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This file is distributed in the hope that it will be useful, but | |
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | |
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | |
16 | * NONINFRINGEMENT. See the GNU General Public License for more | |
17 | * details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this file; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * or visit http://www.gnu.org/licenses/. | |
23 | * | |
24 | * This file may also be available under a different license from Cavium. | |
25 | * Contact Cavium Networks for more information | |
26 | ***********************license end**************************************/ | |
27 | ||
28 | /* | |
29 | * Functions for XAUI initialization, configuration, | |
30 | * and monitoring. | |
31 | * | |
32 | */ | |
33 | ||
34 | #include <asm/octeon/octeon.h> | |
35 | ||
36 | #include "cvmx-config.h" | |
37 | ||
38 | #include "cvmx-helper.h" | |
39 | ||
40 | #include "cvmx-pko-defs.h" | |
41 | #include "cvmx-gmxx-defs.h" | |
42 | #include "cvmx-pcsxx-defs.h" | |
43 | ||
44 | void __cvmx_interrupt_gmxx_enable(int interface); | |
45 | void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); | |
46 | void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); | |
47 | /** | |
48 | * Probe a XAUI interface and determine the number of ports | |
49 | * connected to it. The XAUI interface should still be down | |
50 | * after this call. | |
51 | * | |
52 | * @interface: Interface to probe | |
53 | * | |
54 | * Returns Number of ports on the interface. Zero to disable. | |
55 | */ | |
56 | int __cvmx_helper_xaui_probe(int interface) | |
57 | { | |
58 | int i; | |
59 | union cvmx_gmxx_hg2_control gmx_hg2_control; | |
60 | union cvmx_gmxx_inf_mode mode; | |
61 | ||
62 | /* | |
63 | * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the | |
64 | * interface needs to be enabled before IPD otherwise per port | |
65 | * backpressure may not work properly. | |
66 | */ | |
67 | mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); | |
68 | mode.s.en = 1; | |
69 | cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); | |
70 | ||
71 | __cvmx_helper_setup_gmx(interface, 1); | |
72 | ||
73 | /* | |
74 | * Setup PKO to support 16 ports for HiGig2 virtual | |
75 | * ports. We're pointing all of the PKO packet ports for this | |
76 | * interface to the XAUI. This allows us to use HiGig2 | |
77 | * backpressure per port. | |
78 | */ | |
79 | for (i = 0; i < 16; i++) { | |
80 | union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs; | |
81 | pko_mem_port_ptrs.u64 = 0; | |
82 | /* | |
83 | * We set each PKO port to have equal priority in a | |
84 | * round robin fashion. | |
85 | */ | |
86 | pko_mem_port_ptrs.s.static_p = 0; | |
87 | pko_mem_port_ptrs.s.qos_mask = 0xff; | |
88 | /* All PKO ports map to the same XAUI hardware port */ | |
89 | pko_mem_port_ptrs.s.eid = interface * 4; | |
90 | pko_mem_port_ptrs.s.pid = interface * 16 + i; | |
91 | cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); | |
92 | } | |
93 | ||
94 | /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ | |
95 | gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); | |
96 | if (gmx_hg2_control.s.hg2tx_en) | |
97 | return 16; | |
98 | else | |
99 | return 1; | |
100 | } | |
101 | ||
102 | /** | |
103 | * Bringup and enable a XAUI interface. After this call packet | |
104 | * I/O should be fully functional. This is called with IPD | |
105 | * enabled but PKO disabled. | |
106 | * | |
107 | * @interface: Interface to bring up | |
108 | * | |
109 | * Returns Zero on success, negative on failure | |
110 | */ | |
111 | int __cvmx_helper_xaui_enable(int interface) | |
112 | { | |
113 | union cvmx_gmxx_prtx_cfg gmx_cfg; | |
114 | union cvmx_pcsxx_control1_reg xauiCtl; | |
115 | union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl; | |
116 | union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl; | |
117 | union cvmx_gmxx_rxx_int_en gmx_rx_int_en; | |
118 | union cvmx_gmxx_tx_int_en gmx_tx_int_en; | |
119 | union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; | |
120 | ||
121 | /* (1) Interface has already been enabled. */ | |
122 | ||
123 | /* (2) Disable GMX. */ | |
124 | xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); | |
125 | xauiMiscCtl.s.gmxeno = 1; | |
126 | cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); | |
127 | ||
128 | /* (3) Disable GMX and PCSX interrupts. */ | |
129 | gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface)); | |
130 | cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); | |
131 | gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface)); | |
132 | cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); | |
133 | pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface)); | |
134 | cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); | |
135 | ||
136 | /* (4) Bring up the PCSX and GMX reconciliation layer. */ | |
137 | /* (4)a Set polarity and lane swapping. */ | |
138 | /* (4)b */ | |
139 | gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); | |
140 | /* Enable better IFG packing and improves performance */ | |
141 | gmxXauiTxCtl.s.dic_en = 1; | |
142 | gmxXauiTxCtl.s.uni_en = 0; | |
143 | cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64); | |
144 | ||
145 | /* (4)c Aply reset sequence */ | |
146 | xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); | |
147 | xauiCtl.s.lo_pwr = 0; | |
148 | xauiCtl.s.reset = 1; | |
149 | cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); | |
150 | ||
151 | /* Wait for PCS to come out of reset */ | |
152 | if (CVMX_WAIT_FOR_FIELD64 | |
153 | (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg, | |
154 | reset, ==, 0, 10000)) | |
155 | return -1; | |
156 | /* Wait for PCS to be aligned */ | |
157 | if (CVMX_WAIT_FOR_FIELD64 | |
158 | (CVMX_PCSXX_10GBX_STATUS_REG(interface), | |
159 | union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000)) | |
160 | return -1; | |
161 | /* Wait for RX to be ready */ | |
162 | if (CVMX_WAIT_FOR_FIELD64 | |
163 | (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl, | |
164 | status, ==, 0, 10000)) | |
165 | return -1; | |
166 | ||
167 | /* (6) Configure GMX */ | |
168 | gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); | |
169 | gmx_cfg.s.en = 0; | |
170 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); | |
171 | ||
172 | /* Wait for GMX RX to be idle */ | |
173 | if (CVMX_WAIT_FOR_FIELD64 | |
174 | (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, | |
175 | rx_idle, ==, 1, 10000)) | |
176 | return -1; | |
177 | /* Wait for GMX TX to be idle */ | |
178 | if (CVMX_WAIT_FOR_FIELD64 | |
179 | (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, | |
180 | tx_idle, ==, 1, 10000)) | |
181 | return -1; | |
182 | ||
183 | /* GMX configure */ | |
184 | gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); | |
185 | gmx_cfg.s.speed = 1; | |
186 | gmx_cfg.s.speed_msb = 0; | |
187 | gmx_cfg.s.slottime = 1; | |
188 | cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1); | |
189 | cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512); | |
190 | cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192); | |
191 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); | |
192 | ||
193 | /* (7) Clear out any error state */ | |
194 | cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface), | |
195 | cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface))); | |
196 | cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), | |
197 | cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface))); | |
198 | cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), | |
199 | cvmx_read_csr(CVMX_PCSXX_INT_REG(interface))); | |
200 | ||
201 | /* Wait for receive link */ | |
202 | if (CVMX_WAIT_FOR_FIELD64 | |
203 | (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg, | |
204 | rcv_lnk, ==, 1, 10000)) | |
205 | return -1; | |
206 | if (CVMX_WAIT_FOR_FIELD64 | |
207 | (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, | |
208 | xmtflt, ==, 0, 10000)) | |
209 | return -1; | |
210 | if (CVMX_WAIT_FOR_FIELD64 | |
211 | (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, | |
212 | rcvflt, ==, 0, 10000)) | |
213 | return -1; | |
214 | ||
215 | cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64); | |
216 | cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); | |
217 | cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64); | |
218 | ||
219 | cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0)); | |
220 | ||
221 | /* (8) Enable packet reception */ | |
222 | xauiMiscCtl.s.gmxeno = 0; | |
223 | cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); | |
224 | ||
225 | gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); | |
226 | gmx_cfg.s.en = 1; | |
227 | cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); | |
228 | ||
229 | __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface); | |
230 | __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface); | |
231 | __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface); | |
232 | __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface); | |
233 | __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); | |
234 | __cvmx_interrupt_gmxx_enable(interface); | |
235 | ||
236 | return 0; | |
237 | } | |
238 | ||
239 | /** | |
240 | * Return the link state of an IPD/PKO port as returned by | |
241 | * auto negotiation. The result of this function may not match | |
242 | * Octeon's link config if auto negotiation has changed since | |
243 | * the last call to cvmx_helper_link_set(). | |
244 | * | |
245 | * @ipd_port: IPD/PKO port to query | |
246 | * | |
247 | * Returns Link state | |
248 | */ | |
249 | cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) | |
250 | { | |
251 | int interface = cvmx_helper_get_interface_num(ipd_port); | |
252 | union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; | |
253 | union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; | |
254 | union cvmx_pcsxx_status1_reg pcsxx_status1_reg; | |
255 | cvmx_helper_link_info_t result; | |
256 | ||
257 | gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); | |
258 | gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); | |
259 | pcsxx_status1_reg.u64 = | |
260 | cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface)); | |
261 | result.u64 = 0; | |
262 | ||
263 | /* Only return a link if both RX and TX are happy */ | |
264 | if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) && | |
265 | (pcsxx_status1_reg.s.rcv_lnk == 1)) { | |
266 | result.s.link_up = 1; | |
267 | result.s.full_duplex = 1; | |
268 | result.s.speed = 10000; | |
269 | } else { | |
270 | /* Disable GMX and PCSX interrupts. */ | |
271 | cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); | |
272 | cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); | |
273 | cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); | |
274 | } | |
275 | return result; | |
276 | } | |
277 | ||
278 | /** | |
279 | * Configure an IPD/PKO port for the specified link state. This | |
280 | * function does not influence auto negotiation at the PHY level. | |
281 | * The passed link state must always match the link state returned | |
282 | * by cvmx_helper_link_get(). It is normally best to use | |
283 | * cvmx_helper_link_autoconf() instead. | |
284 | * | |
285 | * @ipd_port: IPD/PKO port to configure | |
286 | * @link_info: The new link state | |
287 | * | |
288 | * Returns Zero on success, negative on failure | |
289 | */ | |
290 | int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info) | |
291 | { | |
292 | int interface = cvmx_helper_get_interface_num(ipd_port); | |
293 | union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; | |
294 | union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; | |
295 | ||
296 | gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); | |
297 | gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); | |
298 | ||
299 | /* If the link shouldn't be up, then just return */ | |
300 | if (!link_info.s.link_up) | |
301 | return 0; | |
302 | ||
303 | /* Do nothing if both RX and TX are happy */ | |
304 | if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0)) | |
305 | return 0; | |
306 | ||
307 | /* Bring the link up */ | |
308 | return __cvmx_helper_xaui_enable(interface); | |
309 | } | |
310 | ||
311 | /** | |
312 | * Configure a port for internal and/or external loopback. Internal loopback | |
313 | * causes packets sent by the port to be received by Octeon. External loopback | |
314 | * causes packets received from the wire to sent out again. | |
315 | * | |
316 | * @ipd_port: IPD/PKO port to loopback. | |
317 | * @enable_internal: | |
318 | * Non zero if you want internal loopback | |
319 | * @enable_external: | |
320 | * Non zero if you want external loopback | |
321 | * | |
322 | * Returns Zero on success, negative on failure. | |
323 | */ | |
324 | extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, | |
325 | int enable_internal, | |
326 | int enable_external) | |
327 | { | |
328 | int interface = cvmx_helper_get_interface_num(ipd_port); | |
329 | union cvmx_pcsxx_control1_reg pcsxx_control1_reg; | |
330 | union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback; | |
331 | ||
332 | /* Set the internal loop */ | |
333 | pcsxx_control1_reg.u64 = | |
334 | cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); | |
335 | pcsxx_control1_reg.s.loopbck1 = enable_internal; | |
336 | cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), | |
337 | pcsxx_control1_reg.u64); | |
338 | ||
339 | /* Set the external loop */ | |
340 | gmxx_xaui_ext_loopback.u64 = | |
341 | cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface)); | |
342 | gmxx_xaui_ext_loopback.s.en = enable_external; | |
343 | cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), | |
344 | gmxx_xaui_ext_loopback.u64); | |
345 | ||
346 | /* Take the link through a reset */ | |
347 | return __cvmx_helper_xaui_enable(interface); | |
348 | } |