diff options
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 1339 |
1 files changed, 806 insertions, 533 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 367b6d46270..5ebde67d429 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -47,6 +47,7 @@ #include <linux/prefetch.h> #include <linux/cache.h> #include <linux/zlib.h> +#include <linux/log2.h> #include "bnx2.h" #include "bnx2_fw.h" @@ -56,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.7.5" -#define DRV_MODULE_RELDATE "April 29, 2008" +#define DRV_MODULE_VERSION "1.7.9" +#define DRV_MODULE_RELDATE "July 18, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -68,7 +69,7 @@ static char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -87,6 +88,7 @@ typedef enum { BCM5708S, BCM5709, BCM5709S, + BCM5716, } board_t; /* indexed by board_t, above */ @@ -102,9 +104,10 @@ static struct { { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, { "Broadcom NetXtreme II BCM5709 1000Base-T" }, { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, + { "Broadcom NetXtreme II BCM5716 1000Base-T" }, }; -static struct pci_device_id bnx2_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, @@ -123,6 +126,8 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, + { PCI_VENDOR_ID_BROADCOM, 0x163b, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, { 0, } }; @@ -226,7 +231,7 @@ static struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); -static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi) +static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) { u32 diff; @@ -235,7 +240,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi) /* The ring uses 256 indices for 255 entries, one of them * needs to be skipped. */ - diff = bp->tx_prod - bnapi->tx_cons; + diff = txr->tx_prod - txr->tx_cons; if (unlikely(diff >= TX_DESC_CNT)) { diff &= 0xffff; if (diff == TX_DESC_CNT) @@ -289,7 +294,6 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) REG_WR(bp, BNX2_CTX_CTX_CTRL, offset | BNX2_CTX_CTX_CTRL_WRITE_REQ); for (i = 0; i < 5; i++) { - u32 val; val = REG_RD(bp, BNX2_CTX_CTX_CTRL); if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0) break; @@ -488,7 +492,7 @@ bnx2_netif_start(struct bnx2 *bp) { if (atomic_dec_and_test(&bp->intr_sem)) { if (netif_running(bp->dev)) { - netif_wake_queue(bp->dev); + netif_tx_wake_all_queues(bp->dev); bnx2_napi_enable(bp); bnx2_enable_int(bp); } @@ -496,99 +500,162 @@ bnx2_netif_start(struct bnx2 *bp) } static void -bnx2_free_mem(struct bnx2 *bp) +bnx2_free_tx_mem(struct bnx2 *bp) { int i; - for (i = 0; i < bp->ctx_pages; i++) { - if (bp->ctx_blk[i]) { - pci_free_consistent(bp->pdev, BCM_PAGE_SIZE, - bp->ctx_blk[i], - bp->ctx_blk_mapping[i]); - bp->ctx_blk[i] = NULL; + for (i = 0; i < bp->num_tx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + + if (txr->tx_desc_ring) { + pci_free_consistent(bp->pdev, TXBD_RING_SIZE, + txr->tx_desc_ring, + txr->tx_desc_mapping); + txr->tx_desc_ring = NULL; } + kfree(txr->tx_buf_ring); + txr->tx_buf_ring = NULL; } - if (bp->status_blk) { - pci_free_consistent(bp->pdev, bp->status_stats_size, - bp->status_blk, bp->status_blk_mapping); - bp->status_blk = NULL; - bp->stats_blk = NULL; +} + +static void +bnx2_free_rx_mem(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->num_rx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + int j; + + for (j = 0; j < bp->rx_max_ring; j++) { + if (rxr->rx_desc_ring[j]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, + rxr->rx_desc_ring[j], + rxr->rx_desc_mapping[j]); + rxr->rx_desc_ring[j] = NULL; + } + if (rxr->rx_buf_ring) + vfree(rxr->rx_buf_ring); + rxr->rx_buf_ring = NULL; + + for (j = 0; j < bp->rx_max_pg_ring; j++) { + if (rxr->rx_pg_desc_ring[j]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, + rxr->rx_pg_desc_ring[i], + rxr->rx_pg_desc_mapping[i]); + rxr->rx_pg_desc_ring[i] = NULL; + } + if (rxr->rx_pg_ring) + vfree(rxr->rx_pg_ring); + rxr->rx_pg_ring = NULL; } - if (bp->tx_desc_ring) { - pci_free_consistent(bp->pdev, TXBD_RING_SIZE, - bp->tx_desc_ring, bp->tx_desc_mapping); - bp->tx_desc_ring = NULL; - } - kfree(bp->tx_buf_ring); - bp->tx_buf_ring = NULL; - for (i = 0; i < bp->rx_max_ring; i++) { - if (bp->rx_desc_ring[i]) - pci_free_consistent(bp->pdev, RXBD_RING_SIZE, - bp->rx_desc_ring[i], - bp->rx_desc_mapping[i]); - bp->rx_desc_ring[i] = NULL; - } - vfree(bp->rx_buf_ring); - bp->rx_buf_ring = NULL; - for (i = 0; i < bp->rx_max_pg_ring; i++) { - if (bp->rx_pg_desc_ring[i]) - pci_free_consistent(bp->pdev, RXBD_RING_SIZE, - bp->rx_pg_desc_ring[i], - bp->rx_pg_desc_mapping[i]); - bp->rx_pg_desc_ring[i] = NULL; - } - if (bp->rx_pg_ring) - vfree(bp->rx_pg_ring); - bp->rx_pg_ring = NULL; } static int -bnx2_alloc_mem(struct bnx2 *bp) +bnx2_alloc_tx_mem(struct bnx2 *bp) { - int i, status_blk_size; + int i; - bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); - if (bp->tx_buf_ring == NULL) - return -ENOMEM; + for (i = 0; i < bp->num_tx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; - bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE, - &bp->tx_desc_mapping); - if (bp->tx_desc_ring == NULL) - goto alloc_mem_err; + txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); + if (txr->tx_buf_ring == NULL) + return -ENOMEM; - bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); - if (bp->rx_buf_ring == NULL) - goto alloc_mem_err; + txr->tx_desc_ring = + pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE, + &txr->tx_desc_mapping); + if (txr->tx_desc_ring == NULL) + return -ENOMEM; + } + return 0; +} + +static int +bnx2_alloc_rx_mem(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->num_rx_rings; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; + int j; - memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * bp->rx_max_ring); + rxr->rx_buf_ring = + vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); + if (rxr->rx_buf_ring == NULL) + return -ENOMEM; - for (i = 0; i < bp->rx_max_ring; i++) { - bp->rx_desc_ring[i] = - pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, - &bp->rx_desc_mapping[i]); - if (bp->rx_desc_ring[i] == NULL) - goto alloc_mem_err; + memset(rxr->rx_buf_ring, 0, + SW_RXBD_RING_SIZE * bp->rx_max_ring); - } + for (j = 0; j < bp->rx_max_ring; j++) { + rxr->rx_desc_ring[j] = + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, + &rxr->rx_desc_mapping[j]); + if (rxr->rx_desc_ring[j] == NULL) + return -ENOMEM; - if (bp->rx_pg_ring_size) { - bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE * - bp->rx_max_pg_ring); - if (bp->rx_pg_ring == NULL) - goto alloc_mem_err; + } + + if (bp->rx_pg_ring_size) { + rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + if (rxr->rx_pg_ring == NULL) + return -ENOMEM; + + memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + } + + for (j = 0; j < bp->rx_max_pg_ring; j++) { + rxr->rx_pg_desc_ring[j] = + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, + &rxr->rx_pg_desc_mapping[j]); + if (rxr->rx_pg_desc_ring[j] == NULL) + return -ENOMEM; - memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE * - bp->rx_max_pg_ring); + } } + return 0; +} - for (i = 0; i < bp->rx_max_pg_ring; i++) { - bp->rx_pg_desc_ring[i] = - pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, - &bp->rx_pg_desc_mapping[i]); - if (bp->rx_pg_desc_ring[i] == NULL) - goto alloc_mem_err; +static void +bnx2_free_mem(struct bnx2 *bp) +{ + int i; + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + + bnx2_free_tx_mem(bp); + bnx2_free_rx_mem(bp); + for (i = 0; i < bp->ctx_pages; i++) { + if (bp->ctx_blk[i]) { + pci_free_consistent(bp->pdev, BCM_PAGE_SIZE, + bp->ctx_blk[i], + bp->ctx_blk_mapping[i]); + bp->ctx_blk[i] = NULL; + } } + if (bnapi->status_blk.msi) { + pci_free_consistent(bp->pdev, bp->status_stats_size, + bnapi->status_blk.msi, + bp->status_blk_mapping); + bnapi->status_blk.msi = NULL; + bp->stats_blk = NULL; + } +} + +static int +bnx2_alloc_mem(struct bnx2 *bp) +{ + int i, status_blk_size, err; + struct bnx2_napi *bnapi; + void *status_blk; /* Combine status and statistics blocks into one allocation. */ status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); @@ -598,27 +665,37 @@ bnx2_alloc_mem(struct bnx2 *bp) bp->status_stats_size = status_blk_size + sizeof(struct statistics_block); - bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, - &bp->status_blk_mapping); - if (bp->status_blk == NULL) + status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, + &bp->status_blk_mapping); + if (status_blk == NULL) goto alloc_mem_err; - memset(bp->status_blk, 0, bp->status_stats_size); + memset(status_blk, 0, bp->status_stats_size); - bp->bnx2_napi[0].status_blk = bp->status_blk; + bnapi = &bp->bnx2_napi[0]; + bnapi->status_blk.msi = status_blk; + bnapi->hw_tx_cons_ptr = + &bnapi->status_blk.msi->status_tx_quick_consumer_index0; + bnapi->hw_rx_cons_ptr = + &bnapi->status_blk.msi->status_rx_quick_consumer_index0; if (bp->flags & BNX2_FLAG_MSIX_CAP) { for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { - struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + struct status_block_msix *sblk; - bnapi->status_blk_msix = (void *) - ((unsigned long) bp->status_blk + - BNX2_SBLK_MSIX_ALIGN_SIZE * i); + bnapi = &bp->bnx2_napi[i]; + + sblk = (void *) (status_blk + + BNX2_SBLK_MSIX_ALIGN_SIZE * i); + bnapi->status_blk.msix = sblk; + bnapi->hw_tx_cons_ptr = + &sblk->status_tx_quick_consumer_index; + bnapi->hw_rx_cons_ptr = + &sblk->status_rx_quick_consumer_index; bnapi->int_num = i << 24; } } - bp->stats_blk = (void *) ((unsigned long) bp->status_blk + - status_blk_size); + bp->stats_blk = status_blk + status_blk_size; bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; @@ -634,6 +711,15 @@ bnx2_alloc_mem(struct bnx2 *bp) goto alloc_mem_err; } } + + err = bnx2_alloc_rx_mem(bp); + if (err) + goto alloc_mem_err; + + err = bnx2_alloc_tx_mem(bp); + if (err) + goto alloc_mem_err; + return 0; alloc_mem_err: @@ -993,9 +1079,9 @@ bnx2_copper_linkup(struct bnx2 *bp) } static void -bnx2_init_rx_context0(struct bnx2 *bp) +bnx2_init_rx_context(struct bnx2 *bp, u32 cid) { - u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID); + u32 val, rx_cid_addr = GET_CID_ADDR(cid); val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE; val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2; @@ -1028,6 +1114,19 @@ bnx2_init_rx_context0(struct bnx2 *bp) bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val); } +static void +bnx2_init_all_rx_contexts(struct bnx2 *bp) +{ + int i; + u32 cid; + + for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) { + if (i == 1) + cid = RX_RSS_CID; + bnx2_init_rx_context(bp, cid); + } +} + static int bnx2_set_mac_link(struct bnx2 *bp) { @@ -1093,7 +1192,7 @@ bnx2_set_mac_link(struct bnx2 *bp) REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE); if (CHIP_NUM(bp) == CHIP_NUM_5709) - bnx2_init_rx_context0(bp); + bnx2_init_all_rx_contexts(bp); return 0; } @@ -1392,7 +1491,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) return adv; } -static int bnx2_fw_sync(struct bnx2 *, u32, int); +static int bnx2_fw_sync(struct bnx2 *, u32, int, int); static int bnx2_setup_remote_phy(struct bnx2 *bp, u8 port) @@ -1445,7 +1544,7 @@ bnx2_setup_remote_phy(struct bnx2 *bp, u8 port) bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg); spin_unlock_bh(&bp->phy_lock); - bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0); + bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0); spin_lock_bh(&bp->phy_lock); return 0; @@ -1875,7 +1974,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port) } static int -bnx2_init_5709s_phy(struct bnx2 *bp) +bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy) { u32 val; @@ -1890,7 +1989,8 @@ bnx2_init_5709s_phy(struct bnx2 *bp) bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG); @@ -1924,11 +2024,12 @@ bnx2_init_5709s_phy(struct bnx2 *bp) } static int -bnx2_init_5708s_phy(struct bnx2 *bp) +bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->mii_up1 = BCM5708S_UP1; @@ -1981,9 +2082,10 @@ bnx2_init_5708s_phy(struct bnx2 *bp) } static int -bnx2_init_5706s_phy(struct bnx2 *bp) +bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy) { - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; @@ -2018,11 +2120,12 @@ bnx2_init_5706s_phy(struct bnx2 *bp) } static int -bnx2_init_copper_phy(struct bnx2 *bp) +bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy) { u32 val; - bnx2_reset_phy(bp); + if (reset_phy) + bnx2_reset_phy(bp); if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) { bnx2_write_phy(bp, 0x18, 0x0c00); @@ -2070,7 +2173,7 @@ bnx2_init_copper_phy(struct bnx2 *bp) static int -bnx2_init_phy(struct bnx2 *bp) +bnx2_init_phy(struct bnx2 *bp, int reset_phy) { u32 val; int rc = 0; @@ -2096,14 +2199,14 @@ bnx2_init_phy(struct bnx2 *bp) if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) - rc = bnx2_init_5706s_phy(bp); + rc = bnx2_init_5706s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5708) - rc = bnx2_init_5708s_phy(bp); + rc = bnx2_init_5708s_phy(bp, reset_phy); else if (CHIP_NUM(bp) == CHIP_NUM_5709) - rc = bnx2_init_5709s_phy(bp); + rc = bnx2_init_5709s_phy(bp, reset_phy); } else { - rc = bnx2_init_copper_phy(bp); + rc = bnx2_init_copper_phy(bp, reset_phy); } setup_phy: @@ -2159,7 +2262,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp) } static int -bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) +bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent) { int i; u32 val; @@ -2169,6 +2272,9 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data); + if (!ack) + return 0; + /* wait for an acknowledgement. */ for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) { msleep(10); @@ -2345,28 +2451,27 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp) } static void -bnx2_set_mac_addr(struct bnx2 *bp) +bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos) { u32 val; - u8 *mac_addr = bp->dev->dev_addr; val = (mac_addr[0] << 8) | mac_addr[1]; - REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val); + REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val); val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) | mac_addr[5]; - REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val); + REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val); } static inline int -bnx2_alloc_rx_page(struct bnx2 *bp, u16 index) +bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { dma_addr_t mapping; - struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct sw_pg *rx_pg = &rxr->rx_pg_ring[index]; struct rx_bd *rxbd = - &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; + &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; struct page *page = alloc_page(GFP_ATOMIC); if (!page) @@ -2381,9 +2486,9 @@ bnx2_alloc_rx_page(struct bnx2 *bp, u16 index) } static void -bnx2_free_rx_page(struct bnx2 *bp, u16 index) +bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { - struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct sw_pg *rx_pg = &rxr->rx_pg_ring[index]; struct page *page = rx_pg->page; if (!page) @@ -2397,12 +2502,12 @@ bnx2_free_rx_page(struct bnx2 *bp, u16 index) } static inline int -bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) +bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) { struct sk_buff *skb; - struct sw_bd *rx_buf = &bp->rx_buf_ring[index]; + struct sw_bd *rx_buf = &rxr->rx_buf_ring[index]; dma_addr_t mapping; - struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; + struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; unsigned long align; skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); @@ -2422,7 +2527,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; - bnapi->rx_prod_bseq += bp->rx_buf_use_size; + rxr->rx_prod_bseq += bp->rx_buf_use_size; return 0; } @@ -2430,7 +2535,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) static int bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) { - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; u32 new_link_state, old_link_state; int is_set = 1; @@ -2466,11 +2571,9 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) { u16 cons; - if (bnapi->int_num == 0) - cons = bnapi->status_blk->status_tx_quick_consumer_index0; - else - cons = bnapi->status_blk_msix->status_tx_quick_consumer_index; - + /* Tell compiler that status block fields can change. */ + barrier(); + cons = *bnapi->hw_tx_cons_ptr; if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT)) cons++; return cons; @@ -2479,11 +2582,16 @@ bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) static int bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; u16 hw_cons, sw_cons, sw_ring_cons; - int tx_pkt = 0; + int tx_pkt = 0, index; + struct netdev_queue *txq; + + index = (bnapi - bp->bnx2_napi); + txq = netdev_get_tx_queue(bp->dev, index); hw_cons = bnx2_get_hw_tx_cons(bnapi); - sw_cons = bnapi->tx_cons; + sw_cons = txr->tx_cons; while (sw_cons != hw_cons) { struct sw_bd *tx_buf; @@ -2492,7 +2600,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_ring_cons = TX_RING_IDX(sw_cons); - tx_buf = &bp->tx_buf_ring[sw_ring_cons]; + tx_buf = &txr->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; /* partial BD completions possible with TSO packets */ @@ -2522,7 +2630,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) pci_unmap_page(bp->pdev, pci_unmap_addr( - &bp->tx_buf_ring[TX_RING_IDX(sw_cons)], + &txr->tx_buf_ring[TX_RING_IDX(sw_cons)], mapping), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); @@ -2538,44 +2646,46 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) hw_cons = bnx2_get_hw_tx_cons(bnapi); } - bnapi->hw_tx_cons = hw_cons; - bnapi->tx_cons = sw_cons; + txr->hw_tx_cons = hw_cons; + txr->tx_cons = sw_cons; + /* Need to make the tx_cons update visible to bnx2_start_xmit() - * before checking for netif_queue_stopped(). Without the + * before checking for netif_tx_queue_stopped(). Without the * memory barrier, there is a small possibility that bnx2_start_xmit() * will miss it and cause the queue to be stopped forever. */ smp_mb(); - if (unlikely(netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) { - netif_tx_lock(bp->dev); - if ((netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) - netif_wake_queue(bp->dev); - netif_tx_unlock(bp->dev); + if (unlikely(netif_tx_queue_stopped(txq)) && + (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) { + __netif_tx_lock(txq, smp_processor_id()); + if ((netif_tx_queue_stopped(txq)) && + (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } + return tx_pkt; } static void -bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi, +bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, int count) { struct sw_pg *cons_rx_pg, *prod_rx_pg; struct rx_bd *cons_bd, *prod_bd; dma_addr_t mapping; int i; - u16 hw_prod = bnapi->rx_pg_prod, prod; - u16 cons = bnapi->rx_pg_cons; + u16 hw_prod = rxr->rx_pg_prod, prod; + u16 cons = rxr->rx_pg_cons; for (i = 0; i < count; i++) { prod = RX_PG_RING_IDX(hw_prod); - prod_rx_pg = &bp->rx_pg_ring[prod]; - cons_rx_pg = &bp->rx_pg_ring[cons]; - cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; - prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + prod_rx_pg = &rxr->rx_pg_ring[prod]; + cons_rx_pg = &rxr->rx_pg_ring[cons]; + cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; if (i == 0 && skb) { struct page *page; @@ -2604,25 +2714,25 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi, cons = RX_PG_RING_IDX(NEXT_RX_BD(cons)); hw_prod = NEXT_RX_BD(hw_prod); } - bnapi->rx_pg_prod = hw_prod; - bnapi->rx_pg_cons = cons; + rxr->rx_pg_prod = hw_prod; + rxr->rx_pg_cons = cons; } static inline void -bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, - u16 cons, u16 prod) +bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, + struct sk_buff *skb, u16 cons, u16 prod) { struct sw_bd *cons_rx_buf, *prod_rx_buf; struct rx_bd *cons_bd, *prod_bd; - cons_rx_buf = &bp->rx_buf_ring[cons]; - prod_rx_buf = &bp->rx_buf_ring[prod]; + cons_rx_buf = &rxr->rx_buf_ring[cons]; + prod_rx_buf = &rxr->rx_buf_ring[prod]; pci_dma_sync_single_for_device(bp->pdev, pci_unmap_addr(cons_rx_buf, mapping), - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE); - bnapi->rx_prod_bseq += bp->rx_buf_use_size; + rxr->rx_prod_bseq += bp->rx_buf_use_size; prod_rx_buf->skb = skb; @@ -2632,33 +2742,33 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pci_unmap_addr_set(prod_rx_buf, mapping, pci_unmap_addr(cons_rx_buf, mapping)); - cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; - prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; } static int -bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, +bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb, unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr, u32 ring_idx) { int err; u16 prod = ring_idx & 0xffff; - err = bnx2_alloc_rx_skb(bp, bnapi, prod); + err = bnx2_alloc_rx_skb(bp, rxr, prod); if (unlikely(err)) { - bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod); + bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod); if (hdr_len) { unsigned int raw_len = len + 4; int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT; - bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages); + bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages); } return err; } - skb_reserve(skb, bp->rx_offset); + skb_reserve(skb, BNX2_RX_OFFSET); pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); @@ -2668,8 +2778,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, } else { unsigned int i, frag_len, frag_size, pages; struct sw_pg *rx_pg; - u16 pg_cons = bnapi->rx_pg_cons; - u16 pg_prod = bnapi->rx_pg_prod; + u16 pg_cons = rxr->rx_pg_cons; + u16 pg_prod = rxr->rx_pg_prod; frag_size = len + 4 - hdr_len; pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT; @@ -2680,9 +2790,9 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, if (unlikely(frag_len <= 4)) { unsigned int tail = 4 - frag_len; - bnapi->rx_pg_cons = pg_cons; - bnapi->rx_pg_prod = pg_prod; - bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, + rxr->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages - i); skb->len -= tail; if (i == 0) { @@ -2696,7 +2806,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, } return 0; } - rx_pg = &bp->rx_pg_ring[pg_cons]; + rx_pg = &rxr->rx_pg_ring[pg_cons]; pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE, PCI_DMA_FROMDEVICE); @@ -2707,11 +2817,12 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len); rx_pg->page = NULL; - err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod)); + err = bnx2_alloc_rx_page(bp, rxr, + RX_PG_RING_IDX(pg_prod)); if (unlikely(err)) { - bnapi->rx_pg_cons = pg_cons; - bnapi->rx_pg_prod = pg_prod; - bnx2_reuse_rx_skb_pages(bp, bnapi, skb, + rxr->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, rxr, skb, pages - i); return err; } @@ -2724,8 +2835,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, pg_prod = NEXT_RX_BD(pg_prod); pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons)); } - bnapi->rx_pg_prod = pg_prod; - bnapi->rx_pg_cons = pg_cons; + rxr->rx_pg_prod = pg_prod; + rxr->rx_pg_cons = pg_cons; } return 0; } @@ -2733,8 +2844,11 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, static inline u16 bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) { - u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0; + u16 cons; + /* Tell compiler that status block fields can change. */ + barrier(); + cons = *bnapi->hw_rx_cons_ptr; if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) cons++; return cons; @@ -2743,13 +2857,14 @@ bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) static int bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; struct l2_fhdr *rx_hdr; int rx_pkt = 0, pg_ring_used = 0; hw_cons = bnx2_get_hw_rx_cons(bnapi); - sw_cons = bnapi->rx_cons; - sw_prod = bnapi->rx_prod; + sw_cons = rxr->rx_cons; + sw_prod = rxr->rx_prod; /* Memory barrier necessary as speculative reads of the rx * buffer can be ahead of the index in the status block @@ -2765,7 +2880,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_ring_cons = RX_RING_IDX(sw_cons); sw_ring_prod = RX_RING_IDX(sw_prod); - rx_buf = &bp->rx_buf_ring[sw_ring_cons]; + rx_buf = &rxr->rx_buf_ring[sw_ring_cons]; skb = rx_buf->skb; rx_buf->skb = NULL; @@ -2773,7 +2888,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) dma_addr = pci_unmap_addr(rx_buf, mapping); pci_dma_sync_single_for_cpu(bp->pdev, dma_addr, - bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); + BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; len = rx_hdr->l2_fhdr_pkt_len; @@ -2785,7 +2901,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) L2_FHDR_ERRORS_TOO_SHORT | L2_FHDR_ERRORS_GIANT_FRAME)) { - bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); goto next_rx; } @@ -2805,22 +2921,23 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) new_skb = netdev_alloc_skb(bp->dev, len + 2); if (new_skb == NULL) { - bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); goto next_rx; } /* aligned copy */ - skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2, + skb_copy_from_linear_data_offset(skb, + BNX2_RX_OFFSET - 2, new_skb->data, len + 2); skb_reserve(new_skb, 2); skb_put(new_skb, len); - bnx2_reuse_rx_skb(bp, bnapi, skb, + bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons, sw_ring_prod); skb = new_skb; - } else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len, + } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len, dma_addr, (sw_ring_cons << 16) | sw_ring_prod))) goto next_rx; @@ -2869,16 +2986,15 @@ next_rx: rmb(); } } - bnapi->rx_cons = sw_cons; - bnapi->rx_prod = sw_prod; + rxr->rx_cons = sw_cons; + rxr->rx_prod = sw_prod; if (pg_ring_used) - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, - bnapi->rx_pg_prod); + REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod); - REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod); + REG_WR16(bp, rxr->rx_bidx_addr, sw_prod); - REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq); + REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq); mmiowb(); @@ -2892,11 +3008,11 @@ next_rx: static irqreturn_t bnx2_msi(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; - prefetch(bnapi->status_blk); + prefetch(bnapi->status_blk.msi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); @@ -2913,11 +3029,11 @@ bnx2_msi(int irq, void *dev_instance) static irqreturn_t bnx2_msi_1shot(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; - prefetch(bnapi->status_blk); + prefetch(bnapi->status_blk.msi); /* Return here if interrupt is disabled. */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) @@ -2931,10 +3047,10 @@ bnx2_msi_1shot(int irq, void *dev_instance) static irqreturn_t bnx2_interrupt(int irq, void *dev_instance) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; - struct status_block *sblk = bnapi->status_blk; + struct bnx2_napi *bnapi = dev_instance; + struct bnx2 *bp = bnapi->bp; + struct net_device *dev = bp->dev; + struct status_block *sblk = bnapi->status_blk.msi; /* When using INTx, it is possible for the interrupt to arrive * at the CPU before the status block posted prior to the @@ -2968,21 +3084,16 @@ bnx2_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static irqreturn_t -bnx2_tx_msix(int irq, void *dev_instance) +static inline int +bnx2_has_fast_work(struct bnx2_napi *bnapi) { - struct net_device *dev = dev_instance; - struct bnx2 *bp = netdev_priv(dev); - struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; - - prefetch(bnapi->status_blk_msix); + struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; + struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; - /* Return here if interrupt is disabled. */ - if (unlikely(atomic_read(&bp->intr_sem) != 0)) - return IRQ_HANDLED; - - netif_rx_schedule(dev, &bnapi->napi); - return IRQ_HANDLED; + if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) || + (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)) + return 1; + return 0; } #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ @@ -2991,10 +3102,9 @@ bnx2_tx_msix(int irq, void *dev_instance) static inline int bnx2_has_work(struct bnx2_napi *bnapi) { - struct status_block *sblk = bnapi->status_blk; + struct status_block *sblk = bnapi->status_blk.msi; - if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) || - (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)) + if (bnx2_has_fast_work(bnapi)) return 1; if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != @@ -3004,33 +3114,9 @@ bnx2_has_work(struct bnx2_napi *bnapi) return 0; } -static int bnx2_tx_poll(struct napi_struct *napi, int budget) -{ - struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); - struct bnx2 *bp = bnapi->bp; - int work_done = 0; - struct status_block_msix *sblk = bnapi->status_blk_msix; - - do { - work_done += bnx2_tx_int(bp, bnapi, budget - work_done); - if (unlikely(work_done >= budget)) - return work_done; - - bnapi->last_status_idx = sblk->status_idx; - rmb(); - } while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons); - - netif_rx_complete(bp->dev, napi); - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bnapi-> |