ethernet-spi.c revision 331722
1/*************************************************************************
2Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
3reserved.
4
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
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
23This 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
25TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26AND 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: stable/11/sys/mips/cavium/octe/ethernet-spi.c 331722 2018-03-29 02:50:57Z eadler $");
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
51static int number_spi_ports;
52static int need_retrain[2] = {0, 0};
53
54static 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
193static 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
223static 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
258int 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
298void 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}
312