aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshemminger@osdl.org <shemminger@osdl.org>2005-11-30 11:45:14 -0800
committerJeff Garzik <jgarzik@pobox.com>2005-12-01 02:20:20 -0500
commit13210ce5c06ed9537558b85e9c0df4248b28f1f7 (patch)
tree8fd431a7f071818b82d156ce57604dfd9cc11ded
parent42eeea0145a1c7570624ddeaa15d3f357a52edf8 (diff)
downloadlinux-13210ce5c06ed9537558b85e9c0df4248b28f1f7.tar.gz
[PATCH] sky2: improve receive performance
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>
-rw-r--r--drivers/net/sky2.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 83361aed49f609..e6f71c1232bcd2 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -72,10 +72,10 @@
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)