#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "2.0.2"
-#define DRV_MODULE_RELDATE "Aug 21, 2009"
+#define DRV_MODULE_VERSION "2.0.3"
+#define DRV_MODULE_RELDATE "Dec 03, 2009"
#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j3.fw"
#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j3.fw"
bnx2_netif_stop(struct bnx2 *bp)
{
bnx2_cnic_stop(bp);
- bnx2_disable_int_sync(bp);
if (netif_running(bp->dev)) {
+ int i;
+
bnx2_napi_disable(bp);
netif_tx_disable(bp->dev);
- bp->dev->trans_start = jiffies; /* prevent tx timeout */
+ /* prevent tx timeout */
+ for (i = 0; i < bp->dev->num_tx_queues; i++) {
+ struct netdev_queue *txq;
+
+ txq = netdev_get_tx_queue(bp->dev, i);
+ txq->trans_start = jiffies;
+ }
}
+ bnx2_disable_int_sync(bp);
}
static void
ring_prod = prod = rxr->rx_pg_prod;
for (i = 0; i < bp->rx_pg_ring_size; i++) {
- if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0)
+ if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
+ printk(KERN_WARNING PFX "%s: init'ed rx page ring %d "
+ "with %d/%d pages only\n",
+ bp->dev->name, ring_num, i, bp->rx_pg_ring_size);
break;
+ }
prod = NEXT_RX_BD(prod);
ring_prod = RX_PG_RING_IDX(prod);
}
ring_prod = prod = rxr->rx_prod;
for (i = 0; i < bp->rx_ring_size; i++) {
- if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0)
+ if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
+ printk(KERN_WARNING PFX "%s: init'ed rx ring %d with "
+ "%d/%d skbs only\n",
+ bp->dev->name, ring_num, i, bp->rx_ring_size);
break;
+ }
prod = NEXT_RX_BD(prod);
ring_prod = RX_RING_IDX(prod);
}
{
struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
- if (!netif_running(bp->dev))
+ rtnl_lock();
+ if (!netif_running(bp->dev)) {
+ rtnl_unlock();
return;
+ }
bnx2_netif_stop(bp);
atomic_set(&bp->intr_sem, 1);
bnx2_netif_start(bp);
+ rtnl_unlock();
+}
+
+static void
+bnx2_dump_state(struct bnx2 *bp)
+{
+ struct net_device *dev = bp->dev;
+
+ printk(KERN_ERR PFX "%s DEBUG: intr_sem[%x]\n", dev->name,
+ atomic_read(&bp->intr_sem));
+ printk(KERN_ERR PFX "%s DEBUG: EMAC_TX_STATUS[%08x] "
+ "RPM_MGMT_PKT_CTRL[%08x]\n", dev->name,
+ REG_RD(bp, BNX2_EMAC_TX_STATUS),
+ REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
+ printk(KERN_ERR PFX "%s DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
+ dev->name, bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
+ bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
+ printk(KERN_ERR PFX "%s DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
+ dev->name, REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
+ if (bp->flags & BNX2_FLAG_USING_MSIX)
+ printk(KERN_ERR PFX "%s DEBUG: PBA[%08x]\n", dev->name,
+ REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
}
static void
{
struct bnx2 *bp = netdev_priv(dev);
+ bnx2_dump_state(bp);
+
/* This allows the netif to be shutdown gracefully before resetting */
schedule_work(&bp->reset_task);
}
}
+static void __devinit
+bnx2_read_vpd_fw_ver(struct bnx2 *bp)
+{
+ int rc, i, v0_len = 0;
+ u8 *data;
+ u8 *v0_str = NULL;
+ bool mn_match = false;
+
+#define BNX2_VPD_NVRAM_OFFSET 0x300
+#define BNX2_VPD_LEN 128
+#define BNX2_MAX_VER_SLEN 30
+
+ data = kmalloc(256, GFP_KERNEL);
+ if (!data)
+ return;
+
+ rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
+ BNX2_VPD_LEN);
+ if (rc)
+ goto vpd_done;
+
+ for (i = 0; i < BNX2_VPD_LEN; i += 4) {
+ data[i] = data[i + BNX2_VPD_LEN + 3];
+ data[i + 1] = data[i + BNX2_VPD_LEN + 2];
+ data[i + 2] = data[i + BNX2_VPD_LEN + 1];
+ data[i + 3] = data[i + BNX2_VPD_LEN];
+ }
+
+ for (i = 0; i <= BNX2_VPD_LEN - 3; ) {
+ unsigned char val = data[i];
+ unsigned int block_end;
+
+ if (val == 0x82 || val == 0x91) {
+ i = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
+ continue;
+ }
+
+ if (val != 0x90)
+ goto vpd_done;
+
+ block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
+ i += 3;
+
+ if (block_end > BNX2_VPD_LEN)
+ goto vpd_done;
+
+ while (i < (block_end - 2)) {
+ int len = data[i + 2];
+
+ if (i + 3 + len > block_end)
+ goto vpd_done;
+
+ if (data[i] == 'M' && data[i + 1] == 'N') {
+ if (len != 4 ||
+ memcmp(&data[i + 3], "1028", 4))
+ goto vpd_done;
+ mn_match = true;
+
+ } else if (data[i] == 'V' && data[i + 1] == '0') {
+ if (len > BNX2_MAX_VER_SLEN)
+ goto vpd_done;
+
+ v0_len = len;
+ v0_str = &data[i + 3];
+ }
+ i += 3 + len;
+
+ if (mn_match && v0_str) {
+ memcpy(bp->fw_version, v0_str, v0_len);
+ bp->fw_version[v0_len] = ' ';
+ goto vpd_done;
+ }
+ }
+ goto vpd_done;
+ }
+
+vpd_done:
+ kfree(data);
+}
+
static int __devinit
bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
goto err_out_unmap;
}
+ bnx2_read_vpd_fw_ver(bp);
+
+ j = strlen(bp->fw_version);
reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
- for (i = 0, j = 0; i < 3; i++) {
+ for (i = 0; i < 3 && j < 24; i++) {
u8 num, k, skip0;
+ if (i == 0) {
+ bp->fw_version[j++] = 'b';
+ bp->fw_version[j++] = 'c';
+ bp->fw_version[j++] = ' ';
+ }
num = (u8) (reg >> (24 - (i * 8)));
for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
if (num >= k || !skip0 || k == 1) {
reg != BNX2_CONDITION_MFW_RUN_NONE) {
u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
- bp->fw_version[j++] = ' ';
- for (i = 0; i < 3; i++) {
+ if (j < 32)
+ bp->fw_version[j++] = ' ';
+ for (i = 0; i < 3 && j < 28; i++) {
reg = bnx2_reg_rd_ind(bp, addr + i * 4);
reg = swab32(reg);
memcpy(&bp->fw_version[j], ®, 4);
}
pci_set_master(pdev);
pci_restore_state(pdev);
+ pci_save_state(pdev);
if (netif_running(dev)) {
bnx2_set_power_state(bp, PCI_D0);