Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] bnx2: refine bnx2_poll

Refine bnx2_poll() logic to write back the most up-to-date status tag
when all work has been processed. This eliminates some occasional
extra interrupts when a older status tag is written even though all
work has been processed.

The idea is to read the status tag just before exiting bnx2_poll() and
then check again for any new work. If no new work is pending, the
status tag written back will not generate any extra interrupt. This
logic is similar to the changes David Miller did to tg3_poll().

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Michael Chan and committed by
John W. Linville
f4e418f7 e3648b3d

+43 -15
+40 -15
drivers/net/bnx2.c
··· 1533 1533 static void 1534 1534 bnx2_tx_int(struct bnx2 *bp) 1535 1535 { 1536 + struct status_block *sblk = bp->status_blk; 1536 1537 u16 hw_cons, sw_cons, sw_ring_cons; 1537 1538 int tx_free_bd = 0; 1538 1539 1539 - hw_cons = bp->status_blk->status_tx_quick_consumer_index0; 1540 + hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0; 1540 1541 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { 1541 1542 hw_cons++; 1542 1543 } ··· 1592 1591 1593 1592 dev_kfree_skb_irq(skb); 1594 1593 1595 - hw_cons = bp->status_blk->status_tx_quick_consumer_index0; 1594 + hw_cons = bp->hw_tx_cons = 1595 + sblk->status_tx_quick_consumer_index0; 1596 + 1596 1597 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { 1597 1598 hw_cons++; 1598 1599 } ··· 1639 1636 static int 1640 1637 bnx2_rx_int(struct bnx2 *bp, int budget) 1641 1638 { 1639 + struct status_block *sblk = bp->status_blk; 1642 1640 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; 1643 1641 struct l2_fhdr *rx_hdr; 1644 1642 int rx_pkt = 0; 1645 1643 1646 - hw_cons = bp->status_blk->status_rx_quick_consumer_index0; 1644 + hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0; 1647 1645 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) { 1648 1646 hw_cons++; 1649 1647 } ··· 1764 1760 1765 1761 if ((rx_pkt == budget)) 1766 1762 break; 1763 + 1764 + /* Refresh hw_cons to see if there is new work */ 1765 + if (sw_cons == hw_cons) { 1766 + hw_cons = bp->hw_rx_cons = 1767 + sblk->status_rx_quick_consumer_index0; 1768 + if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) 1769 + hw_cons++; 1770 + rmb(); 1771 + } 1767 1772 } 1768 1773 bp->rx_cons = sw_cons; 1769 1774 bp->rx_prod = sw_prod; ··· 1840 1827 return IRQ_HANDLED; 1841 1828 } 1842 1829 1830 + static inline int 1831 + bnx2_has_work(struct bnx2 *bp) 1832 + { 1833 + struct status_block *sblk = bp->status_blk; 1834 + 1835 + if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) || 1836 + (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) 1837 + return 1; 1838 + 1839 + if (((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) != 1840 + bp->link_up) 1841 + return 1; 1842 + 1843 + return 0; 1844 + } 1845 + 1843 1846 static int 1844 1847 bnx2_poll(struct net_device *dev, int *budget) 1845 1848 { 1846 1849 struct bnx2 *bp = dev->priv; 1847 - int rx_done = 1; 1848 1850 1849 - bp->last_status_idx = bp->status_blk->status_idx; 1850 - 1851 - rmb(); 1852 1851 if ((bp->status_blk->status_attn_bits & 1853 1852 STATUS_ATTN_BITS_LINK_STATE) != 1854 1853 (bp->status_blk->status_attn_bits_ack & ··· 1871 1846 spin_unlock(&bp->phy_lock); 1872 1847 } 1873 1848 1874 - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) { 1849 + if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) 1875 1850 bnx2_tx_int(bp); 1876 - } 1877 1851 1878 - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) { 1852 + if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) { 1879 1853 int orig_budget = *budget; 1880 1854 int work_done; 1881 1855 ··· 1884 1860 work_done = bnx2_rx_int(bp, orig_budget); 1885 1861 *budget -= work_done; 1886 1862 dev->quota -= work_done; 1887 - 1888 - if (work_done >= orig_budget) { 1889 - rx_done = 0; 1890 - } 1891 1863 } 1892 1864 1893 - if (rx_done) { 1865 + bp->last_status_idx = bp->status_blk->status_idx; 1866 + rmb(); 1867 + 1868 + if (!bnx2_has_work(bp)) { 1894 1869 netif_rx_complete(dev); 1895 1870 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 1896 1871 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | ··· 3245 3222 3246 3223 bp->tx_prod = 0; 3247 3224 bp->tx_cons = 0; 3225 + bp->hw_tx_cons = 0; 3248 3226 bp->tx_prod_bseq = 0; 3249 3227 3250 3228 val = BNX2_L2CTX_TYPE_TYPE_L2; ··· 3278 3254 3279 3255 ring_prod = prod = bp->rx_prod = 0; 3280 3256 bp->rx_cons = 0; 3257 + bp->hw_rx_cons = 0; 3281 3258 bp->rx_prod_bseq = 0; 3282 3259 3283 3260 rxbd = &bp->rx_desc_ring[0];
+3
drivers/net/bnx2.h
··· 3914 3914 u16 tx_cons; 3915 3915 int tx_ring_size; 3916 3916 3917 + u16 hw_tx_cons; 3918 + u16 hw_rx_cons; 3919 + 3917 3920 #ifdef BCM_VLAN 3918 3921 struct vlan_group *vlgrp; 3919 3922 #endif