diff -Nru linux-2.6.8.1-davem269_4/drivers/net/Kconfig linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig --- linux-2.6.8.1-davem269_4/drivers/net/Kconfig 2004-08-14 12:56:00.000000000 +0200 +++ linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/Kconfig 2004-09-14 11:40:40.000000000 +0200 @@ -569,6 +569,22 @@ help Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also . +config SUNGEM_NAPI + bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" + depends on SUNGEM && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + + If in doubt, say N. config NET_VENDOR_3COM bool "3COM cards" --- linux-2.6.8.1-davem269_4/drivers/net/sungem.c 2004-08-14 12:56:23.000000000 +0200 +++ linux-2.6.8.1-davem269_4-sungem-napi/drivers/net/sungem.c 2004-09-14 21:48:04.421487058 +0200 @@ -5,6 +5,9 @@ * * Support for Apple GMAC and assorted PHYs by * Benjamin Herrenscmidt (benh@xxxxxxxxxxxxxxxxxxx) + * + * Support for NAPI and NETPOLL + * (C) 2004 by Harald Welte * * TODO: * - Get rid of all those nasty mdelay's and replace them @@ -71,8 +74,8 @@ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) #define DRV_NAME "sungem" -#define DRV_VERSION "0.98" -#define DRV_RELDATE "8/24/03" +#define DRV_VERSION "0.98-napi" +#define DRV_RELDATE "9/14/04" #define DRV_AUTHOR "David S. Miller (davem@xxxxxxxxxx)" static char version[] __devinitdata = @@ -187,6 +190,29 @@ printk(KERN_DEBUG "%s: mif interrupt\n", gp->dev->name); } +static inline void +gem_irq_disable(struct gem *gp) +{ + /* Make sure we won't get any more interrupts */ + writel(0xffffffff, gp->regs + GREG_IMASK); + mb(); +} + +static inline void +gem_irq_enable(struct gem *gp, unsigned int mask) +{ + /* We don't want TXDONE, but all other interrupts */ + writel(mask, gp->regs + GREG_IMASK); + mb(); +} + +static inline void +gem_irq_acknowledge(struct gem *gp, unsigned int mask) +{ + writel(mask, gp->regs + GREG_IACK); + mb(); +} + static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) { u32 pcs_istat = readl(gp->regs + PCS_ISTAT); @@ -531,6 +557,10 @@ */ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_status) { + /* only those two are part of bits 0..6 and need explicit + * acknowledgement via GREG_IACK */ + gem_irq_acknowledge(gp, (GREG_STAT_RXNOBUF|GREG_STAT_RXTAGERR)); + if (gem_status & GREG_STAT_RXNOBUF) { /* Frame arrived, no free RX buffers available. */ if (netif_msg_rx_err(gp)) @@ -596,6 +626,8 @@ printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n", gp->dev->name, gem_status); + gem_irq_acknowledge(gp, GREG_STAT_TXALL|GREG_STAT_TXINTME); + entry = gp->tx_old; limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT); while (entry != limit) { @@ -678,7 +710,11 @@ } } +#ifdef CONFIG_SUNGEM_NAPI +static void gem_rx(struct gem *gp, int *work_done, int work_to_do) +#else static void gem_rx(struct gem *gp) +#endif { int entry, drops; u32 done; @@ -687,6 +723,8 @@ printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new); + gem_irq_acknowledge(gp, GREG_STAT_RXDONE); + entry = gp->rx_new; drops = 0; done = readl(gp->regs + RXDMA_DONE); @@ -713,6 +751,11 @@ break; } +#ifdef CONFIG_SUNGEM_NAPI + if (*work_done >= work_to_do) + break; + +#endif skb = gp->rx_skbs[entry]; len = (status & RXDCTRL_BUFSZ) >> 16; @@ -775,7 +818,12 @@ skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); skb->ip_summed = CHECKSUM_HW; skb->protocol = eth_type_trans(skb, gp->dev); +#ifdef CONFIG_SUNGEM_NAPI + netif_receive_skb(skb); + (*work_done)++; +#else netif_rx(skb); +#endif gp->net_stats.rx_packets++; gp->net_stats.rx_bytes += len; @@ -798,7 +846,7 @@ { struct net_device *dev = dev_id; struct gem *gp = dev->priv; - u32 gem_status = readl(gp->regs + GREG_STAT); + u32 gem_status = readl(gp->regs + GREG_STAT2); /* Swallow interrupts when shutting the chip down */ if (gp->hw_running == 0) @@ -810,10 +858,21 @@ if (gem_abnormal_irq(dev, gp, gem_status)) goto out; } + if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME)) gem_tx(dev, gp, gem_status); - if (gem_status & GREG_STAT_RXDONE) + + if (gem_status & GREG_STAT_RXDONE) { +#ifdef CONFIG_SUNGEM_NAPI + if (netif_rx_schedule_prep(dev)) { + /* Disable interrupts and register for poll */ + gem_irq_disable(gp); + __netif_rx_schedule(dev); + } +#else gem_rx(gp); +#endif + } out: spin_unlock(&gp->lock); @@ -821,6 +880,29 @@ return IRQ_HANDLED; } +#ifdef CONFIG_SUNGEM_NAPI +static int gem_clean(struct net_device *dev, int *budget) +{ + struct gem *gp = dev->priv; + int work_to_do = min(*budget, dev->quota); + int work_done = 0; + u32 gem_status = readl(gp->regs + GREG_STAT2); + + if (gem_status & GREG_STAT_RXDONE) + gem_rx(gp, &work_done, work_to_do); + + *budget -= work_done; + dev->quota -= work_done; + + if (work_done < work_to_do || !netif_running(dev)) { + __netif_rx_complete(dev); + gem_irq_enable(gp, GREG_STAT_TXDONE); + } + + return (work_done >= work_to_do); +} +#endif + static void gem_tx_timeout(struct net_device *dev) { struct gem *gp = dev->priv; @@ -1018,7 +1100,7 @@ u32 val; /* Make sure we won't get any more interrupts */ - writel(0xffffffff, gp->regs + GREG_IMASK); + gem_irq_disable(gp); /* Reset the chip */ writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST, @@ -1055,7 +1137,7 @@ (void) readl(gp->regs + MAC_RXCFG); udelay(100); - writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); + gem_irq_enable(gp, GREG_STAT_TXDONE); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); @@ -1323,7 +1405,7 @@ /* Make sure we don't get interrupts or tx packets */ netif_stop_queue(gp->dev); - writel(0xffffffff, gp->regs + GREG_IMASK); + gem_irq_disable(gp); /* Reset the chip & rings */ gem_stop(gp); @@ -2218,7 +2300,7 @@ spin_lock_irq(&gp->lock); gp->opened = 0; - writel(0xffffffff, gp->regs + GREG_IMASK); + gem_irq_disable(gp); netif_stop_queue(dev); /* Stop chip */ @@ -2262,7 +2344,7 @@ /* Stop traffic, mark us closed */ netif_device_detach(dev); - writel(0xffffffff, gp->regs + GREG_IMASK); + gem_irq_disable(gp); /* Stop chip */ gem_stop(gp); @@ -2649,6 +2731,16 @@ return 0; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void gem_netpoll(struct net_device *dev) +{ + struct gem *gp = dev->priv; + disable_irq(gp->pdev->irq); + gem_interrupt(gp->pdev->irq, dev, NULL); + enable_irq(gp->pdev->irq); +} +#endif + static int __devinit gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2809,6 +2901,15 @@ dev->ethtool_ops = &gem_ethtool_ops; dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; +#ifdef CONFIG_SUNGEM_NAPI + dev->poll = gem_clean; + dev->weight = 64; +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = gem_netpoll; +#endif + dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0;