OSDN Git Service

[PATCH] sis900: come alive after temporary memory shortage
authorKonstantin Khorenko <khorenko@sw.ru>
Mon, 26 Sep 2005 12:40:42 +0000 (16:40 +0400)
committerMarcelo Tosatti <marcelo@pegasos.cnet>
Wed, 23 Nov 2005 18:56:19 +0000 (12:56 -0600)
Patch solves following problems:
1) Forgotten counter incrementation in sis900_rx() in case
      it doesn't get memory for skb, that leads to whole interface failure.
      Problem is accompanied with messages:
     eth0: Memory squeeze,deferring packet.
     eth0: NULL pointer encountered in Rx ring, skipping
2) If counter cur_rx overflows and there'll be temporary memory problems
      buffer can't be recreated later, when memory IS avaliable.
3) Limit the work in handler to prevent the endless packets processing if
      new packets are generated faster then handled.

Signed-off-by: Konstantin Khorenko <khorenko@sw.ru>
Signed-off-by: Vasily Averin <vvs@sw.ru>
drivers/net/sis900.c

index f801a6d..bffdf0a 100644 (file)
@@ -1613,6 +1613,14 @@ static int sis900_rx(struct net_device *net_dev)
        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;
+       /*
+        * If cur > dirty, then limit = NUM_RX_DESC - cur + dirty =
+        *                              NUM_RX_DESC + (dirty - cur)
+        * If cur < dirty (cur overflowed, dirty - not), then
+        *                      limit = dirty - cur
+        */
+       int rx_work_limit =
+               (sis_priv->dirty_rx - sis_priv->cur_rx) % NUM_RX_DESC;
 
        if (sis900_debug > 3)
                printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
@@ -1622,6 +1630,8 @@ static int sis900_rx(struct net_device *net_dev)
        while (rx_status & OWN) {
                unsigned int rx_size;
 
+               if (--rx_work_limit < 0)
+                       break;
                rx_size = (rx_status & DSIZE) - CRC_SIZE;
 
                if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
@@ -1688,6 +1698,7 @@ static int sis900_rx(struct net_device *net_dev)
                                sis_priv->rx_ring[entry].cmdsts = 0;
                                sis_priv->rx_ring[entry].bufptr = 0;
                                sis_priv->stats.rx_dropped++;
+                               sis_priv->cur_rx++;
                                break;
                        }
                        skb->dev = net_dev;
@@ -1705,7 +1716,7 @@ static int sis900_rx(struct net_device *net_dev)
 
        /* refill the Rx buffer, what if the rate of refilling is slower than 
           consuming ?? */
-       for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) {
+       for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) {
                struct sk_buff *skb;
 
                entry = sis_priv->dirty_rx % NUM_RX_DESC;