]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octe/ethernet-spi.c
MFV r310115,310184:
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octe / ethernet-spi.c
1 /*************************************************************************
2 Copyright (c) 2003-2007  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 This Software, including technical data, may be subject to U.S. export  control laws, including the U.S. Export Administration Act and its  associated regulations, and may be subject to export or import  regulations in other countries.
24
25 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26 AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
27
28 *************************************************************************/
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
38 #include <sys/mbuf.h>
39 #include <sys/rman.h>
40 #include <sys/socket.h>
41
42 #include <net/ethernet.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45
46 #include "wrapper-cvmx-includes.h"
47 #include "ethernet-headers.h"
48
49 #include "octebusvar.h"
50
51 static int number_spi_ports;
52 static int need_retrain[2] = {0, 0};
53
54 static int cvm_oct_spi_rml_interrupt(void *dev_id)
55 {
56         int return_status = FILTER_STRAY;
57         cvmx_npi_rsl_int_blocks_t rsl_int_blocks;
58
59         /* Check and see if this interrupt was caused by the GMX block */
60         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
61         if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */
62
63                 cvmx_spxx_int_reg_t spx_int_reg;
64                 cvmx_stxx_int_reg_t stx_int_reg;
65
66                 spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
67                 cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
68                 if (!need_retrain[1]) {
69
70                         spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
71                         if (spx_int_reg.s.spf)
72                                 printf("SPI1: SRX Spi4 interface down\n");
73                         if (spx_int_reg.s.calerr)
74                                 printf("SPI1: SRX Spi4 Calendar table parity error\n");
75                         if (spx_int_reg.s.syncerr)
76                                 printf("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
77                         if (spx_int_reg.s.diperr)
78                                 printf("SPI1: SRX Spi4 DIP4 error\n");
79                         if (spx_int_reg.s.tpaovr)
80                                 printf("SPI1: SRX Selected port has hit TPA overflow\n");
81                         if (spx_int_reg.s.rsverr)
82                                 printf("SPI1: SRX Spi4 reserved control word detected\n");
83                         if (spx_int_reg.s.drwnng)
84                                 printf("SPI1: SRX Spi4 receive FIFO drowning/overflow\n");
85                         if (spx_int_reg.s.clserr)
86                                 printf("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n");
87                         if (spx_int_reg.s.spiovr)
88                                 printf("SPI1: SRX Spi4 async FIFO overflow\n");
89                         if (spx_int_reg.s.abnorm)
90                                 printf("SPI1: SRX Abnormal packet termination (ERR bit)\n");
91                         if (spx_int_reg.s.prtnxa)
92                                 printf("SPI1: SRX Port out of range\n");
93                 }
94
95                 stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
96                 cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
97                 if (!need_retrain[1]) {
98
99                         stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
100                         if (stx_int_reg.s.syncerr)
101                                 printf("SPI1: STX Interface encountered a fatal error\n");
102                         if (stx_int_reg.s.frmerr)
103                                 printf("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
104                         if (stx_int_reg.s.unxfrm)
105                                 printf("SPI1: STX Unexpected framing sequence\n");
106                         if (stx_int_reg.s.nosync)
107                                 printf("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
108                         if (stx_int_reg.s.diperr)
109                                 printf("SPI1: STX DIP2 error on the Spi4 Status channel\n");
110                         if (stx_int_reg.s.datovr)
111                                 printf("SPI1: STX Spi4 FIFO overflow error\n");
112                         if (stx_int_reg.s.ovrbst)
113                                 printf("SPI1: STX Transmit packet burst too big\n");
114                         if (stx_int_reg.s.calpar1)
115                                 printf("SPI1: STX Calendar Table Parity Error Bank1\n");
116                         if (stx_int_reg.s.calpar0)
117                                 printf("SPI1: STX Calendar Table Parity Error Bank0\n");
118                 }
119
120                 cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
121                 cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
122                 need_retrain[1] = 1;
123                 return_status = FILTER_HANDLED;
124         }
125
126         if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */
127                 cvmx_spxx_int_reg_t spx_int_reg;
128                 cvmx_stxx_int_reg_t stx_int_reg;
129
130                 spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
131                 cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
132                 if (!need_retrain[0]) {
133
134                         spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
135                         if (spx_int_reg.s.spf)
136                                 printf("SPI0: SRX Spi4 interface down\n");
137                         if (spx_int_reg.s.calerr)
138                                 printf("SPI0: SRX Spi4 Calendar table parity error\n");
139                         if (spx_int_reg.s.syncerr)
140                                 printf("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
141                         if (spx_int_reg.s.diperr)
142                                 printf("SPI0: SRX Spi4 DIP4 error\n");
143                         if (spx_int_reg.s.tpaovr)
144                                 printf("SPI0: SRX Selected port has hit TPA overflow\n");
145                         if (spx_int_reg.s.rsverr)
146                                 printf("SPI0: SRX Spi4 reserved control word detected\n");
147                         if (spx_int_reg.s.drwnng)
148                                 printf("SPI0: SRX Spi4 receive FIFO drowning/overflow\n");
149                         if (spx_int_reg.s.clserr)
150                                 printf("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n");
151                         if (spx_int_reg.s.spiovr)
152                                 printf("SPI0: SRX Spi4 async FIFO overflow\n");
153                         if (spx_int_reg.s.abnorm)
154                                 printf("SPI0: SRX Abnormal packet termination (ERR bit)\n");
155                         if (spx_int_reg.s.prtnxa)
156                                 printf("SPI0: SRX Port out of range\n");
157                 }
158
159                 stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
160                 cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
161                 if (!need_retrain[0]) {
162
163                         stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
164                         if (stx_int_reg.s.syncerr)
165                                 printf("SPI0: STX Interface encountered a fatal error\n");
166                         if (stx_int_reg.s.frmerr)
167                                 printf("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
168                         if (stx_int_reg.s.unxfrm)
169                                 printf("SPI0: STX Unexpected framing sequence\n");
170                         if (stx_int_reg.s.nosync)
171                                 printf("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
172                         if (stx_int_reg.s.diperr)
173                                 printf("SPI0: STX DIP2 error on the Spi4 Status channel\n");
174                         if (stx_int_reg.s.datovr)
175                                 printf("SPI0: STX Spi4 FIFO overflow error\n");
176                         if (stx_int_reg.s.ovrbst)
177                                 printf("SPI0: STX Transmit packet burst too big\n");
178                         if (stx_int_reg.s.calpar1)
179                                 printf("SPI0: STX Calendar Table Parity Error Bank1\n");
180                         if (stx_int_reg.s.calpar0)
181                                 printf("SPI0: STX Calendar Table Parity Error Bank0\n");
182                 }
183
184                 cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
185                 cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
186                 need_retrain[0] = 1;
187                 return_status = FILTER_HANDLED;
188         }
189
190         return return_status;
191 }
192
193 static void cvm_oct_spi_enable_error_reporting(int interface)
194 {
195         cvmx_spxx_int_msk_t spxx_int_msk;
196         cvmx_stxx_int_msk_t stxx_int_msk;
197
198         spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
199         spxx_int_msk.s.calerr = 1;
200         spxx_int_msk.s.syncerr = 1;
201         spxx_int_msk.s.diperr = 1;
202         spxx_int_msk.s.tpaovr = 1;
203         spxx_int_msk.s.rsverr = 1;
204         spxx_int_msk.s.drwnng = 1;
205         spxx_int_msk.s.clserr = 1;
206         spxx_int_msk.s.spiovr = 1;
207         spxx_int_msk.s.abnorm = 1;
208         spxx_int_msk.s.prtnxa = 1;
209         cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
210
211         stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
212         stxx_int_msk.s.frmerr = 1;
213         stxx_int_msk.s.unxfrm = 1;
214         stxx_int_msk.s.nosync = 1;
215         stxx_int_msk.s.diperr = 1;
216         stxx_int_msk.s.datovr = 1;
217         stxx_int_msk.s.ovrbst = 1;
218         stxx_int_msk.s.calpar1 = 1;
219         stxx_int_msk.s.calpar0 = 1;
220         cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
221 }
222
223 static void cvm_oct_spi_poll(struct ifnet *ifp)
224 {
225         static int spi4000_port;
226         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
227         int interface;
228
229         for (interface = 0; interface < 2; interface++) {
230
231                 if ((priv->port == interface*16) && need_retrain[interface]) {
232
233                         if (cvmx_spi_restart_interface(interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
234                                 need_retrain[interface] = 0;
235                                 cvm_oct_spi_enable_error_reporting(interface);
236                         }
237                 }
238
239                 /* The SPI4000 TWSI interface is very slow. In order not to
240                    bring the system to a crawl, we only poll a single port
241                    every second. This means negotiation speed changes
242                    take up to 10 seconds, but at least we don't waste
243                    absurd amounts of time waiting for TWSI */
244                 if (priv->port == spi4000_port) {
245                         /* This function does nothing if it is called on an
246                            interface without a SPI4000 */
247                         cvmx_spi4000_check_speed(interface, priv->port);
248                         /* Normal ordering increments. By decrementing
249                            we only match once per iteration */
250                         spi4000_port--;
251                         if (spi4000_port < 0)
252                                 spi4000_port = 10;
253                 }
254         }
255 }
256
257
258 int cvm_oct_spi_init(struct ifnet *ifp)
259 {
260         struct octebus_softc *sc;
261         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
262         int error;
263         int rid;
264
265         if (number_spi_ports == 0) {
266                 sc = device_get_softc(device_get_parent(priv->dev));
267
268                 rid = 0;
269                 sc->sc_spi_irq = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ,
270                                                     &rid, OCTEON_IRQ_RML,
271                                                     OCTEON_IRQ_RML, 1,
272                                                     RF_ACTIVE);
273                 if (sc->sc_spi_irq == NULL) {
274                         device_printf(sc->sc_dev, "could not allocate SPI irq");
275                         return ENXIO;
276                 }
277
278                 error = bus_setup_intr(sc->sc_dev, sc->sc_spi_irq,
279                                        INTR_TYPE_NET | INTR_MPSAFE,
280                                        cvm_oct_spi_rml_interrupt, NULL,
281                                        &number_spi_ports, NULL);
282                 if (error != 0) {
283                         device_printf(sc->sc_dev, "could not setup SPI irq");
284                         return error;
285                 }
286         }
287         number_spi_ports++;
288
289         if ((priv->port == 0) || (priv->port == 16)) {
290                 cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
291                 priv->poll = cvm_oct_spi_poll;
292         }
293         if (cvm_oct_common_init(ifp) != 0)
294             return ENXIO;
295         return 0;
296 }
297
298 void cvm_oct_spi_uninit(struct ifnet *ifp)
299 {
300         int interface;
301
302         cvm_oct_common_uninit(ifp);
303         number_spi_ports--;
304         if (number_spi_ports == 0) {
305                 for (interface = 0; interface < 2; interface++) {
306                         cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
307                         cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
308                 }
309                 panic("%s: IRQ release not yet implemented.", __func__);
310         }
311 }