diff options
author | shemminger@osdl.org <shemminger@osdl.org> | 2005-10-26 15:16:10 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 12:18:53 -0400 |
commit | bea86103313fae2e29f2d6eb9a4bd7cbeabd4d32 (patch) | |
tree | efac21150cc73fda30e8d3d5871747b7585c064c /drivers/net | |
parent | d571b694df3ebc66f7a4c507f5a32579e43c2294 (diff) |
[PATCH] sky2: fix NAPI and receive handling
Speed up the receive and interrupt processing and eliminate a
couple of race conditions from NAPI code.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 63 |
1 files changed, 30 insertions, 33 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 92d69fff8755..a85a8d16908f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -76,7 +76,7 @@ | |||
76 | 76 | ||
77 | #define RX_LE_SIZE 256 | 77 | #define RX_LE_SIZE 256 |
78 | #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) | 78 | #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) |
79 | #define RX_MAX_PENDING (RX_LE_SIZE/2 - 1) | 79 | #define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) |
80 | #define RX_DEF_PENDING 128 | 80 | #define RX_DEF_PENDING 128 |
81 | #define RX_COPY_THRESHOLD 256 | 81 | #define RX_COPY_THRESHOLD 256 |
82 | 82 | ||
@@ -690,7 +690,7 @@ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, | |||
690 | setnew: | 690 | setnew: |
691 | sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); | 691 | sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); |
692 | } | 692 | } |
693 | *last = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)); | 693 | *last = idx; |
694 | } | 694 | } |
695 | 695 | ||
696 | 696 | ||
@@ -723,15 +723,6 @@ static inline void sky2_rx_add(struct sky2_port *sky2, struct ring_info *re) | |||
723 | le->opcode = OP_PACKET | HW_OWNER; | 723 | le->opcode = OP_PACKET | HW_OWNER; |
724 | } | 724 | } |
725 | 725 | ||
726 | /* Tell receiver about new buffers. */ | ||
727 | static inline void rx_set_put(struct net_device *dev) | ||
728 | { | ||
729 | struct sky2_port *sky2 = netdev_priv(dev); | ||
730 | |||
731 | if (sky2->rx_last_put != sky2->rx_put) | ||
732 | sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put, | ||
733 | &sky2->rx_last_put, RX_LE_SIZE); | ||
734 | } | ||
735 | 726 | ||
736 | /* Tell chip where to start receive checksum. | 727 | /* Tell chip where to start receive checksum. |
737 | * Actually has two checksums, but set both same to avoid possible byte | 728 | * Actually has two checksums, but set both same to avoid possible byte |
@@ -1616,6 +1607,10 @@ resubmit: | |||
1616 | re->skb->ip_summed = CHECKSUM_NONE; | 1607 | re->skb->ip_summed = CHECKSUM_NONE; |
1617 | sky2_rx_add(sky2, re); | 1608 | sky2_rx_add(sky2, re); |
1618 | 1609 | ||
1610 | /* Tell receiver about new buffers. */ | ||
1611 | sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put, | ||
1612 | &sky2->rx_last_put, RX_LE_SIZE); | ||
1613 | |||
1619 | return skb; | 1614 | return skb; |
1620 | 1615 | ||
1621 | error: | 1616 | error: |
@@ -1664,16 +1659,26 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1664 | hwidx = sky2_read16(hw, STAT_PUT_IDX); | 1659 | hwidx = sky2_read16(hw, STAT_PUT_IDX); |
1665 | BUG_ON(hwidx >= STATUS_RING_SIZE); | 1660 | BUG_ON(hwidx >= STATUS_RING_SIZE); |
1666 | rmb(); | 1661 | rmb(); |
1667 | while (hw->st_idx != hwidx && work_done < to_do) { | 1662 | |
1663 | do { | ||
1668 | struct sky2_status_le *le = hw->st_le + hw->st_idx; | 1664 | struct sky2_status_le *le = hw->st_le + hw->st_idx; |
1669 | struct sky2_port *sky2; | 1665 | struct sky2_port *sky2; |
1670 | struct sk_buff *skb; | 1666 | struct sk_buff *skb; |
1671 | u32 status; | 1667 | u32 status; |
1672 | u16 length; | 1668 | u16 length; |
1673 | 1669 | ||
1674 | BUG_ON(le->link >= hw->ports); | 1670 | /* Are we done yet? */ |
1675 | if (!hw->dev[le->link]) | 1671 | if (hw->st_idx == hwidx) { |
1676 | goto skip; | 1672 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); |
1673 | hwidx = sky2_read16(hw, STAT_PUT_IDX); | ||
1674 | if (hwidx == hw->st_idx) | ||
1675 | break; | ||
1676 | } | ||
1677 | |||
1678 | hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; | ||
1679 | prefetch(&hw->st_le[hw->st_idx]); | ||
1680 | |||
1681 | BUG_ON(le->link >= hw->ports || !hw->dev[le->link]); | ||
1677 | 1682 | ||
1678 | sky2 = netdev_priv(hw->dev[le->link]); | 1683 | sky2 = netdev_priv(hw->dev[le->link]); |
1679 | status = le32_to_cpu(le->status); | 1684 | status = le32_to_cpu(le->status); |
@@ -1692,6 +1697,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1692 | } else | 1697 | } else |
1693 | #endif | 1698 | #endif |
1694 | netif_receive_skb(skb); | 1699 | netif_receive_skb(skb); |
1700 | ++work_done; | ||
1695 | break; | 1701 | break; |
1696 | 1702 | ||
1697 | #ifdef SKY2_VLAN_TAG_USED | 1703 | #ifdef SKY2_VLAN_TAG_USED |
@@ -1722,22 +1728,11 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1722 | break; | 1728 | break; |
1723 | } | 1729 | } |
1724 | 1730 | ||
1725 | skip: | 1731 | le->opcode = 0; /* paranoia */ |
1726 | hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; | 1732 | } while (work_done < to_do); |
1727 | if (hw->st_idx == hwidx) { | ||
1728 | hwidx = sky2_read16(hw, STAT_PUT_IDX); | ||
1729 | rmb(); | ||
1730 | } | ||
1731 | } | ||
1732 | 1733 | ||
1733 | mmiowb(); | 1734 | mmiowb(); |
1734 | 1735 | ||
1735 | if (hw->dev[0]) | ||
1736 | rx_set_put(hw->dev[0]); | ||
1737 | |||
1738 | if (hw->dev[1]) | ||
1739 | rx_set_put(hw->dev[1]); | ||
1740 | |||
1741 | *budget -= work_done; | 1736 | *budget -= work_done; |
1742 | dev0->quota -= work_done; | 1737 | dev0->quota -= work_done; |
1743 | if (work_done < to_do) { | 1738 | if (work_done < to_do) { |
@@ -1750,10 +1745,10 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1750 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); | 1745 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); |
1751 | } | 1746 | } |
1752 | 1747 | ||
1748 | netif_rx_complete(dev0); | ||
1753 | hw->intr_mask |= Y2_IS_STAT_BMU; | 1749 | hw->intr_mask |= Y2_IS_STAT_BMU; |
1754 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 1750 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
1755 | sky2_read32(hw, B0_IMSK); | 1751 | sky2_read32(hw, B0_IMSK); |
1756 | netif_rx_complete(dev0); | ||
1757 | } | 1752 | } |
1758 | 1753 | ||
1759 | return work_done >= to_do; | 1754 | return work_done >= to_do; |
@@ -1880,6 +1875,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) | |||
1880 | static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) | 1875 | static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) |
1881 | { | 1876 | { |
1882 | struct sky2_hw *hw = dev_id; | 1877 | struct sky2_hw *hw = dev_id; |
1878 | struct net_device *dev0 = hw->dev[0]; | ||
1883 | u32 status; | 1879 | u32 status; |
1884 | 1880 | ||
1885 | status = sky2_read32(hw, B0_Y2_SP_ISRC2); | 1881 | status = sky2_read32(hw, B0_Y2_SP_ISRC2); |
@@ -1890,12 +1886,13 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) | |||
1890 | sky2_hw_intr(hw); | 1886 | sky2_hw_intr(hw); |
1891 | 1887 | ||
1892 | /* Do NAPI for Rx and Tx status */ | 1888 | /* Do NAPI for Rx and Tx status */ |
1893 | if ((status & Y2_IS_STAT_BMU) && netif_rx_schedule_test(hw->dev[0])) { | 1889 | if (status & Y2_IS_STAT_BMU) { |
1894 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); | ||
1895 | |||
1896 | hw->intr_mask &= ~Y2_IS_STAT_BMU; | 1890 | hw->intr_mask &= ~Y2_IS_STAT_BMU; |
1897 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 1891 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
1898 | __netif_rx_schedule(hw->dev[0]); | 1892 | prefetch(&hw->st_le[hw->st_idx]); |
1893 | |||
1894 | if (netif_rx_schedule_test(dev0)) | ||
1895 | __netif_rx_schedule(dev0); | ||
1899 | } | 1896 | } |
1900 | 1897 | ||
1901 | if (status & Y2_IS_IRQ_PHY1) | 1898 | if (status & Y2_IS_IRQ_PHY1) |