xref: /trueos/sys/mips/cavium/octe/ethernet-spi.c (revision 94d2b7f64912987093f1a98573737a32e4e5d8d1)
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 
45 #include "wrapper-cvmx-includes.h"
46 #include "ethernet-headers.h"
47 
48 #include "octebusvar.h"
49 
50 static int number_spi_ports;
51 static int need_retrain[2] = {0, 0};
52 
cvm_oct_spi_rml_interrupt(void * dev_id)53 static int cvm_oct_spi_rml_interrupt(void *dev_id)
54 {
55 	int return_status = FILTER_STRAY;
56 	cvmx_npi_rsl_int_blocks_t rsl_int_blocks;
57 
58 	/* Check and see if this interrupt was caused by the GMX block */
59 	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
60 	if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */
61 
62 		cvmx_spxx_int_reg_t spx_int_reg;
63 		cvmx_stxx_int_reg_t stx_int_reg;
64 
65 		spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
66 		cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
67 		if (!need_retrain[1]) {
68 
69 			spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
70 			if (spx_int_reg.s.spf)
71 				printf("SPI1: SRX Spi4 interface down\n");
72 			if (spx_int_reg.s.calerr)
73 				printf("SPI1: SRX Spi4 Calendar table parity error\n");
74 			if (spx_int_reg.s.syncerr)
75 				printf("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
76 			if (spx_int_reg.s.diperr)
77 				printf("SPI1: SRX Spi4 DIP4 error\n");
78 			if (spx_int_reg.s.tpaovr)
79 				printf("SPI1: SRX Selected port has hit TPA overflow\n");
80 			if (spx_int_reg.s.rsverr)
81 				printf("SPI1: SRX Spi4 reserved control word detected\n");
82 			if (spx_int_reg.s.drwnng)
83 				printf("SPI1: SRX Spi4 receive FIFO drowning/overflow\n");
84 			if (spx_int_reg.s.clserr)
85 				printf("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n");
86 			if (spx_int_reg.s.spiovr)
87 				printf("SPI1: SRX Spi4 async FIFO overflow\n");
88 			if (spx_int_reg.s.abnorm)
89 				printf("SPI1: SRX Abnormal packet termination (ERR bit)\n");
90 			if (spx_int_reg.s.prtnxa)
91 				printf("SPI1: SRX Port out of range\n");
92 		}
93 
94 		stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
95 		cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
96 		if (!need_retrain[1]) {
97 
98 			stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
99 			if (stx_int_reg.s.syncerr)
100 				printf("SPI1: STX Interface encountered a fatal error\n");
101 			if (stx_int_reg.s.frmerr)
102 				printf("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
103 			if (stx_int_reg.s.unxfrm)
104 				printf("SPI1: STX Unexpected framing sequence\n");
105 			if (stx_int_reg.s.nosync)
106 				printf("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
107 			if (stx_int_reg.s.diperr)
108 				printf("SPI1: STX DIP2 error on the Spi4 Status channel\n");
109 			if (stx_int_reg.s.datovr)
110 				printf("SPI1: STX Spi4 FIFO overflow error\n");
111 			if (stx_int_reg.s.ovrbst)
112 				printf("SPI1: STX Transmit packet burst too big\n");
113 			if (stx_int_reg.s.calpar1)
114 				printf("SPI1: STX Calendar Table Parity Error Bank1\n");
115 			if (stx_int_reg.s.calpar0)
116 				printf("SPI1: STX Calendar Table Parity Error Bank0\n");
117 		}
118 
119 		cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
120 		cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
121 		need_retrain[1] = 1;
122 		return_status = FILTER_HANDLED;
123 	}
124 
125 	if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */
126 		cvmx_spxx_int_reg_t spx_int_reg;
127 		cvmx_stxx_int_reg_t stx_int_reg;
128 
129 		spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
130 		cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
131 		if (!need_retrain[0]) {
132 
133 			spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
134 			if (spx_int_reg.s.spf)
135 				printf("SPI0: SRX Spi4 interface down\n");
136 			if (spx_int_reg.s.calerr)
137 				printf("SPI0: SRX Spi4 Calendar table parity error\n");
138 			if (spx_int_reg.s.syncerr)
139 				printf("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
140 			if (spx_int_reg.s.diperr)
141 				printf("SPI0: SRX Spi4 DIP4 error\n");
142 			if (spx_int_reg.s.tpaovr)
143 				printf("SPI0: SRX Selected port has hit TPA overflow\n");
144 			if (spx_int_reg.s.rsverr)
145 				printf("SPI0: SRX Spi4 reserved control word detected\n");
146 			if (spx_int_reg.s.drwnng)
147 				printf("SPI0: SRX Spi4 receive FIFO drowning/overflow\n");
148 			if (spx_int_reg.s.clserr)
149 				printf("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n");
150 			if (spx_int_reg.s.spiovr)
151 				printf("SPI0: SRX Spi4 async FIFO overflow\n");
152 			if (spx_int_reg.s.abnorm)
153 				printf("SPI0: SRX Abnormal packet termination (ERR bit)\n");
154 			if (spx_int_reg.s.prtnxa)
155 				printf("SPI0: SRX Port out of range\n");
156 		}
157 
158 		stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
159 		cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
160 		if (!need_retrain[0]) {
161 
162 			stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
163 			if (stx_int_reg.s.syncerr)
164 				printf("SPI0: STX Interface encountered a fatal error\n");
165 			if (stx_int_reg.s.frmerr)
166 				printf("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
167 			if (stx_int_reg.s.unxfrm)
168 				printf("SPI0: STX Unexpected framing sequence\n");
169 			if (stx_int_reg.s.nosync)
170 				printf("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
171 			if (stx_int_reg.s.diperr)
172 				printf("SPI0: STX DIP2 error on the Spi4 Status channel\n");
173 			if (stx_int_reg.s.datovr)
174 				printf("SPI0: STX Spi4 FIFO overflow error\n");
175 			if (stx_int_reg.s.ovrbst)
176 				printf("SPI0: STX Transmit packet burst too big\n");
177 			if (stx_int_reg.s.calpar1)
178 				printf("SPI0: STX Calendar Table Parity Error Bank1\n");
179 			if (stx_int_reg.s.calpar0)
180 				printf("SPI0: STX Calendar Table Parity Error Bank0\n");
181 		}
182 
183 		cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
184 		cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
185 		need_retrain[0] = 1;
186 		return_status = FILTER_HANDLED;
187 	}
188 
189 	return return_status;
190 }
191 
cvm_oct_spi_enable_error_reporting(int interface)192 static void cvm_oct_spi_enable_error_reporting(int interface)
193 {
194 	cvmx_spxx_int_msk_t spxx_int_msk;
195 	cvmx_stxx_int_msk_t stxx_int_msk;
196 
197 	spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
198 	spxx_int_msk.s.calerr = 1;
199 	spxx_int_msk.s.syncerr = 1;
200 	spxx_int_msk.s.diperr = 1;
201 	spxx_int_msk.s.tpaovr = 1;
202 	spxx_int_msk.s.rsverr = 1;
203 	spxx_int_msk.s.drwnng = 1;
204 	spxx_int_msk.s.clserr = 1;
205 	spxx_int_msk.s.spiovr = 1;
206 	spxx_int_msk.s.abnorm = 1;
207 	spxx_int_msk.s.prtnxa = 1;
208 	cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
209 
210 	stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
211 	stxx_int_msk.s.frmerr = 1;
212 	stxx_int_msk.s.unxfrm = 1;
213 	stxx_int_msk.s.nosync = 1;
214 	stxx_int_msk.s.diperr = 1;
215 	stxx_int_msk.s.datovr = 1;
216 	stxx_int_msk.s.ovrbst = 1;
217 	stxx_int_msk.s.calpar1 = 1;
218 	stxx_int_msk.s.calpar0 = 1;
219 	cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
220 }
221 
cvm_oct_spi_poll(struct ifnet * ifp)222 static void cvm_oct_spi_poll(struct ifnet *ifp)
223 {
224 	static int spi4000_port;
225 	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
226 	int interface;
227 
228 	for (interface = 0; interface < 2; interface++) {
229 
230 		if ((priv->port == interface*16) && need_retrain[interface]) {
231 
232 			if (cvmx_spi_restart_interface(interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
233 				need_retrain[interface] = 0;
234 				cvm_oct_spi_enable_error_reporting(interface);
235 			}
236 		}
237 
238 		/* The SPI4000 TWSI interface is very slow. In order not to
239 		   bring the system to a crawl, we only poll a single port
240 		   every second. This means negotiation speed changes
241 		   take up to 10 seconds, but at least we don't waste
242 		   absurd amounts of time waiting for TWSI */
243 		if (priv->port == spi4000_port) {
244 			/* This function does nothing if it is called on an
245 			   interface without a SPI4000 */
246 			cvmx_spi4000_check_speed(interface, priv->port);
247 			/* Normal ordering increments. By decrementing
248 			   we only match once per iteration */
249 			spi4000_port--;
250 			if (spi4000_port < 0)
251 				spi4000_port = 10;
252 		}
253 	}
254 }
255 
256 
cvm_oct_spi_init(struct ifnet * ifp)257 int cvm_oct_spi_init(struct ifnet *ifp)
258 {
259 	struct octebus_softc *sc;
260 	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
261 	int error;
262 	int rid;
263 
264 	if (number_spi_ports == 0) {
265 		sc = device_get_softc(device_get_parent(priv->dev));
266 
267 		rid = 0;
268 		sc->sc_spi_irq = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ,
269 						    &rid, OCTEON_IRQ_RML,
270 						    OCTEON_IRQ_RML, 1,
271 						    RF_ACTIVE);
272 		if (sc->sc_spi_irq == NULL) {
273 			device_printf(sc->sc_dev, "could not allocate SPI irq");
274 			return ENXIO;
275 		}
276 
277 		error = bus_setup_intr(sc->sc_dev, sc->sc_spi_irq,
278 				       INTR_TYPE_NET | INTR_MPSAFE,
279 				       cvm_oct_spi_rml_interrupt, NULL,
280 				       &number_spi_ports, NULL);
281 		if (error != 0) {
282 			device_printf(sc->sc_dev, "could not setup SPI irq");
283 			return error;
284 		}
285 	}
286 	number_spi_ports++;
287 
288 	if ((priv->port == 0) || (priv->port == 16)) {
289 		cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
290 		priv->poll = cvm_oct_spi_poll;
291 	}
292 	if (cvm_oct_common_init(ifp) != 0)
293 	    return ENXIO;
294 	return 0;
295 }
296 
cvm_oct_spi_uninit(struct ifnet * ifp)297 void cvm_oct_spi_uninit(struct ifnet *ifp)
298 {
299 	int interface;
300 
301 	cvm_oct_common_uninit(ifp);
302 	number_spi_ports--;
303 	if (number_spi_ports == 0) {
304 		for (interface = 0; interface < 2; interface++) {
305 			cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
306 			cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
307 		}
308 		panic("%s: IRQ release not yet implemented.", __func__);
309 	}
310 }
311