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