X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fstarfire.c;h=f9521136a869bde8e313072c26f5979e2f84277a;hb=fef5ba3ae9760fdc2688b7160fa056e7ef2700bb;hp=a6bf5728fed1c5963a90f008db129e715c9f4872;hpb=f71e130966ba429dbd24be08ddbcdf263df9a5ad;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index a6bf572..f952113 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -22,131 +22,14 @@ Support and updates available at http://www.scyld.com/network/starfire.html + [link no longer provides useful info -jgarzik] - ----------------------------------------------------------- - - Linux kernel-specific changes: - - LK1.1.1 (jgarzik): - - Use PCI driver interface - - Fix MOD_xxx races - - softnet fixups - - LK1.1.2 (jgarzik): - - Merge Becker version 0.15 - - LK1.1.3 (Andrew Morton) - - Timer cleanups - - LK1.1.4 (jgarzik): - - Merge Becker version 1.03 - - LK1.2.1 (Ion Badulescu ) - - Support hardware Rx/Tx checksumming - - Use the GFP firmware taken from Adaptec's Netware driver - - LK1.2.2 (Ion Badulescu) - - Backported to 2.2.x - - LK1.2.3 (Ion Badulescu) - - Fix the flaky mdio interface - - More compat clean-ups - - LK1.2.4 (Ion Badulescu) - - More 2.2.x initialization fixes - - LK1.2.5 (Ion Badulescu) - - Several fixes from Manfred Spraul - - LK1.2.6 (Ion Badulescu) - - Fixed ifup/ifdown/ifup problem in 2.4.x - - LK1.2.7 (Ion Badulescu) - - Removed unused code - - Made more functions static and __init - - LK1.2.8 (Ion Badulescu) - - Quell bogus error messages, inform about the Tx threshold - - Removed #ifdef CONFIG_PCI, this driver is PCI only - - LK1.2.9 (Ion Badulescu) - - Merged Jeff Garzik's changes from 2.4.4-pre5 - - Added 2.2.x compatibility stuff required by the above changes - - LK1.2.9a (Ion Badulescu) - - More updates from Jeff Garzik - - LK1.3.0 (Ion Badulescu) - - Merged zerocopy support - - LK1.3.1 (Ion Badulescu) - - Added ethtool support - - Added GPIO (media change) interrupt support - - LK1.3.2 (Ion Badulescu) - - Fixed 2.2.x compatibility issues introduced in 1.3.1 - - Fixed ethtool ioctl returning uninitialized memory - - LK1.3.3 (Ion Badulescu) - - Initialize the TxMode register properly - - Don't dereference dev->priv after freeing it - - LK1.3.4 (Ion Badulescu) - - Fixed initialization timing problems - - Fixed interrupt mask definitions - - LK1.3.5 (jgarzik) - - ethtool NWAY_RST, GLINK, [GS]MSGLVL support - - LK1.3.6: - - Sparc64 support and fixes (Ion Badulescu) - - Better stats and error handling (Ion Badulescu) - - Use new pci_set_mwi() PCI API function (jgarzik) - - LK1.3.7 (Ion Badulescu) - - minimal implementation of tx_timeout() - - correctly shutdown the Rx/Tx engines in netdev_close() - - added calls to netif_carrier_on/off - (patch from Stefan Rompf ) - - VLAN support - - LK1.3.8 (Ion Badulescu) - - adjust DMA burst size on sparc64 - - 64-bit support - - reworked zerocopy support for 64-bit buffers - - working and usable interrupt mitigation/latency - - reduced Tx interrupt frequency for lower interrupt overhead - - LK1.3.9 (Ion Badulescu) - - bugfix for mcast filter - - enable the right kind of Tx interrupts (TxDMADone, not TxDone) - - LK1.4.0 (Ion Badulescu) - - NAPI support - - LK1.4.1 (Ion Badulescu) - - flush PCI posting buffers after disabling Rx interrupts - - put the chip to a D3 slumber on driver unload - - added config option to enable/disable NAPI - - LK1.4.2 (Ion Badulescu) - - finally added firmware (GPL'ed by Adaptec) - - removed compatibility code for 2.2.x - - LK1.4.2.1 (Ion Badulescu) - - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM - - added 32-bit padding to outgoing skb's, removed previous workaround - -TODO: - fix forced speed/duplexing code (broken a long time ago, when - somebody converted the driver to use the generic MII code) - - fix VLAN support */ #define DRV_NAME "starfire" -#define DRV_VERSION "1.03+LK1.4.2.1" -#define DRV_RELDATE "October 3, 2005" +#define DRV_VERSION "2.1" +#define DRV_RELDATE "July 6, 2008" -#include #include #include #include @@ -158,11 +41,12 @@ TODO: - fix forced speed/duplexing code (broken a long time ago, when #include #include #include +#include +#include #include /* Processor type for cache alignment. */ #include #include -#include "starfire_firmware.h" /* * The current frame processor firmware fails to checksum a fragment * of length 1. If and when this is fixed, the #define below can be removed. @@ -185,10 +69,6 @@ TODO: - fix forced speed/duplexing code (broken a long time ago, when #define VLAN_SUPPORT #endif -#ifndef CONFIG_ADAPTEC_STARFIRE_NAPI -#undef HAVE_NETDEV_POLL -#endif - /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -268,10 +148,10 @@ static int full_duplex[MAX_UNITS] = {0, }; * This SUCKS. * We need a much better method to determine if dma_addr_t is 64-bit. */ -#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) +#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ -#define netdrv_addr_t u64 +#define netdrv_addr_t __le64 #define cpu_to_dma(x) cpu_to_le64(x) #define dma_to_cpu(x) le64_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit @@ -280,7 +160,7 @@ static int full_duplex[MAX_UNITS] = {0, }; #define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit #define RX_DESC_ADDR_SIZE RxDescAddr64bit #else /* 32-bit dma_addr_t */ -#define netdrv_addr_t u32 +#define netdrv_addr_t __le32 #define cpu_to_dma(x) cpu_to_le32(x) #define dma_to_cpu(x) le32_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit @@ -293,56 +173,21 @@ static int full_duplex[MAX_UNITS] = {0, }; #define skb_first_frag_len(skb) skb_headlen(skb) #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1) -#ifdef HAVE_NETDEV_POLL -#define init_poll(dev) \ -do { \ - dev->poll = &netdev_poll; \ - dev->weight = max_interrupt_work; \ -} while (0) -#define netdev_rx(dev, ioaddr) \ -do { \ - u32 intr_enable; \ - if (netif_rx_schedule_prep(dev)) { \ - __netif_rx_schedule(dev); \ - intr_enable = readl(ioaddr + IntrEnable); \ - intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ - writel(intr_enable, ioaddr + IntrEnable); \ - readl(ioaddr + IntrEnable); /* flush PCI posting buffers */ \ - } else { \ - /* Paranoia check */ \ - intr_enable = readl(ioaddr + IntrEnable); \ - if (intr_enable & (IntrRxDone | IntrRxEmpty)) { \ - printk(KERN_INFO "%s: interrupt while in polling mode!\n", dev->name); \ - intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ - writel(intr_enable, ioaddr + IntrEnable); \ - } \ - } \ -} while (0) -#define netdev_receive_skb(skb) netif_receive_skb(skb) -#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid) -static int netdev_poll(struct net_device *dev, int *budget); -#else /* not HAVE_NETDEV_POLL */ -#define init_poll(dev) -#define netdev_receive_skb(skb) netif_rx(skb) -#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid) -#define netdev_rx(dev, ioaddr) \ -do { \ - int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \ - __netdev_rx(dev, "a);\ -} while (0) -#endif /* not HAVE_NETDEV_POLL */ -/* end of compatibility code */ - +/* Firmware names */ +#define FIRMWARE_RX "adaptec/starfire_rx.bin" +#define FIRMWARE_TX "adaptec/starfire_tx.bin" /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static const char version[] __devinitconst = KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker \n" -KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; +" (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +MODULE_FIRMWARE(FIRMWARE_RX); +MODULE_FIRMWARE(FIRMWARE_TX); module_param(max_interrupt_work, int, 0); module_param(mtu, int, 0); @@ -613,7 +458,7 @@ enum intr_ctrl_bits { /* The Rx and Tx buffer descriptors. */ struct starfire_rx_desc { - dma_addr_t rxaddr; + netdrv_addr_t rxaddr; }; enum rx_desc_bits { RxDescValid=1, RxDescEndRing=2, @@ -621,25 +466,25 @@ enum rx_desc_bits { /* Completion queue entry. */ struct short_rx_done_desc { - u32 status; /* Low 16 bits is length. */ + __le32 status; /* Low 16 bits is length. */ }; struct basic_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 vlanid; - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 vlanid; + __le16 status2; }; struct csum_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 csum; /* Partial checksum */ - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 csum; /* Partial checksum */ + __le16 status2; }; struct full_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 status3; - u16 status2; - u16 vlanid; - u16 csum; /* partial checksum */ - u32 timestamp; + __le32 status; /* Low 16 bits is length. */ + __le16 status3; + __le16 status2; + __le16 vlanid; + __le16 csum; /* partial checksum */ + __le32 timestamp; }; /* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */ #ifdef VLAN_SUPPORT @@ -656,15 +501,15 @@ enum rx_done_bits { /* Type 1 Tx descriptor. */ struct starfire_tx_desc_1 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 addr; }; /* Type 2 Tx descriptor. */ struct starfire_tx_desc_2 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 reserved; - u64 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 reserved; + __le64 addr; }; #ifdef ADDR_64BITS @@ -682,9 +527,9 @@ enum tx_desc_bits { TxRingWrap=0x04000000, TxCalTCP=0x02000000, }; struct tx_done_desc { - u32 status; /* timestamp, index. */ + __le32 status; /* timestamp, index. */ #if 0 - u32 intrstatus; /* interrupt status */ + __le32 intrstatus; /* interrupt status */ #endif }; @@ -715,6 +560,8 @@ struct netdev_private { struct tx_done_desc *tx_done_q; dma_addr_t tx_done_q_dma; unsigned int tx_done; + struct napi_struct napi; + struct net_device *dev; struct net_device_stats stats; struct pci_dev *pci_dev; #ifdef VLAN_SUPPORT @@ -748,10 +595,11 @@ static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int __netdev_rx(struct net_device *dev, int *quota); +static int netdev_poll(struct napi_struct *napi, int budget); static void refill_rx_ring(struct net_device *dev); static void netdev_error(struct net_device *dev, int intr_status); static void set_rx_mode(struct net_device *dev); @@ -759,7 +607,7 @@ static struct net_device_stats *get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); static void netdev_media_change(struct net_device *dev); -static struct ethtool_ops ethtool_ops; +static const struct ethtool_ops ethtool_ops; #ifdef VLAN_SUPPORT @@ -793,14 +641,31 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) spin_lock(&np->lock); if (debug > 1) printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid); - if (np->vlgrp) - np->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(np->vlgrp, vid, NULL); set_rx_mode(dev); spin_unlock(&np->lock); } #endif /* VLAN_SUPPORT */ +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_tx_timeout = tx_timeout, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = &set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef VLAN_SUPPORT + .ndo_vlan_rx_register = netdev_vlan_rx_register, + .ndo_vlan_rx_add_vid = netdev_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = netdev_vlan_rx_kill_vid, +#endif +}; + static int __devinit starfire_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -837,7 +702,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); irq = pdev->irq; @@ -847,7 +711,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, goto err_out_free_netdev; } - /* ioremap is borken in Linux-2.2.x/sparc64 */ base = ioremap(ioaddr, io_size); if (!base) { printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n", @@ -858,18 +721,16 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, pci_set_master(pdev); /* enable MWI -- it vastly improves Rx performance on sparc64 */ - pci_set_mwi(pdev); + pci_try_set_mwi(pdev); #ifdef ZEROCOPY /* Starfire can do TCP/UDP checksumming */ if (enable_hw_cksum) dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; #endif /* ZEROCOPY */ + #ifdef VLAN_SUPPORT dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - dev->vlan_rx_register = netdev_vlan_rx_register; - dev->vlan_rx_add_vid = netdev_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = netdev_vlan_rx_kill_vid; #endif /* VLAN_RX_KILL_VID */ #ifdef ADDR_64BITS dev->features |= NETIF_F_HIGHDMA; @@ -909,6 +770,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + np->dev = dev; np->base = base; spin_lock_init(&np->lock); pci_set_drvdata(pdev, dev); @@ -964,29 +826,21 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, } } - /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->tx_timeout = tx_timeout; + dev->netdev_ops = &netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - init_poll(dev); - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; SET_ETHTOOL_OPS(dev, ðtool_ops); + netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work); + if (mtu) dev->mtu = mtu; if (register_netdev(dev)) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, netdrv_tbl[chip_idx].name, base); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", + dev->name, netdrv_tbl[chip_idx].name, base, + dev->dev_addr, irq); if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1042,9 +896,9 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2); int result, boguscnt=1000; /* ??? Should we add a busy-wait here? */ - do + do { result = readl(mdio_addr); - while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); + } while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); if (boguscnt == 0) return 0; if ((result & 0xffff) == 0xffff) @@ -1064,14 +918,17 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static int netdev_open(struct net_device *dev) { + const struct firmware *fw_rx, *fw_tx; + const __be32 *fw_rx_data, *fw_tx_data; struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; int i, retval; + size_t tx_size, rx_size; size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size; /* Do we ever need to reset the chip??? */ - retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); + retval = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); if (retval) return retval; @@ -1083,7 +940,7 @@ static int netdev_open(struct net_device *dev) dev->name, dev->irq); /* Allocate the various queues. */ - if (np->queue_mem == 0) { + if (!np->queue_mem) { tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; @@ -1156,11 +1013,11 @@ static int netdev_open(struct net_device *dev) writew(0, ioaddr + PerfFilterTable + 4); writew(0, ioaddr + PerfFilterTable + 8); for (i = 1; i < 16; i++) { - u16 *eaddrs = (u16 *)dev->dev_addr; + __be16 *eaddrs = (__be16 *)dev->dev_addr; void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16; - writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; + writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ @@ -1174,6 +1031,8 @@ static int netdev_open(struct net_device *dev) writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl); + napi_enable(&np->napi); + netif_start_queue(dev); if (debug > 1) @@ -1200,11 +1059,40 @@ static int netdev_open(struct net_device *dev) writel(ETH_P_8021Q, ioaddr + VlanType); #endif /* VLAN_SUPPORT */ + retval = request_firmware(&fw_rx, FIRMWARE_RX, &np->pci_dev->dev); + if (retval) { + printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n", + FIRMWARE_RX); + goto out_init; + } + if (fw_rx->size % 4) { + printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n", + fw_rx->size, FIRMWARE_RX); + retval = -EINVAL; + goto out_rx; + } + retval = request_firmware(&fw_tx, FIRMWARE_TX, &np->pci_dev->dev); + if (retval) { + printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n", + FIRMWARE_TX); + goto out_rx; + } + if (fw_tx->size % 4) { + printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n", + fw_tx->size, FIRMWARE_TX); + retval = -EINVAL; + goto out_tx; + } + fw_rx_data = (const __be32 *)&fw_rx->data[0]; + fw_tx_data = (const __be32 *)&fw_tx->data[0]; + rx_size = fw_rx->size / 4; + tx_size = fw_tx->size / 4; + /* Load Rx/Tx firmware into the frame processors */ - for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++) - writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4); - for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++) - writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4); + for (i = 0; i < rx_size; i++) + writel(be32_to_cpup(&fw_rx_data[i]), ioaddr + RxGfpMem + i * 4); + for (i = 0; i < tx_size; i++) + writel(be32_to_cpup(&fw_tx_data[i]), ioaddr + TxGfpMem + i * 4); if (enable_hw_cksum) /* Enable the Rx and Tx units, and the Rx/Tx frame processors. */ writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl); @@ -1216,7 +1104,14 @@ static int netdev_open(struct net_device *dev) printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); - return 0; +out_tx: + release_firmware(fw_tx); +out_rx: + release_firmware(fw_rx); +out_init: + if (retval) + netdev_close(dev); + return retval; } @@ -1331,7 +1226,7 @@ static void init_ring(struct net_device *dev) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned int entry; @@ -1344,13 +1239,12 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) */ if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) { netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) - if (skb->ip_summed == CHECKSUM_HW) { - skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK); - if (skb == NULL) + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK)) return NETDEV_TX_OK; } #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */ @@ -1371,7 +1265,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) status |= TxDescIntr; np->reap_tx = 0; } - if (skb->ip_summed == CHECKSUM_HW) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { status |= TxCalTCP; np->stats.tx_compressed++; } @@ -1420,13 +1314,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); @@ -1448,8 +1342,28 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs handled = 1; - if (intr_status & (IntrRxDone | IntrRxEmpty)) - netdev_rx(dev, ioaddr); + if (intr_status & (IntrRxDone | IntrRxEmpty)) { + u32 enable; + + if (likely(napi_schedule_prep(&np->napi))) { + __napi_schedule(&np->napi); + enable = readl(ioaddr + IntrEnable); + enable &= ~(IntrRxDone | IntrRxEmpty); + writel(enable, ioaddr + IntrEnable); + /* flush PCI posting buffers */ + readl(ioaddr + IntrEnable); + } else { + /* Paranoia check */ + enable = readl(ioaddr + IntrEnable); + if (enable & (IntrRxDone | IntrRxEmpty)) { + printk(KERN_INFO + "%s: interrupt while in poll!\n", + dev->name); + enable &= ~(IntrRxDone | IntrRxEmpty); + writel(enable, ioaddr + IntrEnable); + } + } + } /* Scavenge the skbuff list based on the Tx-done queue. There are redundant checks here that may be cleaned up @@ -1529,8 +1443,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs } -/* This routine is logically part of the interrupt/poll handler, but separated - for clarity, code sharing between NAPI/non-NAPI, and better register allocation. */ +/* + * This routine is logically part of the interrupt/poll handler, but separated + * for clarity and better register allocation. + */ static int __netdev_rx(struct net_device *dev, int *quota) { struct netdev_private *np = netdev_priv(dev); @@ -1569,14 +1485,13 @@ static int __netdev_rx(struct net_device *dev, int *quota) printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d, quota %d.\n", pkt_len, *quota); /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0); + skb_copy_to_linear_data(skb, np->rx_info[entry].skb->data, pkt_len); pci_dma_sync_single_for_device(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); @@ -1590,13 +1505,11 @@ static int __netdev_rx(struct net_device *dev, int *quota) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13]); + if (debug > 5) { + printk(KERN_DEBUG " Rx data %pM %pM %2.2x%2.2x.\n", + skb->data, skb->data + 6, + skb->data[12], skb->data[13]); + } #endif skb->protocol = eth_type_trans(skb, dev); @@ -1618,20 +1531,26 @@ static int __netdev_rx(struct net_device *dev, int *quota) * Until then, the printk stays. :-) -Ion */ else if (le16_to_cpu(desc->status2) & 0x0040) { - skb->ip_summed = CHECKSUM_HW; + skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = le16_to_cpu(desc->csum); printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2)); } #ifdef VLAN_SUPPORT if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) { - if (debug > 4) - printk(KERN_DEBUG " netdev_rx() vlanid = %d\n", le16_to_cpu(desc->vlanid)); - /* vlan_netdev_receive_skb() expects a packet with the VLAN tag stripped out */ - vlan_netdev_receive_skb(skb, np->vlgrp, le16_to_cpu(desc->vlanid) & VLAN_VID_MASK); + u16 vlid = le16_to_cpu(desc->vlanid); + + if (debug > 4) { + printk(KERN_DEBUG " netdev_rx() vlanid = %d\n", + vlid); + } + /* + * vlan_hwaccel_rx expects a packet with the VLAN tag + * stripped out. + */ + vlan_hwaccel_rx(skb, np->vlgrp, vlid); } else #endif /* VLAN_SUPPORT */ - netdev_receive_skb(skb); - dev->last_rx = jiffies; + netif_receive_skb(skb); np->stats.rx_packets++; next_rx: @@ -1639,6 +1558,11 @@ static int __netdev_rx(struct net_device *dev, int *quota) desc->status = 0; np->rx_done = (np->rx_done + 1) % DONE_Q_SIZE; } + + if (*quota == 0) { /* out of rx quota */ + retcode = 1; + goto out; + } writew(np->rx_done, np->base + CompletionQConsumerIdx); out: @@ -1649,41 +1573,36 @@ static int __netdev_rx(struct net_device *dev, int *quota) return retcode; } - -#ifdef HAVE_NETDEV_POLL -static int netdev_poll(struct net_device *dev, int *budget) +static int netdev_poll(struct napi_struct *napi, int budget) { + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; u32 intr_status; - struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; - int retcode = 0, quota = dev->quota; + int quota = budget; do { writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear); - retcode = __netdev_rx(dev, "a); - *budget -= (dev->quota - quota); - dev->quota = quota; - if (retcode) + if (__netdev_rx(dev, "a)) goto out; intr_status = readl(ioaddr + IntrStatus); } while (intr_status & (IntrRxDone | IntrRxEmpty)); - netif_rx_complete(dev); + napi_complete(napi); intr_status = readl(ioaddr + IntrEnable); intr_status |= IntrRxDone | IntrRxEmpty; writel(intr_status, ioaddr + IntrEnable); out: if (debug > 5) - printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", retcode); + printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", + budget - quota); /* Restart Rx engine if stopped. */ - return retcode; + return budget - quota; } -#endif /* HAVE_NETDEV_POLL */ - static void refill_rx_ring(struct net_device *dev) { @@ -1856,10 +1775,10 @@ static void set_rx_mode(struct net_device *dev) int vlan_count = 0; void __iomem *filter_addr = ioaddr + HashTable + 8; for (i = 0; i < VLAN_VID_MASK; i++) { - if (np->vlgrp->vlan_devices[i]) { + if (vlan_group_get_device(np->vlgrp, i)) { if (vlan_count >= 32) break; - writew(cpu_to_be16(i), filter_addr); + writew(i, filter_addr); filter_addr += 16; vlan_count++; } @@ -1877,33 +1796,33 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode |= AcceptAll; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter; } else if (dev->mc_count <= 14) { /* Use the 16 element perfect filter, skip first two entries. */ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16; - u16 *eaddrs; + __be16 *eaddrs; for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2; i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; + eaddrs = (__be16 *)mclist->dmi_addr; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8; } - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; while (i++ < 16) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } rx_mode |= AcceptBroadcast|PerfectFilter; } else { /* Must use a multicast hash table. */ void __iomem *filter_addr; - u16 *eaddrs; - u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + __be16 *eaddrs; + __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; @@ -1911,17 +1830,17 @@ static void set_rx_mode(struct net_device *dev) /* The chip uses the upper 9 CRC bits as index into the hash table */ int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23; - __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1]; + __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1]; *fptr |= cpu_to_le32(1 << (bit_nr & 31)); } /* Clear the perfect filter list, skip first two entries. */ filter_addr = ioaddr + PerfFilterTable + 2 * 16; - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; for (i = 2; i < 16; i++) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++) writew(mc_filter[i], filter_addr); @@ -1987,7 +1906,7 @@ static void set_msglevel(struct net_device *dev, u32 val) debug = val; } -static struct ethtool_ops ethtool_ops = { +static const struct ethtool_ops ethtool_ops = { .begin = check_if_running, .get_drvinfo = get_drvinfo, .get_settings = get_settings, @@ -2025,6 +1944,8 @@ static int netdev_close(struct net_device *dev) netif_stop_queue(dev); + napi_disable(&np->napi); + if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n", dev->name, (int) readl(ioaddr + IntrStatus)); @@ -2084,14 +2005,45 @@ static int netdev_close(struct net_device *dev) return 0; } +#ifdef CONFIG_PM +static int starfire_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (netif_running(dev)) { + netif_device_detach(dev); + netdev_close(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev,state)); + + return 0; +} + +static int starfire_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (netif_running(dev)) { + netdev_open(dev); + netif_device_attach(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + static void __devexit starfire_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct netdev_private *np = netdev_priv(dev); - if (!dev) - BUG(); + BUG_ON(!dev); unregister_netdev(dev); @@ -2115,6 +2067,10 @@ static struct pci_driver starfire_driver = { .name = DRV_NAME, .probe = starfire_init_one, .remove = __devexit_p(starfire_remove_one), +#ifdef CONFIG_PM + .suspend = starfire_suspend, + .resume = starfire_resume, +#endif /* CONFIG_PM */ .id_table = starfire_pci_tbl, }; @@ -2124,11 +2080,8 @@ static int __init starfire_init (void) /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE printk(version); -#ifdef HAVE_NETDEV_POLL + printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n"); -#else - printk(KERN_INFO DRV_NAME ": polling (NAPI) disabled\n"); -#endif #endif /* we can do this test only at run-time... sigh */ @@ -2137,7 +2090,7 @@ static int __init starfire_init (void) return -ENODEV; } - return pci_module_init (&starfire_driver); + return pci_register_driver(&starfire_driver); }