]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octe/ethernet-spi.c
MFV r329766: 8962 zdb should work on non-idle pools
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octe / ethernet-spi.c
1 /*************************************************************************
2 SPDX-License-Identifier: BSD-3-Clause
3
4 Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
5 reserved.
6
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11
12     * Redistributions of source code must retain the above copyright
13       notice, this list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above
16       copyright notice, this list of conditions and the following
17       disclaimer in the documentation and/or other materials provided
18       with the distribution.
19
20     * Neither the name of Cavium Networks nor the names of
21       its contributors may be used to endorse or promote products
22       derived from this software without specific prior written
23       permission.
24
25 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.
26
27 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
28 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.
29
30 *************************************************************************/
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/rman.h>
42 #include <sys/socket.h>
43
44 #include <net/ethernet.h>
45 #include <net/if.h>
46 #include <net/if_var.h>
47
48 #include "wrapper-cvmx-includes.h"
49 #include "ethernet-headers.h"
50
51 #include "octebusvar.h"
52
53 static int number_spi_ports;
54 static int need_retrain[2] = {0, 0};
55
56 static int cvm_oct_spi_rml_interrupt(void *dev_id)
57 {
58         int return_status = FILTER_STRAY;
59         cvmx_npi_rsl_int_blocks_t rsl_int_blocks;
60
61         /* Check and see if this interrupt was caused by the GMX block */
62         rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
63         if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */
64
65                 cvmx_spxx_int_reg_t spx_int_reg;
66                 cvmx_stxx_int_reg_t stx_int_reg;
67
68                 spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
69                 cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
70                 if (!need_retrain[1]) {
71
72                         spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
73                         if (spx_int_reg.s.spf)
74                                 printf("SPI1: SRX Spi4 interface down\n");
75                         if (spx_int_reg.s.calerr)
76                                 printf("SPI1: SRX Spi4 Calendar table parity error\n");
77                         if (spx_int_reg.s.syncerr)
78                                 printf("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
79                         if (spx_int_reg.s.diperr)
80                                 printf("SPI1: SRX Spi4 DIP4 error\n");
81                         if (spx_int_reg.s.tpaovr)
82                                 printf("SPI1: SRX Selected port has hit TPA overflow\n");
83                         if (spx_int_reg.s.rsverr)
84                                 printf("SPI1: SRX Spi4 reserved control word detected\n");
85                         if (spx_int_reg.s.drwnng)
86                                 printf("SPI1: SRX Spi4 receive FIFO drowning/overflow\n");
87                         if (spx_int_reg.s.clserr)
88                                 printf("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n");
89                         if (spx_int_reg.s.spiovr)
90                                 printf("SPI1: SRX Spi4 async FIFO overflow\n");
91                         if (spx_int_reg.s.abnorm)
92                                 printf("SPI1: SRX Abnormal packet termination (ERR bit)\n");
93                         if (spx_int_reg.s.prtnxa)
94                                 printf("SPI1: SRX Port out of range\n");
95                 }
96
97                 stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
98                 cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
99                 if (!need_retrain[1]) {
100
101                         stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
102                         if (stx_int_reg.s.syncerr)
103                                 printf("SPI1: STX Interface encountered a fatal error\n");
104                         if (stx_int_reg.s.frmerr)
105                                 printf("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
106                         if (stx_int_reg.s.unxfrm)
107                                 printf("SPI1: STX Unexpected framing sequence\n");
108                         if (stx_int_reg.s.nosync)
109                                 printf("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
110                         if (stx_int_reg.s.diperr)
111                                 printf("SPI1: STX DIP2 error on the Spi4 Status channel\n");
112                         if (stx_int_reg.s.datovr)
113                                 printf("SPI1: STX Spi4 FIFO overflow error\n");
114                         if (stx_int_reg.s.ovrbst)
115                                 printf("SPI1: STX Transmit packet burst too big\n");
116                         if (stx_int_reg.s.calpar1)
117                                 printf("SPI1: STX Calendar Table Parity Error Bank1\n");
118                         if (stx_int_reg.s.calpar0)
119                                 printf("SPI1: STX Calendar Table Parity Error Bank0\n");
120                 }
121
122                 cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
123                 cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
124                 need_retrain[1] = 1;
125                 return_status = FILTER_HANDLED;
126         }
127
128         if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */
129                 cvmx_spxx_int_reg_t spx_int_reg;
130                 cvmx_stxx_int_reg_t stx_int_reg;
131
132                 spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
133                 cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
134                 if (!need_retrain[0]) {
135
136                         spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
137                         if (spx_int_reg.s.spf)
138                                 printf("SPI0: SRX Spi4 interface down\n");
139                         if (spx_int_reg.s.calerr)
140                                 printf("SPI0: SRX Spi4 Calendar table parity error\n");
141                         if (spx_int_reg.s.syncerr)
142                                 printf("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
143                         if (spx_int_reg.s.diperr)
144                                 printf("SPI0: SRX Spi4 DIP4 error\n");
145                         if (spx_int_reg.s.tpaovr)
146                                 printf("SPI0: SRX Selected port has hit TPA overflow\n");
147                         if (spx_int_reg.s.rsverr)
148                                 printf("SPI0: SRX Spi4 reserved control word detected\n");
149                         if (spx_int_reg.s.drwnng)
150                                 printf("SPI0: SRX Spi4 receive FIFO drowning/overflow\n");
151                         if (spx_int_reg.s.clserr)
152                                 printf("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n");
153                         if (spx_int_reg.s.spiovr)
154                                 printf("SPI0: SRX Spi4 async FIFO overflow\n");
155                         if (spx_int_reg.s.abnorm)
156                                 printf("SPI0: SRX Abnormal packet termination (ERR bit)\n");
157                         if (spx_int_reg.s.prtnxa)
158                                 printf("SPI0: SRX Port out of range\n");
159                 }
160
161                 stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
162                 cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
163                 if (!need_retrain[0]) {
164
165                         stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
166                         if (stx_int_reg.s.syncerr)
167                                 printf("SPI0: STX Interface encountered a fatal error\n");
168                         if (stx_int_reg.s.frmerr)
169                                 printf("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
170                         if (stx_int_reg.s.unxfrm)
171                                 printf("SPI0: STX Unexpected framing sequence\n");
172                         if (stx_int_reg.s.nosync)
173                                 printf("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
174                         if (stx_int_reg.s.diperr)
175                                 printf("SPI0: STX DIP2 error on the Spi4 Status channel\n");
176                         if (stx_int_reg.s.datovr)
177                                 printf("SPI0: STX Spi4 FIFO overflow error\n");
178                         if (stx_int_reg.s.ovrbst)
179                                 printf("SPI0: STX Transmit packet burst too big\n");
180                         if (stx_int_reg.s.calpar1)
181                                 printf("SPI0: STX Calendar Table Parity Error Bank1\n");
182                         if (stx_int_reg.s.calpar0)
183                                 printf("SPI0: STX Calendar Table Parity Error Bank0\n");
184                 }
185
186                 cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
187                 cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
188                 need_retrain[0] = 1;
189                 return_status = FILTER_HANDLED;
190         }
191
192         return return_status;
193 }
194
195 static void cvm_oct_spi_enable_error_reporting(int interface)
196 {
197         cvmx_spxx_int_msk_t spxx_int_msk;
198         cvmx_stxx_int_msk_t stxx_int_msk;
199
200         spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
201         spxx_int_msk.s.calerr = 1;
202         spxx_int_msk.s.syncerr = 1;
203         spxx_int_msk.s.diperr = 1;
204         spxx_int_msk.s.tpaovr = 1;
205         spxx_int_msk.s.rsverr = 1;
206         spxx_int_msk.s.drwnng = 1;
207         spxx_int_msk.s.clserr = 1;
208         spxx_int_msk.s.spiovr = 1;
209         spxx_int_msk.s.abnorm = 1;
210         spxx_int_msk.s.prtnxa = 1;
211         cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
212
213         stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
214         stxx_int_msk.s.frmerr = 1;
215         stxx_int_msk.s.unxfrm = 1;
216         stxx_int_msk.s.nosync = 1;
217         stxx_int_msk.s.diperr = 1;
218         stxx_int_msk.s.datovr = 1;
219         stxx_int_msk.s.ovrbst = 1;
220         stxx_int_msk.s.calpar1 = 1;
221         stxx_int_msk.s.calpar0 = 1;
222         cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
223 }
224
225 static void cvm_oct_spi_poll(struct ifnet *ifp)
226 {
227         static int spi4000_port;
228         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
229         int interface;
230
231         for (interface = 0; interface < 2; interface++) {
232
233                 if ((priv->port == interface*16) && need_retrain[interface]) {
234
235                         if (cvmx_spi_restart_interface(interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
236                                 need_retrain[interface] = 0;
237                                 cvm_oct_spi_enable_error_reporting(interface);
238                         }
239                 }
240
241                 /* The SPI4000 TWSI interface is very slow. In order not to
242                    bring the system to a crawl, we only poll a single port
243                    every second. This means negotiation speed changes
244                    take up to 10 seconds, but at least we don't waste
245                    absurd amounts of time waiting for TWSI */
246                 if (priv->port == spi4000_port) {
247                         /* This function does nothing if it is called on an
248                            interface without a SPI4000 */
249                         cvmx_spi4000_check_speed(interface, priv->port);
250                         /* Normal ordering increments. By decrementing
251                            we only match once per iteration */
252                         spi4000_port--;
253                         if (spi4000_port < 0)
254                                 spi4000_port = 10;
255                 }
256         }
257 }
258
259
260 int cvm_oct_spi_init(struct ifnet *ifp)
261 {
262         struct octebus_softc *sc;
263         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
264         int error;
265         int rid;
266
267         if (number_spi_ports == 0) {
268                 sc = device_get_softc(device_get_parent(priv->dev));
269
270                 rid = 0;
271                 sc->sc_spi_irq = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ,
272                                                     &rid, OCTEON_IRQ_RML,
273                                                     OCTEON_IRQ_RML, 1,
274                                                     RF_ACTIVE);
275                 if (sc->sc_spi_irq == NULL) {
276                         device_printf(sc->sc_dev, "could not allocate SPI irq");
277                         return ENXIO;
278                 }
279
280                 error = bus_setup_intr(sc->sc_dev, sc->sc_spi_irq,
281                                        INTR_TYPE_NET | INTR_MPSAFE,
282                                        cvm_oct_spi_rml_interrupt, NULL,
283                                        &number_spi_ports, NULL);
284                 if (error != 0) {
285                         device_printf(sc->sc_dev, "could not setup SPI irq");
286                         return error;
287                 }
288         }
289         number_spi_ports++;
290
291         if ((priv->port == 0) || (priv->port == 16)) {
292                 cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
293                 priv->poll = cvm_oct_spi_poll;
294         }
295         if (cvm_oct_common_init(ifp) != 0)
296             return ENXIO;
297         return 0;
298 }
299
300 void cvm_oct_spi_uninit(struct ifnet *ifp)
301 {
302         int interface;
303
304         cvm_oct_common_uninit(ifp);
305         number_spi_ports--;
306         if (number_spi_ports == 0) {
307                 for (interface = 0; interface < 2; interface++) {
308                         cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
309                         cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
310                 }
311                 panic("%s: IRQ release not yet implemented.", __func__);
312         }
313 }