xref: /openbmc/linux/drivers/net/ethernet/toshiba/spider_net.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28df158acSJeff Kirsher /*
38df158acSJeff Kirsher  * Network device driver for Cell Processor-Based Blade and Celleb platform
48df158acSJeff Kirsher  *
58df158acSJeff Kirsher  * (C) Copyright IBM Corp. 2005
68df158acSJeff Kirsher  * (C) Copyright 2006 TOSHIBA CORPORATION
78df158acSJeff Kirsher  *
88df158acSJeff Kirsher  * Authors : Utz Bacher <utz.bacher@de.ibm.com>
98df158acSJeff Kirsher  *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
108df158acSJeff Kirsher  */
118df158acSJeff Kirsher 
128df158acSJeff Kirsher #include <linux/compiler.h>
138df158acSJeff Kirsher #include <linux/crc32.h>
148df158acSJeff Kirsher #include <linux/delay.h>
158df158acSJeff Kirsher #include <linux/etherdevice.h>
168df158acSJeff Kirsher #include <linux/ethtool.h>
178df158acSJeff Kirsher #include <linux/firmware.h>
188df158acSJeff Kirsher #include <linux/if_vlan.h>
198df158acSJeff Kirsher #include <linux/in.h>
208df158acSJeff Kirsher #include <linux/init.h>
218df158acSJeff Kirsher #include <linux/interrupt.h>
228df158acSJeff Kirsher #include <linux/gfp.h>
238df158acSJeff Kirsher #include <linux/ioport.h>
248df158acSJeff Kirsher #include <linux/ip.h>
258df158acSJeff Kirsher #include <linux/kernel.h>
268df158acSJeff Kirsher #include <linux/mii.h>
278df158acSJeff Kirsher #include <linux/module.h>
288df158acSJeff Kirsher #include <linux/netdevice.h>
298df158acSJeff Kirsher #include <linux/device.h>
308df158acSJeff Kirsher #include <linux/pci.h>
318df158acSJeff Kirsher #include <linux/skbuff.h>
328df158acSJeff Kirsher #include <linux/tcp.h>
338df158acSJeff Kirsher #include <linux/types.h>
348df158acSJeff Kirsher #include <linux/vmalloc.h>
358df158acSJeff Kirsher #include <linux/wait.h>
368df158acSJeff Kirsher #include <linux/workqueue.h>
378df158acSJeff Kirsher #include <linux/bitops.h>
386bff3ffcSChristophe Leroy #include <linux/of.h>
398df158acSJeff Kirsher #include <net/checksum.h>
408df158acSJeff Kirsher 
418df158acSJeff Kirsher #include "spider_net.h"
428df158acSJeff Kirsher 
438df158acSJeff Kirsher MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
448df158acSJeff Kirsher 	      "<Jens.Osterkamp@de.ibm.com>");
458df158acSJeff Kirsher MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
468df158acSJeff Kirsher MODULE_LICENSE("GPL");
478df158acSJeff Kirsher MODULE_VERSION(VERSION);
488df158acSJeff Kirsher MODULE_FIRMWARE(SPIDER_NET_FIRMWARE_NAME);
498df158acSJeff Kirsher 
508df158acSJeff Kirsher static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
518df158acSJeff Kirsher static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
528df158acSJeff Kirsher 
538df158acSJeff Kirsher module_param(rx_descriptors, int, 0444);
548df158acSJeff Kirsher module_param(tx_descriptors, int, 0444);
558df158acSJeff Kirsher 
568df158acSJeff Kirsher MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
578df158acSJeff Kirsher 		 "in rx chains");
588df158acSJeff Kirsher MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
598df158acSJeff Kirsher 		 "in tx chain");
608df158acSJeff Kirsher 
618df158acSJeff Kirsher char spider_net_driver_name[] = "spidernet";
628df158acSJeff Kirsher 
639baa3c34SBenoit Taine static const struct pci_device_id spider_net_pci_tbl[] = {
648df158acSJeff Kirsher 	{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
658df158acSJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
668df158acSJeff Kirsher 	{ 0, }
678df158acSJeff Kirsher };
688df158acSJeff Kirsher 
698df158acSJeff Kirsher MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
708df158acSJeff Kirsher 
718df158acSJeff Kirsher /**
728df158acSJeff Kirsher  * spider_net_read_reg - reads an SMMIO register of a card
738df158acSJeff Kirsher  * @card: device structure
748df158acSJeff Kirsher  * @reg: register to read from
758df158acSJeff Kirsher  *
768df158acSJeff Kirsher  * returns the content of the specified SMMIO register.
778df158acSJeff Kirsher  */
788df158acSJeff Kirsher static inline u32
spider_net_read_reg(struct spider_net_card * card,u32 reg)798df158acSJeff Kirsher spider_net_read_reg(struct spider_net_card *card, u32 reg)
808df158acSJeff Kirsher {
818df158acSJeff Kirsher 	/* We use the powerpc specific variants instead of readl_be() because
828df158acSJeff Kirsher 	 * we know spidernet is not a real PCI device and we can thus avoid the
838df158acSJeff Kirsher 	 * performance hit caused by the PCI workarounds.
848df158acSJeff Kirsher 	 */
858df158acSJeff Kirsher 	return in_be32(card->regs + reg);
868df158acSJeff Kirsher }
878df158acSJeff Kirsher 
888df158acSJeff Kirsher /**
898df158acSJeff Kirsher  * spider_net_write_reg - writes to an SMMIO register of a card
908df158acSJeff Kirsher  * @card: device structure
918df158acSJeff Kirsher  * @reg: register to write to
928df158acSJeff Kirsher  * @value: value to write into the specified SMMIO register
938df158acSJeff Kirsher  */
948df158acSJeff Kirsher static inline void
spider_net_write_reg(struct spider_net_card * card,u32 reg,u32 value)958df158acSJeff Kirsher spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
968df158acSJeff Kirsher {
978df158acSJeff Kirsher 	/* We use the powerpc specific variants instead of writel_be() because
988df158acSJeff Kirsher 	 * we know spidernet is not a real PCI device and we can thus avoid the
998df158acSJeff Kirsher 	 * performance hit caused by the PCI workarounds.
1008df158acSJeff Kirsher 	 */
1018df158acSJeff Kirsher 	out_be32(card->regs + reg, value);
1028df158acSJeff Kirsher }
1038df158acSJeff Kirsher 
10449ce9c2cSBen Hutchings /**
10549ce9c2cSBen Hutchings  * spider_net_write_phy - write to phy register
1068df158acSJeff Kirsher  * @netdev: adapter to be written to
1078df158acSJeff Kirsher  * @mii_id: id of MII
1088df158acSJeff Kirsher  * @reg: PHY register
1098df158acSJeff Kirsher  * @val: value to be written to phy register
1108df158acSJeff Kirsher  *
1118df158acSJeff Kirsher  * spider_net_write_phy_register writes to an arbitrary PHY
1128df158acSJeff Kirsher  * register via the spider GPCWOPCMD register. We assume the queue does
1138df158acSJeff Kirsher  * not run full (not more than 15 commands outstanding).
1148df158acSJeff Kirsher  **/
1158df158acSJeff Kirsher static void
spider_net_write_phy(struct net_device * netdev,int mii_id,int reg,int val)1168df158acSJeff Kirsher spider_net_write_phy(struct net_device *netdev, int mii_id,
1178df158acSJeff Kirsher 		     int reg, int val)
1188df158acSJeff Kirsher {
1198df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
1208df158acSJeff Kirsher 	u32 writevalue;
1218df158acSJeff Kirsher 
1228df158acSJeff Kirsher 	writevalue = ((u32)mii_id << 21) |
1238df158acSJeff Kirsher 		((u32)reg << 16) | ((u32)val);
1248df158acSJeff Kirsher 
1258df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GPCWOPCMD, writevalue);
1268df158acSJeff Kirsher }
1278df158acSJeff Kirsher 
12849ce9c2cSBen Hutchings /**
12949ce9c2cSBen Hutchings  * spider_net_read_phy - read from phy register
1308df158acSJeff Kirsher  * @netdev: network device to be read from
1318df158acSJeff Kirsher  * @mii_id: id of MII
1328df158acSJeff Kirsher  * @reg: PHY register
1338df158acSJeff Kirsher  *
1348df158acSJeff Kirsher  * Returns value read from PHY register
1358df158acSJeff Kirsher  *
1368df158acSJeff Kirsher  * spider_net_write_phy reads from an arbitrary PHY
1378df158acSJeff Kirsher  * register via the spider GPCROPCMD register
1388df158acSJeff Kirsher  **/
1398df158acSJeff Kirsher static int
spider_net_read_phy(struct net_device * netdev,int mii_id,int reg)1408df158acSJeff Kirsher spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
1418df158acSJeff Kirsher {
1428df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
1438df158acSJeff Kirsher 	u32 readvalue;
1448df158acSJeff Kirsher 
1458df158acSJeff Kirsher 	readvalue = ((u32)mii_id << 21) | ((u32)reg << 16);
1468df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GPCROPCMD, readvalue);
1478df158acSJeff Kirsher 
1488df158acSJeff Kirsher 	/* we don't use semaphores to wait for an SPIDER_NET_GPROPCMPINT
1498df158acSJeff Kirsher 	 * interrupt, as we poll for the completion of the read operation
150142c1d2eSYixing Liu 	 * in spider_net_read_phy. Should take about 50 us
151142c1d2eSYixing Liu 	 */
1528df158acSJeff Kirsher 	do {
1538df158acSJeff Kirsher 		readvalue = spider_net_read_reg(card, SPIDER_NET_GPCROPCMD);
1548df158acSJeff Kirsher 	} while (readvalue & SPIDER_NET_GPREXEC);
1558df158acSJeff Kirsher 
1568df158acSJeff Kirsher 	readvalue &= SPIDER_NET_GPRDAT_MASK;
1578df158acSJeff Kirsher 
1588df158acSJeff Kirsher 	return readvalue;
1598df158acSJeff Kirsher }
1608df158acSJeff Kirsher 
1618df158acSJeff Kirsher /**
1628df158acSJeff Kirsher  * spider_net_setup_aneg - initial auto-negotiation setup
1638df158acSJeff Kirsher  * @card: device structure
1648df158acSJeff Kirsher  **/
1658df158acSJeff Kirsher static void
spider_net_setup_aneg(struct spider_net_card * card)1668df158acSJeff Kirsher spider_net_setup_aneg(struct spider_net_card *card)
1678df158acSJeff Kirsher {
1688df158acSJeff Kirsher 	struct mii_phy *phy = &card->phy;
1698df158acSJeff Kirsher 	u32 advertise = 0;
1708df158acSJeff Kirsher 	u16 bmsr, estat;
1718df158acSJeff Kirsher 
1728df158acSJeff Kirsher 	bmsr  = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
1738df158acSJeff Kirsher 	estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
1748df158acSJeff Kirsher 
1758df158acSJeff Kirsher 	if (bmsr & BMSR_10HALF)
1768df158acSJeff Kirsher 		advertise |= ADVERTISED_10baseT_Half;
1778df158acSJeff Kirsher 	if (bmsr & BMSR_10FULL)
1788df158acSJeff Kirsher 		advertise |= ADVERTISED_10baseT_Full;
1798df158acSJeff Kirsher 	if (bmsr & BMSR_100HALF)
1808df158acSJeff Kirsher 		advertise |= ADVERTISED_100baseT_Half;
1818df158acSJeff Kirsher 	if (bmsr & BMSR_100FULL)
1828df158acSJeff Kirsher 		advertise |= ADVERTISED_100baseT_Full;
1838df158acSJeff Kirsher 
1848df158acSJeff Kirsher 	if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
1858df158acSJeff Kirsher 		advertise |= SUPPORTED_1000baseT_Full;
1868df158acSJeff Kirsher 	if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
1878df158acSJeff Kirsher 		advertise |= SUPPORTED_1000baseT_Half;
1888df158acSJeff Kirsher 
18919e2f6feSDavid S. Miller 	sungem_phy_probe(phy, phy->mii_id);
1908df158acSJeff Kirsher 	phy->def->ops->setup_aneg(phy, advertise);
1918df158acSJeff Kirsher 
1928df158acSJeff Kirsher }
1938df158acSJeff Kirsher 
1948df158acSJeff Kirsher /**
1958df158acSJeff Kirsher  * spider_net_rx_irq_off - switch off rx irq on this spider card
1968df158acSJeff Kirsher  * @card: device structure
1978df158acSJeff Kirsher  *
1988df158acSJeff Kirsher  * switches off rx irq by masking them out in the GHIINTnMSK register
1998df158acSJeff Kirsher  */
2008df158acSJeff Kirsher static void
spider_net_rx_irq_off(struct spider_net_card * card)2018df158acSJeff Kirsher spider_net_rx_irq_off(struct spider_net_card *card)
2028df158acSJeff Kirsher {
2038df158acSJeff Kirsher 	u32 regvalue;
2048df158acSJeff Kirsher 
2058df158acSJeff Kirsher 	regvalue = SPIDER_NET_INT0_MASK_VALUE & (~SPIDER_NET_RXINT);
2068df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
2078df158acSJeff Kirsher }
2088df158acSJeff Kirsher 
2098df158acSJeff Kirsher /**
2108df158acSJeff Kirsher  * spider_net_rx_irq_on - switch on rx irq on this spider card
2118df158acSJeff Kirsher  * @card: device structure
2128df158acSJeff Kirsher  *
2138df158acSJeff Kirsher  * switches on rx irq by enabling them in the GHIINTnMSK register
2148df158acSJeff Kirsher  */
2158df158acSJeff Kirsher static void
spider_net_rx_irq_on(struct spider_net_card * card)2168df158acSJeff Kirsher spider_net_rx_irq_on(struct spider_net_card *card)
2178df158acSJeff Kirsher {
2188df158acSJeff Kirsher 	u32 regvalue;
2198df158acSJeff Kirsher 
2208df158acSJeff Kirsher 	regvalue = SPIDER_NET_INT0_MASK_VALUE | SPIDER_NET_RXINT;
2218df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue);
2228df158acSJeff Kirsher }
2238df158acSJeff Kirsher 
2248df158acSJeff Kirsher /**
2258df158acSJeff Kirsher  * spider_net_set_promisc - sets the unicast address or the promiscuous mode
2268df158acSJeff Kirsher  * @card: card structure
2278df158acSJeff Kirsher  *
2288df158acSJeff Kirsher  * spider_net_set_promisc sets the unicast destination address filter and
2298df158acSJeff Kirsher  * thus either allows for non-promisc mode or promisc mode
2308df158acSJeff Kirsher  */
2318df158acSJeff Kirsher static void
spider_net_set_promisc(struct spider_net_card * card)2328df158acSJeff Kirsher spider_net_set_promisc(struct spider_net_card *card)
2338df158acSJeff Kirsher {
2348df158acSJeff Kirsher 	u32 macu, macl;
2358df158acSJeff Kirsher 	struct net_device *netdev = card->netdev;
2368df158acSJeff Kirsher 
2378df158acSJeff Kirsher 	if (netdev->flags & IFF_PROMISC) {
2388df158acSJeff Kirsher 		/* clear destination entry 0 */
2398df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, 0);
2408df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, 0);
2418df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
2428df158acSJeff Kirsher 				     SPIDER_NET_PROMISC_VALUE);
2438df158acSJeff Kirsher 	} else {
2448df158acSJeff Kirsher 		macu = netdev->dev_addr[0];
2458df158acSJeff Kirsher 		macu <<= 8;
2468df158acSJeff Kirsher 		macu |= netdev->dev_addr[1];
2478df158acSJeff Kirsher 		memcpy(&macl, &netdev->dev_addr[2], sizeof(macl));
2488df158acSJeff Kirsher 
2498df158acSJeff Kirsher 		macu |= SPIDER_NET_UA_DESCR_VALUE;
2508df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR, macu);
2518df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUAFILnR + 0x04, macl);
2528df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R,
2538df158acSJeff Kirsher 				     SPIDER_NET_NONPROMISC_VALUE);
2548df158acSJeff Kirsher 	}
2558df158acSJeff Kirsher }
2568df158acSJeff Kirsher 
2578df158acSJeff Kirsher /**
2588df158acSJeff Kirsher  * spider_net_get_descr_status -- returns the status of a descriptor
259e242d598SLee Jones  * @hwdescr: descriptor to look at
2608df158acSJeff Kirsher  *
2618df158acSJeff Kirsher  * returns the status as in the dmac_cmd_status field of the descriptor
2628df158acSJeff Kirsher  */
2638df158acSJeff Kirsher static inline int
spider_net_get_descr_status(struct spider_net_hw_descr * hwdescr)2648df158acSJeff Kirsher spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
2658df158acSJeff Kirsher {
2668df158acSJeff Kirsher 	return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
2678df158acSJeff Kirsher }
2688df158acSJeff Kirsher 
2698df158acSJeff Kirsher /**
2708df158acSJeff Kirsher  * spider_net_free_chain - free descriptor chain
2718df158acSJeff Kirsher  * @card: card structure
2728df158acSJeff Kirsher  * @chain: address of chain
2738df158acSJeff Kirsher  *
2748df158acSJeff Kirsher  */
2758df158acSJeff Kirsher static void
spider_net_free_chain(struct spider_net_card * card,struct spider_net_descr_chain * chain)2768df158acSJeff Kirsher spider_net_free_chain(struct spider_net_card *card,
2778df158acSJeff Kirsher 		      struct spider_net_descr_chain *chain)
2788df158acSJeff Kirsher {
2798df158acSJeff Kirsher 	struct spider_net_descr *descr;
2808df158acSJeff Kirsher 
2818df158acSJeff Kirsher 	descr = chain->ring;
2828df158acSJeff Kirsher 	do {
2838df158acSJeff Kirsher 		descr->bus_addr = 0;
2848df158acSJeff Kirsher 		descr->hwdescr->next_descr_addr = 0;
2858df158acSJeff Kirsher 		descr = descr->next;
2868df158acSJeff Kirsher 	} while (descr != chain->ring);
2878df158acSJeff Kirsher 
28836f28f76SChristophe JAILLET 	dma_free_coherent(&card->pdev->dev, chain->num_desc * sizeof(struct spider_net_hw_descr),
2898df158acSJeff Kirsher 			  chain->hwring, chain->dma_addr);
2908df158acSJeff Kirsher }
2918df158acSJeff Kirsher 
2928df158acSJeff Kirsher /**
2938df158acSJeff Kirsher  * spider_net_init_chain - alloc and link descriptor chain
2948df158acSJeff Kirsher  * @card: card structure
2958df158acSJeff Kirsher  * @chain: address of chain
2968df158acSJeff Kirsher  *
2978df158acSJeff Kirsher  * We manage a circular list that mirrors the hardware structure,
2988df158acSJeff Kirsher  * except that the hardware uses bus addresses.
2998df158acSJeff Kirsher  *
3008df158acSJeff Kirsher  * Returns 0 on success, <0 on failure
3018df158acSJeff Kirsher  */
3028df158acSJeff Kirsher static int
spider_net_init_chain(struct spider_net_card * card,struct spider_net_descr_chain * chain)3038df158acSJeff Kirsher spider_net_init_chain(struct spider_net_card *card,
3048df158acSJeff Kirsher 		       struct spider_net_descr_chain *chain)
3058df158acSJeff Kirsher {
3068df158acSJeff Kirsher 	int i;
3078df158acSJeff Kirsher 	struct spider_net_descr *descr;
3088df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr;
3098df158acSJeff Kirsher 	dma_addr_t buf;
3108df158acSJeff Kirsher 	size_t alloc_size;
3118df158acSJeff Kirsher 
3128df158acSJeff Kirsher 	alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
3138df158acSJeff Kirsher 
3148df158acSJeff Kirsher 	chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
3158df158acSJeff Kirsher 					   &chain->dma_addr, GFP_KERNEL);
3168df158acSJeff Kirsher 	if (!chain->hwring)
3178df158acSJeff Kirsher 		return -ENOMEM;
3188df158acSJeff Kirsher 
3198df158acSJeff Kirsher 	/* Set up the hardware pointers in each descriptor */
3208df158acSJeff Kirsher 	descr = chain->ring;
3218df158acSJeff Kirsher 	hwdescr = chain->hwring;
3228df158acSJeff Kirsher 	buf = chain->dma_addr;
3238df158acSJeff Kirsher 	for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
3248df158acSJeff Kirsher 		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
3258df158acSJeff Kirsher 		hwdescr->next_descr_addr = 0;
3268df158acSJeff Kirsher 
3278df158acSJeff Kirsher 		descr->hwdescr = hwdescr;
3288df158acSJeff Kirsher 		descr->bus_addr = buf;
3298df158acSJeff Kirsher 		descr->next = descr + 1;
3308df158acSJeff Kirsher 		descr->prev = descr - 1;
3318df158acSJeff Kirsher 
3328df158acSJeff Kirsher 		buf += sizeof(struct spider_net_hw_descr);
3338df158acSJeff Kirsher 	}
3348df158acSJeff Kirsher 	/* do actual circular list */
3358df158acSJeff Kirsher 	(descr-1)->next = chain->ring;
3368df158acSJeff Kirsher 	chain->ring->prev = descr-1;
3378df158acSJeff Kirsher 
3388df158acSJeff Kirsher 	spin_lock_init(&chain->lock);
3398df158acSJeff Kirsher 	chain->head = chain->ring;
3408df158acSJeff Kirsher 	chain->tail = chain->ring;
3418df158acSJeff Kirsher 	return 0;
3428df158acSJeff Kirsher }
3438df158acSJeff Kirsher 
3448df158acSJeff Kirsher /**
3458df158acSJeff Kirsher  * spider_net_free_rx_chain_contents - frees descr contents in rx chain
3468df158acSJeff Kirsher  * @card: card structure
3478df158acSJeff Kirsher  *
3488df158acSJeff Kirsher  * returns 0 on success, <0 on failure
3498df158acSJeff Kirsher  */
3508df158acSJeff Kirsher static void
spider_net_free_rx_chain_contents(struct spider_net_card * card)3518df158acSJeff Kirsher spider_net_free_rx_chain_contents(struct spider_net_card *card)
3528df158acSJeff Kirsher {
3538df158acSJeff Kirsher 	struct spider_net_descr *descr;
3548df158acSJeff Kirsher 
3558df158acSJeff Kirsher 	descr = card->rx_chain.head;
3568df158acSJeff Kirsher 	do {
3578df158acSJeff Kirsher 		if (descr->skb) {
35827d57f85SChristophe JAILLET 			dma_unmap_single(&card->pdev->dev,
35927d57f85SChristophe JAILLET 					 descr->hwdescr->buf_addr,
3608df158acSJeff Kirsher 					 SPIDER_NET_MAX_FRAME,
36127d57f85SChristophe JAILLET 					 DMA_BIDIRECTIONAL);
3628df158acSJeff Kirsher 			dev_kfree_skb(descr->skb);
3638df158acSJeff Kirsher 			descr->skb = NULL;
3648df158acSJeff Kirsher 		}
3658df158acSJeff Kirsher 		descr = descr->next;
3668df158acSJeff Kirsher 	} while (descr != card->rx_chain.head);
3678df158acSJeff Kirsher }
3688df158acSJeff Kirsher 
3698df158acSJeff Kirsher /**
3708df158acSJeff Kirsher  * spider_net_prepare_rx_descr - Reinitialize RX descriptor
3718df158acSJeff Kirsher  * @card: card structure
3728df158acSJeff Kirsher  * @descr: descriptor to re-init
3738df158acSJeff Kirsher  *
3748df158acSJeff Kirsher  * Return 0 on success, <0 on failure.
3758df158acSJeff Kirsher  *
3768df158acSJeff Kirsher  * Allocates a new rx skb, iommu-maps it and attaches it to the
3778df158acSJeff Kirsher  * descriptor. Mark the descriptor as activated, ready-to-use.
3788df158acSJeff Kirsher  */
3798df158acSJeff Kirsher static int
spider_net_prepare_rx_descr(struct spider_net_card * card,struct spider_net_descr * descr)3808df158acSJeff Kirsher spider_net_prepare_rx_descr(struct spider_net_card *card,
3818df158acSJeff Kirsher 			    struct spider_net_descr *descr)
3828df158acSJeff Kirsher {
3838df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr = descr->hwdescr;
3848df158acSJeff Kirsher 	dma_addr_t buf;
3858df158acSJeff Kirsher 	int offset;
3868df158acSJeff Kirsher 	int bufsize;
3878df158acSJeff Kirsher 
3888df158acSJeff Kirsher 	/* we need to round up the buffer size to a multiple of 128 */
3898df158acSJeff Kirsher 	bufsize = (SPIDER_NET_MAX_FRAME + SPIDER_NET_RXBUF_ALIGN - 1) &
3908df158acSJeff Kirsher 		(~(SPIDER_NET_RXBUF_ALIGN - 1));
3918df158acSJeff Kirsher 
3928df158acSJeff Kirsher 	/* and we need to have it 128 byte aligned, therefore we allocate a
393142c1d2eSYixing Liu 	 * bit more
394142c1d2eSYixing Liu 	 */
3958df158acSJeff Kirsher 	/* allocate an skb */
3968df158acSJeff Kirsher 	descr->skb = netdev_alloc_skb(card->netdev,
3978df158acSJeff Kirsher 				      bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
3988df158acSJeff Kirsher 	if (!descr->skb) {
3998df158acSJeff Kirsher 		if (netif_msg_rx_err(card) && net_ratelimit())
4008df158acSJeff Kirsher 			dev_err(&card->netdev->dev,
4018df158acSJeff Kirsher 			        "Not enough memory to allocate rx buffer\n");
4028df158acSJeff Kirsher 		card->spider_stats.alloc_rx_skb_error++;
4038df158acSJeff Kirsher 		return -ENOMEM;
4048df158acSJeff Kirsher 	}
4058df158acSJeff Kirsher 	hwdescr->buf_size = bufsize;
4068df158acSJeff Kirsher 	hwdescr->result_size = 0;
4078df158acSJeff Kirsher 	hwdescr->valid_size = 0;
4088df158acSJeff Kirsher 	hwdescr->data_status = 0;
4098df158acSJeff Kirsher 	hwdescr->data_error = 0;
4108df158acSJeff Kirsher 
4118df158acSJeff Kirsher 	offset = ((unsigned long)descr->skb->data) &
4128df158acSJeff Kirsher 		(SPIDER_NET_RXBUF_ALIGN - 1);
4138df158acSJeff Kirsher 	if (offset)
4148df158acSJeff Kirsher 		skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
4158df158acSJeff Kirsher 	/* iommu-map the skb */
41627d57f85SChristophe JAILLET 	buf = dma_map_single(&card->pdev->dev, descr->skb->data,
41727d57f85SChristophe JAILLET 			     SPIDER_NET_MAX_FRAME, DMA_FROM_DEVICE);
41827d57f85SChristophe JAILLET 	if (dma_mapping_error(&card->pdev->dev, buf)) {
4198df158acSJeff Kirsher 		dev_kfree_skb_any(descr->skb);
4208df158acSJeff Kirsher 		descr->skb = NULL;
4218df158acSJeff Kirsher 		if (netif_msg_rx_err(card) && net_ratelimit())
4228df158acSJeff Kirsher 			dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
4238df158acSJeff Kirsher 		card->spider_stats.rx_iommu_map_error++;
4248df158acSJeff Kirsher 		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
4258df158acSJeff Kirsher 	} else {
4268df158acSJeff Kirsher 		hwdescr->buf_addr = buf;
4278df158acSJeff Kirsher 		wmb();
4288df158acSJeff Kirsher 		hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
4298df158acSJeff Kirsher 					 SPIDER_NET_DMAC_NOINTR_COMPLETE;
4308df158acSJeff Kirsher 	}
4318df158acSJeff Kirsher 
4328df158acSJeff Kirsher 	return 0;
4338df158acSJeff Kirsher }
4348df158acSJeff Kirsher 
4358df158acSJeff Kirsher /**
4368df158acSJeff Kirsher  * spider_net_enable_rxchtails - sets RX dmac chain tail addresses
4378df158acSJeff Kirsher  * @card: card structure
4388df158acSJeff Kirsher  *
4398df158acSJeff Kirsher  * spider_net_enable_rxchtails sets the RX DMAC chain tail addresses in the
4408df158acSJeff Kirsher  * chip by writing to the appropriate register. DMA is enabled in
4418df158acSJeff Kirsher  * spider_net_enable_rxdmac.
4428df158acSJeff Kirsher  */
4438df158acSJeff Kirsher static inline void
spider_net_enable_rxchtails(struct spider_net_card * card)4448df158acSJeff Kirsher spider_net_enable_rxchtails(struct spider_net_card *card)
4458df158acSJeff Kirsher {
4468df158acSJeff Kirsher 	/* assume chain is aligned correctly */
4478df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDADCHA ,
4488df158acSJeff Kirsher 			     card->rx_chain.tail->bus_addr);
4498df158acSJeff Kirsher }
4508df158acSJeff Kirsher 
4518df158acSJeff Kirsher /**
4528df158acSJeff Kirsher  * spider_net_enable_rxdmac - enables a receive DMA controller
4538df158acSJeff Kirsher  * @card: card structure
4548df158acSJeff Kirsher  *
4558df158acSJeff Kirsher  * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
4568df158acSJeff Kirsher  * in the GDADMACCNTR register
4578df158acSJeff Kirsher  */
4588df158acSJeff Kirsher static inline void
spider_net_enable_rxdmac(struct spider_net_card * card)4598df158acSJeff Kirsher spider_net_enable_rxdmac(struct spider_net_card *card)
4608df158acSJeff Kirsher {
4618df158acSJeff Kirsher 	wmb();
4628df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
4638df158acSJeff Kirsher 			     SPIDER_NET_DMA_RX_VALUE);
4648df158acSJeff Kirsher }
4658df158acSJeff Kirsher 
4668df158acSJeff Kirsher /**
4678df158acSJeff Kirsher  * spider_net_disable_rxdmac - disables the receive DMA controller
4688df158acSJeff Kirsher  * @card: card structure
4698df158acSJeff Kirsher  *
4708df158acSJeff Kirsher  * spider_net_disable_rxdmac terminates processing on the DMA controller
4718df158acSJeff Kirsher  * by turing off the DMA controller, with the force-end flag set.
4728df158acSJeff Kirsher  */
4738df158acSJeff Kirsher static inline void
spider_net_disable_rxdmac(struct spider_net_card * card)4748df158acSJeff Kirsher spider_net_disable_rxdmac(struct spider_net_card *card)
4758df158acSJeff Kirsher {
4768df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
4778df158acSJeff Kirsher 			     SPIDER_NET_DMA_RX_FEND_VALUE);
4788df158acSJeff Kirsher }
4798df158acSJeff Kirsher 
4808df158acSJeff Kirsher /**
4818df158acSJeff Kirsher  * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
4828df158acSJeff Kirsher  * @card: card structure
4838df158acSJeff Kirsher  *
4848df158acSJeff Kirsher  * refills descriptors in the rx chain: allocates skbs and iommu-maps them.
4858df158acSJeff Kirsher  */
4868df158acSJeff Kirsher static void
spider_net_refill_rx_chain(struct spider_net_card * card)4878df158acSJeff Kirsher spider_net_refill_rx_chain(struct spider_net_card *card)
4888df158acSJeff Kirsher {
4898df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
4908df158acSJeff Kirsher 	unsigned long flags;
4918df158acSJeff Kirsher 
4928df158acSJeff Kirsher 	/* one context doing the refill (and a second context seeing that
4938df158acSJeff Kirsher 	 * and omitting it) is ok. If called by NAPI, we'll be called again
4948df158acSJeff Kirsher 	 * as spider_net_decode_one_descr is called several times. If some
495142c1d2eSYixing Liu 	 * interrupt calls us, the NAPI is about to clean up anyway.
496142c1d2eSYixing Liu 	 */
4978df158acSJeff Kirsher 	if (!spin_trylock_irqsave(&chain->lock, flags))
4988df158acSJeff Kirsher 		return;
4998df158acSJeff Kirsher 
5008df158acSJeff Kirsher 	while (spider_net_get_descr_status(chain->head->hwdescr) ==
5018df158acSJeff Kirsher 			SPIDER_NET_DESCR_NOT_IN_USE) {
5028df158acSJeff Kirsher 		if (spider_net_prepare_rx_descr(card, chain->head))
5038df158acSJeff Kirsher 			break;
5048df158acSJeff Kirsher 		chain->head = chain->head->next;
5058df158acSJeff Kirsher 	}
5068df158acSJeff Kirsher 
5078df158acSJeff Kirsher 	spin_unlock_irqrestore(&chain->lock, flags);
5088df158acSJeff Kirsher }
5098df158acSJeff Kirsher 
5108df158acSJeff Kirsher /**
5118df158acSJeff Kirsher  * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
5128df158acSJeff Kirsher  * @card: card structure
5138df158acSJeff Kirsher  *
5148df158acSJeff Kirsher  * Returns 0 on success, <0 on failure.
5158df158acSJeff Kirsher  */
5168df158acSJeff Kirsher static int
spider_net_alloc_rx_skbs(struct spider_net_card * card)5178df158acSJeff Kirsher spider_net_alloc_rx_skbs(struct spider_net_card *card)
5188df158acSJeff Kirsher {
5198df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
5208df158acSJeff Kirsher 	struct spider_net_descr *start = chain->tail;
5218df158acSJeff Kirsher 	struct spider_net_descr *descr = start;
5228df158acSJeff Kirsher 
5238df158acSJeff Kirsher 	/* Link up the hardware chain pointers */
5248df158acSJeff Kirsher 	do {
5258df158acSJeff Kirsher 		descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
5268df158acSJeff Kirsher 		descr = descr->next;
5278df158acSJeff Kirsher 	} while (descr != start);
5288df158acSJeff Kirsher 
5298df158acSJeff Kirsher 	/* Put at least one buffer into the chain. if this fails,
5308df158acSJeff Kirsher 	 * we've got a problem. If not, spider_net_refill_rx_chain
531142c1d2eSYixing Liu 	 * will do the rest at the end of this function.
532142c1d2eSYixing Liu 	 */
5338df158acSJeff Kirsher 	if (spider_net_prepare_rx_descr(card, chain->head))
5348df158acSJeff Kirsher 		goto error;
5358df158acSJeff Kirsher 	else
5368df158acSJeff Kirsher 		chain->head = chain->head->next;
5378df158acSJeff Kirsher 
5388df158acSJeff Kirsher 	/* This will allocate the rest of the rx buffers;
539142c1d2eSYixing Liu 	 * if not, it's business as usual later on.
540142c1d2eSYixing Liu 	 */
5418df158acSJeff Kirsher 	spider_net_refill_rx_chain(card);
5428df158acSJeff Kirsher 	spider_net_enable_rxdmac(card);
5438df158acSJeff Kirsher 	return 0;
5448df158acSJeff Kirsher 
5458df158acSJeff Kirsher error:
5468df158acSJeff Kirsher 	spider_net_free_rx_chain_contents(card);
5478df158acSJeff Kirsher 	return -ENOMEM;
5488df158acSJeff Kirsher }
5498df158acSJeff Kirsher 
5508df158acSJeff Kirsher /**
5518df158acSJeff Kirsher  * spider_net_get_multicast_hash - generates hash for multicast filter table
552e242d598SLee Jones  * @netdev: interface device structure
5538df158acSJeff Kirsher  * @addr: multicast address
5548df158acSJeff Kirsher  *
5558df158acSJeff Kirsher  * returns the hash value.
5568df158acSJeff Kirsher  *
5578df158acSJeff Kirsher  * spider_net_get_multicast_hash calculates a hash value for a given multicast
5588df158acSJeff Kirsher  * address, that is used to set the multicast filter tables
5598df158acSJeff Kirsher  */
5608df158acSJeff Kirsher static u8
spider_net_get_multicast_hash(struct net_device * netdev,__u8 * addr)5618df158acSJeff Kirsher spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
5628df158acSJeff Kirsher {
5638df158acSJeff Kirsher 	u32 crc;
5648df158acSJeff Kirsher 	u8 hash;
5658df158acSJeff Kirsher 	char addr_for_crc[ETH_ALEN] = { 0, };
5668df158acSJeff Kirsher 	int i, bit;
5678df158acSJeff Kirsher 
5688df158acSJeff Kirsher 	for (i = 0; i < ETH_ALEN * 8; i++) {
5698df158acSJeff Kirsher 		bit = (addr[i / 8] >> (i % 8)) & 1;
5708df158acSJeff Kirsher 		addr_for_crc[ETH_ALEN - 1 - i / 8] += bit << (7 - (i % 8));
5718df158acSJeff Kirsher 	}
5728df158acSJeff Kirsher 
5738df158acSJeff Kirsher 	crc = crc32_be(~0, addr_for_crc, netdev->addr_len);
5748df158acSJeff Kirsher 
5758df158acSJeff Kirsher 	hash = (crc >> 27);
5768df158acSJeff Kirsher 	hash <<= 3;
5778df158acSJeff Kirsher 	hash |= crc & 7;
5788df158acSJeff Kirsher 	hash &= 0xff;
5798df158acSJeff Kirsher 
5808df158acSJeff Kirsher 	return hash;
5818df158acSJeff Kirsher }
5828df158acSJeff Kirsher 
5838df158acSJeff Kirsher /**
5848df158acSJeff Kirsher  * spider_net_set_multi - sets multicast addresses and promisc flags
5858df158acSJeff Kirsher  * @netdev: interface device structure
5868df158acSJeff Kirsher  *
5878df158acSJeff Kirsher  * spider_net_set_multi configures multicast addresses as needed for the
5888df158acSJeff Kirsher  * netdev interface. It also sets up multicast, allmulti and promisc
5898df158acSJeff Kirsher  * flags appropriately
5908df158acSJeff Kirsher  */
5918df158acSJeff Kirsher static void
spider_net_set_multi(struct net_device * netdev)5928df158acSJeff Kirsher spider_net_set_multi(struct net_device *netdev)
5938df158acSJeff Kirsher {
5948df158acSJeff Kirsher 	struct netdev_hw_addr *ha;
5958df158acSJeff Kirsher 	u8 hash;
5968df158acSJeff Kirsher 	int i;
5978df158acSJeff Kirsher 	u32 reg;
5988df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
599699e53e4SChristophe JAILLET 	DECLARE_BITMAP(bitmask, SPIDER_NET_MULTICAST_HASHES);
6008df158acSJeff Kirsher 
6018df158acSJeff Kirsher 	spider_net_set_promisc(card);
6028df158acSJeff Kirsher 
6038df158acSJeff Kirsher 	if (netdev->flags & IFF_ALLMULTI) {
604699e53e4SChristophe JAILLET 		bitmap_fill(bitmask, SPIDER_NET_MULTICAST_HASHES);
6058df158acSJeff Kirsher 		goto write_hash;
6068df158acSJeff Kirsher 	}
6078df158acSJeff Kirsher 
608699e53e4SChristophe JAILLET 	bitmap_zero(bitmask, SPIDER_NET_MULTICAST_HASHES);
609699e53e4SChristophe JAILLET 
6108df158acSJeff Kirsher 	/* well, we know, what the broadcast hash value is: it's xfd
6118df158acSJeff Kirsher 	hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
612699e53e4SChristophe JAILLET 	__set_bit(0xfd, bitmask);
6138df158acSJeff Kirsher 
6148df158acSJeff Kirsher 	netdev_for_each_mc_addr(ha, netdev) {
6158df158acSJeff Kirsher 		hash = spider_net_get_multicast_hash(netdev, ha->addr);
616699e53e4SChristophe JAILLET 		__set_bit(hash, bitmask);
6178df158acSJeff Kirsher 	}
6188df158acSJeff Kirsher 
6198df158acSJeff Kirsher write_hash:
6208df158acSJeff Kirsher 	for (i = 0; i < SPIDER_NET_MULTICAST_HASHES / 4; i++) {
6218df158acSJeff Kirsher 		reg = 0;
6228df158acSJeff Kirsher 		if (test_bit(i * 4, bitmask))
6238df158acSJeff Kirsher 			reg += 0x08;
6248df158acSJeff Kirsher 		reg <<= 8;
6258df158acSJeff Kirsher 		if (test_bit(i * 4 + 1, bitmask))
6268df158acSJeff Kirsher 			reg += 0x08;
6278df158acSJeff Kirsher 		reg <<= 8;
6288df158acSJeff Kirsher 		if (test_bit(i * 4 + 2, bitmask))
6298df158acSJeff Kirsher 			reg += 0x08;
6308df158acSJeff Kirsher 		reg <<= 8;
6318df158acSJeff Kirsher 		if (test_bit(i * 4 + 3, bitmask))
6328df158acSJeff Kirsher 			reg += 0x08;
6338df158acSJeff Kirsher 
6348df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMRMHFILnR + i * 4, reg);
6358df158acSJeff Kirsher 	}
6368df158acSJeff Kirsher }
6378df158acSJeff Kirsher 
6388df158acSJeff Kirsher /**
6398df158acSJeff Kirsher  * spider_net_prepare_tx_descr - fill tx descriptor with skb data
6408df158acSJeff Kirsher  * @card: card structure
6418df158acSJeff Kirsher  * @skb: packet to use
6428df158acSJeff Kirsher  *
6438df158acSJeff Kirsher  * returns 0 on success, <0 on failure.
6448df158acSJeff Kirsher  *
6458df158acSJeff Kirsher  * fills out the descriptor structure with skb data and len. Copies data,
6468df158acSJeff Kirsher  * if needed (32bit DMA!)
6478df158acSJeff Kirsher  */
6488df158acSJeff Kirsher static int
spider_net_prepare_tx_descr(struct spider_net_card * card,struct sk_buff * skb)6498df158acSJeff Kirsher spider_net_prepare_tx_descr(struct spider_net_card *card,
6508df158acSJeff Kirsher 			    struct sk_buff *skb)
6518df158acSJeff Kirsher {
6528df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->tx_chain;
6538df158acSJeff Kirsher 	struct spider_net_descr *descr;
6548df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr;
6558df158acSJeff Kirsher 	dma_addr_t buf;
6568df158acSJeff Kirsher 	unsigned long flags;
6578df158acSJeff Kirsher 
65827d57f85SChristophe JAILLET 	buf = dma_map_single(&card->pdev->dev, skb->data, skb->len,
65927d57f85SChristophe JAILLET 			     DMA_TO_DEVICE);
66027d57f85SChristophe JAILLET 	if (dma_mapping_error(&card->pdev->dev, buf)) {
6618df158acSJeff Kirsher 		if (netif_msg_tx_err(card) && net_ratelimit())
6628df158acSJeff Kirsher 			dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
6638df158acSJeff Kirsher 				  "Dropping packet\n", skb->data, skb->len);
6648df158acSJeff Kirsher 		card->spider_stats.tx_iommu_map_error++;
6658df158acSJeff Kirsher 		return -ENOMEM;
6668df158acSJeff Kirsher 	}
6678df158acSJeff Kirsher 
6688df158acSJeff Kirsher 	spin_lock_irqsave(&chain->lock, flags);
6698df158acSJeff Kirsher 	descr = card->tx_chain.head;
6708df158acSJeff Kirsher 	if (descr->next == chain->tail->prev) {
6718df158acSJeff Kirsher 		spin_unlock_irqrestore(&chain->lock, flags);
67227d57f85SChristophe JAILLET 		dma_unmap_single(&card->pdev->dev, buf, skb->len,
67327d57f85SChristophe JAILLET 				 DMA_TO_DEVICE);
6748df158acSJeff Kirsher 		return -ENOMEM;
6758df158acSJeff Kirsher 	}
6768df158acSJeff Kirsher 	hwdescr = descr->hwdescr;
6778df158acSJeff Kirsher 	chain->head = descr->next;
6788df158acSJeff Kirsher 
6798df158acSJeff Kirsher 	descr->skb = skb;
6808df158acSJeff Kirsher 	hwdescr->buf_addr = buf;
6818df158acSJeff Kirsher 	hwdescr->buf_size = skb->len;
6828df158acSJeff Kirsher 	hwdescr->next_descr_addr = 0;
6838df158acSJeff Kirsher 	hwdescr->data_status = 0;
6848df158acSJeff Kirsher 
6858df158acSJeff Kirsher 	hwdescr->dmac_cmd_status =
6868df158acSJeff Kirsher 			SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
6878df158acSJeff Kirsher 	spin_unlock_irqrestore(&chain->lock, flags);
6888df158acSJeff Kirsher 
6898df158acSJeff Kirsher 	if (skb->ip_summed == CHECKSUM_PARTIAL)
6908df158acSJeff Kirsher 		switch (ip_hdr(skb)->protocol) {
6918df158acSJeff Kirsher 		case IPPROTO_TCP:
6928df158acSJeff Kirsher 			hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
6938df158acSJeff Kirsher 			break;
6948df158acSJeff Kirsher 		case IPPROTO_UDP:
6958df158acSJeff Kirsher 			hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
6968df158acSJeff Kirsher 			break;
6978df158acSJeff Kirsher 		}
6988df158acSJeff Kirsher 
6998df158acSJeff Kirsher 	/* Chain the bus address, so that the DMA engine finds this descr. */
7008df158acSJeff Kirsher 	wmb();
7018df158acSJeff Kirsher 	descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
7028df158acSJeff Kirsher 
703860e9538SFlorian Westphal 	netif_trans_update(card->netdev); /* set netdev watchdog timer */
7048df158acSJeff Kirsher 	return 0;
7058df158acSJeff Kirsher }
7068df158acSJeff Kirsher 
7078df158acSJeff Kirsher static int
spider_net_set_low_watermark(struct spider_net_card * card)7088df158acSJeff Kirsher spider_net_set_low_watermark(struct spider_net_card *card)
7098df158acSJeff Kirsher {
7108df158acSJeff Kirsher 	struct spider_net_descr *descr = card->tx_chain.tail;
7118df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr;
7128df158acSJeff Kirsher 	unsigned long flags;
7138df158acSJeff Kirsher 	int status;
7148df158acSJeff Kirsher 	int cnt=0;
7158df158acSJeff Kirsher 	int i;
7168df158acSJeff Kirsher 
7178df158acSJeff Kirsher 	/* Measure the length of the queue. Measurement does not
718142c1d2eSYixing Liu 	 * need to be precise -- does not need a lock.
719142c1d2eSYixing Liu 	 */
7208df158acSJeff Kirsher 	while (descr != card->tx_chain.head) {
7218df158acSJeff Kirsher 		status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
7228df158acSJeff Kirsher 		if (status == SPIDER_NET_DESCR_NOT_IN_USE)
7238df158acSJeff Kirsher 			break;
7248df158acSJeff Kirsher 		descr = descr->next;
7258df158acSJeff Kirsher 		cnt++;
7268df158acSJeff Kirsher 	}
7278df158acSJeff Kirsher 
7288df158acSJeff Kirsher 	/* If TX queue is short, don't even bother with interrupts */
7298df158acSJeff Kirsher 	if (cnt < card->tx_chain.num_desc/4)
7308df158acSJeff Kirsher 		return cnt;
7318df158acSJeff Kirsher 
7328df158acSJeff Kirsher 	/* Set low-watermark 3/4th's of the way into the queue. */
7338df158acSJeff Kirsher 	descr = card->tx_chain.tail;
7348df158acSJeff Kirsher 	cnt = (cnt*3)/4;
7358df158acSJeff Kirsher 	for (i=0;i<cnt; i++)
7368df158acSJeff Kirsher 		descr = descr->next;
7378df158acSJeff Kirsher 
7388df158acSJeff Kirsher 	/* Set the new watermark, clear the old watermark */
7398df158acSJeff Kirsher 	spin_lock_irqsave(&card->tx_chain.lock, flags);
7408df158acSJeff Kirsher 	descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
7418df158acSJeff Kirsher 	if (card->low_watermark && card->low_watermark != descr) {
7428df158acSJeff Kirsher 		hwdescr = card->low_watermark->hwdescr;
7438df158acSJeff Kirsher 		hwdescr->dmac_cmd_status =
7448df158acSJeff Kirsher 		     hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
7458df158acSJeff Kirsher 	}
7468df158acSJeff Kirsher 	card->low_watermark = descr;
7478df158acSJeff Kirsher 	spin_unlock_irqrestore(&card->tx_chain.lock, flags);
7488df158acSJeff Kirsher 	return cnt;
7498df158acSJeff Kirsher }
7508df158acSJeff Kirsher 
7518df158acSJeff Kirsher /**
7528df158acSJeff Kirsher  * spider_net_release_tx_chain - processes sent tx descriptors
7538df158acSJeff Kirsher  * @card: adapter structure
7548df158acSJeff Kirsher  * @brutal: if set, don't care about whether descriptor seems to be in use
7558df158acSJeff Kirsher  *
7568df158acSJeff Kirsher  * returns 0 if the tx ring is empty, otherwise 1.
7578df158acSJeff Kirsher  *
7588df158acSJeff Kirsher  * spider_net_release_tx_chain releases the tx descriptors that spider has
7598df158acSJeff Kirsher  * finished with (if non-brutal) or simply release tx descriptors (if brutal).
7608df158acSJeff Kirsher  * If some other context is calling this function, we return 1 so that we're
7618df158acSJeff Kirsher  * scheduled again (if we were scheduled) and will not lose initiative.
7628df158acSJeff Kirsher  */
7638df158acSJeff Kirsher static int
spider_net_release_tx_chain(struct spider_net_card * card,int brutal)7648df158acSJeff Kirsher spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
7658df158acSJeff Kirsher {
7668df158acSJeff Kirsher 	struct net_device *dev = card->netdev;
7678df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->tx_chain;
7688df158acSJeff Kirsher 	struct spider_net_descr *descr;
7698df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr;
7708df158acSJeff Kirsher 	struct sk_buff *skb;
7718df158acSJeff Kirsher 	u32 buf_addr;
7728df158acSJeff Kirsher 	unsigned long flags;
7738df158acSJeff Kirsher 	int status;
7748df158acSJeff Kirsher 
7758df158acSJeff Kirsher 	while (1) {
7768df158acSJeff Kirsher 		spin_lock_irqsave(&chain->lock, flags);
7778df158acSJeff Kirsher 		if (chain->tail == chain->head) {
7788df158acSJeff Kirsher 			spin_unlock_irqrestore(&chain->lock, flags);
7798df158acSJeff Kirsher 			return 0;
7808df158acSJeff Kirsher 		}
7818df158acSJeff Kirsher 		descr = chain->tail;
7828df158acSJeff Kirsher 		hwdescr = descr->hwdescr;
7838df158acSJeff Kirsher 
7848df158acSJeff Kirsher 		status = spider_net_get_descr_status(hwdescr);
7858df158acSJeff Kirsher 		switch (status) {
7868df158acSJeff Kirsher 		case SPIDER_NET_DESCR_COMPLETE:
7878df158acSJeff Kirsher 			dev->stats.tx_packets++;
7888df158acSJeff Kirsher 			dev->stats.tx_bytes += descr->skb->len;
7898df158acSJeff Kirsher 			break;
7908df158acSJeff Kirsher 
7918df158acSJeff Kirsher 		case SPIDER_NET_DESCR_CARDOWNED:
7928df158acSJeff Kirsher 			if (!brutal) {
7938df158acSJeff Kirsher 				spin_unlock_irqrestore(&chain->lock, flags);
7948df158acSJeff Kirsher 				return 1;
7958df158acSJeff Kirsher 			}
7968df158acSJeff Kirsher 
7978df158acSJeff Kirsher 			/* fallthrough, if we release the descriptors
7988df158acSJeff Kirsher 			 * brutally (then we don't care about
799142c1d2eSYixing Liu 			 * SPIDER_NET_DESCR_CARDOWNED)
800142c1d2eSYixing Liu 			 */
801df561f66SGustavo A. R. Silva 			fallthrough;
8028df158acSJeff Kirsher 
8038df158acSJeff Kirsher 		case SPIDER_NET_DESCR_RESPONSE_ERROR:
8048df158acSJeff Kirsher 		case SPIDER_NET_DESCR_PROTECTION_ERROR:
8058df158acSJeff Kirsher 		case SPIDER_NET_DESCR_FORCE_END:
8068df158acSJeff Kirsher 			if (netif_msg_tx_err(card))
8078df158acSJeff Kirsher 				dev_err(&card->netdev->dev, "forcing end of tx descriptor "
8088df158acSJeff Kirsher 				       "with status x%02x\n", status);
8098df158acSJeff Kirsher 			dev->stats.tx_errors++;
8108df158acSJeff Kirsher 			break;
8118df158acSJeff Kirsher 
8128df158acSJeff Kirsher 		default:
8138df158acSJeff Kirsher 			dev->stats.tx_dropped++;
8148df158acSJeff Kirsher 			if (!brutal) {
8158df158acSJeff Kirsher 				spin_unlock_irqrestore(&chain->lock, flags);
8168df158acSJeff Kirsher 				return 1;
8178df158acSJeff Kirsher 			}
8188df158acSJeff Kirsher 		}
8198df158acSJeff Kirsher 
8208df158acSJeff Kirsher 		chain->tail = descr->next;
8218df158acSJeff Kirsher 		hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
8228df158acSJeff Kirsher 		skb = descr->skb;
8238df158acSJeff Kirsher 		descr->skb = NULL;
8248df158acSJeff Kirsher 		buf_addr = hwdescr->buf_addr;
8258df158acSJeff Kirsher 		spin_unlock_irqrestore(&chain->lock, flags);
8268df158acSJeff Kirsher 
8278df158acSJeff Kirsher 		/* unmap the skb */
8288df158acSJeff Kirsher 		if (skb) {
82927d57f85SChristophe JAILLET 			dma_unmap_single(&card->pdev->dev, buf_addr, skb->len,
83027d57f85SChristophe JAILLET 					 DMA_TO_DEVICE);
83120eca054SEric W. Biederman 			dev_consume_skb_any(skb);
8328df158acSJeff Kirsher 		}
8338df158acSJeff Kirsher 	}
8348df158acSJeff Kirsher 	return 0;
8358df158acSJeff Kirsher }
8368df158acSJeff Kirsher 
8378df158acSJeff Kirsher /**
8388df158acSJeff Kirsher  * spider_net_kick_tx_dma - enables TX DMA processing
8398df158acSJeff Kirsher  * @card: card structure
8408df158acSJeff Kirsher  *
8418df158acSJeff Kirsher  * This routine will start the transmit DMA running if
8428df158acSJeff Kirsher  * it is not already running. This routine ned only be
8438df158acSJeff Kirsher  * called when queueing a new packet to an empty tx queue.
8448df158acSJeff Kirsher  * Writes the current tx chain head as start address
8458df158acSJeff Kirsher  * of the tx descriptor chain and enables the transmission
8468df158acSJeff Kirsher  * DMA engine.
8478df158acSJeff Kirsher  */
8488df158acSJeff Kirsher static inline void
spider_net_kick_tx_dma(struct spider_net_card * card)8498df158acSJeff Kirsher spider_net_kick_tx_dma(struct spider_net_card *card)
8508df158acSJeff Kirsher {
8518df158acSJeff Kirsher 	struct spider_net_descr *descr;
8528df158acSJeff Kirsher 
8538df158acSJeff Kirsher 	if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) &
8548df158acSJeff Kirsher 			SPIDER_NET_TX_DMA_EN)
8558df158acSJeff Kirsher 		goto out;
8568df158acSJeff Kirsher 
8578df158acSJeff Kirsher 	descr = card->tx_chain.tail;
8588df158acSJeff Kirsher 	for (;;) {
8598df158acSJeff Kirsher 		if (spider_net_get_descr_status(descr->hwdescr) ==
8608df158acSJeff Kirsher 				SPIDER_NET_DESCR_CARDOWNED) {
8618df158acSJeff Kirsher 			spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
8628df158acSJeff Kirsher 					descr->bus_addr);
8638df158acSJeff Kirsher 			spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
8648df158acSJeff Kirsher 					SPIDER_NET_DMA_TX_VALUE);
8658df158acSJeff Kirsher 			break;
8668df158acSJeff Kirsher 		}
8678df158acSJeff Kirsher 		if (descr == card->tx_chain.head)
8688df158acSJeff Kirsher 			break;
8698df158acSJeff Kirsher 		descr = descr->next;
8708df158acSJeff Kirsher 	}
8718df158acSJeff Kirsher 
8728df158acSJeff Kirsher out:
8738df158acSJeff Kirsher 	mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
8748df158acSJeff Kirsher }
8758df158acSJeff Kirsher 
8768df158acSJeff Kirsher /**
8778df158acSJeff Kirsher  * spider_net_xmit - transmits a frame over the device
8788df158acSJeff Kirsher  * @skb: packet to send out
8798df158acSJeff Kirsher  * @netdev: interface device structure
8808df158acSJeff Kirsher  *
881bacade82SYueHaibing  * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure
8828df158acSJeff Kirsher  */
883bacade82SYueHaibing static netdev_tx_t
spider_net_xmit(struct sk_buff * skb,struct net_device * netdev)8848df158acSJeff Kirsher spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
8858df158acSJeff Kirsher {
8868df158acSJeff Kirsher 	int cnt;
8878df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
8888df158acSJeff Kirsher 
8898df158acSJeff Kirsher 	spider_net_release_tx_chain(card, 0);
8908df158acSJeff Kirsher 
8918df158acSJeff Kirsher 	if (spider_net_prepare_tx_descr(card, skb) != 0) {
8928df158acSJeff Kirsher 		netdev->stats.tx_dropped++;
8938df158acSJeff Kirsher 		netif_stop_queue(netdev);
8948df158acSJeff Kirsher 		return NETDEV_TX_BUSY;
8958df158acSJeff Kirsher 	}
8968df158acSJeff Kirsher 
8978df158acSJeff Kirsher 	cnt = spider_net_set_low_watermark(card);
8988df158acSJeff Kirsher 	if (cnt < 5)
8998df158acSJeff Kirsher 		spider_net_kick_tx_dma(card);
9008df158acSJeff Kirsher 	return NETDEV_TX_OK;
9018df158acSJeff Kirsher }
9028df158acSJeff Kirsher 
9038df158acSJeff Kirsher /**
9048df158acSJeff Kirsher  * spider_net_cleanup_tx_ring - cleans up the TX ring
905e242d598SLee Jones  * @t: timer context used to obtain the pointer to net card data structure
9068df158acSJeff Kirsher  *
9078df158acSJeff Kirsher  * spider_net_cleanup_tx_ring is called by either the tx_timer
9088df158acSJeff Kirsher  * or from the NAPI polling routine.
9098df158acSJeff Kirsher  * This routine releases resources associted with transmitted
9108df158acSJeff Kirsher  * packets, including updating the queue tail pointer.
9118df158acSJeff Kirsher  */
9128df158acSJeff Kirsher static void
spider_net_cleanup_tx_ring(struct timer_list * t)913e99e88a9SKees Cook spider_net_cleanup_tx_ring(struct timer_list *t)
9148df158acSJeff Kirsher {
915e99e88a9SKees Cook 	struct spider_net_card *card = from_timer(card, t, tx_timer);
9168df158acSJeff Kirsher 	if ((spider_net_release_tx_chain(card, 0) != 0) &&
9178df158acSJeff Kirsher 	    (card->netdev->flags & IFF_UP)) {
9188df158acSJeff Kirsher 		spider_net_kick_tx_dma(card);
9198df158acSJeff Kirsher 		netif_wake_queue(card->netdev);
9208df158acSJeff Kirsher 	}
9218df158acSJeff Kirsher }
9228df158acSJeff Kirsher 
9238df158acSJeff Kirsher /**
9248df158acSJeff Kirsher  * spider_net_do_ioctl - called for device ioctls
9258df158acSJeff Kirsher  * @netdev: interface device structure
9268df158acSJeff Kirsher  * @ifr: request parameter structure for ioctl
9278df158acSJeff Kirsher  * @cmd: command code for ioctl
9288df158acSJeff Kirsher  *
9298df158acSJeff Kirsher  * returns 0 on success, <0 on failure. Currently, we have no special ioctls.
9308df158acSJeff Kirsher  * -EOPNOTSUPP is returned, if an unknown ioctl was requested
9318df158acSJeff Kirsher  */
9328df158acSJeff Kirsher static int
spider_net_do_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)9338df158acSJeff Kirsher spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
9348df158acSJeff Kirsher {
9358df158acSJeff Kirsher 	switch (cmd) {
9368df158acSJeff Kirsher 	default:
9378df158acSJeff Kirsher 		return -EOPNOTSUPP;
9388df158acSJeff Kirsher 	}
9398df158acSJeff Kirsher }
9408df158acSJeff Kirsher 
9418df158acSJeff Kirsher /**
9428df158acSJeff Kirsher  * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
9438df158acSJeff Kirsher  * @descr: descriptor to process
9448df158acSJeff Kirsher  * @card: card structure
9458df158acSJeff Kirsher  *
9468df158acSJeff Kirsher  * Fills out skb structure and passes the data to the stack.
9478df158acSJeff Kirsher  * The descriptor state is not changed.
9488df158acSJeff Kirsher  */
9498df158acSJeff Kirsher static void
spider_net_pass_skb_up(struct spider_net_descr * descr,struct spider_net_card * card)9508df158acSJeff Kirsher spider_net_pass_skb_up(struct spider_net_descr *descr,
9518df158acSJeff Kirsher 		       struct spider_net_card *card)
9528df158acSJeff Kirsher {
9538df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr = descr->hwdescr;
9548df158acSJeff Kirsher 	struct sk_buff *skb = descr->skb;
9558df158acSJeff Kirsher 	struct net_device *netdev = card->netdev;
9568df158acSJeff Kirsher 	u32 data_status = hwdescr->data_status;
9578df158acSJeff Kirsher 	u32 data_error = hwdescr->data_error;
9588df158acSJeff Kirsher 
9598df158acSJeff Kirsher 	skb_put(skb, hwdescr->valid_size);
9608df158acSJeff Kirsher 
9618df158acSJeff Kirsher 	/* the card seems to add 2 bytes of junk in front
962142c1d2eSYixing Liu 	 * of the ethernet frame
963142c1d2eSYixing Liu 	 */
9648df158acSJeff Kirsher #define SPIDER_MISALIGN		2
9658df158acSJeff Kirsher 	skb_pull(skb, SPIDER_MISALIGN);
9668df158acSJeff Kirsher 	skb->protocol = eth_type_trans(skb, netdev);
9678df158acSJeff Kirsher 
9688df158acSJeff Kirsher 	/* checksum offload */
9698df158acSJeff Kirsher 	skb_checksum_none_assert(skb);
9708df158acSJeff Kirsher 	if (netdev->features & NETIF_F_RXCSUM) {
9718df158acSJeff Kirsher 		if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) ==
9728df158acSJeff Kirsher 		       SPIDER_NET_DATA_STATUS_CKSUM_MASK) &&
9738df158acSJeff Kirsher 		     !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
9748df158acSJeff Kirsher 			skb->ip_summed = CHECKSUM_UNNECESSARY;
9758df158acSJeff Kirsher 	}
9768df158acSJeff Kirsher 
9778df158acSJeff Kirsher 	if (data_status & SPIDER_NET_VLAN_PACKET) {
9788df158acSJeff Kirsher 		/* further enhancements: HW-accel VLAN */
9798df158acSJeff Kirsher 	}
9808df158acSJeff Kirsher 
9818df158acSJeff Kirsher 	/* update netdevice statistics */
9828df158acSJeff Kirsher 	netdev->stats.rx_packets++;
9838df158acSJeff Kirsher 	netdev->stats.rx_bytes += skb->len;
9848df158acSJeff Kirsher 
9858df158acSJeff Kirsher 	/* pass skb up to stack */
9868df158acSJeff Kirsher 	netif_receive_skb(skb);
9878df158acSJeff Kirsher }
9888df158acSJeff Kirsher 
show_rx_chain(struct spider_net_card * card)9898df158acSJeff Kirsher static void show_rx_chain(struct spider_net_card *card)
9908df158acSJeff Kirsher {
9918df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
9928df158acSJeff Kirsher 	struct spider_net_descr *start= chain->tail;
9938df158acSJeff Kirsher 	struct spider_net_descr *descr= start;
9948df158acSJeff Kirsher 	struct spider_net_hw_descr *hwd = start->hwdescr;
9958df158acSJeff Kirsher 	struct device *dev = &card->netdev->dev;
9968df158acSJeff Kirsher 	u32 curr_desc, next_desc;
9978df158acSJeff Kirsher 	int status;
9988df158acSJeff Kirsher 
9998df158acSJeff Kirsher 	int tot = 0;
10008df158acSJeff Kirsher 	int cnt = 0;
10018df158acSJeff Kirsher 	int off = start - chain->ring;
10028df158acSJeff Kirsher 	int cstat = hwd->dmac_cmd_status;
10038df158acSJeff Kirsher 
10048df158acSJeff Kirsher 	dev_info(dev, "Total number of descrs=%d\n",
10058df158acSJeff Kirsher 		chain->num_desc);
10068df158acSJeff Kirsher 	dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
10078df158acSJeff Kirsher 		off, cstat);
10088df158acSJeff Kirsher 
10098df158acSJeff Kirsher 	curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
10108df158acSJeff Kirsher 	next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
10118df158acSJeff Kirsher 
10128df158acSJeff Kirsher 	status = cstat;
10138df158acSJeff Kirsher 	do
10148df158acSJeff Kirsher 	{
10158df158acSJeff Kirsher 		hwd = descr->hwdescr;
10168df158acSJeff Kirsher 		off = descr - chain->ring;
10178df158acSJeff Kirsher 		status = hwd->dmac_cmd_status;
10188df158acSJeff Kirsher 
10198df158acSJeff Kirsher 		if (descr == chain->head)
10208df158acSJeff Kirsher 			dev_info(dev, "Chain head is at %d, head status=0x%x\n",
10218df158acSJeff Kirsher 			         off, status);
10228df158acSJeff Kirsher 
10238df158acSJeff Kirsher 		if (curr_desc == descr->bus_addr)
10248df158acSJeff Kirsher 			dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
10258df158acSJeff Kirsher 			         off, status);
10268df158acSJeff Kirsher 
10278df158acSJeff Kirsher 		if (next_desc == descr->bus_addr)
10288df158acSJeff Kirsher 			dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
10298df158acSJeff Kirsher 			         off, status);
10308df158acSJeff Kirsher 
10318df158acSJeff Kirsher 		if (hwd->next_descr_addr == 0)
10328df158acSJeff Kirsher 			dev_info(dev, "chain is cut at %d\n", off);
10338df158acSJeff Kirsher 
10348df158acSJeff Kirsher 		if (cstat != status) {
10358df158acSJeff Kirsher 			int from = (chain->num_desc + off - cnt) % chain->num_desc;
10368df158acSJeff Kirsher 			int to = (chain->num_desc + off - 1) % chain->num_desc;
10378df158acSJeff Kirsher 			dev_info(dev, "Have %d (from %d to %d) descrs "
10388df158acSJeff Kirsher 			         "with stat=0x%08x\n", cnt, from, to, cstat);
10398df158acSJeff Kirsher 			cstat = status;
10408df158acSJeff Kirsher 			cnt = 0;
10418df158acSJeff Kirsher 		}
10428df158acSJeff Kirsher 
10438df158acSJeff Kirsher 		cnt ++;
10448df158acSJeff Kirsher 		tot ++;
10458df158acSJeff Kirsher 		descr = descr->next;
10468df158acSJeff Kirsher 	} while (descr != start);
10478df158acSJeff Kirsher 
10488df158acSJeff Kirsher 	dev_info(dev, "Last %d descrs with stat=0x%08x "
10498df158acSJeff Kirsher 	         "for a total of %d descrs\n", cnt, cstat, tot);
10508df158acSJeff Kirsher 
10518df158acSJeff Kirsher #ifdef DEBUG
10528df158acSJeff Kirsher 	/* Now dump the whole ring */
10538df158acSJeff Kirsher 	descr = start;
10548df158acSJeff Kirsher 	do
10558df158acSJeff Kirsher 	{
10568df158acSJeff Kirsher 		struct spider_net_hw_descr *hwd = descr->hwdescr;
10578df158acSJeff Kirsher 		status = spider_net_get_descr_status(hwd);
10588df158acSJeff Kirsher 		cnt = descr - chain->ring;
10598df158acSJeff Kirsher 		dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
10608df158acSJeff Kirsher 		         cnt, status, descr->skb);
10618df158acSJeff Kirsher 		dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
10628df158acSJeff Kirsher 		         descr->bus_addr, hwd->buf_addr, hwd->buf_size);
10638df158acSJeff Kirsher 		dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
10648df158acSJeff Kirsher 		         hwd->next_descr_addr, hwd->result_size,
10658df158acSJeff Kirsher 		         hwd->valid_size);
10668df158acSJeff Kirsher 		dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
10678df158acSJeff Kirsher 		         hwd->dmac_cmd_status, hwd->data_status,
10688df158acSJeff Kirsher 		         hwd->data_error);
10698df158acSJeff Kirsher 		dev_info(dev, "\n");
10708df158acSJeff Kirsher 
10718df158acSJeff Kirsher 		descr = descr->next;
10728df158acSJeff Kirsher 	} while (descr != start);
10738df158acSJeff Kirsher #endif
10748df158acSJeff Kirsher 
10758df158acSJeff Kirsher }
10768df158acSJeff Kirsher 
10778df158acSJeff Kirsher /**
10788df158acSJeff Kirsher  * spider_net_resync_head_ptr - Advance head ptr past empty descrs
1079e242d598SLee Jones  * @card: card structure
10808df158acSJeff Kirsher  *
10818df158acSJeff Kirsher  * If the driver fails to keep up and empty the queue, then the
10828df158acSJeff Kirsher  * hardware wil run out of room to put incoming packets. This
10838df158acSJeff Kirsher  * will cause the hardware to skip descrs that are full (instead
10848df158acSJeff Kirsher  * of halting/retrying). Thus, once the driver runs, it wil need
10858df158acSJeff Kirsher  * to "catch up" to where the hardware chain pointer is at.
10868df158acSJeff Kirsher  */
spider_net_resync_head_ptr(struct spider_net_card * card)10878df158acSJeff Kirsher static void spider_net_resync_head_ptr(struct spider_net_card *card)
10888df158acSJeff Kirsher {
10898df158acSJeff Kirsher 	unsigned long flags;
10908df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
10918df158acSJeff Kirsher 	struct spider_net_descr *descr;
10928df158acSJeff Kirsher 	int i, status;
10938df158acSJeff Kirsher 
10948df158acSJeff Kirsher 	/* Advance head pointer past any empty descrs */
10958df158acSJeff Kirsher 	descr = chain->head;
10968df158acSJeff Kirsher 	status = spider_net_get_descr_status(descr->hwdescr);
10978df158acSJeff Kirsher 
10988df158acSJeff Kirsher 	if (status == SPIDER_NET_DESCR_NOT_IN_USE)
10998df158acSJeff Kirsher 		return;
11008df158acSJeff Kirsher 
11018df158acSJeff Kirsher 	spin_lock_irqsave(&chain->lock, flags);
11028df158acSJeff Kirsher 
11038df158acSJeff Kirsher 	descr = chain->head;
11048df158acSJeff Kirsher 	status = spider_net_get_descr_status(descr->hwdescr);
11058df158acSJeff Kirsher 	for (i=0; i<chain->num_desc; i++) {
11068df158acSJeff Kirsher 		if (status != SPIDER_NET_DESCR_CARDOWNED) break;
11078df158acSJeff Kirsher 		descr = descr->next;
11088df158acSJeff Kirsher 		status = spider_net_get_descr_status(descr->hwdescr);
11098df158acSJeff Kirsher 	}
11108df158acSJeff Kirsher 	chain->head = descr;
11118df158acSJeff Kirsher 
11128df158acSJeff Kirsher 	spin_unlock_irqrestore(&chain->lock, flags);
11138df158acSJeff Kirsher }
11148df158acSJeff Kirsher 
spider_net_resync_tail_ptr(struct spider_net_card * card)11158df158acSJeff Kirsher static int spider_net_resync_tail_ptr(struct spider_net_card *card)
11168df158acSJeff Kirsher {
11178df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
11188df158acSJeff Kirsher 	struct spider_net_descr *descr;
11198df158acSJeff Kirsher 	int i, status;
11208df158acSJeff Kirsher 
11218df158acSJeff Kirsher 	/* Advance tail pointer past any empty and reaped descrs */
11228df158acSJeff Kirsher 	descr = chain->tail;
11238df158acSJeff Kirsher 	status = spider_net_get_descr_status(descr->hwdescr);
11248df158acSJeff Kirsher 
11258df158acSJeff Kirsher 	for (i=0; i<chain->num_desc; i++) {
11268df158acSJeff Kirsher 		if ((status != SPIDER_NET_DESCR_CARDOWNED) &&
11278df158acSJeff Kirsher 		    (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;
11288df158acSJeff Kirsher 		descr = descr->next;
11298df158acSJeff Kirsher 		status = spider_net_get_descr_status(descr->hwdescr);
11308df158acSJeff Kirsher 	}
11318df158acSJeff Kirsher 	chain->tail = descr;
11328df158acSJeff Kirsher 
11338df158acSJeff Kirsher 	if ((i == chain->num_desc) || (i == 0))
11348df158acSJeff Kirsher 		return 1;
11358df158acSJeff Kirsher 	return 0;
11368df158acSJeff Kirsher }
11378df158acSJeff Kirsher 
11388df158acSJeff Kirsher /**
11398df158acSJeff Kirsher  * spider_net_decode_one_descr - processes an RX descriptor
11408df158acSJeff Kirsher  * @card: card structure
11418df158acSJeff Kirsher  *
11428df158acSJeff Kirsher  * Returns 1 if a packet has been sent to the stack, otherwise 0.
11438df158acSJeff Kirsher  *
11448df158acSJeff Kirsher  * Processes an RX descriptor by iommu-unmapping the data buffer
11458df158acSJeff Kirsher  * and passing the packet up to the stack. This function is called
11468df158acSJeff Kirsher  * in softirq context, e.g. either bottom half from interrupt or
11478df158acSJeff Kirsher  * NAPI polling context.
11488df158acSJeff Kirsher  */
11498df158acSJeff Kirsher static int
spider_net_decode_one_descr(struct spider_net_card * card)11508df158acSJeff Kirsher spider_net_decode_one_descr(struct spider_net_card *card)
11518df158acSJeff Kirsher {
11528df158acSJeff Kirsher 	struct net_device *dev = card->netdev;
11538df158acSJeff Kirsher 	struct spider_net_descr_chain *chain = &card->rx_chain;
11548df158acSJeff Kirsher 	struct spider_net_descr *descr = chain->tail;
11558df158acSJeff Kirsher 	struct spider_net_hw_descr *hwdescr = descr->hwdescr;
11568df158acSJeff Kirsher 	u32 hw_buf_addr;
11578df158acSJeff Kirsher 	int status;
11588df158acSJeff Kirsher 
11598df158acSJeff Kirsher 	status = spider_net_get_descr_status(hwdescr);
11608df158acSJeff Kirsher 
11618df158acSJeff Kirsher 	/* Nothing in the descriptor, or ring must be empty */
11628df158acSJeff Kirsher 	if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
11638df158acSJeff Kirsher 	    (status == SPIDER_NET_DESCR_NOT_IN_USE))
11648df158acSJeff Kirsher 		return 0;
11658df158acSJeff Kirsher 
11668df158acSJeff Kirsher 	/* descriptor definitively used -- move on tail */
11678df158acSJeff Kirsher 	chain->tail = descr->next;
11688df158acSJeff Kirsher 
11698df158acSJeff Kirsher 	/* unmap descriptor */
11708df158acSJeff Kirsher 	hw_buf_addr = hwdescr->buf_addr;
11718df158acSJeff Kirsher 	hwdescr->buf_addr = 0xffffffff;
117227d57f85SChristophe JAILLET 	dma_unmap_single(&card->pdev->dev, hw_buf_addr, SPIDER_NET_MAX_FRAME,
117327d57f85SChristophe JAILLET 			 DMA_FROM_DEVICE);
11748df158acSJeff Kirsher 
11758df158acSJeff Kirsher 	if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
11768df158acSJeff Kirsher 	     (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
11778df158acSJeff Kirsher 	     (status == SPIDER_NET_DESCR_FORCE_END) ) {
11788df158acSJeff Kirsher 		if (netif_msg_rx_err(card))
11798df158acSJeff Kirsher 			dev_err(&dev->dev,
11808df158acSJeff Kirsher 			       "dropping RX descriptor with state %d\n", status);
11818df158acSJeff Kirsher 		dev->stats.rx_dropped++;
11828df158acSJeff Kirsher 		goto bad_desc;
11838df158acSJeff Kirsher 	}
11848df158acSJeff Kirsher 
11858df158acSJeff Kirsher 	if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
11868df158acSJeff Kirsher 	     (status != SPIDER_NET_DESCR_FRAME_END) ) {
11878df158acSJeff Kirsher 		if (netif_msg_rx_err(card))
11888df158acSJeff Kirsher 			dev_err(&card->netdev->dev,
11898df158acSJeff Kirsher 			       "RX descriptor with unknown state %d\n", status);
11908df158acSJeff Kirsher 		card->spider_stats.rx_desc_unk_state++;
11918df158acSJeff Kirsher 		goto bad_desc;
11928df158acSJeff Kirsher 	}
11938df158acSJeff Kirsher 
11948df158acSJeff Kirsher 	/* The cases we'll throw away the packet immediately */
11958df158acSJeff Kirsher 	if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
11968df158acSJeff Kirsher 		if (netif_msg_rx_err(card))
11978df158acSJeff Kirsher 			dev_err(&card->netdev->dev,
11988df158acSJeff Kirsher 			       "error in received descriptor found, "
11998df158acSJeff Kirsher 			       "data_status=x%08x, data_error=x%08x\n",
12008df158acSJeff Kirsher 			       hwdescr->data_status, hwdescr->data_error);
12018df158acSJeff Kirsher 		goto bad_desc;
12028df158acSJeff Kirsher 	}
12038df158acSJeff Kirsher 
12048df158acSJeff Kirsher 	if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
12058df158acSJeff Kirsher 		dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
12068df158acSJeff Kirsher 			       hwdescr->dmac_cmd_status);
12078df158acSJeff Kirsher 		pr_err("buf_addr=x%08x\n", hw_buf_addr);
12088df158acSJeff Kirsher 		pr_err("buf_size=x%08x\n", hwdescr->buf_size);
12098df158acSJeff Kirsher 		pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
12108df158acSJeff Kirsher 		pr_err("result_size=x%08x\n", hwdescr->result_size);
12118df158acSJeff Kirsher 		pr_err("valid_size=x%08x\n", hwdescr->valid_size);
12128df158acSJeff Kirsher 		pr_err("data_status=x%08x\n", hwdescr->data_status);
12138df158acSJeff Kirsher 		pr_err("data_error=x%08x\n", hwdescr->data_error);
12148df158acSJeff Kirsher 		pr_err("which=%ld\n", descr - card->rx_chain.ring);
12158df158acSJeff Kirsher 
12168df158acSJeff Kirsher 		card->spider_stats.rx_desc_error++;
12178df158acSJeff Kirsher 		goto bad_desc;
12188df158acSJeff Kirsher 	}
12198df158acSJeff Kirsher 
12208df158acSJeff Kirsher 	/* Ok, we've got a packet in descr */
12218df158acSJeff Kirsher 	spider_net_pass_skb_up(descr, card);
12228df158acSJeff Kirsher 	descr->skb = NULL;
12238df158acSJeff Kirsher 	hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
12248df158acSJeff Kirsher 	return 1;
12258df158acSJeff Kirsher 
12268df158acSJeff Kirsher bad_desc:
12278df158acSJeff Kirsher 	if (netif_msg_rx_err(card))
12288df158acSJeff Kirsher 		show_rx_chain(card);
12298df158acSJeff Kirsher 	dev_kfree_skb_irq(descr->skb);
12308df158acSJeff Kirsher 	descr->skb = NULL;
12318df158acSJeff Kirsher 	hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
12328df158acSJeff Kirsher 	return 0;
12338df158acSJeff Kirsher }
12348df158acSJeff Kirsher 
12358df158acSJeff Kirsher /**
12368df158acSJeff Kirsher  * spider_net_poll - NAPI poll function called by the stack to return packets
1237e242d598SLee Jones  * @napi: napi device structure
12388df158acSJeff Kirsher  * @budget: number of packets we can pass to the stack at most
12398df158acSJeff Kirsher  *
12408df158acSJeff Kirsher  * returns 0 if no more packets available to the driver/stack. Returns 1,
12418df158acSJeff Kirsher  * if the quota is exceeded, but the driver has still packets.
12428df158acSJeff Kirsher  *
12438df158acSJeff Kirsher  * spider_net_poll returns all packets from the rx descriptors to the stack
12448df158acSJeff Kirsher  * (using netif_receive_skb). If all/enough packets are up, the driver
12458df158acSJeff Kirsher  * reenables interrupts and returns 0. If not, 1 is returned.
12468df158acSJeff Kirsher  */
spider_net_poll(struct napi_struct * napi,int budget)12478df158acSJeff Kirsher static int spider_net_poll(struct napi_struct *napi, int budget)
12488df158acSJeff Kirsher {
12498df158acSJeff Kirsher 	struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
12508df158acSJeff Kirsher 	int packets_done = 0;
12518df158acSJeff Kirsher 
12528df158acSJeff Kirsher 	while (packets_done < budget) {
12538df158acSJeff Kirsher 		if (!spider_net_decode_one_descr(card))
12548df158acSJeff Kirsher 			break;
12558df158acSJeff Kirsher 
12568df158acSJeff Kirsher 		packets_done++;
12578df158acSJeff Kirsher 	}
12588df158acSJeff Kirsher 
12598df158acSJeff Kirsher 	if ((packets_done == 0) && (card->num_rx_ints != 0)) {
12608df158acSJeff Kirsher 		if (!spider_net_resync_tail_ptr(card))
12618df158acSJeff Kirsher 			packets_done = budget;
12628df158acSJeff Kirsher 		spider_net_resync_head_ptr(card);
12638df158acSJeff Kirsher 	}
12648df158acSJeff Kirsher 	card->num_rx_ints = 0;
12658df158acSJeff Kirsher 
12668df158acSJeff Kirsher 	spider_net_refill_rx_chain(card);
12678df158acSJeff Kirsher 	spider_net_enable_rxdmac(card);
12688df158acSJeff Kirsher 
1269e99e88a9SKees Cook 	spider_net_cleanup_tx_ring(&card->tx_timer);
12708df158acSJeff Kirsher 
12718df158acSJeff Kirsher 	/* if all packets are in the stack, enable interrupts and return 0 */
12728df158acSJeff Kirsher 	/* if not, return 1 */
12738df158acSJeff Kirsher 	if (packets_done < budget) {
12746ad20165SEric Dumazet 		napi_complete_done(napi, packets_done);
12758df158acSJeff Kirsher 		spider_net_rx_irq_on(card);
12768df158acSJeff Kirsher 		card->ignore_rx_ramfull = 0;
12778df158acSJeff Kirsher 	}
12788df158acSJeff Kirsher 
12798df158acSJeff Kirsher 	return packets_done;
12808df158acSJeff Kirsher }
12818df158acSJeff Kirsher 
12828df158acSJeff Kirsher /**
12838df158acSJeff Kirsher  * spider_net_set_mac - sets the MAC of an interface
12848df158acSJeff Kirsher  * @netdev: interface device structure
1285e242d598SLee Jones  * @p: pointer to new MAC address
12868df158acSJeff Kirsher  *
12878df158acSJeff Kirsher  * Returns 0 on success, <0 on failure. Currently, we don't support this
12888df158acSJeff Kirsher  * and will always return EOPNOTSUPP.
12898df158acSJeff Kirsher  */
12908df158acSJeff Kirsher static int
spider_net_set_mac(struct net_device * netdev,void * p)12918df158acSJeff Kirsher spider_net_set_mac(struct net_device *netdev, void *p)
12928df158acSJeff Kirsher {
12938df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
12948df158acSJeff Kirsher 	u32 macl, macu, regvalue;
12958df158acSJeff Kirsher 	struct sockaddr *addr = p;
12968df158acSJeff Kirsher 
12978df158acSJeff Kirsher 	if (!is_valid_ether_addr(addr->sa_data))
12988df158acSJeff Kirsher 		return -EADDRNOTAVAIL;
12998df158acSJeff Kirsher 
1300a96d317fSJakub Kicinski 	eth_hw_addr_set(netdev, addr->sa_data);
13010f6a6701SAntoine Ténart 
13028df158acSJeff Kirsher 	/* switch off GMACTPE and GMACRPE */
13038df158acSJeff Kirsher 	regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
13048df158acSJeff Kirsher 	regvalue &= ~((1 << 5) | (1 << 6));
13058df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
13068df158acSJeff Kirsher 
13078df158acSJeff Kirsher 	/* write mac */
130896aacedeSAntoine Ténart 	macu = (netdev->dev_addr[0]<<24) + (netdev->dev_addr[1]<<16) +
130996aacedeSAntoine Ténart 		(netdev->dev_addr[2]<<8) + (netdev->dev_addr[3]);
131096aacedeSAntoine Ténart 	macl = (netdev->dev_addr[4]<<8) + (netdev->dev_addr[5]);
13118df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);
13128df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);
13138df158acSJeff Kirsher 
13148df158acSJeff Kirsher 	/* switch GMACTPE and GMACRPE back on */
13158df158acSJeff Kirsher 	regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);
13168df158acSJeff Kirsher 	regvalue |= ((1 << 5) | (1 << 6));
13178df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);
13188df158acSJeff Kirsher 
13198df158acSJeff Kirsher 	spider_net_set_promisc(card);
13208df158acSJeff Kirsher 
13218df158acSJeff Kirsher 	return 0;
13228df158acSJeff Kirsher }
13238df158acSJeff Kirsher 
13248df158acSJeff Kirsher /**
13258df158acSJeff Kirsher  * spider_net_link_reset
13268df158acSJeff Kirsher  * @netdev: net device structure
13278df158acSJeff Kirsher  *
13288df158acSJeff Kirsher  * This is called when the PHY_LINK signal is asserted. For the blade this is
13298df158acSJeff Kirsher  * not connected so we should never get here.
13308df158acSJeff Kirsher  *
13318df158acSJeff Kirsher  */
13328df158acSJeff Kirsher static void
spider_net_link_reset(struct net_device * netdev)13338df158acSJeff Kirsher spider_net_link_reset(struct net_device *netdev)
13348df158acSJeff Kirsher {
13358df158acSJeff Kirsher 
13368df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
13378df158acSJeff Kirsher 
13388df158acSJeff Kirsher 	del_timer_sync(&card->aneg_timer);
13398df158acSJeff Kirsher 
13408df158acSJeff Kirsher 	/* clear interrupt, block further interrupts */
13418df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACST,
13428df158acSJeff Kirsher 			     spider_net_read_reg(card, SPIDER_NET_GMACST));
13438df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
13448df158acSJeff Kirsher 
13458df158acSJeff Kirsher 	/* reset phy and setup aneg */
13468df158acSJeff Kirsher 	card->aneg_count = 0;
13478df158acSJeff Kirsher 	card->medium = BCM54XX_COPPER;
13488df158acSJeff Kirsher 	spider_net_setup_aneg(card);
13498df158acSJeff Kirsher 	mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
13508df158acSJeff Kirsher 
13518df158acSJeff Kirsher }
13528df158acSJeff Kirsher 
13538df158acSJeff Kirsher /**
13548df158acSJeff Kirsher  * spider_net_handle_error_irq - handles errors raised by an interrupt
13558df158acSJeff Kirsher  * @card: card structure
13568df158acSJeff Kirsher  * @status_reg: interrupt status register 0 (GHIINT0STS)
1357e242d598SLee Jones  * @error_reg1: interrupt status register 1 (GHIINT1STS)
1358e242d598SLee Jones  * @error_reg2: interrupt status register 2 (GHIINT2STS)
13598df158acSJeff Kirsher  *
13608df158acSJeff Kirsher  * spider_net_handle_error_irq treats or ignores all error conditions
13618df158acSJeff Kirsher  * found when an interrupt is presented
13628df158acSJeff Kirsher  */
13638df158acSJeff Kirsher static void
spider_net_handle_error_irq(struct spider_net_card * card,u32 status_reg,u32 error_reg1,u32 error_reg2)13648df158acSJeff Kirsher spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg,
13658df158acSJeff Kirsher 			    u32 error_reg1, u32 error_reg2)
13668df158acSJeff Kirsher {
13678df158acSJeff Kirsher 	u32 i;
13688df158acSJeff Kirsher 	int show_error = 1;
13698df158acSJeff Kirsher 
13708df158acSJeff Kirsher 	/* check GHIINT0STS ************************************/
13718df158acSJeff Kirsher 	if (status_reg)
13728df158acSJeff Kirsher 		for (i = 0; i < 32; i++)
13738df158acSJeff Kirsher 			if (status_reg & (1<<i))
13748df158acSJeff Kirsher 				switch (i)
13758df158acSJeff Kirsher 	{
13768df158acSJeff Kirsher 	/* let error_reg1 and error_reg2 evaluation decide, what to do
13778df158acSJeff Kirsher 	case SPIDER_NET_PHYINT:
13788df158acSJeff Kirsher 	case SPIDER_NET_GMAC2INT:
13798df158acSJeff Kirsher 	case SPIDER_NET_GMAC1INT:
13808df158acSJeff Kirsher 	case SPIDER_NET_GFIFOINT:
13818df158acSJeff Kirsher 	case SPIDER_NET_DMACINT:
13828df158acSJeff Kirsher 	case SPIDER_NET_GSYSINT:
13838df158acSJeff Kirsher 		break; */
13848df158acSJeff Kirsher 
13858df158acSJeff Kirsher 	case SPIDER_NET_GIPSINT:
13868df158acSJeff Kirsher 		show_error = 0;
13878df158acSJeff Kirsher 		break;
13888df158acSJeff Kirsher 
13898df158acSJeff Kirsher 	case SPIDER_NET_GPWOPCMPINT:
13908df158acSJeff Kirsher 		/* PHY write operation completed */
13918df158acSJeff Kirsher 		show_error = 0;
13928df158acSJeff Kirsher 		break;
13938df158acSJeff Kirsher 	case SPIDER_NET_GPROPCMPINT:
13948df158acSJeff Kirsher 		/* PHY read operation completed */
13958df158acSJeff Kirsher 		/* we don't use semaphores, as we poll for the completion
13968df158acSJeff Kirsher 		 * of the read operation in spider_net_read_phy. Should take
1397142c1d2eSYixing Liu 		 * about 50 us
1398142c1d2eSYixing Liu 		 */
13998df158acSJeff Kirsher 		show_error = 0;
14008df158acSJeff Kirsher 		break;
14018df158acSJeff Kirsher 	case SPIDER_NET_GPWFFINT:
14028df158acSJeff Kirsher 		/* PHY command queue full */
14038df158acSJeff Kirsher 		if (netif_msg_intr(card))
14048df158acSJeff Kirsher 			dev_err(&card->netdev->dev, "PHY write queue full\n");
14058df158acSJeff Kirsher 		show_error = 0;
14068df158acSJeff Kirsher 		break;
14078df158acSJeff Kirsher 
14088df158acSJeff Kirsher 	/* case SPIDER_NET_GRMDADRINT: not used. print a message */
14098df158acSJeff Kirsher 	/* case SPIDER_NET_GRMARPINT: not used. print a message */
14108df158acSJeff Kirsher 	/* case SPIDER_NET_GRMMPINT: not used. print a message */
14118df158acSJeff Kirsher 
14128df158acSJeff Kirsher 	case SPIDER_NET_GDTDEN0INT:
14138df158acSJeff Kirsher 		/* someone has set TX_DMA_EN to 0 */
14148df158acSJeff Kirsher 		show_error = 0;
14158df158acSJeff Kirsher 		break;
14168df158acSJeff Kirsher 
1417df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDDDEN0INT:
1418df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDCDEN0INT:
1419df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDBDEN0INT:
14208df158acSJeff Kirsher 	case SPIDER_NET_GDADEN0INT:
14218df158acSJeff Kirsher 		/* someone has set RX_DMA_EN to 0 */
14228df158acSJeff Kirsher 		show_error = 0;
14238df158acSJeff Kirsher 		break;
14248df158acSJeff Kirsher 
14258df158acSJeff Kirsher 	/* RX interrupts */
14268df158acSJeff Kirsher 	case SPIDER_NET_GDDFDCINT:
14278df158acSJeff Kirsher 	case SPIDER_NET_GDCFDCINT:
14288df158acSJeff Kirsher 	case SPIDER_NET_GDBFDCINT:
14298df158acSJeff Kirsher 	case SPIDER_NET_GDAFDCINT:
14308df158acSJeff Kirsher 	/* case SPIDER_NET_GDNMINT: not used. print a message */
14318df158acSJeff Kirsher 	/* case SPIDER_NET_GCNMINT: not used. print a message */
14328df158acSJeff Kirsher 	/* case SPIDER_NET_GBNMINT: not used. print a message */
14338df158acSJeff Kirsher 	/* case SPIDER_NET_GANMINT: not used. print a message */
14348df158acSJeff Kirsher 	/* case SPIDER_NET_GRFNMINT: not used. print a message */
14358df158acSJeff Kirsher 		show_error = 0;
14368df158acSJeff Kirsher 		break;
14378df158acSJeff Kirsher 
14388df158acSJeff Kirsher 	/* TX interrupts */
14398df158acSJeff Kirsher 	case SPIDER_NET_GDTFDCINT:
14408df158acSJeff Kirsher 		show_error = 0;
14418df158acSJeff Kirsher 		break;
14428df158acSJeff Kirsher 	case SPIDER_NET_GTTEDINT:
14438df158acSJeff Kirsher 		show_error = 0;
14448df158acSJeff Kirsher 		break;
14458df158acSJeff Kirsher 	case SPIDER_NET_GDTDCEINT:
14468df158acSJeff Kirsher 		/* chain end. If a descriptor should be sent, kick off
14478df158acSJeff Kirsher 		 * tx dma
14488df158acSJeff Kirsher 		if (card->tx_chain.tail != card->tx_chain.head)
14498df158acSJeff Kirsher 			spider_net_kick_tx_dma(card);
14508df158acSJeff Kirsher 		*/
14518df158acSJeff Kirsher 		show_error = 0;
14528df158acSJeff Kirsher 		break;
14538df158acSJeff Kirsher 
14548df158acSJeff Kirsher 	/* case SPIDER_NET_G1TMCNTINT: not used. print a message */
14558df158acSJeff Kirsher 	/* case SPIDER_NET_GFREECNTINT: not used. print a message */
14568df158acSJeff Kirsher 	}
14578df158acSJeff Kirsher 
14588df158acSJeff Kirsher 	/* check GHIINT1STS ************************************/
14598df158acSJeff Kirsher 	if (error_reg1)
14608df158acSJeff Kirsher 		for (i = 0; i < 32; i++)
14618df158acSJeff Kirsher 			if (error_reg1 & (1<<i))
14628df158acSJeff Kirsher 				switch (i)
14638df158acSJeff Kirsher 	{
14648df158acSJeff Kirsher 	case SPIDER_NET_GTMFLLINT:
14658df158acSJeff Kirsher 		/* TX RAM full may happen on a usual case.
1466142c1d2eSYixing Liu 		 * Logging is not needed.
1467142c1d2eSYixing Liu 		 */
14688df158acSJeff Kirsher 		show_error = 0;
14698df158acSJeff Kirsher 		break;
1470df561f66SGustavo A. R. Silva 	case SPIDER_NET_GRFDFLLINT:
1471df561f66SGustavo A. R. Silva 	case SPIDER_NET_GRFCFLLINT:
1472df561f66SGustavo A. R. Silva 	case SPIDER_NET_GRFBFLLINT:
1473df561f66SGustavo A. R. Silva 	case SPIDER_NET_GRFAFLLINT:
14748df158acSJeff Kirsher 	case SPIDER_NET_GRMFLLINT:
14758df158acSJeff Kirsher 		/* Could happen when rx chain is full */
14768df158acSJeff Kirsher 		if (card->ignore_rx_ramfull == 0) {
14778df158acSJeff Kirsher 			card->ignore_rx_ramfull = 1;
14788df158acSJeff Kirsher 			spider_net_resync_head_ptr(card);
14798df158acSJeff Kirsher 			spider_net_refill_rx_chain(card);
14808df158acSJeff Kirsher 			spider_net_enable_rxdmac(card);
14818df158acSJeff Kirsher 			card->num_rx_ints ++;
14828df158acSJeff Kirsher 			napi_schedule(&card->napi);
14838df158acSJeff Kirsher 		}
14848df158acSJeff Kirsher 		show_error = 0;
14858df158acSJeff Kirsher 		break;
14868df158acSJeff Kirsher 
14878df158acSJeff Kirsher 	/* case SPIDER_NET_GTMSHTINT: problem, print a message */
14888df158acSJeff Kirsher 	case SPIDER_NET_GDTINVDINT:
14898df158acSJeff Kirsher 		/* allrighty. tx from previous descr ok */
14908df158acSJeff Kirsher 		show_error = 0;
14918df158acSJeff Kirsher 		break;
14928df158acSJeff Kirsher 
14938df158acSJeff Kirsher 	/* chain end */
1494df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDDDCEINT:
1495df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDCDCEINT:
1496df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDBDCEINT:
14978df158acSJeff Kirsher 	case SPIDER_NET_GDADCEINT:
14988df158acSJeff Kirsher 		spider_net_resync_head_ptr(card);
14998df158acSJeff Kirsher 		spider_net_refill_rx_chain(card);
15008df158acSJeff Kirsher 		spider_net_enable_rxdmac(card);
15018df158acSJeff Kirsher 		card->num_rx_ints ++;
15028df158acSJeff Kirsher 		napi_schedule(&card->napi);
15038df158acSJeff Kirsher 		show_error = 0;
15048df158acSJeff Kirsher 		break;
15058df158acSJeff Kirsher 
15068df158acSJeff Kirsher 	/* invalid descriptor */
1507df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDDINVDINT:
1508df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDCINVDINT:
1509df561f66SGustavo A. R. Silva 	case SPIDER_NET_GDBINVDINT:
15108df158acSJeff Kirsher 	case SPIDER_NET_GDAINVDINT:
15118df158acSJeff Kirsher 		/* Could happen when rx chain is full */
15128df158acSJeff Kirsher 		spider_net_resync_head_ptr(card);
15138df158acSJeff Kirsher 		spider_net_refill_rx_chain(card);
15148df158acSJeff Kirsher 		spider_net_enable_rxdmac(card);
15158df158acSJeff Kirsher 		card->num_rx_ints ++;
15168df158acSJeff Kirsher 		napi_schedule(&card->napi);
15178df158acSJeff Kirsher 		show_error = 0;
15188df158acSJeff Kirsher 		break;
15198df158acSJeff Kirsher 
15208df158acSJeff Kirsher 	/* case SPIDER_NET_GDTRSERINT: problem, print a message */
15218df158acSJeff Kirsher 	/* case SPIDER_NET_GDDRSERINT: problem, print a message */
15228df158acSJeff Kirsher 	/* case SPIDER_NET_GDCRSERINT: problem, print a message */
15238df158acSJeff Kirsher 	/* case SPIDER_NET_GDBRSERINT: problem, print a message */
15248df158acSJeff Kirsher 	/* case SPIDER_NET_GDARSERINT: problem, print a message */
15258df158acSJeff Kirsher 	/* case SPIDER_NET_GDSERINT: problem, print a message */
15268df158acSJeff Kirsher 	/* case SPIDER_NET_GDTPTERINT: problem, print a message */
15278df158acSJeff Kirsher 	/* case SPIDER_NET_GDDPTERINT: problem, print a message */
15288df158acSJeff Kirsher 	/* case SPIDER_NET_GDCPTERINT: problem, print a message */
15298df158acSJeff Kirsher 	/* case SPIDER_NET_GDBPTERINT: problem, print a message */
15308df158acSJeff Kirsher 	/* case SPIDER_NET_GDAPTERINT: problem, print a message */
15318df158acSJeff Kirsher 	default:
15328df158acSJeff Kirsher 		show_error = 1;
15338df158acSJeff Kirsher 		break;
15348df158acSJeff Kirsher 	}
15358df158acSJeff Kirsher 
15368df158acSJeff Kirsher 	/* check GHIINT2STS ************************************/
15378df158acSJeff Kirsher 	if (error_reg2)
15388df158acSJeff Kirsher 		for (i = 0; i < 32; i++)
15398df158acSJeff Kirsher 			if (error_reg2 & (1<<i))
15408df158acSJeff Kirsher 				switch (i)
15418df158acSJeff Kirsher 	{
15428df158acSJeff Kirsher 	/* there is nothing we can (want  to) do at this time. Log a
15438df158acSJeff Kirsher 	 * message, we can switch on and off the specific values later on
15448df158acSJeff Kirsher 	case SPIDER_NET_GPROPERINT:
15458df158acSJeff Kirsher 	case SPIDER_NET_GMCTCRSNGINT:
15468df158acSJeff Kirsher 	case SPIDER_NET_GMCTLCOLINT:
15478df158acSJeff Kirsher 	case SPIDER_NET_GMCTTMOTINT:
15488df158acSJeff Kirsher 	case SPIDER_NET_GMCRCAERINT:
15498df158acSJeff Kirsher 	case SPIDER_NET_GMCRCALERINT:
15508df158acSJeff Kirsher 	case SPIDER_NET_GMCRALNERINT:
15518df158acSJeff Kirsher 	case SPIDER_NET_GMCROVRINT:
15528df158acSJeff Kirsher 	case SPIDER_NET_GMCRRNTINT:
15538df158acSJeff Kirsher 	case SPIDER_NET_GMCRRXERINT:
15548df158acSJeff Kirsher 	case SPIDER_NET_GTITCSERINT:
15558df158acSJeff Kirsher 	case SPIDER_NET_GTIFMTERINT:
15568df158acSJeff Kirsher 	case SPIDER_NET_GTIPKTRVKINT:
15578df158acSJeff Kirsher 	case SPIDER_NET_GTISPINGINT:
15588df158acSJeff Kirsher 	case SPIDER_NET_GTISADNGINT:
15598df158acSJeff Kirsher 	case SPIDER_NET_GTISPDNGINT:
15608df158acSJeff Kirsher 	case SPIDER_NET_GRIFMTERINT:
15618df158acSJeff Kirsher 	case SPIDER_NET_GRIPKTRVKINT:
15628df158acSJeff Kirsher 	case SPIDER_NET_GRISPINGINT:
15638df158acSJeff Kirsher 	case SPIDER_NET_GRISADNGINT:
15648df158acSJeff Kirsher 	case SPIDER_NET_GRISPDNGINT:
15658df158acSJeff Kirsher 		break;
15668df158acSJeff Kirsher 	*/
15678df158acSJeff Kirsher 		default:
15688df158acSJeff Kirsher 			break;
15698df158acSJeff Kirsher 	}
15708df158acSJeff Kirsher 
15718df158acSJeff Kirsher 	if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
15728df158acSJeff Kirsher 		dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
15738df158acSJeff Kirsher 		       "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
15748df158acSJeff Kirsher 		       status_reg, error_reg1, error_reg2);
15758df158acSJeff Kirsher 
15768df158acSJeff Kirsher 	/* clear interrupt sources */
15778df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT1STS, error_reg1);
15788df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT2STS, error_reg2);
15798df158acSJeff Kirsher }
15808df158acSJeff Kirsher 
15818df158acSJeff Kirsher /**
15828df158acSJeff Kirsher  * spider_net_interrupt - interrupt handler for spider_net
15838df158acSJeff Kirsher  * @irq: interrupt number
15848df158acSJeff Kirsher  * @ptr: pointer to net_device
15858df158acSJeff Kirsher  *
15868df158acSJeff Kirsher  * returns IRQ_HANDLED, if interrupt was for driver, or IRQ_NONE, if no
15878df158acSJeff Kirsher  * interrupt found raised by card.
15888df158acSJeff Kirsher  *
15898df158acSJeff Kirsher  * This is the interrupt handler, that turns off
15908df158acSJeff Kirsher  * interrupts for this device and makes the stack poll the driver
15918df158acSJeff Kirsher  */
15928df158acSJeff Kirsher static irqreturn_t
spider_net_interrupt(int irq,void * ptr)15938df158acSJeff Kirsher spider_net_interrupt(int irq, void *ptr)
15948df158acSJeff Kirsher {
15958df158acSJeff Kirsher 	struct net_device *netdev = ptr;
15968df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
15978df158acSJeff Kirsher 	u32 status_reg, error_reg1, error_reg2;
15988df158acSJeff Kirsher 
15998df158acSJeff Kirsher 	status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
16008df158acSJeff Kirsher 	error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
16018df158acSJeff Kirsher 	error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
16028df158acSJeff Kirsher 
16038df158acSJeff Kirsher 	if (!(status_reg & SPIDER_NET_INT0_MASK_VALUE) &&
16048df158acSJeff Kirsher 	    !(error_reg1 & SPIDER_NET_INT1_MASK_VALUE) &&
16058df158acSJeff Kirsher 	    !(error_reg2 & SPIDER_NET_INT2_MASK_VALUE))
16068df158acSJeff Kirsher 		return IRQ_NONE;
16078df158acSJeff Kirsher 
16088df158acSJeff Kirsher 	if (status_reg & SPIDER_NET_RXINT ) {
16098df158acSJeff Kirsher 		spider_net_rx_irq_off(card);
16108df158acSJeff Kirsher 		napi_schedule(&card->napi);
16118df158acSJeff Kirsher 		card->num_rx_ints ++;
16128df158acSJeff Kirsher 	}
16138df158acSJeff Kirsher 	if (status_reg & SPIDER_NET_TXINT)
16148df158acSJeff Kirsher 		napi_schedule(&card->napi);
16158df158acSJeff Kirsher 
16168df158acSJeff Kirsher 	if (status_reg & SPIDER_NET_LINKINT)
16178df158acSJeff Kirsher 		spider_net_link_reset(netdev);
16188df158acSJeff Kirsher 
16198df158acSJeff Kirsher 	if (status_reg & SPIDER_NET_ERRINT )
16208df158acSJeff Kirsher 		spider_net_handle_error_irq(card, status_reg,
16218df158acSJeff Kirsher 					    error_reg1, error_reg2);
16228df158acSJeff Kirsher 
16238df158acSJeff Kirsher 	/* clear interrupt sources */
16248df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg);
16258df158acSJeff Kirsher 
16268df158acSJeff Kirsher 	return IRQ_HANDLED;
16278df158acSJeff Kirsher }
16288df158acSJeff Kirsher 
16298df158acSJeff Kirsher #ifdef CONFIG_NET_POLL_CONTROLLER
16308df158acSJeff Kirsher /**
16318df158acSJeff Kirsher  * spider_net_poll_controller - artificial interrupt for netconsole etc.
16328df158acSJeff Kirsher  * @netdev: interface device structure
16338df158acSJeff Kirsher  *
1634d9d6ef25SMauro Carvalho Chehab  * see Documentation/networking/netconsole.rst
16358df158acSJeff Kirsher  */
16368df158acSJeff Kirsher static void
spider_net_poll_controller(struct net_device * netdev)16378df158acSJeff Kirsher spider_net_poll_controller(struct net_device *netdev)
16388df158acSJeff Kirsher {
16398df158acSJeff Kirsher 	disable_irq(netdev->irq);
16408df158acSJeff Kirsher 	spider_net_interrupt(netdev->irq, netdev);
16418df158acSJeff Kirsher 	enable_irq(netdev->irq);
16428df158acSJeff Kirsher }
16438df158acSJeff Kirsher #endif /* CONFIG_NET_POLL_CONTROLLER */
16448df158acSJeff Kirsher 
16458df158acSJeff Kirsher /**
16468df158acSJeff Kirsher  * spider_net_enable_interrupts - enable interrupts
16478df158acSJeff Kirsher  * @card: card structure
16488df158acSJeff Kirsher  *
16498df158acSJeff Kirsher  * spider_net_enable_interrupt enables several interrupts
16508df158acSJeff Kirsher  */
16518df158acSJeff Kirsher static void
spider_net_enable_interrupts(struct spider_net_card * card)16528df158acSJeff Kirsher spider_net_enable_interrupts(struct spider_net_card *card)
16538df158acSJeff Kirsher {
16548df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
16558df158acSJeff Kirsher 			     SPIDER_NET_INT0_MASK_VALUE);
16568df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK,
16578df158acSJeff Kirsher 			     SPIDER_NET_INT1_MASK_VALUE);
16588df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
16598df158acSJeff Kirsher 			     SPIDER_NET_INT2_MASK_VALUE);
16608df158acSJeff Kirsher }
16618df158acSJeff Kirsher 
16628df158acSJeff Kirsher /**
16638df158acSJeff Kirsher  * spider_net_disable_interrupts - disable interrupts
16648df158acSJeff Kirsher  * @card: card structure
16658df158acSJeff Kirsher  *
16668df158acSJeff Kirsher  * spider_net_disable_interrupts disables all the interrupts
16678df158acSJeff Kirsher  */
16688df158acSJeff Kirsher static void
spider_net_disable_interrupts(struct spider_net_card * card)16698df158acSJeff Kirsher spider_net_disable_interrupts(struct spider_net_card *card)
16708df158acSJeff Kirsher {
16718df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
16728df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
16738df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
16748df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
16758df158acSJeff Kirsher }
16768df158acSJeff Kirsher 
16778df158acSJeff Kirsher /**
16788df158acSJeff Kirsher  * spider_net_init_card - initializes the card
16798df158acSJeff Kirsher  * @card: card structure
16808df158acSJeff Kirsher  *
16818df158acSJeff Kirsher  * spider_net_init_card initializes the card so that other registers can
16828df158acSJeff Kirsher  * be used
16838df158acSJeff Kirsher  */
16848df158acSJeff Kirsher static void
spider_net_init_card(struct spider_net_card * card)16858df158acSJeff Kirsher spider_net_init_card(struct spider_net_card *card)
16868df158acSJeff Kirsher {
16878df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
16888df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_STOP_VALUE);
16898df158acSJeff Kirsher 
16908df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
16918df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_RUN_VALUE);
16928df158acSJeff Kirsher 
16938df158acSJeff Kirsher 	/* trigger ETOMOD signal */
16948df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
16958df158acSJeff Kirsher 		spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
16968df158acSJeff Kirsher 
16978df158acSJeff Kirsher 	spider_net_disable_interrupts(card);
16988df158acSJeff Kirsher }
16998df158acSJeff Kirsher 
17008df158acSJeff Kirsher /**
17018df158acSJeff Kirsher  * spider_net_enable_card - enables the card by setting all kinds of regs
17028df158acSJeff Kirsher  * @card: card structure
17038df158acSJeff Kirsher  *
17048df158acSJeff Kirsher  * spider_net_enable_card sets a lot of SMMIO registers to enable the device
17058df158acSJeff Kirsher  */
17068df158acSJeff Kirsher static void
spider_net_enable_card(struct spider_net_card * card)17078df158acSJeff Kirsher spider_net_enable_card(struct spider_net_card *card)
17088df158acSJeff Kirsher {
17098df158acSJeff Kirsher 	int i;
17108df158acSJeff Kirsher 	/* the following array consists of (register),(value) pairs
1711142c1d2eSYixing Liu 	 * that are set in this function. A register of 0 ends the list
1712142c1d2eSYixing Liu 	 */
17138df158acSJeff Kirsher 	u32 regs[][2] = {
17148df158acSJeff Kirsher 		{ SPIDER_NET_GRESUMINTNUM, 0 },
17158df158acSJeff Kirsher 		{ SPIDER_NET_GREINTNUM, 0 },
17168df158acSJeff Kirsher 
17178df158acSJeff Kirsher 		/* set interrupt frame number registers */
17188df158acSJeff Kirsher 		/* clear the single DMA engine registers first */
17198df158acSJeff Kirsher 		{ SPIDER_NET_GFAFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
17208df158acSJeff Kirsher 		{ SPIDER_NET_GFBFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
17218df158acSJeff Kirsher 		{ SPIDER_NET_GFCFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
17228df158acSJeff Kirsher 		{ SPIDER_NET_GFDFRMNUM, SPIDER_NET_GFXFRAMES_VALUE },
17238df158acSJeff Kirsher 		/* then set, what we really need */
17248df158acSJeff Kirsher 		{ SPIDER_NET_GFFRMNUM, SPIDER_NET_FRAMENUM_VALUE },
17258df158acSJeff Kirsher 
17268df158acSJeff Kirsher 		/* timer counter registers and stuff */
17278df158acSJeff Kirsher 		{ SPIDER_NET_GFREECNNUM, 0 },
17288df158acSJeff Kirsher 		{ SPIDER_NET_GONETIMENUM, 0 },
17298df158acSJeff Kirsher 		{ SPIDER_NET_GTOUTFRMNUM, 0 },
17308df158acSJeff Kirsher 
17318df158acSJeff Kirsher 		/* RX mode setting */
17328df158acSJeff Kirsher 		{ SPIDER_NET_GRXMDSET, SPIDER_NET_RXMODE_VALUE },
17338df158acSJeff Kirsher 		/* TX mode setting */
17348df158acSJeff Kirsher 		{ SPIDER_NET_GTXMDSET, SPIDER_NET_TXMODE_VALUE },
17358df158acSJeff Kirsher 		/* IPSEC mode setting */
17368df158acSJeff Kirsher 		{ SPIDER_NET_GIPSECINIT, SPIDER_NET_IPSECINIT_VALUE },
17378df158acSJeff Kirsher 
17388df158acSJeff Kirsher 		{ SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
17398df158acSJeff Kirsher 
17408df158acSJeff Kirsher 		{ SPIDER_NET_GMRWOLCTRL, 0 },
17418df158acSJeff Kirsher 		{ SPIDER_NET_GTESTMD, 0x10000000 },
17428df158acSJeff Kirsher 		{ SPIDER_NET_GTTQMSK, 0x00400040 },
17438df158acSJeff Kirsher 
17448df158acSJeff Kirsher 		{ SPIDER_NET_GMACINTEN, 0 },
17458df158acSJeff Kirsher 
17468df158acSJeff Kirsher 		/* flow control stuff */
17478df158acSJeff Kirsher 		{ SPIDER_NET_GMACAPAUSE, SPIDER_NET_MACAPAUSE_VALUE },
17488df158acSJeff Kirsher 		{ SPIDER_NET_GMACTXPAUSE, SPIDER_NET_TXPAUSE_VALUE },
17498df158acSJeff Kirsher 
17508df158acSJeff Kirsher 		{ SPIDER_NET_GMACBSTLMT, SPIDER_NET_BURSTLMT_VALUE },
17518df158acSJeff Kirsher 		{ 0, 0}
17528df158acSJeff Kirsher 	};
17538df158acSJeff Kirsher 
17548df158acSJeff Kirsher 	i = 0;
17558df158acSJeff Kirsher 	while (regs[i][0]) {
17568df158acSJeff Kirsher 		spider_net_write_reg(card, regs[i][0], regs[i][1]);
17578df158acSJeff Kirsher 		i++;
17588df158acSJeff Kirsher 	}
17598df158acSJeff Kirsher 
17608df158acSJeff Kirsher 	/* clear unicast filter table entries 1 to 14 */
17618df158acSJeff Kirsher 	for (i = 1; i <= 14; i++) {
17628df158acSJeff Kirsher 		spider_net_write_reg(card,
17638df158acSJeff Kirsher 				     SPIDER_NET_GMRUAFILnR + i * 8,
17648df158acSJeff Kirsher 				     0x00080000);
17658df158acSJeff Kirsher 		spider_net_write_reg(card,
17668df158acSJeff Kirsher 				     SPIDER_NET_GMRUAFILnR + i * 8 + 4,
17678df158acSJeff Kirsher 				     0x00000000);
17688df158acSJeff Kirsher 	}
17698df158acSJeff Kirsher 
17708df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMRUA0FIL15R, 0x08080000);
17718df158acSJeff Kirsher 
17728df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_ECMODE, SPIDER_NET_ECMODE_VALUE);
17738df158acSJeff Kirsher 
17748df158acSJeff Kirsher 	/* set chain tail address for RX chains and
1775142c1d2eSYixing Liu 	 * enable DMA
1776142c1d2eSYixing Liu 	 */
17778df158acSJeff Kirsher 	spider_net_enable_rxchtails(card);
17788df158acSJeff Kirsher 	spider_net_enable_rxdmac(card);
17798df158acSJeff Kirsher 
17808df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
17818df158acSJeff Kirsher 
17828df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
17838df158acSJeff Kirsher 			     SPIDER_NET_LENLMT_VALUE);
17848df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
17858df158acSJeff Kirsher 			     SPIDER_NET_OPMODE_VALUE);
17868df158acSJeff Kirsher 
17878df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
17888df158acSJeff Kirsher 			     SPIDER_NET_GDTBSTA);
17898df158acSJeff Kirsher }
17908df158acSJeff Kirsher 
17918df158acSJeff Kirsher /**
17928df158acSJeff Kirsher  * spider_net_download_firmware - loads firmware into the adapter
17938df158acSJeff Kirsher  * @card: card structure
17948df158acSJeff Kirsher  * @firmware_ptr: pointer to firmware data
17958df158acSJeff Kirsher  *
17968df158acSJeff Kirsher  * spider_net_download_firmware loads the firmware data into the
17978df158acSJeff Kirsher  * adapter. It assumes the length etc. to be allright.
17988df158acSJeff Kirsher  */
17998df158acSJeff Kirsher static int
spider_net_download_firmware(struct spider_net_card * card,const void * firmware_ptr)18008df158acSJeff Kirsher spider_net_download_firmware(struct spider_net_card *card,
18018df158acSJeff Kirsher 			     const void *firmware_ptr)
18028df158acSJeff Kirsher {
18038df158acSJeff Kirsher 	int sequencer, i;
18048df158acSJeff Kirsher 	const u32 *fw_ptr = firmware_ptr;
18058df158acSJeff Kirsher 
18068df158acSJeff Kirsher 	/* stop sequencers */
18078df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GSINIT,
18088df158acSJeff Kirsher 			     SPIDER_NET_STOP_SEQ_VALUE);
18098df158acSJeff Kirsher 
18108df158acSJeff Kirsher 	for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
18118df158acSJeff Kirsher 	     sequencer++) {
18128df158acSJeff Kirsher 		spider_net_write_reg(card,
18138df158acSJeff Kirsher 				     SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
18148df158acSJeff Kirsher 		for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
18158df158acSJeff Kirsher 			spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
18168df158acSJeff Kirsher 					     sequencer * 8, *fw_ptr);
18178df158acSJeff Kirsher 			fw_ptr++;
18188df158acSJeff Kirsher 		}
18198df158acSJeff Kirsher 	}
18208df158acSJeff Kirsher 
18218df158acSJeff Kirsher 	if (spider_net_read_reg(card, SPIDER_NET_GSINIT))
18228df158acSJeff Kirsher 		return -EIO;
18238df158acSJeff Kirsher 
18248df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GSINIT,
18258df158acSJeff Kirsher 			     SPIDER_NET_RUN_SEQ_VALUE);
18268df158acSJeff Kirsher 
18278df158acSJeff Kirsher 	return 0;
18288df158acSJeff Kirsher }
18298df158acSJeff Kirsher 
18308df158acSJeff Kirsher /**
18318df158acSJeff Kirsher  * spider_net_init_firmware - reads in firmware parts
18328df158acSJeff Kirsher  * @card: card structure
18338df158acSJeff Kirsher  *
18348df158acSJeff Kirsher  * Returns 0 on success, <0 on failure
18358df158acSJeff Kirsher  *
18368df158acSJeff Kirsher  * spider_net_init_firmware opens the sequencer firmware and does some basic
18378df158acSJeff Kirsher  * checks. This function opens and releases the firmware structure. A call
18388df158acSJeff Kirsher  * to download the firmware is performed before the release.
18398df158acSJeff Kirsher  *
18408df158acSJeff Kirsher  * Firmware format
18418df158acSJeff Kirsher  * ===============
18428df158acSJeff Kirsher  * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
18438df158acSJeff Kirsher  * the program for each sequencer. Use the command
18448df158acSJeff Kirsher  *    tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt              \
18458df158acSJeff Kirsher  *         Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt   \
18468df158acSJeff Kirsher  *         Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
18478df158acSJeff Kirsher  *
18488df158acSJeff Kirsher  * to generate spider_fw.bin, if you have sequencer programs with something
18498df158acSJeff Kirsher  * like the following contents for each sequencer:
18508df158acSJeff Kirsher  *    <ONE LINE COMMENT>
18518df158acSJeff Kirsher  *    <FIRST 4-BYTES-WORD FOR SEQUENCER>
18528df158acSJeff Kirsher  *    <SECOND 4-BYTES-WORD FOR SEQUENCER>
18538df158acSJeff Kirsher  *     ...
18548df158acSJeff Kirsher  *    <1024th 4-BYTES-WORD FOR SEQUENCER>
18558df158acSJeff Kirsher  */
18568df158acSJeff Kirsher static int
spider_net_init_firmware(struct spider_net_card * card)18578df158acSJeff Kirsher spider_net_init_firmware(struct spider_net_card *card)
18588df158acSJeff Kirsher {
18598df158acSJeff Kirsher 	struct firmware *firmware = NULL;
18608df158acSJeff Kirsher 	struct device_node *dn;
18618df158acSJeff Kirsher 	const u8 *fw_prop = NULL;
18628df158acSJeff Kirsher 	int err = -ENOENT;
18638df158acSJeff Kirsher 	int fw_size;
18648df158acSJeff Kirsher 
18658df158acSJeff Kirsher 	if (request_firmware((const struct firmware **)&firmware,
18668df158acSJeff Kirsher 			     SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
18678df158acSJeff Kirsher 		if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
18688df158acSJeff Kirsher 		     netif_msg_probe(card) ) {
18698df158acSJeff Kirsher 			dev_err(&card->netdev->dev,
18708df158acSJeff Kirsher 			       "Incorrect size of spidernet firmware in " \
18718df158acSJeff Kirsher 			       "filesystem. Looking in host firmware...\n");
18728df158acSJeff Kirsher 			goto try_host_fw;
18738df158acSJeff Kirsher 		}
18748df158acSJeff Kirsher 		err = spider_net_download_firmware(card, firmware->data);
18758df158acSJeff Kirsher 
18768df158acSJeff Kirsher 		release_firmware(firmware);
18778df158acSJeff Kirsher 		if (err)
18788df158acSJeff Kirsher 			goto try_host_fw;
18798df158acSJeff Kirsher 
18808df158acSJeff Kirsher 		goto done;
18818df158acSJeff Kirsher 	}
18828df158acSJeff Kirsher 
18838df158acSJeff Kirsher try_host_fw:
18848df158acSJeff Kirsher 	dn = pci_device_to_OF_node(card->pdev);
18858df158acSJeff Kirsher 	if (!dn)
18868df158acSJeff Kirsher 		goto out_err;
18878df158acSJeff Kirsher 
18888df158acSJeff Kirsher 	fw_prop = of_get_property(dn, "firmware", &fw_size);
18898df158acSJeff Kirsher 	if (!fw_prop)
18908df158acSJeff Kirsher 		goto out_err;
18918df158acSJeff Kirsher 
18928df158acSJeff Kirsher 	if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
18938df158acSJeff Kirsher 	     netif_msg_probe(card) ) {
18948df158acSJeff Kirsher 		dev_err(&card->netdev->dev,
18958df158acSJeff Kirsher 		       "Incorrect size of spidernet firmware in host firmware\n");
18968df158acSJeff Kirsher 		goto done;
18978df158acSJeff Kirsher 	}
18988df158acSJeff Kirsher 
18998df158acSJeff Kirsher 	err = spider_net_download_firmware(card, fw_prop);
19008df158acSJeff Kirsher 
19018df158acSJeff Kirsher done:
19028df158acSJeff Kirsher 	return err;
19038df158acSJeff Kirsher out_err:
19048df158acSJeff Kirsher 	if (netif_msg_probe(card))
19058df158acSJeff Kirsher 		dev_err(&card->netdev->dev,
19068df158acSJeff Kirsher 		       "Couldn't find spidernet firmware in filesystem " \
19078df158acSJeff Kirsher 		       "or host firmware\n");
19088df158acSJeff Kirsher 	return err;
19098df158acSJeff Kirsher }
19108df158acSJeff Kirsher 
19118df158acSJeff Kirsher /**
19128df158acSJeff Kirsher  * spider_net_open - called upon ifonfig up
19138df158acSJeff Kirsher  * @netdev: interface device structure
19148df158acSJeff Kirsher  *
19158df158acSJeff Kirsher  * returns 0 on success, <0 on failure
19168df158acSJeff Kirsher  *
19178df158acSJeff Kirsher  * spider_net_open allocates all the descriptors and memory needed for
19188df158acSJeff Kirsher  * operation, sets up multicast list and enables interrupts
19198df158acSJeff Kirsher  */
19208df158acSJeff Kirsher int
spider_net_open(struct net_device * netdev)19218df158acSJeff Kirsher spider_net_open(struct net_device *netdev)
19228df158acSJeff Kirsher {
19238df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
19248df158acSJeff Kirsher 	int result;
19258df158acSJeff Kirsher 
19268df158acSJeff Kirsher 	result = spider_net_init_firmware(card);
19278df158acSJeff Kirsher 	if (result)
19288df158acSJeff Kirsher 		goto init_firmware_failed;
19298df158acSJeff Kirsher 
19308df158acSJeff Kirsher 	/* start probing with copper */
19318df158acSJeff Kirsher 	card->aneg_count = 0;
19328df158acSJeff Kirsher 	card->medium = BCM54XX_COPPER;
19338df158acSJeff Kirsher 	spider_net_setup_aneg(card);
19348df158acSJeff Kirsher 	if (card->phy.def->phy_id)
19358df158acSJeff Kirsher 		mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
19368df158acSJeff Kirsher 
19378df158acSJeff Kirsher 	result = spider_net_init_chain(card, &card->tx_chain);
19388df158acSJeff Kirsher 	if (result)
19398df158acSJeff Kirsher 		goto alloc_tx_failed;
19408df158acSJeff Kirsher 	card->low_watermark = NULL;
19418df158acSJeff Kirsher 
19428df158acSJeff Kirsher 	result = spider_net_init_chain(card, &card->rx_chain);
19438df158acSJeff Kirsher 	if (result)
19448df158acSJeff Kirsher 		goto alloc_rx_failed;
19458df158acSJeff Kirsher 
19468df158acSJeff Kirsher 	/* Allocate rx skbs */
1947228fb087SWei Yongjun 	result = spider_net_alloc_rx_skbs(card);
1948228fb087SWei Yongjun 	if (result)
19498df158acSJeff Kirsher 		goto alloc_skbs_failed;
19508df158acSJeff Kirsher 
19518df158acSJeff Kirsher 	spider_net_set_multi(netdev);
19528df158acSJeff Kirsher 
19538df158acSJeff Kirsher 	/* further enhancement: setup hw vlan, if needed */
19548df158acSJeff Kirsher 
19558df158acSJeff Kirsher 	result = -EBUSY;
19568df158acSJeff Kirsher 	if (request_irq(netdev->irq, spider_net_interrupt,
19578df158acSJeff Kirsher 			     IRQF_SHARED, netdev->name, netdev))
19588df158acSJeff Kirsher 		goto register_int_failed;
19598df158acSJeff Kirsher 
19608df158acSJeff Kirsher 	spider_net_enable_card(card);
19618df158acSJeff Kirsher 
19628df158acSJeff Kirsher 	netif_start_queue(netdev);
19638df158acSJeff Kirsher 	netif_carrier_on(netdev);
19648df158acSJeff Kirsher 	napi_enable(&card->napi);
19658df158acSJeff Kirsher 
19668df158acSJeff Kirsher 	spider_net_enable_interrupts(card);
19678df158acSJeff Kirsher 
19688df158acSJeff Kirsher 	return 0;
19698df158acSJeff Kirsher 
19708df158acSJeff Kirsher register_int_failed:
19718df158acSJeff Kirsher 	spider_net_free_rx_chain_contents(card);
19728df158acSJeff Kirsher alloc_skbs_failed:
19738df158acSJeff Kirsher 	spider_net_free_chain(card, &card->rx_chain);
19748df158acSJeff Kirsher alloc_rx_failed:
19758df158acSJeff Kirsher 	spider_net_free_chain(card, &card->tx_chain);
19768df158acSJeff Kirsher alloc_tx_failed:
19778df158acSJeff Kirsher 	del_timer_sync(&card->aneg_timer);
19788df158acSJeff Kirsher init_firmware_failed:
19798df158acSJeff Kirsher 	return result;
19808df158acSJeff Kirsher }
19818df158acSJeff Kirsher 
19828df158acSJeff Kirsher /**
19838df158acSJeff Kirsher  * spider_net_link_phy
1984e242d598SLee Jones  * @t: timer context used to obtain the pointer to net card data structure
19858df158acSJeff Kirsher  */
spider_net_link_phy(struct timer_list * t)1986e99e88a9SKees Cook static void spider_net_link_phy(struct timer_list *t)
19878df158acSJeff Kirsher {
1988e99e88a9SKees Cook 	struct spider_net_card *card = from_timer(card, t, aneg_timer);
19898df158acSJeff Kirsher 	struct mii_phy *phy = &card->phy;
19908df158acSJeff Kirsher 
19918df158acSJeff Kirsher 	/* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
19928df158acSJeff Kirsher 	if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
19938df158acSJeff Kirsher 
19948df158acSJeff Kirsher 		pr_debug("%s: link is down trying to bring it up\n",
19958df158acSJeff Kirsher 			 card->netdev->name);
19968df158acSJeff Kirsher 
19978df158acSJeff Kirsher 		switch (card->medium) {
19988df158acSJeff Kirsher 		case BCM54XX_COPPER:
19998df158acSJeff Kirsher 			/* enable fiber with autonegotiation first */
20008df158acSJeff Kirsher 			if (phy->def->ops->enable_fiber)
20018df158acSJeff Kirsher 				phy->def->ops->enable_fiber(phy, 1);
20028df158acSJeff Kirsher 			card->medium = BCM54XX_FIBER;
20038df158acSJeff Kirsher 			break;
20048df158acSJeff Kirsher 
20058df158acSJeff Kirsher 		case BCM54XX_FIBER:
20068df158acSJeff Kirsher 			/* fiber didn't come up, try to disable fiber autoneg */
20078df158acSJeff Kirsher 			if (phy->def->ops->enable_fiber)
20088df158acSJeff Kirsher 				phy->def->ops->enable_fiber(phy, 0);
20098df158acSJeff Kirsher 			card->medium = BCM54XX_UNKNOWN;
20108df158acSJeff Kirsher 			break;
20118df158acSJeff Kirsher 
20128df158acSJeff Kirsher 		case BCM54XX_UNKNOWN:
20138df158acSJeff Kirsher 			/* copper, fiber with and without failed,
2014142c1d2eSYixing Liu 			 * retry from beginning
2015142c1d2eSYixing Liu 			 */
20168df158acSJeff Kirsher 			spider_net_setup_aneg(card);
20178df158acSJeff Kirsher 			card->medium = BCM54XX_COPPER;
20188df158acSJeff Kirsher 			break;
20198df158acSJeff Kirsher 		}
20208df158acSJeff Kirsher 
20218df158acSJeff Kirsher 		card->aneg_count = 0;
20228df158acSJeff Kirsher 		mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
20238df158acSJeff Kirsher 		return;
20248df158acSJeff Kirsher 	}
20258df158acSJeff Kirsher 
20268df158acSJeff Kirsher 	/* link still not up, try again later */
20278df158acSJeff Kirsher 	if (!(phy->def->ops->poll_link(phy))) {
20288df158acSJeff Kirsher 		card->aneg_count++;
20298df158acSJeff Kirsher 		mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
20308df158acSJeff Kirsher 		return;
20318df158acSJeff Kirsher 	}
20328df158acSJeff Kirsher 
20338df158acSJeff Kirsher 	/* link came up, get abilities */
20348df158acSJeff Kirsher 	phy->def->ops->read_link(phy);
20358df158acSJeff Kirsher 
20368df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACST,
20378df158acSJeff Kirsher 			     spider_net_read_reg(card, SPIDER_NET_GMACST));
20388df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
20398df158acSJeff Kirsher 
20408df158acSJeff Kirsher 	if (phy->speed == 1000)
20418df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
20428df158acSJeff Kirsher 	else
20438df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
20448df158acSJeff Kirsher 
20458df158acSJeff Kirsher 	card->aneg_count = 0;
20468df158acSJeff Kirsher 
20478df158acSJeff Kirsher 	pr_info("%s: link up, %i Mbps, %s-duplex %sautoneg.\n",
20488df158acSJeff Kirsher 		card->netdev->name, phy->speed,
20498df158acSJeff Kirsher 		phy->duplex == 1 ? "Full" : "Half",
20508df158acSJeff Kirsher 		phy->autoneg == 1 ? "" : "no ");
20518df158acSJeff Kirsher }
20528df158acSJeff Kirsher 
20538df158acSJeff Kirsher /**
20548df158acSJeff Kirsher  * spider_net_setup_phy - setup PHY
20558df158acSJeff Kirsher  * @card: card structure
20568df158acSJeff Kirsher  *
20578df158acSJeff Kirsher  * returns 0 on success, <0 on failure
20588df158acSJeff Kirsher  *
20598df158acSJeff Kirsher  * spider_net_setup_phy is used as part of spider_net_probe.
20608df158acSJeff Kirsher  **/
20618df158acSJeff Kirsher static int
spider_net_setup_phy(struct spider_net_card * card)20628df158acSJeff Kirsher spider_net_setup_phy(struct spider_net_card *card)
20638df158acSJeff Kirsher {
20648df158acSJeff Kirsher 	struct mii_phy *phy = &card->phy;
20658df158acSJeff Kirsher 
20668df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
20678df158acSJeff Kirsher 			     SPIDER_NET_DMASEL_VALUE);
20688df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
20698df158acSJeff Kirsher 			     SPIDER_NET_PHY_CTRL_VALUE);
20708df158acSJeff Kirsher 
20718df158acSJeff Kirsher 	phy->dev = card->netdev;
20728df158acSJeff Kirsher 	phy->mdio_read = spider_net_read_phy;
20738df158acSJeff Kirsher 	phy->mdio_write = spider_net_write_phy;
20748df158acSJeff Kirsher 
20758df158acSJeff Kirsher 	for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
20768df158acSJeff Kirsher 		unsigned short id;
20778df158acSJeff Kirsher 		id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
20788df158acSJeff Kirsher 		if (id != 0x0000 && id != 0xffff) {
207919e2f6feSDavid S. Miller 			if (!sungem_phy_probe(phy, phy->mii_id)) {
20808df158acSJeff Kirsher 				pr_info("Found %s.\n", phy->def->name);
20818df158acSJeff Kirsher 				break;
20828df158acSJeff Kirsher 			}
20838df158acSJeff Kirsher 		}
20848df158acSJeff Kirsher 	}
20858df158acSJeff Kirsher 
20868df158acSJeff Kirsher 	return 0;
20878df158acSJeff Kirsher }
20888df158acSJeff Kirsher 
20898df158acSJeff Kirsher /**
20908df158acSJeff Kirsher  * spider_net_workaround_rxramfull - work around firmware bug
20918df158acSJeff Kirsher  * @card: card structure
20928df158acSJeff Kirsher  *
20938df158acSJeff Kirsher  * no return value
20948df158acSJeff Kirsher  **/
20958df158acSJeff Kirsher static void
spider_net_workaround_rxramfull(struct spider_net_card * card)20968df158acSJeff Kirsher spider_net_workaround_rxramfull(struct spider_net_card *card)
20978df158acSJeff Kirsher {
20988df158acSJeff Kirsher 	int i, sequencer = 0;
20998df158acSJeff Kirsher 
21008df158acSJeff Kirsher 	/* cancel reset */
21018df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
21028df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_RUN_VALUE);
21038df158acSJeff Kirsher 
21048df158acSJeff Kirsher 	/* empty sequencer data */
21058df158acSJeff Kirsher 	for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
21068df158acSJeff Kirsher 	     sequencer++) {
21078df158acSJeff Kirsher 		spider_net_write_reg(card, SPIDER_NET_GSnPRGADR +
21088df158acSJeff Kirsher 				     sequencer * 8, 0x0);
21098df158acSJeff Kirsher 		for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
21108df158acSJeff Kirsher 			spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
21118df158acSJeff Kirsher 					     sequencer * 8, 0x0);
21128df158acSJeff Kirsher 		}
21138df158acSJeff Kirsher 	}
21148df158acSJeff Kirsher 
21158df158acSJeff Kirsher 	/* set sequencer operation */
21168df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GSINIT, 0x000000fe);
21178df158acSJeff Kirsher 
21188df158acSJeff Kirsher 	/* reset */
21198df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
21208df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_STOP_VALUE);
21218df158acSJeff Kirsher }
21228df158acSJeff Kirsher 
21238df158acSJeff Kirsher /**
21248df158acSJeff Kirsher  * spider_net_stop - called upon ifconfig down
21258df158acSJeff Kirsher  * @netdev: interface device structure
21268df158acSJeff Kirsher  *
21278df158acSJeff Kirsher  * always returns 0
21288df158acSJeff Kirsher  */
21298df158acSJeff Kirsher int
spider_net_stop(struct net_device * netdev)21308df158acSJeff Kirsher spider_net_stop(struct net_device *netdev)
21318df158acSJeff Kirsher {
21328df158acSJeff Kirsher 	struct spider_net_card *card = netdev_priv(netdev);
21338df158acSJeff Kirsher 
21348df158acSJeff Kirsher 	napi_disable(&card->napi);
21358df158acSJeff Kirsher 	netif_carrier_off(netdev);
21368df158acSJeff Kirsher 	netif_stop_queue(netdev);
21378df158acSJeff Kirsher 	del_timer_sync(&card->tx_timer);
21388df158acSJeff Kirsher 	del_timer_sync(&card->aneg_timer);
21398df158acSJeff Kirsher 
21408df158acSJeff Kirsher 	spider_net_disable_interrupts(card);
21418df158acSJeff Kirsher 
21428df158acSJeff Kirsher 	free_irq(netdev->irq, netdev);
21438df158acSJeff Kirsher 
21448df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
21458df158acSJeff Kirsher 			     SPIDER_NET_DMA_TX_FEND_VALUE);
21468df158acSJeff Kirsher 
21478df158acSJeff Kirsher 	/* turn off DMA, force end */
21488df158acSJeff Kirsher 	spider_net_disable_rxdmac(card);
21498df158acSJeff Kirsher 
21508df158acSJeff Kirsher 	/* release chains */
21518df158acSJeff Kirsher 	spider_net_release_tx_chain(card, 1);
21528df158acSJeff Kirsher 	spider_net_free_rx_chain_contents(card);
21538df158acSJeff Kirsher 
21548df158acSJeff Kirsher 	spider_net_free_chain(card, &card->tx_chain);
21558df158acSJeff Kirsher 	spider_net_free_chain(card, &card->rx_chain);
21568df158acSJeff Kirsher 
21578df158acSJeff Kirsher 	return 0;
21588df158acSJeff Kirsher }
21598df158acSJeff Kirsher 
21608df158acSJeff Kirsher /**
21618df158acSJeff Kirsher  * spider_net_tx_timeout_task - task scheduled by the watchdog timeout
21628df158acSJeff Kirsher  * function (to be called not under interrupt status)
2163e242d598SLee Jones  * @work: work context used to obtain the pointer to net card data structure
21648df158acSJeff Kirsher  *
21658df158acSJeff Kirsher  * called as task when tx hangs, resets interface (if interface is up)
21668df158acSJeff Kirsher  */
21678df158acSJeff Kirsher static void
spider_net_tx_timeout_task(struct work_struct * work)21688df158acSJeff Kirsher spider_net_tx_timeout_task(struct work_struct *work)
21698df158acSJeff Kirsher {
21708df158acSJeff Kirsher 	struct spider_net_card *card =
21718df158acSJeff Kirsher 		container_of(work, struct spider_net_card, tx_timeout_task);
21728df158acSJeff Kirsher 	struct net_device *netdev = card->netdev;
21738df158acSJeff Kirsher 
21748df158acSJeff Kirsher 	if (!(netdev->flags & IFF_UP))
21758df158acSJeff Kirsher 		goto out;
21768df158acSJeff Kirsher 
21778df158acSJeff Kirsher 	netif_device_detach(netdev);
21788df158acSJeff Kirsher 	spider_net_stop(netdev);
21798df158acSJeff Kirsher 
21808df158acSJeff Kirsher 	spider_net_workaround_rxramfull(card);
21818df158acSJeff Kirsher 	spider_net_init_card(card);
21828df158acSJeff Kirsher 
21838df158acSJeff Kirsher 	if (spider_net_setup_phy(card))
21848df158acSJeff Kirsher 		goto out;
21858df158acSJeff Kirsher 
21868df158acSJeff Kirsher 	spider_net_open(netdev);
21878df158acSJeff Kirsher 	spider_net_kick_tx_dma(card);
21888df158acSJeff Kirsher 	netif_device_attach(netdev);
21898df158acSJeff Kirsher 
21908df158acSJeff Kirsher out:
21918df158acSJeff Kirsher 	atomic_dec(&card->tx_timeout_task_counter);
21928df158acSJeff Kirsher }
21938df158acSJeff Kirsher 
21948df158acSJeff Kirsher /**
21958df158acSJeff Kirsher  * spider_net_tx_timeout - called when the tx timeout watchdog kicks in.
21968df158acSJeff Kirsher  * @netdev: interface device structure
2197e242d598SLee Jones  * @txqueue: unused
21988df158acSJeff Kirsher  *
21998df158acSJeff Kirsher  * called, if tx hangs. Schedules a task that resets the interface
22008df158acSJeff Kirsher  */
22018df158acSJeff Kirsher static void
spider_net_tx_timeout(struct net_device * netdev,unsigned int txqueue)22020290bd29SMichael S. Tsirkin spider_net_tx_timeout(struct net_device *netdev, unsigned int txqueue)
22038df158acSJeff Kirsher {
22048df158acSJeff Kirsher 	struct spider_net_card *card;
22058df158acSJeff Kirsher 
22068df158acSJeff Kirsher 	card = netdev_priv(netdev);
22078df158acSJeff Kirsher 	atomic_inc(&card->tx_timeout_task_counter);
22088df158acSJeff Kirsher 	if (netdev->flags & IFF_UP)
22098df158acSJeff Kirsher 		schedule_work(&card->tx_timeout_task);
22108df158acSJeff Kirsher 	else
22118df158acSJeff Kirsher 		atomic_dec(&card->tx_timeout_task_counter);
22128df158acSJeff Kirsher 	card->spider_stats.tx_timeouts++;
22138df158acSJeff Kirsher }
22148df158acSJeff Kirsher 
22158df158acSJeff Kirsher static const struct net_device_ops spider_net_ops = {
22168df158acSJeff Kirsher 	.ndo_open		= spider_net_open,
22178df158acSJeff Kirsher 	.ndo_stop		= spider_net_stop,
22188df158acSJeff Kirsher 	.ndo_start_xmit		= spider_net_xmit,
2219afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= spider_net_set_multi,
22208df158acSJeff Kirsher 	.ndo_set_mac_address	= spider_net_set_mac,
2221a7605370SArnd Bergmann 	.ndo_eth_ioctl		= spider_net_do_ioctl,
22228df158acSJeff Kirsher 	.ndo_tx_timeout		= spider_net_tx_timeout,
22238df158acSJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
22248df158acSJeff Kirsher 	/* HW VLAN */
22258df158acSJeff Kirsher #ifdef CONFIG_NET_POLL_CONTROLLER
22268df158acSJeff Kirsher 	/* poll controller */
22278df158acSJeff Kirsher 	.ndo_poll_controller	= spider_net_poll_controller,
22288df158acSJeff Kirsher #endif /* CONFIG_NET_POLL_CONTROLLER */
22298df158acSJeff Kirsher };
22308df158acSJeff Kirsher 
22318df158acSJeff Kirsher /**
22328df158acSJeff Kirsher  * spider_net_setup_netdev_ops - initialization of net_device operations
22338df158acSJeff Kirsher  * @netdev: net_device structure
22348df158acSJeff Kirsher  *
22358df158acSJeff Kirsher  * fills out function pointers in the net_device structure
22368df158acSJeff Kirsher  */
22378df158acSJeff Kirsher static void
spider_net_setup_netdev_ops(struct net_device * netdev)22388df158acSJeff Kirsher spider_net_setup_netdev_ops(struct net_device *netdev)
22398df158acSJeff Kirsher {
22408df158acSJeff Kirsher 	netdev->netdev_ops = &spider_net_ops;
22418df158acSJeff Kirsher 	netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
22428df158acSJeff Kirsher 	/* ethtool ops */
22438df158acSJeff Kirsher 	netdev->ethtool_ops = &spider_net_ethtool_ops;
22448df158acSJeff Kirsher }
22458df158acSJeff Kirsher 
22468df158acSJeff Kirsher /**
22478df158acSJeff Kirsher  * spider_net_setup_netdev - initialization of net_device
22488df158acSJeff Kirsher  * @card: card structure
22498df158acSJeff Kirsher  *
22508df158acSJeff Kirsher  * Returns 0 on success or <0 on failure
22518df158acSJeff Kirsher  *
22528df158acSJeff Kirsher  * spider_net_setup_netdev initializes the net_device structure
22538df158acSJeff Kirsher  **/
22548df158acSJeff Kirsher static int
spider_net_setup_netdev(struct spider_net_card * card)22558df158acSJeff Kirsher spider_net_setup_netdev(struct spider_net_card *card)
22568df158acSJeff Kirsher {
22578df158acSJeff Kirsher 	int result;
22588df158acSJeff Kirsher 	struct net_device *netdev = card->netdev;
22598df158acSJeff Kirsher 	struct device_node *dn;
22608df158acSJeff Kirsher 	struct sockaddr addr;
22618df158acSJeff Kirsher 	const u8 *mac;
22628df158acSJeff Kirsher 
22638df158acSJeff Kirsher 	SET_NETDEV_DEV(netdev, &card->pdev->dev);
22648df158acSJeff Kirsher 
22658df158acSJeff Kirsher 	pci_set_drvdata(card->pdev, netdev);
22668df158acSJeff Kirsher 
2267e99e88a9SKees Cook 	timer_setup(&card->tx_timer, spider_net_cleanup_tx_ring, 0);
22688df158acSJeff Kirsher 	netdev->irq = card->pdev->irq;
22698df158acSJeff Kirsher 
22708df158acSJeff Kirsher 	card->aneg_count = 0;
2271e99e88a9SKees Cook 	timer_setup(&card->aneg_timer, spider_net_link_phy, 0);
22728df158acSJeff Kirsher 
2273b48b89f9SJakub Kicinski 	netif_napi_add(netdev, &card->napi, spider_net_poll);
22748df158acSJeff Kirsher 
22758df158acSJeff Kirsher 	spider_net_setup_netdev_ops(netdev);
22768df158acSJeff Kirsher 
22778df158acSJeff Kirsher 	netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
22788df158acSJeff Kirsher 	if (SPIDER_NET_RX_CSUM_DEFAULT)
22798df158acSJeff Kirsher 		netdev->features |= NETIF_F_RXCSUM;
22808df158acSJeff Kirsher 	netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX;
2281f646968fSPatrick McHardy 	/* some time: NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
2282142c1d2eSYixing Liu 	 *		NETIF_F_HW_VLAN_CTAG_FILTER
2283142c1d2eSYixing Liu 	 */
22848df158acSJeff Kirsher 
22851281a2c7SJarod Wilson 	/* MTU range: 64 - 2294 */
22861281a2c7SJarod Wilson 	netdev->min_mtu = SPIDER_NET_MIN_MTU;
22871281a2c7SJarod Wilson 	netdev->max_mtu = SPIDER_NET_MAX_MTU;
22881281a2c7SJarod Wilson 
22898df158acSJeff Kirsher 	netdev->irq = card->pdev->irq;
22908df158acSJeff Kirsher 	card->num_rx_ints = 0;
22918df158acSJeff Kirsher 	card->ignore_rx_ramfull = 0;
22928df158acSJeff Kirsher 
22938df158acSJeff Kirsher 	dn = pci_device_to_OF_node(card->pdev);
22948df158acSJeff Kirsher 	if (!dn)
22958df158acSJeff Kirsher 		return -EIO;
22968df158acSJeff Kirsher 
22978df158acSJeff Kirsher 	mac = of_get_property(dn, "local-mac-address", NULL);
22988df158acSJeff Kirsher 	if (!mac)
22998df158acSJeff Kirsher 		return -EIO;
23008df158acSJeff Kirsher 	memcpy(addr.sa_data, mac, ETH_ALEN);
23018df158acSJeff Kirsher 
23028df158acSJeff Kirsher 	result = spider_net_set_mac(netdev, &addr);
23038df158acSJeff Kirsher 	if ((result) && (netif_msg_probe(card)))
23048df158acSJeff Kirsher 		dev_err(&card->netdev->dev,
23058df158acSJeff Kirsher 		        "Failed to set MAC address: %i\n", result);
23068df158acSJeff Kirsher 
23078df158acSJeff Kirsher 	result = register_netdev(netdev);
23088df158acSJeff Kirsher 	if (result) {
23098df158acSJeff Kirsher 		if (netif_msg_probe(card))
23108df158acSJeff Kirsher 			dev_err(&card->netdev->dev,
23118df158acSJeff Kirsher 			        "Couldn't register net_device: %i\n", result);
23128df158acSJeff Kirsher 		return result;
23138df158acSJeff Kirsher 	}
23148df158acSJeff Kirsher 
23158df158acSJeff Kirsher 	if (netif_msg_probe(card))
23168df158acSJeff Kirsher 		pr_info("Initialized device %s.\n", netdev->name);
23178df158acSJeff Kirsher 
23188df158acSJeff Kirsher 	return 0;
23198df158acSJeff Kirsher }
23208df158acSJeff Kirsher 
23218df158acSJeff Kirsher /**
23228df158acSJeff Kirsher  * spider_net_alloc_card - allocates net_device and card structure
23238df158acSJeff Kirsher  *
23248df158acSJeff Kirsher  * returns the card structure or NULL in case of errors
23258df158acSJeff Kirsher  *
23268df158acSJeff Kirsher  * the card and net_device structures are linked to each other
23278df158acSJeff Kirsher  */
23288df158acSJeff Kirsher static struct spider_net_card *
spider_net_alloc_card(void)23298df158acSJeff Kirsher spider_net_alloc_card(void)
23308df158acSJeff Kirsher {
23318df158acSJeff Kirsher 	struct net_device *netdev;
23328df158acSJeff Kirsher 	struct spider_net_card *card;
23338df158acSJeff Kirsher 
23343f1071ecSGustavo A. R. Silva 	netdev = alloc_etherdev(struct_size(card, darray,
2335*a2cc67b0SGustavo A. R. Silva 					    size_add(tx_descriptors, rx_descriptors)));
23368df158acSJeff Kirsher 	if (!netdev)
23378df158acSJeff Kirsher 		return NULL;
23388df158acSJeff Kirsher 
23398df158acSJeff Kirsher 	card = netdev_priv(netdev);
23408df158acSJeff Kirsher 	card->netdev = netdev;
23418df158acSJeff Kirsher 	card->msg_enable = SPIDER_NET_DEFAULT_MSG;
23428df158acSJeff Kirsher 	INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task);
23438df158acSJeff Kirsher 	init_waitqueue_head(&card->waitq);
23448df158acSJeff Kirsher 	atomic_set(&card->tx_timeout_task_counter, 0);
23458df158acSJeff Kirsher 
23468df158acSJeff Kirsher 	card->rx_chain.num_desc = rx_descriptors;
23478df158acSJeff Kirsher 	card->rx_chain.ring = card->darray;
23488df158acSJeff Kirsher 	card->tx_chain.num_desc = tx_descriptors;
23498df158acSJeff Kirsher 	card->tx_chain.ring = card->darray + rx_descriptors;
23508df158acSJeff Kirsher 
23518df158acSJeff Kirsher 	return card;
23528df158acSJeff Kirsher }
23538df158acSJeff Kirsher 
23548df158acSJeff Kirsher /**
23558df158acSJeff Kirsher  * spider_net_undo_pci_setup - releases PCI ressources
23568df158acSJeff Kirsher  * @card: card structure
23578df158acSJeff Kirsher  *
23588df158acSJeff Kirsher  * spider_net_undo_pci_setup releases the mapped regions
23598df158acSJeff Kirsher  */
23608df158acSJeff Kirsher static void
spider_net_undo_pci_setup(struct spider_net_card * card)23618df158acSJeff Kirsher spider_net_undo_pci_setup(struct spider_net_card *card)
23628df158acSJeff Kirsher {
23638df158acSJeff Kirsher 	iounmap(card->regs);
23648df158acSJeff Kirsher 	pci_release_regions(card->pdev);
23658df158acSJeff Kirsher }
23668df158acSJeff Kirsher 
23678df158acSJeff Kirsher /**
23688df158acSJeff Kirsher  * spider_net_setup_pci_dev - sets up the device in terms of PCI operations
23698df158acSJeff Kirsher  * @pdev: PCI device
23708df158acSJeff Kirsher  *
23718df158acSJeff Kirsher  * Returns the card structure or NULL if any errors occur
23728df158acSJeff Kirsher  *
23738df158acSJeff Kirsher  * spider_net_setup_pci_dev initializes pdev and together with the
23748df158acSJeff Kirsher  * functions called in spider_net_open configures the device so that
23758df158acSJeff Kirsher  * data can be transferred over it
23768df158acSJeff Kirsher  * The net_device structure is attached to the card structure, if the
23778df158acSJeff Kirsher  * function returns without error.
23788df158acSJeff Kirsher  **/
23798df158acSJeff Kirsher static struct spider_net_card *
spider_net_setup_pci_dev(struct pci_dev * pdev)23808df158acSJeff Kirsher spider_net_setup_pci_dev(struct pci_dev *pdev)
23818df158acSJeff Kirsher {
23828df158acSJeff Kirsher 	struct spider_net_card *card;
23838df158acSJeff Kirsher 	unsigned long mmio_start, mmio_len;
23848df158acSJeff Kirsher 
23858df158acSJeff Kirsher 	if (pci_enable_device(pdev)) {
23868df158acSJeff Kirsher 		dev_err(&pdev->dev, "Couldn't enable PCI device\n");
23878df158acSJeff Kirsher 		return NULL;
23888df158acSJeff Kirsher 	}
23898df158acSJeff Kirsher 
23908df158acSJeff Kirsher 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
23918df158acSJeff Kirsher 		dev_err(&pdev->dev,
23928df158acSJeff Kirsher 		        "Couldn't find proper PCI device base address.\n");
23938df158acSJeff Kirsher 		goto out_disable_dev;
23948df158acSJeff Kirsher 	}
23958df158acSJeff Kirsher 
23968df158acSJeff Kirsher 	if (pci_request_regions(pdev, spider_net_driver_name)) {
23978df158acSJeff Kirsher 		dev_err(&pdev->dev,
23988df158acSJeff Kirsher 		        "Couldn't obtain PCI resources, aborting.\n");
23998df158acSJeff Kirsher 		goto out_disable_dev;
24008df158acSJeff Kirsher 	}
24018df158acSJeff Kirsher 
24028df158acSJeff Kirsher 	pci_set_master(pdev);
24038df158acSJeff Kirsher 
24048df158acSJeff Kirsher 	card = spider_net_alloc_card();
24058df158acSJeff Kirsher 	if (!card) {
24068df158acSJeff Kirsher 		dev_err(&pdev->dev,
24078df158acSJeff Kirsher 		        "Couldn't allocate net_device structure, aborting.\n");
24088df158acSJeff Kirsher 		goto out_release_regions;
24098df158acSJeff Kirsher 	}
24108df158acSJeff Kirsher 	card->pdev = pdev;
24118df158acSJeff Kirsher 
24128df158acSJeff Kirsher 	/* fetch base address and length of first resource */
24138df158acSJeff Kirsher 	mmio_start = pci_resource_start(pdev, 0);
24148df158acSJeff Kirsher 	mmio_len = pci_resource_len(pdev, 0);
24158df158acSJeff Kirsher 
24168df158acSJeff Kirsher 	card->netdev->mem_start = mmio_start;
24178df158acSJeff Kirsher 	card->netdev->mem_end = mmio_start + mmio_len;
24188df158acSJeff Kirsher 	card->regs = ioremap(mmio_start, mmio_len);
24198df158acSJeff Kirsher 
24208df158acSJeff Kirsher 	if (!card->regs) {
24218df158acSJeff Kirsher 		dev_err(&pdev->dev,
24228df158acSJeff Kirsher 		        "Couldn't obtain PCI resources, aborting.\n");
24238df158acSJeff Kirsher 		goto out_release_regions;
24248df158acSJeff Kirsher 	}
24258df158acSJeff Kirsher 
24268df158acSJeff Kirsher 	return card;
24278df158acSJeff Kirsher 
24288df158acSJeff Kirsher out_release_regions:
24298df158acSJeff Kirsher 	pci_release_regions(pdev);
24308df158acSJeff Kirsher out_disable_dev:
24318df158acSJeff Kirsher 	pci_disable_device(pdev);
24328df158acSJeff Kirsher 	return NULL;
24338df158acSJeff Kirsher }
24348df158acSJeff Kirsher 
24358df158acSJeff Kirsher /**
24368df158acSJeff Kirsher  * spider_net_probe - initialization of a device
24378df158acSJeff Kirsher  * @pdev: PCI device
24388df158acSJeff Kirsher  * @ent: entry in the device id list
24398df158acSJeff Kirsher  *
24408df158acSJeff Kirsher  * Returns 0 on success, <0 on failure
24418df158acSJeff Kirsher  *
24428df158acSJeff Kirsher  * spider_net_probe initializes pdev and registers a net_device
24438df158acSJeff Kirsher  * structure for it. After that, the device can be ifconfig'ed up
24448df158acSJeff Kirsher  **/
2445671a1435SBill Pemberton static int
spider_net_probe(struct pci_dev * pdev,const struct pci_device_id * ent)24468df158acSJeff Kirsher spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
24478df158acSJeff Kirsher {
24488df158acSJeff Kirsher 	int err = -EIO;
24498df158acSJeff Kirsher 	struct spider_net_card *card;
24508df158acSJeff Kirsher 
24518df158acSJeff Kirsher 	card = spider_net_setup_pci_dev(pdev);
24528df158acSJeff Kirsher 	if (!card)
24538df158acSJeff Kirsher 		goto out;
24548df158acSJeff Kirsher 
24558df158acSJeff Kirsher 	spider_net_workaround_rxramfull(card);
24568df158acSJeff Kirsher 	spider_net_init_card(card);
24578df158acSJeff Kirsher 
24588df158acSJeff Kirsher 	err = spider_net_setup_phy(card);
24598df158acSJeff Kirsher 	if (err)
24608df158acSJeff Kirsher 		goto out_undo_pci;
24618df158acSJeff Kirsher 
24628df158acSJeff Kirsher 	err = spider_net_setup_netdev(card);
24638df158acSJeff Kirsher 	if (err)
24648df158acSJeff Kirsher 		goto out_undo_pci;
24658df158acSJeff Kirsher 
24668df158acSJeff Kirsher 	return 0;
24678df158acSJeff Kirsher 
24688df158acSJeff Kirsher out_undo_pci:
24698df158acSJeff Kirsher 	spider_net_undo_pci_setup(card);
24708df158acSJeff Kirsher 	free_netdev(card->netdev);
24718df158acSJeff Kirsher out:
24728df158acSJeff Kirsher 	return err;
24738df158acSJeff Kirsher }
24748df158acSJeff Kirsher 
24758df158acSJeff Kirsher /**
24768df158acSJeff Kirsher  * spider_net_remove - removal of a device
24778df158acSJeff Kirsher  * @pdev: PCI device
24788df158acSJeff Kirsher  *
24798df158acSJeff Kirsher  * Returns 0 on success, <0 on failure
24808df158acSJeff Kirsher  *
24818df158acSJeff Kirsher  * spider_net_remove is called to remove the device and unregisters the
24828df158acSJeff Kirsher  * net_device
24838df158acSJeff Kirsher  **/
2484671a1435SBill Pemberton static void
spider_net_remove(struct pci_dev * pdev)24858df158acSJeff Kirsher spider_net_remove(struct pci_dev *pdev)
24868df158acSJeff Kirsher {
24878df158acSJeff Kirsher 	struct net_device *netdev;
24888df158acSJeff Kirsher 	struct spider_net_card *card;
24898df158acSJeff Kirsher 
24908df158acSJeff Kirsher 	netdev = pci_get_drvdata(pdev);
24918df158acSJeff Kirsher 	card = netdev_priv(netdev);
24928df158acSJeff Kirsher 
24938df158acSJeff Kirsher 	wait_event(card->waitq,
24948df158acSJeff Kirsher 		   atomic_read(&card->tx_timeout_task_counter) == 0);
24958df158acSJeff Kirsher 
24968df158acSJeff Kirsher 	unregister_netdev(netdev);
24978df158acSJeff Kirsher 
24988df158acSJeff Kirsher 	/* switch off card */
24998df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
25008df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_STOP_VALUE);
25018df158acSJeff Kirsher 	spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
25028df158acSJeff Kirsher 			     SPIDER_NET_CKRCTRL_RUN_VALUE);
25038df158acSJeff Kirsher 
25048df158acSJeff Kirsher 	spider_net_undo_pci_setup(card);
25058df158acSJeff Kirsher 	free_netdev(netdev);
25068df158acSJeff Kirsher }
25078df158acSJeff Kirsher 
25088df158acSJeff Kirsher static struct pci_driver spider_net_driver = {
25098df158acSJeff Kirsher 	.name		= spider_net_driver_name,
25108df158acSJeff Kirsher 	.id_table	= spider_net_pci_tbl,
25118df158acSJeff Kirsher 	.probe		= spider_net_probe,
2512671a1435SBill Pemberton 	.remove		= spider_net_remove
25138df158acSJeff Kirsher };
25148df158acSJeff Kirsher 
25158df158acSJeff Kirsher /**
25168df158acSJeff Kirsher  * spider_net_init - init function when the driver is loaded
25178df158acSJeff Kirsher  *
25188df158acSJeff Kirsher  * spider_net_init registers the device driver
25198df158acSJeff Kirsher  */
spider_net_init(void)25208df158acSJeff Kirsher static int __init spider_net_init(void)
25218df158acSJeff Kirsher {
25228df158acSJeff Kirsher 	printk(KERN_INFO "Spidernet version %s.\n", VERSION);
25238df158acSJeff Kirsher 
25248df158acSJeff Kirsher 	if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
25258df158acSJeff Kirsher 		rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
25268df158acSJeff Kirsher 		pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
25278df158acSJeff Kirsher 	}
25288df158acSJeff Kirsher 	if (rx_descriptors > SPIDER_NET_RX_DESCRIPTORS_MAX) {
25298df158acSJeff Kirsher 		rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MAX;
25308df158acSJeff Kirsher 		pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
25318df158acSJeff Kirsher 	}
25328df158acSJeff Kirsher 	if (tx_descriptors < SPIDER_NET_TX_DESCRIPTORS_MIN) {
25338df158acSJeff Kirsher 		tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MIN;
25348df158acSJeff Kirsher 		pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
25358df158acSJeff Kirsher 	}
25368df158acSJeff Kirsher 	if (tx_descriptors > SPIDER_NET_TX_DESCRIPTORS_MAX) {
25378df158acSJeff Kirsher 		tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_MAX;
25388df158acSJeff Kirsher 		pr_info("adjusting tx descriptors to %i.\n", tx_descriptors);
25398df158acSJeff Kirsher 	}
25408df158acSJeff Kirsher 
25418df158acSJeff Kirsher 	return pci_register_driver(&spider_net_driver);
25428df158acSJeff Kirsher }
25438df158acSJeff Kirsher 
25448df158acSJeff Kirsher /**
25458df158acSJeff Kirsher  * spider_net_cleanup - exit function when driver is unloaded
25468df158acSJeff Kirsher  *
25478df158acSJeff Kirsher  * spider_net_cleanup unregisters the device driver
25488df158acSJeff Kirsher  */
spider_net_cleanup(void)25498df158acSJeff Kirsher static void __exit spider_net_cleanup(void)
25508df158acSJeff Kirsher {
25518df158acSJeff Kirsher 	pci_unregister_driver(&spider_net_driver);
25528df158acSJeff Kirsher }
25538df158acSJeff Kirsher 
25548df158acSJeff Kirsher module_init(spider_net_init);
25558df158acSJeff Kirsher module_exit(spider_net_cleanup);
2556