Hi Daniele,

Attached is a patch for converting the sis900 driver to NAPI. Please take a
look at let me know what you think. I'm not 100% sure if I'm handling the 
rotting packet issue correctly or that I have the locking right in tx_timeout.
These might be areas to look at closely.

I didn't see much saving in interrupts on my machine (too fast, I guess). But
I still think its beneficial: pushing work out of the interrupt handler into
a bottom half is a good thing and we no longer need to disable interrupts 
in start_xmit. 

I did see a significant boost to tx performance by optimizing start_xmit: more
than double pps in pktgen.

I'm also attaching some test results for various iterations of development.

Regards,
Mandeep

Daniele Venzano ([EMAIL PROTECTED]) wrote:
> ----- Message d'origine -----
> De: jamal <[EMAIL PROTECTED]>
> Date: Fri, 31 Aug 2007 09:50:03 -0400
> Sujet: Re: Re: pktgen terminating condition
> 
> >I dont know if you followed the discussion - by defering the freeing of
> >skbs, you will be slowing down socket apps sending from the local
> >machine. It may be ok if the socket buffers were huge, but that comes at
> >the cost of system memory (which may not be a big deal)
> >Do you by any chance recall why you used the idle interupt instead of
> >txok to kick the prunning of tx descriptors?
> 
> That should be asked to the original author of the driver, that I wasn't able 
> to contact when I took over the maintainership several years ago.
> I think that since this chip is usually used on cheap/low performance 
> (relatively speaking) devices it was felt that generating an interrupt for 
> each transmitted packet was going to affect the performance of the system too 
> much. At the start, if I remember correctly, this was a chip thought for 
> consumer use, where transmissions won't happen continuously for long periods 
> of time. Then the sis900 started to get used everywhere, from embedded 
> systems to (cheap) server motherboards and the usage scenario changed.
> 
> 
> --
> Daniele Venzano
> [EMAIL PROTECTED]
Tested using pktgen.

cpuinfo:
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 6
model           : 8
model name      : AMD Geode NX
stepping        : 1
cpu MHz         : 1397.641
cache size      : 256 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov 
pat pse36 mmx fxsr sse syscall mp mmxext 3dnowext 3dnow ts fid vid
bogomips        : 2796.00
clflush size    : 32

meminfo:
MemTotal:       907092 kB


Results in pps. Sending 400000 60-byte packets.
Other than Iteration 5 and 6, there is 1 interrupt per packet.

Iteration 0 (replace TxIDLE with TxOK):
62222, 62052, 62335

Iteration 1 (optimize sis900_start_xmit):
148815, 148815, 148829

Iteration 2 (convert Rx to NAPI):
148669, 148635, 148677

Iteration 3 (remove tx_full dev state variable):
148677, 148528, 148532

Iteration 4 (optimize finish_xmit):
148677, 148676, 148689

Iteration 5 (move tx completion code into NAPI poll):
147751, 147658, 147809
Interrupts:
359270, 360747, 358010

Iteration 6 (cleanup + rotting packet handling + rx optimization):
148652, 148680, 148681
Interrupts:
399927, 399841, 399835

diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 7c6e480..862e15a 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -185,7 +185,6 @@ struct sis900_private {
        dma_addr_t tx_ring_dma;
        dma_addr_t rx_ring_dma;
 
-       unsigned int tx_full; /* The Tx queue is full. */
        u8 host_bridge_rev;
        u8 chipset_rev;
 };
@@ -202,8 +201,10 @@ MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum 
events handled per in
 MODULE_PARM_DESC(sis900_debug, "SiS 900/7016 bitmapped debugging message 
level");
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static void sis900_poll(struct net_device *dev);
+static void sis900_poll_controller(struct net_device *dev);
 #endif
+
+static int sis900_poll(struct net_device *dev, int *budget);
 static int sis900_open(struct net_device *net_dev);
 static int sis900_mii_probe (struct net_device * net_dev);
 static void sis900_init_rxfilter (struct net_device * net_dev);
@@ -216,8 +217,8 @@ static void sis900_tx_timeout(struct net_device *net_dev);
 static void sis900_init_tx_ring(struct net_device *net_dev);
 static void sis900_init_rx_ring(struct net_device *net_dev);
 static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
-static int sis900_rx(struct net_device *net_dev);
-static void sis900_finish_xmit (struct net_device *net_dev);
+static int sis900_rx(struct net_device *net_dev, int limit);
+static int sis900_finish_xmit (struct net_device *net_dev);
 static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
 static int sis900_close(struct net_device *net_dev);
 static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
@@ -474,9 +475,11 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
        net_dev->tx_timeout = sis900_tx_timeout;
        net_dev->watchdog_timeo = TX_TIMEOUT;
        net_dev->ethtool_ops = &sis900_ethtool_ops;
+       net_dev->poll = &sis900_poll;
+       net_dev->weight = 64;
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-        net_dev->poll_controller = &sis900_poll;
+        net_dev->poll_controller = &sis900_poll_controller;
 #endif
 
        if (sis900_debug > 0)
@@ -979,13 +982,44 @@ static u16 sis900_reset_phy(struct net_device *net_dev, 
int phy_addr)
        return status;
 }
 
+static int sis900_poll(struct net_device *dev, int *budget)
+{
+       struct sis900_private *sis_priv = dev->priv;
+       long ioaddr = dev->base_addr;
+       int limit = min_t(int, dev->quota, *budget);
+       int rx_work_done;
+       int tx_work_done;
+
+       /* run TX completion thread */
+       spin_lock(sis_priv->lock);
+       tx_work_done = sis900_finish_xmit(dev);
+       spin_unlock(sis_priv->lock);
+
+       /* run RX thread */
+       rx_work_done = sis900_rx(dev, limit);
+       *budget -= rx_work_done;
+       dev->quota -= rx_work_done;
+
+       /* re-enable interrupts if no work done */
+       if (rx_work_done + tx_work_done == 0) {
+               netif_rx_complete(dev);
+               /* Enable all known interrupts. */
+               outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
+               /* Handle rotting packet */
+               sis900_rx(dev, NUM_RX_DESC);
+               return 0;
+       }
+
+       return 1;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling 'interrupt' - used by things like netconsole to send skbs
  * without having to re-enable interrupts. It's not called while
  * the interrupt routine is executing.
 */
-static void sis900_poll(struct net_device *dev)
+static void sis900_poll_controller(struct net_device *dev)
 {
        disable_irq(dev->irq);
        sis900_interrupt(dev->irq, dev);
@@ -1032,7 +1066,7 @@ sis900_open(struct net_device *net_dev)
        sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
+       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
        outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
        outl(IE, ioaddr + ier);
 
@@ -1102,7 +1136,6 @@ sis900_init_tx_ring(struct net_device *net_dev)
        long ioaddr = net_dev->base_addr;
        int i;
 
-       sis_priv->tx_full = 0;
        sis_priv->dirty_tx = sis_priv->cur_tx = 0;
 
        for (i = 0; i < NUM_TX_DESC; i++) {
@@ -1517,7 +1550,6 @@ static void sis900_tx_timeout(struct net_device *net_dev)
 {
        struct sis900_private *sis_priv = net_dev->priv;
        long ioaddr = net_dev->base_addr;
-       unsigned long flags;
        int i;
 
        if(netif_msg_tx_err(sis_priv))
@@ -1527,8 +1559,8 @@ static void sis900_tx_timeout(struct net_device *net_dev)
        /* Disable interrupts by clearing the interrupt mask. */
        outl(0x0000, ioaddr + imr);
 
-       /* use spinlock to prevent interrupt handler accessing buffer ring */
-       spin_lock_irqsave(&sis_priv->lock, flags);
+       /* use spinlock to prevent bh from accessing buffer ring */
+       spin_lock_bh(&sis_priv->lock);
 
        /* discard unsent packets */
        sis_priv->dirty_tx = sis_priv->cur_tx = 0;
@@ -1546,10 +1578,9 @@ static void sis900_tx_timeout(struct net_device *net_dev)
                        sis_priv->stats.tx_dropped++;
                }
        }
-       sis_priv->tx_full = 0;
        netif_wake_queue(net_dev);
 
-       spin_unlock_irqrestore(&sis_priv->lock, flags);
+       spin_unlock_bh(&sis_priv->lock);
 
        net_dev->trans_start = jiffies;
 
@@ -1557,7 +1588,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
        outl(sis_priv->tx_ring_dma, ioaddr + txdp);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
+       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
        return;
 }
 
@@ -1574,52 +1605,27 @@ static void sis900_tx_timeout(struct net_device 
*net_dev)
 static int
 sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 {
-       struct sis900_private *sis_priv = net_dev->priv;
        long ioaddr = net_dev->base_addr;
-       unsigned int  entry;
-       unsigned long flags;
-       unsigned int  index_cur_tx, index_dirty_tx;
-       unsigned int  count_dirty_tx;
+       struct sis900_private *sis_priv = net_dev->priv;
+        unsigned int entry;
 
-       /* Don't transmit data before the complete of auto-negotiation */
-       if(!sis_priv->autong_complete){
+       /* Don't transmit data before auto-negotiation is complete */
+       if(unlikely(!sis_priv->autong_complete)){
                netif_stop_queue(net_dev);
                return 1;
        }
 
-       spin_lock_irqsave(&sis_priv->lock, flags);
-
-       /* Calculate the next Tx descriptor entry. */
-       entry = sis_priv->cur_tx % NUM_TX_DESC;
+       /* Set the Tx descriptor and enable Transmit State Machine */
+        entry = sis_priv->cur_tx++ % NUM_TX_DESC;
        sis_priv->tx_skbuff[entry] = skb;
-
-       /* set the transmit buffer descriptor and enable Transmit State Machine 
*/
        sis_priv->tx_ring[entry].bufptr = pci_map_single(sis_priv->pci_dev,
                skb->data, skb->len, PCI_DMA_TODEVICE);
        sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
        outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
 
-       sis_priv->cur_tx ++;
-       index_cur_tx = sis_priv->cur_tx;
-       index_dirty_tx = sis_priv->dirty_tx;
-
-       for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; 
index_dirty_tx++)
-               count_dirty_tx ++;
-
-       if (index_cur_tx == index_dirty_tx) {
-               /* dirty_tx is met in the cycle of cur_tx, buffer full */
-               sis_priv->tx_full = 1;
-               netif_stop_queue(net_dev);
-       } else if (count_dirty_tx < NUM_TX_DESC) {
-               /* Typical path, tell upper layer that more transmission is 
possible */
-               netif_start_queue(net_dev);
-       } else {
-               /* buffer full, tell upper layer no more transmission */
-               sis_priv->tx_full = 1;
+        /* If Tx ring is full, tell upper layer no more transmission */
+       if (unlikely(sis_priv->cur_tx - sis_priv->dirty_tx >= NUM_TX_DESC))
                netif_stop_queue(net_dev);
-       }
-
-       spin_unlock_irqrestore(&sis_priv->lock, flags);
 
        net_dev->trans_start = jiffies;
 
@@ -1650,32 +1656,27 @@ static irqreturn_t sis900_interrupt(int irq, void 
*dev_instance)
        u32 status;
        unsigned int handled = 0;
 
-       spin_lock (&sis_priv->lock);
-
-       do {
-               status = inl(ioaddr + isr);
-
-               if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 
0)
-                       /* nothing intresting happened */
-                       break;
+       while ((status = inl(ioaddr + isr))) {
                handled = 1;
 
-               /* why dow't we break after Tx/Rx case ?? keyword: full-duplex 
*/
-               if (status & (RxORN | RxERR | RxOK))
-                       /* Rx interrupt */
-                       sis900_rx(net_dev);
+               /* why don't we break after Tx/Rx case ?? 
+                * keyword: full-duplex 
+                */
 
-               if (status & (TxURN | TxERR | TxIDLE))
-                       /* Tx interrupt */
-                       sis900_finish_xmit(net_dev);
+               /* Rx interrupt */
+                if (status & (TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) {
+                       /* Disable all interrupts. */
+                       outl(0, ioaddr + imr);
+                       netif_rx_schedule(net_dev);
+               }
 
                /* something strange happened !!! */
-               if (status & HIBERR) {
+               if (status & HIBERR)
                        if(netif_msg_intr(sis_priv))
                                printk(KERN_INFO "%s: Abnormal interrupt,"
-                                       "status %#8.8x.\n", net_dev->name, 
status);
-                       break;
-               }
+                                       "status %#8.8x.\n", 
+                                       net_dev->name, status);
+
                if (--boguscnt < 0) {
                        if(netif_msg_intr(sis_priv))
                                printk(KERN_INFO "%s: Too much work at 
interrupt, "
@@ -1683,14 +1684,13 @@ static irqreturn_t sis900_interrupt(int irq, void 
*dev_instance)
                                        net_dev->name, status);
                        break;
                }
-       } while (1);
+       }
 
        if(netif_msg_intr(sis_priv))
                printk(KERN_DEBUG "%s: exiting interrupt, "
                       "interrupt status = 0x%#8.8x.\n",
                       net_dev->name, inl(ioaddr + isr));
 
-       spin_unlock (&sis_priv->lock);
        return IRQ_RETVAL(handled);
 }
 
@@ -1704,25 +1704,29 @@ static irqreturn_t sis900_interrupt(int irq, void 
*dev_instance)
  *     don't do "too much" work here
  */
 
-static int sis900_rx(struct net_device *net_dev)
+static int sis900_rx(struct net_device *net_dev, int limit)
 {
        struct sis900_private *sis_priv = net_dev->priv;
+       struct net_device_stats *stats = &sis_priv->stats;
        long ioaddr = net_dev->base_addr;
-       unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;
-       u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
-       int rx_work_limit;
+       int cur_rx = sis_priv->cur_rx;
+       int dirty_rx, orig_dirty_rx = sis_priv->dirty_rx;
+       int count;
 
        if (netif_msg_rx_status(sis_priv))
-               printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
-                      "status:0x%8.8x\n",
-                      sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
-       rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx;
+               printk(KERN_DEBUG "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d\n",
+                      cur_rx, orig_dirty_rx);
 
-       while (rx_status & OWN) {
+       for (count = 0; count < limit; cur_rx++, count++) {
+               unsigned int entry;
+               u32 rx_status;
                unsigned int rx_size;
                unsigned int data_size;
 
-               if (--rx_work_limit < 0)
+               entry = cur_rx % NUM_RX_DESC;
+               rx_status = sis_priv->rx_ring[entry].cmdsts;
+
+               if ((rx_status & OWN) == 0)
                        break;
 
                data_size = rx_status & DSIZE;
@@ -1735,113 +1739,71 @@ static int sis900_rx(struct net_device *net_dev)
 #endif
 
                if (rx_status & 
(ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
-                       /* corrupted packet received */
-                       if (netif_msg_rx_err(sis_priv))
-                               printk(KERN_DEBUG "%s: Corrupted packet "
-                                      "received, buffer status = 
0x%8.8x/%d.\n",
-                                      net_dev->name, rx_status, data_size);
-                       sis_priv->stats.rx_errors++;
+                       pci_unmap_single(sis_priv->pci_dev,
+                               sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
+                               PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(sis_priv->rx_skbuff[entry]);
+
+                       stats->rx_errors++;
                        if (rx_status & OVERRUN)
-                               sis_priv->stats.rx_over_errors++;
+                               stats->rx_over_errors++;
                        if (rx_status & (TOOLONG|RUNT))
-                               sis_priv->stats.rx_length_errors++;
+                               stats->rx_length_errors++;
                        if (rx_status & (RXISERR | FAERR))
-                               sis_priv->stats.rx_frame_errors++;
+                               stats->rx_frame_errors++;
                        if (rx_status & CRCERR)
-                               sis_priv->stats.rx_crc_errors++;
-                       /* reset buffer descriptor state */
-                       sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+                               stats->rx_crc_errors++;
                } else {
                        struct sk_buff * skb;
-                       struct sk_buff * rx_skb;
 
                        pci_unmap_single(sis_priv->pci_dev,
                                sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
                                PCI_DMA_FROMDEVICE);
 
-                       /* refill the Rx buffer, what if there is not enought
-                        * memory for new socket buffer ?? */
-                       if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
-                               /*
-                                * Not enough memory to refill the buffer
-                                * so we need to recycle the old one so
-                                * as to avoid creating a memory hole
-                                * in the rx ring
-                                */
-                               skb = sis_priv->rx_skbuff[entry];
-                               sis_priv->stats.rx_dropped++;
-                               goto refill_rx_ring;
-                       }       
-
-                       /* This situation should never happen, but due to
-                          some unknow bugs, it is possible that
-                          we are working on NULL sk_buff :-( */
-                       if (sis_priv->rx_skbuff[entry] == NULL) {
-                               if (netif_msg_rx_err(sis_priv))
-                                       printk(KERN_WARNING "%s: NULL pointer "
-                                             "encountered in Rx ring\n"
-                                             "cur_rx:%4.4d, dirty_rx:%4.4d\n",
-                                             net_dev->name, sis_priv->cur_rx,
-                                             sis_priv->dirty_rx);
-                               break;
-                       }
-
                        /* give the socket buffer to upper layers */
-                       rx_skb = sis_priv->rx_skbuff[entry];
-                       skb_put(rx_skb, rx_size);
-                       rx_skb->protocol = eth_type_trans(rx_skb, net_dev);
-                       netif_rx(rx_skb);
+                       skb = sis_priv->rx_skbuff[entry];
+                       skb_put(skb, rx_size);
+                       skb->protocol = eth_type_trans(skb, net_dev);
+                       netif_receive_skb(skb);
 
                        /* some network statistics */
                        if ((rx_status & BCAST) == MCAST)
-                               sis_priv->stats.multicast++;
+                               stats->multicast++;
                        net_dev->last_rx = jiffies;
-                       sis_priv->stats.rx_bytes += rx_size;
-                       sis_priv->stats.rx_packets++;
-                       sis_priv->dirty_rx++;
-refill_rx_ring:
-                       sis_priv->rx_skbuff[entry] = skb;
-                       sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
-                       sis_priv->rx_ring[entry].bufptr =
-                               pci_map_single(sis_priv->pci_dev, skb->data,
-                                       RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       stats->rx_bytes += rx_size;
+                       stats->rx_packets++;
                }
-               sis_priv->cur_rx++;
-               entry = sis_priv->cur_rx % NUM_RX_DESC;
-               rx_status = sis_priv->rx_ring[entry].cmdsts;
-       } // while
+       }
 
-       /* refill the Rx buffer, what if the rate of refilling is slower
-        * than consuming ?? */
-       for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) {
+       /* refill the Rx ring. */
+       for (dirty_rx = orig_dirty_rx; dirty_rx < cur_rx; dirty_rx++) {
                struct sk_buff *skb;
+               unsigned int entry;
 
-               entry = sis_priv->dirty_rx % NUM_RX_DESC;
-
-               if (sis_priv->rx_skbuff[entry] == NULL) {
-                       if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
-                               /* not enough memory for skbuff, this makes a
-                                * "hole" on the buffer ring, it is not clear
-                                * how the hardware will react to this kind
-                                * of degenerated buffer */
-                               if (netif_msg_rx_err(sis_priv))
-                                       printk(KERN_INFO "%s: Memory squeeze,"
-                                               "deferring packet.\n",
-                                               net_dev->name);
-                               sis_priv->stats.rx_dropped++;
-                               break;
-                       }
-                       sis_priv->rx_skbuff[entry] = skb;
-                       sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
-                       sis_priv->rx_ring[entry].bufptr =
-                               pci_map_single(sis_priv->pci_dev, skb->data,
-                                       RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+               if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
+                       if (netif_msg_rx_err(sis_priv))
+                               printk(KERN_INFO "%s: Memory squeeze,"
+                                       "deferring packet.\n",
+                                       net_dev->name);
+                       break;
                }
+
+               entry = dirty_rx % NUM_RX_DESC;
+               sis_priv->rx_skbuff[entry] = skb;
+               sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+                       sis_priv->rx_ring[entry].bufptr =
+                       pci_map_single(sis_priv->pci_dev, skb->data,
+                               RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
        }
+
        /* re-enable the potentially idle receive state matchine */
-       outl(RxENA | inl(ioaddr + cr), ioaddr + cr );
+       if (dirty_rx != orig_dirty_rx)
+               outl(RxENA | inl(ioaddr + cr), ioaddr + cr );
 
-       return 0;
+       sis_priv->dirty_rx = dirty_rx;
+       sis_priv->cur_rx = cur_rx;
+
+       return count;
 }
 
 /**
@@ -1854,24 +1816,28 @@ refill_rx_ring:
  *     don't do "too much" work here
  */
 
-static void sis900_finish_xmit (struct net_device *net_dev)
+static int sis900_finish_xmit (struct net_device *net_dev)
 {
        struct sis900_private *sis_priv = net_dev->priv;
+       struct net_device_stats *stats = &sis_priv->stats;
+       int cur_tx = sis_priv->cur_tx;
+       int orig_dirty_tx = sis_priv->dirty_tx;
+       int dirty_tx;
 
-       for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) {
+       for (dirty_tx = orig_dirty_tx; dirty_tx < cur_tx; dirty_tx++) {
                struct sk_buff *skb;
                unsigned int entry;
                u32 tx_status;
 
-               entry = sis_priv->dirty_tx % NUM_TX_DESC;
+               entry = dirty_tx % NUM_TX_DESC;
                tx_status = sis_priv->tx_ring[entry].cmdsts;
 
-               if (tx_status & OWN) {
-                       /* The packet is not transmitted yet (owned by 
hardware) !
-                        * Note: the interrupt is generated only when Tx Machine
-                        * is idle, so this is an almost impossible case */
+               /* The packet is not transmitted yet (owned by hardware) !
+                * Note: the interrupt is generated only when Tx Machine
+                * is idle, so this is an almost impossible case 
+                */
+               if (tx_status & OWN)
                        break;
-               }
 
                if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
                        /* packet unsuccessfully transmitted */
@@ -1879,20 +1845,20 @@ static void sis900_finish_xmit (struct net_device 
*net_dev)
                                printk(KERN_DEBUG "%s: Transmit "
                                       "error, Tx status %8.8x.\n",
                                       net_dev->name, tx_status);
-                       sis_priv->stats.tx_errors++;
+                       stats->tx_errors++;
                        if (tx_status & UNDERRUN)
-                               sis_priv->stats.tx_fifo_errors++;
+                               stats->tx_fifo_errors++;
                        if (tx_status & ABORT)
-                               sis_priv->stats.tx_aborted_errors++;
+                               stats->tx_aborted_errors++;
                        if (tx_status & NOCARRIER)
-                               sis_priv->stats.tx_carrier_errors++;
+                               stats->tx_carrier_errors++;
                        if (tx_status & OWCOLL)
-                               sis_priv->stats.tx_window_errors++;
+                               stats->tx_window_errors++;
                } else {
                        /* packet successfully transmitted */
-                       sis_priv->stats.collisions += (tx_status & COLCNT) >> 
16;
-                       sis_priv->stats.tx_bytes += tx_status & DSIZE;
-                       sis_priv->stats.tx_packets++;
+                       stats->collisions += (tx_status & COLCNT) >> 16;
+                       stats->tx_bytes += tx_status & DSIZE;
+                       stats->tx_packets++;
                }
                /* Free the original skb. */
                skb = sis_priv->tx_skbuff[entry];
@@ -1905,13 +1871,15 @@ static void sis900_finish_xmit (struct net_device 
*net_dev)
                sis_priv->tx_ring[entry].cmdsts = 0;
        }
 
-       if (sis_priv->tx_full && netif_queue_stopped(net_dev) &&
-           sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
-               /* The ring is no longer full, clear tx_full and schedule
-                * more transmission by netif_wake_queue(net_dev) */
-               sis_priv->tx_full = 0;
+       /* The ring is no longer full, schedule
+        * more transmission by netif_wake_queue(net_dev) 
+        */
+       if (netif_queue_stopped(net_dev) && (cur_tx - dirty_tx < NUM_TX_DESC))
                netif_wake_queue (net_dev);
-       }
+
+       sis_priv->dirty_tx = dirty_tx;
+
+       return dirty_tx - orig_dirty_tx;
 }
 
 /**
@@ -2462,7 +2430,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
        sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
 
        /* Enable all known interrupts by setting the interrupt mask. */
-       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
+       outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
        outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
        outl(IE, ioaddr + ier);
 
diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
index 150511a..671af28 100644
--- a/drivers/net/sis900.h
+++ b/drivers/net/sis900.h
@@ -319,8 +319,8 @@ enum sis630_revision_id {
 #define TX_BUF_SIZE     (MAX_FRAME_SIZE+18)
 #define RX_BUF_SIZE     (MAX_FRAME_SIZE+18)
 
-#define NUM_TX_DESC     16             /* Number of Tx descriptor registers. */
-#define NUM_RX_DESC     16             /* Number of Rx descriptor registers. */
+#define NUM_TX_DESC     64     /* Number of Tx descriptor registers. */
+#define NUM_RX_DESC     64     /* Number of Rx descriptor registers. */
 #define TX_TOTAL_SIZE  NUM_TX_DESC*sizeof(BufferDesc)
 #define RX_TOTAL_SIZE  NUM_RX_DESC*sizeof(BufferDesc)
 

Reply via email to