Commit 13210ce5 authored by shemminger@osdl.org's avatar shemminger@osdl.org Committed by Jeff Garzik

[PATCH] sky2: improve receive performance

Changes to receive side processing:
	* bigger receive ring
	* clean up polling loop
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 42eeea01
...@@ -72,10 +72,10 @@ ...@@ -72,10 +72,10 @@
unlikely((hw)->chip_id == CHIP_ID_YUKON_EC && \ unlikely((hw)->chip_id == CHIP_ID_YUKON_EC && \
(hw)->chip_rev == CHIP_REV_YU_EC_A1) (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_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le))
#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) #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 RX_COPY_THRESHOLD 256
#define TX_RING_SIZE 512 #define TX_RING_SIZE 512
...@@ -1596,7 +1596,6 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, ...@@ -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 ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct net_device *dev;
const unsigned int bufsize = rx_size(sky2); const unsigned int bufsize = rx_size(sky2);
if (unlikely(netif_msg_rx_status(sky2))) if (unlikely(netif_msg_rx_status(sky2)))
...@@ -1643,11 +1642,6 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, ...@@ -1643,11 +1642,6 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
} }
skb_put(skb, length); skb_put(skb, length);
dev = sky2->netdev;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
dev->last_rx = jiffies;
resubmit: resubmit:
re->skb->ip_summed = CHECKSUM_NONE; re->skb->ip_summed = CHECKSUM_NONE;
sky2_rx_add(sky2, re); sky2_rx_add(sky2, re);
...@@ -1702,35 +1696,42 @@ static int sky2_poll(struct net_device *dev0, int *budget) ...@@ -1702,35 +1696,42 @@ static int sky2_poll(struct net_device *dev0, int *budget)
BUG_ON(hwidx >= STATUS_RING_SIZE); BUG_ON(hwidx >= STATUS_RING_SIZE);
rmb(); rmb();
do { while (hwidx != hw->st_idx) {
struct sky2_status_le *le = hw->st_le + hw->st_idx; struct sky2_status_le *le = hw->st_le + hw->st_idx;
struct net_device *dev;
struct sky2_port *sky2; struct sky2_port *sky2;
struct sk_buff *skb; struct sk_buff *skb;
u32 status; u32 status;
u16 length; u16 length;
u8 op;
/* Are we done yet? */ le = hw->st_le + hw->st_idx;
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;
}
hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; 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]); 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); status = le32_to_cpu(le->status);
length = le16_to_cpu(le->length); length = le16_to_cpu(le->length);
op = le->opcode & ~HW_OWNER;
le->opcode = 0;
switch (le->opcode & ~HW_OWNER) { switch (op) {
case OP_RXSTAT: case OP_RXSTAT:
skb = sky2_receive(sky2, length, status); skb = sky2_receive(sky2, length, status);
if (!skb) if (!skb)
break; break;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED #ifdef SKY2_VLAN_TAG_USED
if (sky2->vlgrp && (status & GMR_FS_VLAN)) { if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
vlan_hwaccel_receive_skb(skb, vlan_hwaccel_receive_skb(skb,
...@@ -1739,7 +1740,9 @@ static int sky2_poll(struct net_device *dev0, int *budget) ...@@ -1739,7 +1740,9 @@ static int sky2_poll(struct net_device *dev0, int *budget)
} else } else
#endif #endif
netif_receive_skb(skb); netif_receive_skb(skb);
++work_done;
if (++work_done >= to_do)
goto exit_loop;
break; break;
#ifdef SKY2_VLAN_TAG_USED #ifdef SKY2_VLAN_TAG_USED
...@@ -1765,18 +1768,15 @@ static int sky2_poll(struct net_device *dev0, int *budget) ...@@ -1765,18 +1768,15 @@ static int sky2_poll(struct net_device *dev0, int *budget)
default: default:
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"unknown status opcode 0x%x\n", "unknown status opcode 0x%x\n", op);
le->opcode);
break; break;
} }
}
le->opcode = 0; /* paranoia */ exit_loop:
} while (work_done < to_do);
mmiowb(); mmiowb();
*budget -= work_done;
dev0->quota -= work_done;
if (work_done < to_do) { if (work_done < to_do) {
/* /*
* Another chip workaround, need to restart TX timer if status * Another chip workaround, need to restart TX timer if status
...@@ -1790,11 +1790,13 @@ static int sky2_poll(struct net_device *dev0, int *budget) ...@@ -1790,11 +1790,13 @@ static int sky2_poll(struct net_device *dev0, int *budget)
netif_rx_complete(dev0); netif_rx_complete(dev0);
hw->intr_mask |= Y2_IS_STAT_BMU; hw->intr_mask |= Y2_IS_STAT_BMU;
sky2_write32(hw, B0_IMSK, hw->intr_mask); 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) static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment