Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ethernet-spi.c
Go to the documentation of this file.
1 /**********************************************************************
2  * Author: Cavium Networks
3  *
4  * Contact: [email protected]
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2007 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 **********************************************************************/
27 #include <linux/kernel.h>
28 #include <linux/netdevice.h>
29 #include <linux/interrupt.h>
30 #include <net/dst.h>
31 
32 #include <asm/octeon/octeon.h>
33 
34 #include "ethernet-defines.h"
35 #include "octeon-ethernet.h"
36 #include "ethernet-util.h"
37 
38 #include <asm/octeon/cvmx-spi.h>
39 
43 
44 static int number_spi_ports;
45 static int need_retrain[2] = { 0, 0 };
46 
47 static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id)
48 {
49  irqreturn_t return_status = IRQ_NONE;
50  union cvmx_npi_rsl_int_blocks rsl_int_blocks;
51 
52  /* Check and see if this interrupt was caused by the GMX block */
53  rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
54  if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */
55 
56  union cvmx_spxx_int_reg spx_int_reg;
57  union cvmx_stxx_int_reg stx_int_reg;
58 
59  spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
60  cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
61  if (!need_retrain[1]) {
62 
63  spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
64  if (spx_int_reg.s.spf)
65  pr_err("SPI1: SRX Spi4 interface down\n");
66  if (spx_int_reg.s.calerr)
67  pr_err("SPI1: SRX Spi4 Calendar table "
68  "parity error\n");
69  if (spx_int_reg.s.syncerr)
70  pr_err("SPI1: SRX Consecutive Spi4 DIP4 "
71  "errors have exceeded "
72  "SPX_ERR_CTL[ERRCNT]\n");
73  if (spx_int_reg.s.diperr)
74  pr_err("SPI1: SRX Spi4 DIP4 error\n");
75  if (spx_int_reg.s.tpaovr)
76  pr_err("SPI1: SRX Selected port has hit "
77  "TPA overflow\n");
78  if (spx_int_reg.s.rsverr)
79  pr_err("SPI1: SRX Spi4 reserved control "
80  "word detected\n");
81  if (spx_int_reg.s.drwnng)
82  pr_err("SPI1: SRX Spi4 receive FIFO "
83  "drowning/overflow\n");
84  if (spx_int_reg.s.clserr)
85  pr_err("SPI1: SRX Spi4 packet closed on "
86  "non-16B alignment without EOP\n");
87  if (spx_int_reg.s.spiovr)
88  pr_err("SPI1: SRX Spi4 async FIFO overflow\n");
89  if (spx_int_reg.s.abnorm)
90  pr_err("SPI1: SRX Abnormal packet "
91  "termination (ERR bit)\n");
92  if (spx_int_reg.s.prtnxa)
93  pr_err("SPI1: SRX Port out of range\n");
94  }
95 
96  stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
97  cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
98  if (!need_retrain[1]) {
99 
100  stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
101  if (stx_int_reg.s.syncerr)
102  pr_err("SPI1: STX Interface encountered a "
103  "fatal error\n");
104  if (stx_int_reg.s.frmerr)
105  pr_err("SPI1: STX FRMCNT has exceeded "
106  "STX_DIP_CNT[MAXFRM]\n");
107  if (stx_int_reg.s.unxfrm)
108  pr_err("SPI1: STX Unexpected framing "
109  "sequence\n");
110  if (stx_int_reg.s.nosync)
111  pr_err("SPI1: STX ERRCNT has exceeded "
112  "STX_DIP_CNT[MAXDIP]\n");
113  if (stx_int_reg.s.diperr)
114  pr_err("SPI1: STX DIP2 error on the Spi4 "
115  "Status channel\n");
116  if (stx_int_reg.s.datovr)
117  pr_err("SPI1: STX Spi4 FIFO overflow error\n");
118  if (stx_int_reg.s.ovrbst)
119  pr_err("SPI1: STX Transmit packet burst "
120  "too big\n");
121  if (stx_int_reg.s.calpar1)
122  pr_err("SPI1: STX Calendar Table Parity "
123  "Error Bank1\n");
124  if (stx_int_reg.s.calpar0)
125  pr_err("SPI1: STX Calendar Table Parity "
126  "Error Bank0\n");
127  }
128 
129  cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
130  cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
131  need_retrain[1] = 1;
132  return_status = IRQ_HANDLED;
133  }
134 
135  if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */
136  union cvmx_spxx_int_reg spx_int_reg;
137  union cvmx_stxx_int_reg stx_int_reg;
138 
139  spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
140  cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
141  if (!need_retrain[0]) {
142 
143  spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
144  if (spx_int_reg.s.spf)
145  pr_err("SPI0: SRX Spi4 interface down\n");
146  if (spx_int_reg.s.calerr)
147  pr_err("SPI0: SRX Spi4 Calendar table "
148  "parity error\n");
149  if (spx_int_reg.s.syncerr)
150  pr_err("SPI0: SRX Consecutive Spi4 DIP4 "
151  "errors have exceeded "
152  "SPX_ERR_CTL[ERRCNT]\n");
153  if (spx_int_reg.s.diperr)
154  pr_err("SPI0: SRX Spi4 DIP4 error\n");
155  if (spx_int_reg.s.tpaovr)
156  pr_err("SPI0: SRX Selected port has hit "
157  "TPA overflow\n");
158  if (spx_int_reg.s.rsverr)
159  pr_err("SPI0: SRX Spi4 reserved control "
160  "word detected\n");
161  if (spx_int_reg.s.drwnng)
162  pr_err("SPI0: SRX Spi4 receive FIFO "
163  "drowning/overflow\n");
164  if (spx_int_reg.s.clserr)
165  pr_err("SPI0: SRX Spi4 packet closed on "
166  "non-16B alignment without EOP\n");
167  if (spx_int_reg.s.spiovr)
168  pr_err("SPI0: SRX Spi4 async FIFO overflow\n");
169  if (spx_int_reg.s.abnorm)
170  pr_err("SPI0: SRX Abnormal packet "
171  "termination (ERR bit)\n");
172  if (spx_int_reg.s.prtnxa)
173  pr_err("SPI0: SRX Port out of range\n");
174  }
175 
176  stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
177  cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
178  if (!need_retrain[0]) {
179 
180  stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
181  if (stx_int_reg.s.syncerr)
182  pr_err("SPI0: STX Interface encountered a "
183  "fatal error\n");
184  if (stx_int_reg.s.frmerr)
185  pr_err("SPI0: STX FRMCNT has exceeded "
186  "STX_DIP_CNT[MAXFRM]\n");
187  if (stx_int_reg.s.unxfrm)
188  pr_err("SPI0: STX Unexpected framing "
189  "sequence\n");
190  if (stx_int_reg.s.nosync)
191  pr_err("SPI0: STX ERRCNT has exceeded "
192  "STX_DIP_CNT[MAXDIP]\n");
193  if (stx_int_reg.s.diperr)
194  pr_err("SPI0: STX DIP2 error on the Spi4 "
195  "Status channel\n");
196  if (stx_int_reg.s.datovr)
197  pr_err("SPI0: STX Spi4 FIFO overflow error\n");
198  if (stx_int_reg.s.ovrbst)
199  pr_err("SPI0: STX Transmit packet burst "
200  "too big\n");
201  if (stx_int_reg.s.calpar1)
202  pr_err("SPI0: STX Calendar Table Parity "
203  "Error Bank1\n");
204  if (stx_int_reg.s.calpar0)
205  pr_err("SPI0: STX Calendar Table Parity "
206  "Error Bank0\n");
207  }
208 
209  cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
210  cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
211  need_retrain[0] = 1;
212  return_status = IRQ_HANDLED;
213  }
214 
215  return return_status;
216 }
217 
218 static void cvm_oct_spi_enable_error_reporting(int interface)
219 {
220  union cvmx_spxx_int_msk spxx_int_msk;
221  union cvmx_stxx_int_msk stxx_int_msk;
222 
223  spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
224  spxx_int_msk.s.calerr = 1;
225  spxx_int_msk.s.syncerr = 1;
226  spxx_int_msk.s.diperr = 1;
227  spxx_int_msk.s.tpaovr = 1;
228  spxx_int_msk.s.rsverr = 1;
229  spxx_int_msk.s.drwnng = 1;
230  spxx_int_msk.s.clserr = 1;
231  spxx_int_msk.s.spiovr = 1;
232  spxx_int_msk.s.abnorm = 1;
233  spxx_int_msk.s.prtnxa = 1;
234  cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
235 
236  stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
237  stxx_int_msk.s.frmerr = 1;
238  stxx_int_msk.s.unxfrm = 1;
239  stxx_int_msk.s.nosync = 1;
240  stxx_int_msk.s.diperr = 1;
241  stxx_int_msk.s.datovr = 1;
242  stxx_int_msk.s.ovrbst = 1;
243  stxx_int_msk.s.calpar1 = 1;
244  stxx_int_msk.s.calpar0 = 1;
245  cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
246 }
247 
248 static void cvm_oct_spi_poll(struct net_device *dev)
249 {
250  static int spi4000_port;
251  struct octeon_ethernet *priv = netdev_priv(dev);
252  int interface;
253 
254  for (interface = 0; interface < 2; interface++) {
255 
256  if ((priv->port == interface * 16) && need_retrain[interface]) {
257 
259  (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
260  need_retrain[interface] = 0;
261  cvm_oct_spi_enable_error_reporting(interface);
262  }
263  }
264 
265  /*
266  * The SPI4000 TWSI interface is very slow. In order
267  * not to bring the system to a crawl, we only poll a
268  * single port every second. This means negotiation
269  * speed changes take up to 10 seconds, but at least
270  * we don't waste absurd amounts of time waiting for
271  * TWSI.
272  */
273  if (priv->port == spi4000_port) {
274  /*
275  * This function does nothing if it is called on an
276  * interface without a SPI4000.
277  */
278  cvmx_spi4000_check_speed(interface, priv->port);
279  /*
280  * Normal ordering increments. By decrementing
281  * we only match once per iteration.
282  */
283  spi4000_port--;
284  if (spi4000_port < 0)
285  spi4000_port = 10;
286  }
287  }
288 }
289 
290 int cvm_oct_spi_init(struct net_device *dev)
291 {
292  int r;
293  struct octeon_ethernet *priv = netdev_priv(dev);
294 
295  if (number_spi_ports == 0) {
296  r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
297  IRQF_SHARED, "SPI", &number_spi_ports);
298  if (r)
299  return r;
300  }
301  number_spi_ports++;
302 
303  if ((priv->port == 0) || (priv->port == 16)) {
304  cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
305  priv->poll = cvm_oct_spi_poll;
306  }
307  cvm_oct_common_init(dev);
308  return 0;
309 }
310 
312 {
313  int interface;
314 
316  number_spi_ports--;
317  if (number_spi_ports == 0) {
318  for (interface = 0; interface < 2; interface++) {
319  cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
320  cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
321  }
322  free_irq(OCTEON_IRQ_RML, &number_spi_ports);
323  }
324 }