]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[PATCH] sky2: improve receive performance
authorshemminger@osdl.org <shemminger@osdl.org>
Wed, 30 Nov 2005 19:45:14 +0000 (11:45 -0800)
committerJeff Garzik <jgarzik@pobox.com>
Thu, 1 Dec 2005 07:20:20 +0000 (02:20 -0500)
Changes to receive side processing:
* bigger receive ring
* clean up polling loop

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
drivers/net/sky2.c

index 83361aed49f6090c3ce59470dfab078562664b7a..e6f71c1232bcd2e637705c20ecba7669e7dfc63b 100644 (file)
        unlikely((hw)->chip_id == CHIP_ID_YUKON_EC && \
                 (hw)->chip_rev == CHIP_REV_YU_EC_A1)
 
-#define RX_LE_SIZE             256
+#define RX_LE_SIZE             512
 #define RX_LE_BYTES            (RX_LE_SIZE*sizeof(struct sky2_rx_le))
 #define RX_MAX_PENDING         (RX_LE_SIZE/2 - 2)
-#define RX_DEF_PENDING         128
+#define RX_DEF_PENDING         RX_MAX_PENDING
 #define RX_COPY_THRESHOLD      256
 
 #define TX_RING_SIZE           512
@@ -1596,7 +1596,6 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
 {
        struct ring_info *re = sky2->rx_ring + sky2->rx_next;
        struct sk_buff *skb = NULL;
-       struct net_device *dev;
        const unsigned int bufsize = rx_size(sky2);
 
        if (unlikely(netif_msg_rx_status(sky2)))
@@ -1643,11 +1642,6 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
        }
 
        skb_put(skb, length);
-       dev = sky2->netdev;
-       skb->dev = dev;
-       skb->protocol = eth_type_trans(skb, dev);
-       dev->last_rx = jiffies;
-
 resubmit:
        re->skb->ip_summed = CHECKSUM_NONE;
        sky2_rx_add(sky2, re);
@@ -1702,35 +1696,42 @@ static int sky2_poll(struct net_device *dev0, int *budget)
        BUG_ON(hwidx >= STATUS_RING_SIZE);
        rmb();
 
-       do {
-               struct sky2_status_le *le = hw->st_le + hw->st_idx;
+       while (hwidx != hw->st_idx) {
+               struct sky2_status_le *le  = hw->st_le + hw->st_idx;
+               struct net_device *dev;
                struct sky2_port *sky2;
                struct sk_buff *skb;
                u32 status;
                u16 length;
+               u8 op;
 
-               /* Are we done yet? */
-               if (hw->st_idx == hwidx) {
-                       sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
-                       hwidx = sky2_read16(hw, STAT_PUT_IDX);
-                       if (hwidx == hw->st_idx)
-                               break;
-               }
-
+               le = hw->st_le + hw->st_idx;
                hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE;
-               prefetch(&hw->st_le[hw->st_idx]);
+               prefetch(hw->st_le + hw->st_idx);
 
                BUG_ON(le->link >= hw->ports || !hw->dev[le->link]);
 
-               sky2 = netdev_priv(hw->dev[le->link]);
+               BUG_ON(le->link >= 2);
+               dev = hw->dev[le->link];
+               if (dev == NULL || !netif_running(dev))
+                       continue;
+
+               sky2 = netdev_priv(dev);
                status = le32_to_cpu(le->status);
                length = le16_to_cpu(le->length);
+               op = le->opcode & ~HW_OWNER;
+               le->opcode = 0;
 
-               switch (le->opcode & ~HW_OWNER) {
+               switch (op) {
                case OP_RXSTAT:
                        skb = sky2_receive(sky2, length, status);
                        if (!skb)
                                break;
+
+                       skb->dev = dev;
+                       skb->protocol = eth_type_trans(skb, dev);
+                       dev->last_rx = jiffies;
+
 #ifdef SKY2_VLAN_TAG_USED
                        if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
                                vlan_hwaccel_receive_skb(skb,
@@ -1739,7 +1740,9 @@ static int sky2_poll(struct net_device *dev0, int *budget)
                        } else
 #endif
                                netif_receive_skb(skb);
-                       ++work_done;
+
+                       if (++work_done >= to_do)
+                               goto exit_loop;
                        break;
 
 #ifdef SKY2_VLAN_TAG_USED
@@ -1765,18 +1768,15 @@ static int sky2_poll(struct net_device *dev0, int *budget)
                default:
                        if (net_ratelimit())
                                printk(KERN_WARNING PFX
-                                      "unknown status opcode 0x%x\n",
-                                      le->opcode);
+                                      "unknown status opcode 0x%x\n", op);
                        break;
                }
+       }
 
-               le->opcode = 0; /* paranoia */
-       } while (work_done < to_do);
+exit_loop:
 
        mmiowb();
 
-       *budget -= work_done;
-       dev0->quota -= work_done;
        if (work_done < to_do) {
                /*
                 * Another chip workaround, need to restart TX timer if status
@@ -1790,11 +1790,13 @@ static int sky2_poll(struct net_device *dev0, int *budget)
                netif_rx_complete(dev0);
                hw->intr_mask |= Y2_IS_STAT_BMU;
                sky2_write32(hw, B0_IMSK, hw->intr_mask);
-               sky2_read32(hw, B0_IMSK);
+               mmiowb();
+               return 0;
+       } else {
+               *budget -= work_done;
+               dev0->quota -= work_done;
+               return 1;
        }
-
-       return work_done >= to_do;
-
 }
 
 static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)