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$");
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
50static int number_spi_ports;
51static int need_retrain[2] = {0, 0};
52
53static 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
192static 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
222static 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
257int 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, CVMX_IRQ_RML,
270						    CVMX_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	cvm_oct_common_init(ifp);
293	return 0;
294}
295
296void cvm_oct_spi_uninit(struct ifnet *ifp)
297{
298	int interface;
299
300	cvm_oct_common_uninit(ifp);
301	number_spi_ports--;
302	if (number_spi_ports == 0) {
303		for (interface = 0; interface < 2; interface++) {
304			cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
305			cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
306		}
307		panic("%s: IRQ release not yet implemented.", __func__);
308	}
309}
310