1210311Sjmallett/*************************************************************************
2210311SjmallettCopyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
3210311Sjmallettreserved.
4210311Sjmallett
5210311Sjmallett
6210311SjmallettRedistribution and use in source and binary forms, with or without
7210311Sjmallettmodification, are permitted provided that the following conditions are
8210311Sjmallettmet:
9210311Sjmallett
10210311Sjmallett    * Redistributions of source code must retain the above copyright
11210311Sjmallett      notice, this list of conditions and the following disclaimer.
12210311Sjmallett
13210311Sjmallett    * Redistributions in binary form must reproduce the above
14210311Sjmallett      copyright notice, this list of conditions and the following
15210311Sjmallett      disclaimer in the documentation and/or other materials provided
16210311Sjmallett      with the distribution.
17210311Sjmallett
18210311Sjmallett    * Neither the name of Cavium Networks nor the names of
19210311Sjmallett      its contributors may be used to endorse or promote products
20210311Sjmallett      derived from this software without specific prior written
21210311Sjmallett      permission.
22210311Sjmallett
23210311SjmallettThis 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.
24210311Sjmallett
25210311SjmallettTO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26210311SjmallettAND 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.
27210311Sjmallett
28210311Sjmallett*************************************************************************/
29210311Sjmallett
30210311Sjmallett#include <sys/cdefs.h>
31210311Sjmallett__FBSDID("$FreeBSD$");
32210311Sjmallett
33210311Sjmallett#include <sys/param.h>
34210311Sjmallett#include <sys/systm.h>
35210311Sjmallett#include <sys/bus.h>
36210311Sjmallett#include <sys/endian.h>
37210311Sjmallett#include <sys/kernel.h>
38210311Sjmallett#include <sys/mbuf.h>
39210311Sjmallett#include <sys/rman.h>
40210311Sjmallett#include <sys/socket.h>
41210311Sjmallett
42210311Sjmallett#include <net/ethernet.h>
43210311Sjmallett#include <net/if.h>
44210311Sjmallett
45210311Sjmallett#include "wrapper-cvmx-includes.h"
46210311Sjmallett#include "ethernet-headers.h"
47210311Sjmallett
48210311Sjmallett#include "octebusvar.h"
49210311Sjmallett
50210311Sjmallettstatic int number_spi_ports;
51210311Sjmallettstatic int need_retrain[2] = {0, 0};
52210311Sjmallett
53210311Sjmallettstatic int cvm_oct_spi_rml_interrupt(void *dev_id)
54210311Sjmallett{
55210311Sjmallett	int return_status = FILTER_STRAY;
56210311Sjmallett	cvmx_npi_rsl_int_blocks_t rsl_int_blocks;
57210311Sjmallett
58210311Sjmallett	/* Check and see if this interrupt was caused by the GMX block */
59210311Sjmallett	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
60210311Sjmallett	if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */
61210311Sjmallett
62210311Sjmallett		cvmx_spxx_int_reg_t spx_int_reg;
63210311Sjmallett		cvmx_stxx_int_reg_t stx_int_reg;
64210311Sjmallett
65210311Sjmallett		spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
66210311Sjmallett		cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
67210311Sjmallett		if (!need_retrain[1]) {
68210311Sjmallett
69210311Sjmallett			spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
70210311Sjmallett			if (spx_int_reg.s.spf)
71210311Sjmallett				printf("SPI1: SRX Spi4 interface down\n");
72210311Sjmallett			if (spx_int_reg.s.calerr)
73210311Sjmallett				printf("SPI1: SRX Spi4 Calendar table parity error\n");
74210311Sjmallett			if (spx_int_reg.s.syncerr)
75210311Sjmallett				printf("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
76210311Sjmallett			if (spx_int_reg.s.diperr)
77210311Sjmallett				printf("SPI1: SRX Spi4 DIP4 error\n");
78210311Sjmallett			if (spx_int_reg.s.tpaovr)
79210311Sjmallett				printf("SPI1: SRX Selected port has hit TPA overflow\n");
80210311Sjmallett			if (spx_int_reg.s.rsverr)
81210311Sjmallett				printf("SPI1: SRX Spi4 reserved control word detected\n");
82210311Sjmallett			if (spx_int_reg.s.drwnng)
83210311Sjmallett				printf("SPI1: SRX Spi4 receive FIFO drowning/overflow\n");
84210311Sjmallett			if (spx_int_reg.s.clserr)
85210311Sjmallett				printf("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n");
86210311Sjmallett			if (spx_int_reg.s.spiovr)
87210311Sjmallett				printf("SPI1: SRX Spi4 async FIFO overflow\n");
88210311Sjmallett			if (spx_int_reg.s.abnorm)
89210311Sjmallett				printf("SPI1: SRX Abnormal packet termination (ERR bit)\n");
90210311Sjmallett			if (spx_int_reg.s.prtnxa)
91210311Sjmallett				printf("SPI1: SRX Port out of range\n");
92210311Sjmallett		}
93210311Sjmallett
94210311Sjmallett		stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
95210311Sjmallett		cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
96210311Sjmallett		if (!need_retrain[1]) {
97210311Sjmallett
98210311Sjmallett			stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
99210311Sjmallett			if (stx_int_reg.s.syncerr)
100210311Sjmallett				printf("SPI1: STX Interface encountered a fatal error\n");
101210311Sjmallett			if (stx_int_reg.s.frmerr)
102210311Sjmallett				printf("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
103210311Sjmallett			if (stx_int_reg.s.unxfrm)
104210311Sjmallett				printf("SPI1: STX Unexpected framing sequence\n");
105210311Sjmallett			if (stx_int_reg.s.nosync)
106210311Sjmallett				printf("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
107210311Sjmallett			if (stx_int_reg.s.diperr)
108210311Sjmallett				printf("SPI1: STX DIP2 error on the Spi4 Status channel\n");
109210311Sjmallett			if (stx_int_reg.s.datovr)
110210311Sjmallett				printf("SPI1: STX Spi4 FIFO overflow error\n");
111210311Sjmallett			if (stx_int_reg.s.ovrbst)
112210311Sjmallett				printf("SPI1: STX Transmit packet burst too big\n");
113210311Sjmallett			if (stx_int_reg.s.calpar1)
114210311Sjmallett				printf("SPI1: STX Calendar Table Parity Error Bank1\n");
115210311Sjmallett			if (stx_int_reg.s.calpar0)
116210311Sjmallett				printf("SPI1: STX Calendar Table Parity Error Bank0\n");
117210311Sjmallett		}
118210311Sjmallett
119210311Sjmallett		cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
120210311Sjmallett		cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
121210311Sjmallett		need_retrain[1] = 1;
122210311Sjmallett		return_status = FILTER_HANDLED;
123210311Sjmallett	}
124210311Sjmallett
125210311Sjmallett	if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */
126210311Sjmallett		cvmx_spxx_int_reg_t spx_int_reg;
127210311Sjmallett		cvmx_stxx_int_reg_t stx_int_reg;
128210311Sjmallett
129210311Sjmallett		spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
130210311Sjmallett		cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
131210311Sjmallett		if (!need_retrain[0]) {
132210311Sjmallett
133210311Sjmallett			spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
134210311Sjmallett			if (spx_int_reg.s.spf)
135210311Sjmallett				printf("SPI0: SRX Spi4 interface down\n");
136210311Sjmallett			if (spx_int_reg.s.calerr)
137210311Sjmallett				printf("SPI0: SRX Spi4 Calendar table parity error\n");
138210311Sjmallett			if (spx_int_reg.s.syncerr)
139210311Sjmallett				printf("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
140210311Sjmallett			if (spx_int_reg.s.diperr)
141210311Sjmallett				printf("SPI0: SRX Spi4 DIP4 error\n");
142210311Sjmallett			if (spx_int_reg.s.tpaovr)
143210311Sjmallett				printf("SPI0: SRX Selected port has hit TPA overflow\n");
144210311Sjmallett			if (spx_int_reg.s.rsverr)
145210311Sjmallett				printf("SPI0: SRX Spi4 reserved control word detected\n");
146210311Sjmallett			if (spx_int_reg.s.drwnng)
147210311Sjmallett				printf("SPI0: SRX Spi4 receive FIFO drowning/overflow\n");
148210311Sjmallett			if (spx_int_reg.s.clserr)
149210311Sjmallett				printf("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n");
150210311Sjmallett			if (spx_int_reg.s.spiovr)
151210311Sjmallett				printf("SPI0: SRX Spi4 async FIFO overflow\n");
152210311Sjmallett			if (spx_int_reg.s.abnorm)
153210311Sjmallett				printf("SPI0: SRX Abnormal packet termination (ERR bit)\n");
154210311Sjmallett			if (spx_int_reg.s.prtnxa)
155210311Sjmallett				printf("SPI0: SRX Port out of range\n");
156210311Sjmallett		}
157210311Sjmallett
158210311Sjmallett		stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
159210311Sjmallett		cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
160210311Sjmallett		if (!need_retrain[0]) {
161210311Sjmallett
162210311Sjmallett			stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
163210311Sjmallett			if (stx_int_reg.s.syncerr)
164210311Sjmallett				printf("SPI0: STX Interface encountered a fatal error\n");
165210311Sjmallett			if (stx_int_reg.s.frmerr)
166210311Sjmallett				printf("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
167210311Sjmallett			if (stx_int_reg.s.unxfrm)
168210311Sjmallett				printf("SPI0: STX Unexpected framing sequence\n");
169210311Sjmallett			if (stx_int_reg.s.nosync)
170210311Sjmallett				printf("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
171210311Sjmallett			if (stx_int_reg.s.diperr)
172210311Sjmallett				printf("SPI0: STX DIP2 error on the Spi4 Status channel\n");
173210311Sjmallett			if (stx_int_reg.s.datovr)
174210311Sjmallett				printf("SPI0: STX Spi4 FIFO overflow error\n");
175210311Sjmallett			if (stx_int_reg.s.ovrbst)
176210311Sjmallett				printf("SPI0: STX Transmit packet burst too big\n");
177210311Sjmallett			if (stx_int_reg.s.calpar1)
178210311Sjmallett				printf("SPI0: STX Calendar Table Parity Error Bank1\n");
179210311Sjmallett			if (stx_int_reg.s.calpar0)
180210311Sjmallett				printf("SPI0: STX Calendar Table Parity Error Bank0\n");
181210311Sjmallett		}
182210311Sjmallett
183210311Sjmallett		cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
184210311Sjmallett		cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
185210311Sjmallett		need_retrain[0] = 1;
186210311Sjmallett		return_status = FILTER_HANDLED;
187210311Sjmallett	}
188210311Sjmallett
189210311Sjmallett	return return_status;
190210311Sjmallett}
191210311Sjmallett
192210311Sjmallettstatic void cvm_oct_spi_enable_error_reporting(int interface)
193210311Sjmallett{
194210311Sjmallett	cvmx_spxx_int_msk_t spxx_int_msk;
195210311Sjmallett	cvmx_stxx_int_msk_t stxx_int_msk;
196210311Sjmallett
197210311Sjmallett	spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
198210311Sjmallett	spxx_int_msk.s.calerr = 1;
199210311Sjmallett	spxx_int_msk.s.syncerr = 1;
200210311Sjmallett	spxx_int_msk.s.diperr = 1;
201210311Sjmallett	spxx_int_msk.s.tpaovr = 1;
202210311Sjmallett	spxx_int_msk.s.rsverr = 1;
203210311Sjmallett	spxx_int_msk.s.drwnng = 1;
204210311Sjmallett	spxx_int_msk.s.clserr = 1;
205210311Sjmallett	spxx_int_msk.s.spiovr = 1;
206210311Sjmallett	spxx_int_msk.s.abnorm = 1;
207210311Sjmallett	spxx_int_msk.s.prtnxa = 1;
208210311Sjmallett	cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
209210311Sjmallett
210210311Sjmallett	stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
211210311Sjmallett	stxx_int_msk.s.frmerr = 1;
212210311Sjmallett	stxx_int_msk.s.unxfrm = 1;
213210311Sjmallett	stxx_int_msk.s.nosync = 1;
214210311Sjmallett	stxx_int_msk.s.diperr = 1;
215210311Sjmallett	stxx_int_msk.s.datovr = 1;
216210311Sjmallett	stxx_int_msk.s.ovrbst = 1;
217210311Sjmallett	stxx_int_msk.s.calpar1 = 1;
218210311Sjmallett	stxx_int_msk.s.calpar0 = 1;
219210311Sjmallett	cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
220210311Sjmallett}
221210311Sjmallett
222210311Sjmallettstatic void cvm_oct_spi_poll(struct ifnet *ifp)
223210311Sjmallett{
224210311Sjmallett	static int spi4000_port;
225210311Sjmallett	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
226210311Sjmallett	int interface;
227210311Sjmallett
228210311Sjmallett	for (interface = 0; interface < 2; interface++) {
229210311Sjmallett
230210311Sjmallett		if ((priv->port == interface*16) && need_retrain[interface]) {
231210311Sjmallett
232210311Sjmallett			if (cvmx_spi_restart_interface(interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
233210311Sjmallett				need_retrain[interface] = 0;
234210311Sjmallett				cvm_oct_spi_enable_error_reporting(interface);
235210311Sjmallett			}
236210311Sjmallett		}
237210311Sjmallett
238210311Sjmallett		/* The SPI4000 TWSI interface is very slow. In order not to
239210311Sjmallett		   bring the system to a crawl, we only poll a single port
240210311Sjmallett		   every second. This means negotiation speed changes
241210311Sjmallett		   take up to 10 seconds, but at least we don't waste
242210311Sjmallett		   absurd amounts of time waiting for TWSI */
243210311Sjmallett		if (priv->port == spi4000_port) {
244210311Sjmallett			/* This function does nothing if it is called on an
245210311Sjmallett			   interface without a SPI4000 */
246210311Sjmallett			cvmx_spi4000_check_speed(interface, priv->port);
247210311Sjmallett			/* Normal ordering increments. By decrementing
248210311Sjmallett			   we only match once per iteration */
249210311Sjmallett			spi4000_port--;
250210311Sjmallett			if (spi4000_port < 0)
251210311Sjmallett				spi4000_port = 10;
252210311Sjmallett		}
253210311Sjmallett	}
254210311Sjmallett}
255210311Sjmallett
256210311Sjmallett
257210311Sjmallettint cvm_oct_spi_init(struct ifnet *ifp)
258210311Sjmallett{
259210311Sjmallett	struct octebus_softc *sc;
260210311Sjmallett	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
261210311Sjmallett	int error;
262210311Sjmallett	int rid;
263210311Sjmallett
264210311Sjmallett	if (number_spi_ports == 0) {
265210311Sjmallett		sc = device_get_softc(device_get_parent(priv->dev));
266210311Sjmallett
267210311Sjmallett		rid = 0;
268210311Sjmallett		sc->sc_spi_irq = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ,
269232812Sjmallett						    &rid, OCTEON_IRQ_RML,
270232812Sjmallett						    OCTEON_IRQ_RML, 1,
271210311Sjmallett						    RF_ACTIVE);
272210311Sjmallett		if (sc->sc_spi_irq == NULL) {
273210311Sjmallett			device_printf(sc->sc_dev, "could not allocate SPI irq");
274210311Sjmallett			return ENXIO;
275210311Sjmallett		}
276210311Sjmallett
277210311Sjmallett		error = bus_setup_intr(sc->sc_dev, sc->sc_spi_irq,
278210311Sjmallett				       INTR_TYPE_NET | INTR_MPSAFE,
279210311Sjmallett				       cvm_oct_spi_rml_interrupt, NULL,
280210311Sjmallett				       &number_spi_ports, NULL);
281210311Sjmallett		if (error != 0) {
282210311Sjmallett			device_printf(sc->sc_dev, "could not setup SPI irq");
283210311Sjmallett			return error;
284210311Sjmallett		}
285210311Sjmallett	}
286210311Sjmallett	number_spi_ports++;
287210311Sjmallett
288210311Sjmallett	if ((priv->port == 0) || (priv->port == 16)) {
289210311Sjmallett		cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
290210311Sjmallett		priv->poll = cvm_oct_spi_poll;
291210311Sjmallett	}
292231987Sgonzo	if (cvm_oct_common_init(ifp) != 0)
293231987Sgonzo	    return ENXIO;
294210311Sjmallett	return 0;
295210311Sjmallett}
296210311Sjmallett
297210311Sjmallettvoid cvm_oct_spi_uninit(struct ifnet *ifp)
298210311Sjmallett{
299210311Sjmallett	int interface;
300210311Sjmallett
301210311Sjmallett	cvm_oct_common_uninit(ifp);
302210311Sjmallett	number_spi_ports--;
303210311Sjmallett	if (number_spi_ports == 0) {
304210311Sjmallett		for (interface = 0; interface < 2; interface++) {
305210311Sjmallett			cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
306210311Sjmallett			cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
307210311Sjmallett		}
308210311Sjmallett		panic("%s: IRQ release not yet implemented.", __func__);
309210311Sjmallett	}
310210311Sjmallett}
311