--- eepro100.c.ori Wed Jun 12 17:25:28 2002 +++ eepro100-napi.c Wed Jun 12 17:11:38 2002 @@ -25,6 +25,8 @@ Disabled FC and ER, to avoid lockups when when we get FCP interrupts. 2000 Jul 17 Goutham Rao PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary + 2002 Jun 12 Zhang Fuxin + add NAPI support */ static const char *version = @@ -115,6 +117,8 @@ #include #include +#define CONFIG_EEPRO100_NAPI + MODULE_AUTHOR("Maintainer: Andrey V. Savochkin "); MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver"); MODULE_LICENSE("GPL"); @@ -494,8 +498,34 @@ #ifdef CONFIG_PM u32 pm_state[16]; #endif + + /* added by zfx for NAPI*/ +#ifdef CONFIG_EEPRO100_NAPI + + /* used to pass rx_work_limit into speedo_rx,i don't want to + * change its prototype + */ + int curr_work_limit; + unsigned long poll_switch; + unsigned long failed_poll_switch; + unsigned long done_poll; + unsigned long notdone_poll; + unsigned long empty_poll; + unsigned long soft_reset_count; + unsigned long rx_resume_count; + unsigned long alloc_fail; + unsigned long long poll_cycles; + +#ifdef CONFIG_NET_FASTROUTE + unsigned long fastroute_hit; + unsigned long fastroute_success; + unsigned long fastroute_defer; +#endif + +#endif }; + /* The parameters for a CmdConfigure operation. There are so many options that it would be difficult to document each bit. We mostly use the default or recommended settings. */ @@ -546,6 +576,14 @@ static void set_rx_mode(struct net_device *dev); static void speedo_show_state(struct net_device *dev); +#ifdef CONFIG_EEPRO100_NAPI + +static int speedo_poll (struct net_device *dev, int *budget); +static void enable_rx_and_rxnobuf_ints(struct net_device *dev); +static void disable_rx_and_rxnobuf_ints(struct net_device *dev); + +#endif + #ifdef honor_default_port @@ -842,6 +880,10 @@ dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_EEPRO100_NAPI + dev->poll = speedo_poll; + dev->quota = dev->weight = RX_RING_SIZE; +#endif return 0; } @@ -1517,6 +1559,9 @@ struct speedo_private *sp; long ioaddr, boguscnt = max_interrupt_work; unsigned short status; +#ifdef CONFIG_EEPRO100_NAPI + int first = 1; +#endif #ifndef final_version if (dev == NULL) { @@ -1543,16 +1588,21 @@ /* Acknowledge all of the current interrupt sources ASAP. */ /* Will change from 0xfc00 to 0xff00 when we start handling FCP and ER interrupts --Dragan */ +#ifndef CONFIG_EEPRO100_NAPI outw(status & 0xfc00, ioaddr + SCBStatus); +#else + /* Rx & RxNoBuf is acked in speedo_poll */ + outw(status & 0xac00, ioaddr + SCBStatus); +#endif if (speedo_debug > 4) printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", dev->name, status); +#ifndef CONFIG_EEPRO100_NAPI if ((status & 0xfc00) == 0) break; - if ((status & 0x5000) || /* Packet received, or Rx error. */ (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed) /* Need to gather the postponed packet. */ @@ -1560,8 +1610,33 @@ /* Always check if all rx buffers are allocated. --SAW */ speedo_refill_rx_buffers(dev, 0); +#else + /* Packet received, or Rx error. */ + if (first && ((status & 0x5000) || (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed || (status & 0x3c) != 0x10 )) + /* Need to gather the postponed packet. */ + { + if (speedo_debug > 4) + printk("switching to poll,status=%x\n",status); + first = 0; + if (netif_rx_schedule_prep(dev)) { + sp->poll_switch++; + /* disable interrupts caused by arriving packets */ + disable_rx_and_rxnobuf_ints(dev); + /* tell system we have work to be done. */ + __netif_rx_schedule(dev); + }else { + sp->failed_poll_switch++; + } + + } + + if ((status & 0xac00) == 0) + break; +#endif spin_lock(&sp->lock); + +#ifndef CONFIG_EEPRO100_NAPI /* * The chip may have suspended reception for various reasons. * Check for that, and re-prime it should this be the case. @@ -1581,7 +1656,7 @@ /* these are all reserved values */ break; } - +#endif /* User interrupt, Command/Tx unit interrupt or CU not active. */ if (status & 0xA400) { @@ -1602,7 +1677,12 @@ /* Clear all interrupt sources. */ /* Will change from 0xfc00 to 0xff00 when we start handling FCP and ER interrupts --Dragan */ +#ifndef CONFIG_EEPRO100_NAPI outw(0xfc00, ioaddr + SCBStatus); +#else + outw(0xac00, ioaddr + SCBStatus); +#endif + break; } } while (1); @@ -1611,7 +1691,9 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); +#ifndef final_version clear_bit(0, (void*)&sp->in_interrupt); +#endif return; } @@ -1625,6 +1707,9 @@ sp->rx_skbuff[entry] = skb; if (skb == NULL) { sp->rx_ringp[entry] = NULL; +#ifdef CONFIG_EEPRO100_NAPI + sp->alloc_fail++; +#endif return NULL; } rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; @@ -1705,12 +1790,112 @@ speedo_refill_rx_buf(dev, force) != -1); } +#ifdef CONFIG_EEPRO100_NAPI +static void enable_rx_and_rxnobuf_ints(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + outw(SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); + inw(ioaddr + SCBStatus); /* flushes last write, read-safe */ +}; + +static void disable_rx_and_rxnobuf_ints(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + outw(SCBMaskRxDone | SCBMaskRxSuspend | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); + inw(ioaddr + SCBStatus); /* flushes last write, read-safe */ +}; + +static int speedo_poll (struct net_device *dev, int *budget) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + long ioaddr, received = 0; + unsigned short intr_status; + + ioaddr = dev->base_addr; + intr_status = inw(ioaddr + SCBStatus); + + if (speedo_debug > 4) + printk(KERN_DEBUG " In speedo_poll().\n"); + + sp->curr_work_limit = *budget; + if (sp->curr_work_limit > dev->quota) + sp->curr_work_limit = dev->quota; + + do { + /* ack Rx & RxNobuf intrs*/ + outw(intr_status & 0x5000, ioaddr + SCBStatus); + + received += speedo_rx(dev); + + if (sp->curr_work_limit < 0) /* out of quota */ + goto not_done; + + /* no packets on ring; but new ones can arrive since we last checked */ + intr_status = inw(ioaddr + SCBStatus); + + if ((intr_status & 0x5000) == 0) { + /* If something arrives in this narrow window,an interrupt + * will be generated + */ + goto done; + } + /* done! at least thats what it looks like ;-> + if new packets came in after our last check on status bits + they'll be caught by the while check and we go back and clear them + since we havent exceeded our quota + */ + } while (intr_status & 0x5000); + +done: + if (!received) { + if (speedo_debug > 4) printk("received==0\n"); + received = 1; + sp->empty_poll++; + } + dev->quota -= received; + *budget -= received; + + /* we are happy/done, no more packets on ring; put us back + * to where we can start processing interrupts again + */ + netif_rx_complete(dev); + enable_rx_and_rxnobuf_ints(dev); + + sp->done_poll++; + + if (speedo_debug > 3) + printk("done,received=%lu\n",received); + + return 0; /* done */ + +not_done: + if (!received) { + if (speedo_debug > 4) printk("received==0\n"); + received = 1; + sp->empty_poll++; + } + dev->quota -= received; + *budget -= received; + + sp->notdone_poll++; + + if (speedo_debug > 3) + printk("not done,received=%lu\n",received); + + return 1; /* not_done */ +} + +#endif /* NAPI */ + static int speedo_rx(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry = sp->cur_rx % RX_RING_SIZE; +#ifndef CONFIG_EEPRO100_NAPI int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; +#endif + int received = 0; int alloc_ok = 1; if (speedo_debug > 4) @@ -1725,11 +1910,42 @@ status = le32_to_cpu(sp->rx_ringp[entry]->status); pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; +#ifndef CONFIG_EEPRO100_NAPI if (!(status & RxComplete)) break; if (--rx_work_limit < 0) break; +#else + if (!(status & RxComplete)) { + int intr_status; + unsigned long ioaddr = dev->base_addr; + + intr_status = inw(ioaddr + SCBStatus); + /* We check receiver state here because if + * we have to do soft reset,sp->cur_rx should + * point to an empty entry or something + * unexpected will happen + */ + if (intr_status | 0x1000) { /* suspended */ + outw(0x5000,ioaddr + SCBStatus); + /* No resources */ + if ((intr_status & 0x3c) == 0x28) { + outw(RxResumeNoResources,ioaddr+SCBCmd); + sp->rx_resume_count++; + }else if ((intr_status & 0x3c) == 0x8) { + if (speedo_debug > 4) + printk("No resource,reset\n"); + speedo_rx_soft_reset(dev); + sp->soft_reset_count++; + } + } + break; + } + + if (--sp->curr_work_limit < 0) + break; +#endif /* Check for a rare out-of-memory case: the current buffer is the last buffer allocated in the RX ring. --SAW */ @@ -1793,7 +2009,12 @@ PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); +#ifndef CONFIG_EEPRO100_NAPI netif_rx(skb); +#else + netif_receive_skb(skb); + received ++; +#endif dev->last_rx = jiffies; sp->stats.rx_packets++; sp->stats.rx_bytes += pkt_len; @@ -1811,7 +2032,7 @@ sp->last_rx_time = jiffies; - return 0; + return received; } static int