diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-07-12 18:23:48 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-07-12 18:39:22 -0400 |
commit | 22e1170310ec6afa41e0dc7ac9dfac735d82dcab (patch) | |
tree | fc6df3250b682443b7f12072dbae259d25fee91b /drivers/net/sky2.c | |
parent | afa195da458cb06f302c37f8d37b21b177060aed (diff) |
[PATCH] sky2: optimize receive restart
When the driver handles multiple packets per NAPI poll, it is
better to reload the receive ring, then tell the hardware. Otherwise,
under packet storm with flow control, the driver/hardware will degrade
down to one packet getting through per pause-exchange.
Likewise on transmit, don't wakeup until a little more than minimum
ring space is available.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e65689ebe147..d98f28c34e5c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) | 65 | #define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) |
66 | #define RX_DEF_PENDING RX_MAX_PENDING | 66 | #define RX_DEF_PENDING RX_MAX_PENDING |
67 | #define RX_SKB_ALIGN 8 | 67 | #define RX_SKB_ALIGN 8 |
68 | #define RX_BUF_WRITE 16 | ||
68 | 69 | ||
69 | #define TX_RING_SIZE 512 | 70 | #define TX_RING_SIZE 512 |
70 | #define TX_DEF_PENDING (TX_RING_SIZE - 1) | 71 | #define TX_DEF_PENDING (TX_RING_SIZE - 1) |
@@ -1390,7 +1391,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) | |||
1390 | } | 1391 | } |
1391 | 1392 | ||
1392 | sky2->tx_cons = put; | 1393 | sky2->tx_cons = put; |
1393 | if (tx_avail(sky2) > MAX_SKB_TX_LE) | 1394 | if (tx_avail(sky2) > MAX_SKB_TX_LE + 4) |
1394 | netif_wake_queue(dev); | 1395 | netif_wake_queue(dev); |
1395 | } | 1396 | } |
1396 | 1397 | ||
@@ -1889,9 +1890,6 @@ resubmit: | |||
1889 | re->skb->ip_summed = CHECKSUM_NONE; | 1890 | re->skb->ip_summed = CHECKSUM_NONE; |
1890 | sky2_rx_add(sky2, re->mapaddr); | 1891 | sky2_rx_add(sky2, re->mapaddr); |
1891 | 1892 | ||
1892 | /* Tell receiver about new buffers. */ | ||
1893 | sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put); | ||
1894 | |||
1895 | return skb; | 1893 | return skb; |
1896 | 1894 | ||
1897 | oversize: | 1895 | oversize: |
@@ -1938,7 +1936,9 @@ static inline int sky2_more_work(const struct sky2_hw *hw) | |||
1938 | /* Process status response ring */ | 1936 | /* Process status response ring */ |
1939 | static int sky2_status_intr(struct sky2_hw *hw, int to_do) | 1937 | static int sky2_status_intr(struct sky2_hw *hw, int to_do) |
1940 | { | 1938 | { |
1939 | struct sky2_port *sky2; | ||
1941 | int work_done = 0; | 1940 | int work_done = 0; |
1941 | unsigned buf_write[2] = { 0, 0 }; | ||
1942 | u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); | 1942 | u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); |
1943 | 1943 | ||
1944 | rmb(); | 1944 | rmb(); |
@@ -1946,7 +1946,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) | |||
1946 | while (hw->st_idx != hwidx) { | 1946 | while (hw->st_idx != hwidx) { |
1947 | struct sky2_status_le *le = hw->st_le + hw->st_idx; | 1947 | struct sky2_status_le *le = hw->st_le + hw->st_idx; |
1948 | struct net_device *dev; | 1948 | struct net_device *dev; |
1949 | struct sky2_port *sky2; | ||
1950 | struct sk_buff *skb; | 1949 | struct sk_buff *skb; |
1951 | u32 status; | 1950 | u32 status; |
1952 | u16 length; | 1951 | u16 length; |
@@ -1979,6 +1978,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) | |||
1979 | #endif | 1978 | #endif |
1980 | netif_receive_skb(skb); | 1979 | netif_receive_skb(skb); |
1981 | 1980 | ||
1981 | /* Update receiver after 16 frames */ | ||
1982 | if (++buf_write[le->link] == RX_BUF_WRITE) { | ||
1983 | sky2_put_idx(hw, rxqaddr[le->link], | ||
1984 | sky2->rx_put); | ||
1985 | buf_write[le->link] = 0; | ||
1986 | } | ||
1987 | |||
1988 | /* Stop after net poll weight */ | ||
1982 | if (++work_done >= to_do) | 1989 | if (++work_done >= to_do) |
1983 | goto exit_loop; | 1990 | goto exit_loop; |
1984 | break; | 1991 | break; |
@@ -2017,6 +2024,16 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) | |||
2017 | } | 2024 | } |
2018 | 2025 | ||
2019 | exit_loop: | 2026 | exit_loop: |
2027 | if (buf_write[0]) { | ||
2028 | sky2 = netdev_priv(hw->dev[0]); | ||
2029 | sky2_put_idx(hw, Q_R1, sky2->rx_put); | ||
2030 | } | ||
2031 | |||
2032 | if (buf_write[1]) { | ||
2033 | sky2 = netdev_priv(hw->dev[1]); | ||
2034 | sky2_put_idx(hw, Q_R2, sky2->rx_put); | ||
2035 | } | ||
2036 | |||
2020 | return work_done; | 2037 | return work_done; |
2021 | } | 2038 | } |
2022 | 2039 | ||