brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · 699c98c Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This file is based on code from OCTEON SDK by Cavium Networks.4 *5 * Copyright (c) 2003-2007 Cavium Networks6 */7 8#include <linux/kernel.h>9#include <linux/netdevice.h>10#include <linux/interrupt.h>11#include <net/dst.h>12 13#include "octeon-ethernet.h"14#include "ethernet-defines.h"15#include "ethernet-util.h"16 17static int number_spi_ports;18static int need_retrain[2] = { 0, 0 };19 20static void cvm_oct_spxx_int_pr(union cvmx_spxx_int_reg spx_int_reg, int index)21{22	if (spx_int_reg.s.spf)23		pr_err("SPI%d: SRX Spi4 interface down\n", index);24	if (spx_int_reg.s.calerr)25		pr_err("SPI%d: SRX Spi4 Calendar table parity error\n", index);26	if (spx_int_reg.s.syncerr)27		pr_err("SPI%d: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n",28		       index);29	if (spx_int_reg.s.diperr)30		pr_err("SPI%d: SRX Spi4 DIP4 error\n", index);31	if (spx_int_reg.s.tpaovr)32		pr_err("SPI%d: SRX Selected port has hit TPA overflow\n",33		       index);34	if (spx_int_reg.s.rsverr)35		pr_err("SPI%d: SRX Spi4 reserved control word detected\n",36		       index);37	if (spx_int_reg.s.drwnng)38		pr_err("SPI%d: SRX Spi4 receive FIFO drowning/overflow\n",39		       index);40	if (spx_int_reg.s.clserr)41		pr_err("SPI%d: SRX Spi4 packet closed on non-16B alignment without EOP\n",42		       index);43	if (spx_int_reg.s.spiovr)44		pr_err("SPI%d: SRX Spi4 async FIFO overflow\n", index);45	if (spx_int_reg.s.abnorm)46		pr_err("SPI%d: SRX Abnormal packet termination (ERR bit)\n",47		       index);48	if (spx_int_reg.s.prtnxa)49		pr_err("SPI%d: SRX Port out of range\n", index);50}51 52static void cvm_oct_stxx_int_pr(union cvmx_stxx_int_reg stx_int_reg, int index)53{54	if (stx_int_reg.s.syncerr)55		pr_err("SPI%d: STX Interface encountered a fatal error\n",56		       index);57	if (stx_int_reg.s.frmerr)58		pr_err("SPI%d: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n",59		       index);60	if (stx_int_reg.s.unxfrm)61		pr_err("SPI%d: STX Unexpected framing sequence\n", index);62	if (stx_int_reg.s.nosync)63		pr_err("SPI%d: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n",64		       index);65	if (stx_int_reg.s.diperr)66		pr_err("SPI%d: STX DIP2 error on the Spi4 Status channel\n",67		       index);68	if (stx_int_reg.s.datovr)69		pr_err("SPI%d: STX Spi4 FIFO overflow error\n", index);70	if (stx_int_reg.s.ovrbst)71		pr_err("SPI%d: STX Transmit packet burst too big\n", index);72	if (stx_int_reg.s.calpar1)73		pr_err("SPI%d: STX Calendar Table Parity Error Bank%d\n",74		       index, 1);75	if (stx_int_reg.s.calpar0)76		pr_err("SPI%d: STX Calendar Table Parity Error Bank%d\n",77		       index, 0);78}79 80static irqreturn_t cvm_oct_spi_spx_int(int index)81{82	union cvmx_spxx_int_reg spx_int_reg;83	union cvmx_stxx_int_reg stx_int_reg;84 85	spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(index));86	cvmx_write_csr(CVMX_SPXX_INT_REG(index), spx_int_reg.u64);87	if (!need_retrain[index]) {88		spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(index));89		cvm_oct_spxx_int_pr(spx_int_reg, index);90	}91 92	stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(index));93	cvmx_write_csr(CVMX_STXX_INT_REG(index), stx_int_reg.u64);94	if (!need_retrain[index]) {95		stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(index));96		cvm_oct_stxx_int_pr(stx_int_reg, index);97	}98 99	cvmx_write_csr(CVMX_SPXX_INT_MSK(index), 0);100	cvmx_write_csr(CVMX_STXX_INT_MSK(index), 0);101	need_retrain[index] = 1;102 103	return IRQ_HANDLED;104}105 106static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id)107{108	irqreturn_t return_status = IRQ_NONE;109	union cvmx_npi_rsl_int_blocks rsl_int_blocks;110 111	/* Check and see if this interrupt was caused by the GMX block */112	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);113	if (rsl_int_blocks.s.spx1) /* 19 - SPX1_INT_REG & STX1_INT_REG */114		return_status = cvm_oct_spi_spx_int(1);115 116	if (rsl_int_blocks.s.spx0) /* 18 - SPX0_INT_REG & STX0_INT_REG */117		return_status = cvm_oct_spi_spx_int(0);118 119	return return_status;120}121 122static void cvm_oct_spi_enable_error_reporting(int interface)123{124	union cvmx_spxx_int_msk spxx_int_msk;125	union cvmx_stxx_int_msk stxx_int_msk;126 127	spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));128	spxx_int_msk.s.calerr = 1;129	spxx_int_msk.s.syncerr = 1;130	spxx_int_msk.s.diperr = 1;131	spxx_int_msk.s.tpaovr = 1;132	spxx_int_msk.s.rsverr = 1;133	spxx_int_msk.s.drwnng = 1;134	spxx_int_msk.s.clserr = 1;135	spxx_int_msk.s.spiovr = 1;136	spxx_int_msk.s.abnorm = 1;137	spxx_int_msk.s.prtnxa = 1;138	cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);139 140	stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));141	stxx_int_msk.s.frmerr = 1;142	stxx_int_msk.s.unxfrm = 1;143	stxx_int_msk.s.nosync = 1;144	stxx_int_msk.s.diperr = 1;145	stxx_int_msk.s.datovr = 1;146	stxx_int_msk.s.ovrbst = 1;147	stxx_int_msk.s.calpar1 = 1;148	stxx_int_msk.s.calpar0 = 1;149	cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);150}151 152static void cvm_oct_spi_poll(struct net_device *dev)153{154	static int spi4000_port;155	struct octeon_ethernet *priv = netdev_priv(dev);156	int interface;157 158	for (interface = 0; interface < 2; interface++) {159		if ((priv->port == interface * 16) && need_retrain[interface]) {160			if (cvmx_spi_restart_interface161			    (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {162				need_retrain[interface] = 0;163				cvm_oct_spi_enable_error_reporting(interface);164			}165		}166 167		/*168		 * The SPI4000 TWSI interface is very slow. In order169		 * not to bring the system to a crawl, we only poll a170		 * single port every second. This means negotiation171		 * speed changes take up to 10 seconds, but at least172		 * we don't waste absurd amounts of time waiting for173		 * TWSI.174		 */175		if (priv->port == spi4000_port) {176			/*177			 * This function does nothing if it is called on an178			 * interface without a SPI4000.179			 */180			cvmx_spi4000_check_speed(interface, priv->port);181			/*182			 * Normal ordering increments. By decrementing183			 * we only match once per iteration.184			 */185			spi4000_port--;186			if (spi4000_port < 0)187				spi4000_port = 10;188		}189	}190}191 192int cvm_oct_spi_init(struct net_device *dev)193{194	int r;195	struct octeon_ethernet *priv = netdev_priv(dev);196 197	if (number_spi_ports == 0) {198		r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,199				IRQF_SHARED, "SPI", &number_spi_ports);200		if (r)201			return r;202	}203	number_spi_ports++;204 205	if (priv->port == 0 || priv->port == 16) {206		cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));207		priv->poll = cvm_oct_spi_poll;208	}209	cvm_oct_common_init(dev);210	return 0;211}212 213void cvm_oct_spi_uninit(struct net_device *dev)214{215	int interface;216 217	cvm_oct_common_uninit(dev);218	number_spi_ports--;219	if (number_spi_ports == 0) {220		for (interface = 0; interface < 2; interface++) {221			cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);222			cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);223		}224		free_irq(OCTEON_IRQ_RML, &number_spi_ports);225	}226}227