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