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