#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.7.6"
-#define DRV_MODULE_RELDATE "May 16, 2008"
+#define DRV_MODULE_VERSION "1.7.7"
+#define DRV_MODULE_RELDATE "June 17, 2008"
#define RUN_AT(x) (jiffies + (x))
"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);
BCM5708S,
BCM5709,
BCM5709S,
+ BCM5716,
} board_t;
/* indexed by board_t, above */
{ "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,
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, }
};
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)
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;
}
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;
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);
}
if (!(bp->flags & BNX2_FLAG_NO_WOL))
- bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
+ 1, 0);
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
}
static void
-bnx2_init_remote_phy(struct bnx2 *bp)
+bnx2_init_fw_cap(struct bnx2 *bp)
{
- u32 val;
+ u32 val, sig = 0;
bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
- if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
- return;
+ bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
+
+ if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
+ bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
return;
- if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
+ if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
+ bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
+ sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
+ }
+
+ if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
+ (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
+ u32 link;
+
bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
- val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
- if (val & BNX2_LINK_STATUS_SERDES_LINK)
+ link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
+ if (link & BNX2_LINK_STATUS_SERDES_LINK)
bp->phy_port = PORT_FIBRE;
else
bp->phy_port = PORT_TP;
- if (netif_running(bp->dev)) {
- u32 sig;
-
- sig = BNX2_DRV_ACK_CAP_SIGNATURE |
- BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
- bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
- }
+ sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
+ BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
}
+
+ if (netif_running(bp->dev) && sig)
+ bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
}
static void
udelay(5);
/* Wait for the firmware to tell us it is ok to issue a reset. */
- bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
/* Deposit a driver reset signature so the firmware knows that
* this is a soft reset. */
}
/* Wait for the firmware to finish its initialization. */
- rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
+ rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
if (rc)
return rc;
spin_lock_bh(&bp->phy_lock);
old_port = bp->phy_port;
- bnx2_init_remote_phy(bp);
+ bnx2_init_fw_cap(bp);
if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
old_port != bp->phy_port)
bnx2_set_default_remote_link(bp);
BNX2_HC_CONFIG_COLLECT_STATS;
}
- if (bp->flags & BNX2_FLAG_USING_MSIX) {
- u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
- BNX2_HC_SB_CONFIG_1;
-
+ if (bp->irq_nvecs > 1) {
REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
BNX2_HC_MSIX_BIT_VECTOR_VAL);
+ val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
+ }
+
+ if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
+ val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+ REG_WR(bp, BNX2_HC_CONFIG, val);
+
+ for (i = 1; i < bp->irq_nvecs; i++) {
+ u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+ BNX2_HC_SB_CONFIG_1;
+
REG_WR(bp, base,
BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
+ BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
BNX2_HC_SB_CONFIG_1_ONE_SHOT);
REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
(bp->tx_ticks_int << 16) | bp->tx_ticks);
- val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
- }
+ REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
+ (bp->rx_quick_cons_trip_int << 16) |
+ bp->rx_quick_cons_trip);
- if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
- val |= BNX2_HC_CONFIG_ONE_SHOT;
-
- REG_WR(bp, BNX2_HC_CONFIG, val);
+ REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
+ (bp->rx_ticks_int << 16) | bp->rx_ticks);
+ }
/* Clear internal stats counters. */
REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
}
rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
- 0);
+ 1, 0);
REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
- BNX2_L2CTX_RBDC_JUMBO_KEY);
+ BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
bnx2_init_all_rings(struct bnx2 *bp)
{
int i;
+ u32 val;
bnx2_clear_ring_states(bp);
REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
(TX_TSS_CID << 7));
+ REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
+ bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
+
for (i = 0; i < bp->num_rx_rings; i++)
bnx2_init_rx_ring(bp, i);
+
+ if (bp->num_rx_rings > 1) {
+ u32 tbl_32;
+ u8 *tbl = (u8 *) &tbl_32;
+
+ bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
+ BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
+
+ for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
+ tbl[i % 4] = i % (bp->num_rx_rings - 1);
+ if ((i % 4) == 3)
+ bnx2_reg_wr_ind(bp,
+ BNX2_RXP_SCRATCH_RSS_TBL + i,
+ cpu_to_be32(tbl_32));
+ }
+
+ val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
+ BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
+
+ REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
+
+ }
}
static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
}
static void
-bnx2_enable_msix(struct bnx2 *bp)
+bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
{
int i, rc;
struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
if (rc != 0)
return;
- bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
+ bp->irq_nvecs = msix_vecs;
bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
bp->irq_tbl[i].vector = msix_ent[i].vector;
static void
bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
{
+ int cpus = num_online_cpus();
+ int msix_vecs = min(cpus + 1, RX_MAX_RSS_RINGS);
+
bp->irq_tbl[0].handler = bnx2_interrupt;
strcpy(bp->irq_tbl[0].name, bp->dev->name);
bp->irq_nvecs = 1;
bp->irq_tbl[0].vector = bp->pdev->irq;
- if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
- bnx2_enable_msix(bp);
+ if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
+ bnx2_enable_msix(bp, msix_vecs);
if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
!(bp->flags & BNX2_FLAG_USING_MSIX)) {
}
}
bp->num_tx_rings = 1;
- bp->num_rx_rings = 1;
+ bp->num_rx_rings = bp->irq_nvecs;
}
/* Called with rtnl_lock */
bnx2_setup_int_mode(bp, disable_msi);
bnx2_napi_enable(bp);
rc = bnx2_alloc_mem(bp);
- if (rc) {
- bnx2_napi_disable(bp);
- bnx2_free_mem(bp);
- return rc;
- }
+ if (rc)
+ goto open_err;
rc = bnx2_request_irq(bp);
-
- if (rc) {
- bnx2_napi_disable(bp);
- bnx2_free_mem(bp);
- return rc;
- }
+ if (rc)
+ goto open_err;
rc = bnx2_init_nic(bp, 1);
-
- if (rc) {
- bnx2_napi_disable(bp);
- bnx2_free_irq(bp);
- bnx2_free_skbs(bp);
- bnx2_free_mem(bp);
- return rc;
- }
+ if (rc)
+ goto open_err;
mod_timer(&bp->timer, jiffies + bp->current_interval);
rc = bnx2_request_irq(bp);
if (rc) {
- bnx2_napi_disable(bp);
- bnx2_free_skbs(bp);
- bnx2_free_mem(bp);
del_timer_sync(&bp->timer);
- return rc;
+ goto open_err;
}
bnx2_enable_int(bp);
}
netif_start_queue(dev);
return 0;
+
+open_err:
+ bnx2_napi_disable(bp);
+ bnx2_free_skbs(bp);
+ bnx2_free_irq(bp);
+ bnx2_free_mem(bp);
+ return rc;
}
static void
bp->vlgrp = vlgrp;
bnx2_set_rx_mode(dev);
+ if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
bnx2_netif_start(bp);
}
!(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
goto err_out_unlock;
+ /* If device is down, we can store the settings only if the user
+ * is setting the currently active port.
+ */
+ if (!netif_running(dev) && cmd->port != bp->phy_port)
+ goto err_out_unlock;
+
if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED;
bp->req_line_speed = req_line_speed;
bp->req_duplex = req_duplex;
- err = bnx2_setup_phy(bp, cmd->port);
+ err = 0;
+ /* If device is down, the new settings will be picked up when it is
+ * brought up.
+ */
+ if (netif_running(dev))
+ err = bnx2_setup_phy(bp, cmd->port);
err_out_unlock:
spin_unlock_bh(&bp->phy_lock);
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
}
- bnx2_init_remote_phy(bp);
-
} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
CHIP_NUM(bp) == CHIP_NUM_5708)
bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
CHIP_REV(bp) == CHIP_REV_Bx))
bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
+ bnx2_init_fw_cap(bp);
+
if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
(CHIP_ID(bp) == CHIP_ID_5708_B0) ||
(CHIP_ID(bp) == CHIP_ID_5708_B1)) {