Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cvmx-helper-xaui.c
Go to the documentation of this file.
1 /***********************license start***************
2  * Author: Cavium Networks
3  *
4  * Contact: [email protected]
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 <asm/octeon/cvmx-config.h>
37 
38 #include <asm/octeon/cvmx-helper.h>
39 
43 
47 
49 {
50  union cvmx_gmxx_hg2_control gmx_hg2_control;
51 
52  /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
53  gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
54  if (gmx_hg2_control.s.hg2tx_en)
55  return 16;
56  else
57  return 1;
58 }
59 
70 {
71  int i;
72  union cvmx_gmxx_inf_mode mode;
73 
74  /*
75  * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
76  * interface needs to be enabled before IPD otherwise per port
77  * backpressure may not work properly.
78  */
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  /*
86  * Setup PKO to support 16 ports for HiGig2 virtual
87  * ports. We're pointing all of the PKO packet ports for this
88  * interface to the XAUI. This allows us to use HiGig2
89  * backpressure per port.
90  */
91  for (i = 0; i < 16; i++) {
92  union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
93  pko_mem_port_ptrs.u64 = 0;
94  /*
95  * We set each PKO port to have equal priority in a
96  * round robin fashion.
97  */
98  pko_mem_port_ptrs.s.static_p = 0;
99  pko_mem_port_ptrs.s.qos_mask = 0xff;
100  /* All PKO ports map to the same XAUI hardware port */
101  pko_mem_port_ptrs.s.eid = interface * 4;
102  pko_mem_port_ptrs.s.pid = interface * 16 + i;
103  cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
104  }
105  return __cvmx_helper_xaui_enumerate(interface);
106 }
107 
118 {
119  union cvmx_gmxx_prtx_cfg gmx_cfg;
120  union cvmx_pcsxx_control1_reg xauiCtl;
121  union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl;
122  union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl;
123  union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
124  union cvmx_gmxx_tx_int_en gmx_tx_int_en;
125  union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
126 
127  /* (1) Interface has already been enabled. */
128 
129  /* (2) Disable GMX. */
130  xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
131  xauiMiscCtl.s.gmxeno = 1;
132  cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
133 
134  /* (3) Disable GMX and PCSX interrupts. */
135  gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface));
136  cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
137  gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
138  cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
139  pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
140  cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
141 
142  /* (4) Bring up the PCSX and GMX reconciliation layer. */
143  /* (4)a Set polarity and lane swapping. */
144  /* (4)b */
145  gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
146  /* Enable better IFG packing and improves performance */
147  gmxXauiTxCtl.s.dic_en = 1;
148  gmxXauiTxCtl.s.uni_en = 0;
149  cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
150 
151  /* (4)c Aply reset sequence */
152  xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
153  xauiCtl.s.lo_pwr = 0;
154  xauiCtl.s.reset = 1;
155  cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
156 
157  /* Wait for PCS to come out of reset */
159  (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg,
160  reset, ==, 0, 10000))
161  return -1;
162  /* Wait for PCS to be aligned */
164  (CVMX_PCSXX_10GBX_STATUS_REG(interface),
165  union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000))
166  return -1;
167  /* Wait for RX to be ready */
169  (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl,
170  status, ==, 0, 10000))
171  return -1;
172 
173  /* (6) Configure GMX */
174  gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
175  gmx_cfg.s.en = 0;
176  cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
177 
178  /* Wait for GMX RX to be idle */
180  (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
181  rx_idle, ==, 1, 10000))
182  return -1;
183  /* Wait for GMX TX to be idle */
185  (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
186  tx_idle, ==, 1, 10000))
187  return -1;
188 
189  /* GMX configure */
190  gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
191  gmx_cfg.s.speed = 1;
192  gmx_cfg.s.speed_msb = 0;
193  gmx_cfg.s.slottime = 1;
194  cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
195  cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
196  cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
197  cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
198 
199  /* (7) Clear out any error state */
200  cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface),
201  cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface)));
202  cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface),
203  cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
204  cvmx_write_csr(CVMX_PCSXX_INT_REG(interface),
205  cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
206 
207  /* Wait for receive link */
209  (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg,
210  rcv_lnk, ==, 1, 10000))
211  return -1;
213  (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
214  xmtflt, ==, 0, 10000))
215  return -1;
217  (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
218  rcvflt, ==, 0, 10000))
219  return -1;
220 
221  cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64);
222  cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
223  cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
224 
226 
227  /* (8) Enable packet reception */
228  xauiMiscCtl.s.gmxeno = 0;
229  cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
230 
231  gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
232  gmx_cfg.s.en = 1;
233  cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
234 
240  __cvmx_interrupt_gmxx_enable(interface);
241 
242  return 0;
243 }
244 
256 {
257  int interface = cvmx_helper_get_interface_num(ipd_port);
258  union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
259  union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
260  union cvmx_pcsxx_status1_reg pcsxx_status1_reg;
262 
263  gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
264  gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
265  pcsxx_status1_reg.u64 =
266  cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
267  result.u64 = 0;
268 
269  /* Only return a link if both RX and TX are happy */
270  if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
271  (pcsxx_status1_reg.s.rcv_lnk == 1)) {
272  result.s.link_up = 1;
273  result.s.full_duplex = 1;
274  result.s.speed = 10000;
275  } else {
276  /* Disable GMX and PCSX interrupts. */
277  cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
278  cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
279  cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
280  }
281  return result;
282 }
283 
297 {
298  int interface = cvmx_helper_get_interface_num(ipd_port);
299  union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
300  union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
301 
302  gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
303  gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
304 
305  /* If the link shouldn't be up, then just return */
306  if (!link_info.s.link_up)
307  return 0;
308 
309  /* Do nothing if both RX and TX are happy */
310  if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
311  return 0;
312 
313  /* Bring the link up */
315 }
316 
331  int enable_internal,
332  int enable_external)
333 {
334  int interface = cvmx_helper_get_interface_num(ipd_port);
335  union cvmx_pcsxx_control1_reg pcsxx_control1_reg;
336  union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback;
337 
338  /* Set the internal loop */
339  pcsxx_control1_reg.u64 =
340  cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
341  pcsxx_control1_reg.s.loopbck1 = enable_internal;
342  cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface),
343  pcsxx_control1_reg.u64);
344 
345  /* Set the external loop */
346  gmxx_xaui_ext_loopback.u64 =
347  cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
348  gmxx_xaui_ext_loopback.s.en = enable_external;
349  cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface),
350  gmxx_xaui_ext_loopback.u64);
351 
352  /* Take the link through a reset */
354 }