[PATCH] e100: Fix TX hang and RMCP Ping issue (due to a microcode loading issue)
[safe/jmp/linux-2.6] / drivers / net / bnx2.c
index 08086a9..49fa1e4 100644 (file)
@@ -14,8 +14,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.2.21"
-#define DRV_MODULE_RELDATE     "September 7, 2005"
+#define DRV_MODULE_VERSION     "1.4.30"
+#define DRV_MODULE_RELDATE     "October 11, 2005"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -26,7 +26,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 Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -437,6 +437,62 @@ alloc_mem_err:
 }
 
 static void
+bnx2_report_fw_link(struct bnx2 *bp)
+{
+       u32 fw_link_status = 0;
+
+       if (bp->link_up) {
+               u32 bmsr;
+
+               switch (bp->line_speed) {
+               case SPEED_10:
+                       if (bp->duplex == DUPLEX_HALF)
+                               fw_link_status = BNX2_LINK_STATUS_10HALF;
+                       else
+                               fw_link_status = BNX2_LINK_STATUS_10FULL;
+                       break;
+               case SPEED_100:
+                       if (bp->duplex == DUPLEX_HALF)
+                               fw_link_status = BNX2_LINK_STATUS_100HALF;
+                       else
+                               fw_link_status = BNX2_LINK_STATUS_100FULL;
+                       break;
+               case SPEED_1000:
+                       if (bp->duplex == DUPLEX_HALF)
+                               fw_link_status = BNX2_LINK_STATUS_1000HALF;
+                       else
+                               fw_link_status = BNX2_LINK_STATUS_1000FULL;
+                       break;
+               case SPEED_2500:
+                       if (bp->duplex == DUPLEX_HALF)
+                               fw_link_status = BNX2_LINK_STATUS_2500HALF;
+                       else
+                               fw_link_status = BNX2_LINK_STATUS_2500FULL;
+                       break;
+               }
+
+               fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
+
+               if (bp->autoneg) {
+                       fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
+
+                       bnx2_read_phy(bp, MII_BMSR, &bmsr);
+                       bnx2_read_phy(bp, MII_BMSR, &bmsr);
+
+                       if (!(bmsr & BMSR_ANEGCOMPLETE) ||
+                           bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
+                               fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
+                       else
+                               fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
+               }
+       }
+       else
+               fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
+
+       REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
+}
+
+static void
 bnx2_report_link(struct bnx2 *bp)
 {
        if (bp->link_up) {
@@ -467,6 +523,8 @@ bnx2_report_link(struct bnx2 *bp)
                netif_carrier_off(bp->dev);
                printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
        }
+
+       bnx2_report_fw_link(bp);
 }
 
 static void
@@ -1123,13 +1181,13 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
                bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
        }
 
-       val = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_CONFIG) &
+       val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
              BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
 
        if (val) {
                u32 is_backplane;
 
-               is_backplane = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
+               is_backplane = REG_RD_IND(bp, bp->shmem_base +
                                          BNX2_SHARED_HW_CFG_CONFIG);
                if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
                        bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
@@ -1280,13 +1338,13 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data)
        bp->fw_wr_seq++;
        msg_data |= bp->fw_wr_seq;
 
-       REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data);
+       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
 
        /* wait for an acknowledgement. */
        for (i = 0; i < (FW_ACK_TIME_OUT_MS * 1000)/5; i++) {
                udelay(5);
 
-               val = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_FW_MB);
+               val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
 
                if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
                        break;
@@ -1299,7 +1357,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data)
                msg_data &= ~BNX2_DRV_MSG_CODE;
                msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
 
-               REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data);
+               REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
 
                bp->fw_timed_out = 1;
 
@@ -1475,10 +1533,11 @@ bnx2_phy_int(struct bnx2 *bp)
 static void
 bnx2_tx_int(struct bnx2 *bp)
 {
+       struct status_block *sblk = bp->status_blk;
        u16 hw_cons, sw_cons, sw_ring_cons;
        int tx_free_bd = 0;
 
-       hw_cons = bp->status_blk->status_tx_quick_consumer_index0;
+       hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
        if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
                hw_cons++;
        }
@@ -1533,7 +1592,9 @@ bnx2_tx_int(struct bnx2 *bp)
 
                dev_kfree_skb_irq(skb);
 
-               hw_cons = bp->status_blk->status_tx_quick_consumer_index0;
+               hw_cons = bp->hw_tx_cons =
+                       sblk->status_tx_quick_consumer_index0;
+
                if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
                        hw_cons++;
                }
@@ -1578,11 +1639,12 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
 static int
 bnx2_rx_int(struct bnx2 *bp, int budget)
 {
+       struct status_block *sblk = bp->status_blk;
        u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
        struct l2_fhdr *rx_hdr;
        int rx_pkt = 0;
 
-       hw_cons = bp->status_blk->status_rx_quick_consumer_index0;
+       hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
        if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
                hw_cons++;
        }
@@ -1702,6 +1764,15 @@ next_rx:
 
                if ((rx_pkt == budget))
                        break;
+
+               /* Refresh hw_cons to see if there is new work */
+               if (sw_cons == hw_cons) {
+                       hw_cons = bp->hw_rx_cons =
+                               sblk->status_rx_quick_consumer_index0;
+                       if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)
+                               hw_cons++;
+                       rmb();
+               }
        }
        bp->rx_cons = sw_cons;
        bp->rx_prod = sw_prod;
@@ -1769,15 +1840,27 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+static inline int
+bnx2_has_work(struct bnx2 *bp)
+{
+       struct status_block *sblk = bp->status_blk;
+
+       if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
+           (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
+               return 1;
+
+       if (((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) !=
+           bp->link_up)
+               return 1;
+
+       return 0;
+}
+
 static int
 bnx2_poll(struct net_device *dev, int *budget)
 {
        struct bnx2 *bp = dev->priv;
-       int rx_done = 1;
-
-       bp->last_status_idx = bp->status_blk->status_idx;
 
-       rmb();
        if ((bp->status_blk->status_attn_bits &
                STATUS_ATTN_BITS_LINK_STATE) !=
                (bp->status_blk->status_attn_bits_ack &
@@ -1788,11 +1871,10 @@ bnx2_poll(struct net_device *dev, int *budget)
                spin_unlock(&bp->phy_lock);
        }
 
-       if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) {
+       if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
                bnx2_tx_int(bp);
-       }
 
-       if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) {
+       if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
                int orig_budget = *budget;
                int work_done;
 
@@ -1802,13 +1884,12 @@ bnx2_poll(struct net_device *dev, int *budget)
                work_done = bnx2_rx_int(bp, orig_budget);
                *budget -= work_done;
                dev->quota -= work_done;
-               
-               if (work_done >= orig_budget) {
-                       rx_done = 0;
-               }
        }
        
-       if (rx_done) {
+       bp->last_status_idx = bp->status_blk->status_idx;
+       rmb();
+
+       if (!bnx2_has_work(bp)) {
                netif_rx_complete(dev);
                REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
                        BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
@@ -2626,7 +2707,7 @@ bnx2_init_nvram(struct bnx2 *bp)
 
        if (j == entry_count) {
                bp->flash_info = NULL;
-               printk(KERN_ALERT "Unknown flash/EEPROM type.\n");
+               printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
                rc = -ENODEV;
        }
 
@@ -2935,7 +3016,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
 
        /* Deposit a driver reset signature so the firmware knows that
         * this is a soft reset. */
-       REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_RESET_SIGNATURE,
+       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
                   BNX2_DRV_RESET_SIGNATURE_MAGIC);
 
        bp->fw_timed_out = 0;
@@ -3164,6 +3245,7 @@ bnx2_init_tx_ring(struct bnx2 *bp)
 
        bp->tx_prod = 0;
        bp->tx_cons = 0;
+       bp->hw_tx_cons = 0;
        bp->tx_prod_bseq = 0;
        
        val = BNX2_L2CTX_TYPE_TYPE_L2;
@@ -3196,6 +3278,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
 
        ring_prod = prod = bp->rx_prod = 0;
        bp->rx_cons = 0;
+       bp->hw_rx_cons = 0;
        bp->rx_prod_bseq = 0;
                
        rxbd = &bp->rx_desc_ring[0];
@@ -3281,7 +3364,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
                struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
                struct sk_buff *skb = rx_buf->skb;
 
-               if (skb == 0)
+               if (skb == NULL)
                        continue;
 
                pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
@@ -3820,6 +3903,8 @@ bnx2_test_loopback(struct bnx2 *bp)
 
        pkt_size = 1514;
        skb = dev_alloc_skb(pkt_size);
+       if (!skb)
+               return -ENOMEM;
        packet = skb_put(skb, pkt_size);
        memcpy(packet, bp->mac_addr, 6);
        memset(packet + 6, 0x0, 8);
@@ -4012,7 +4097,7 @@ bnx2_timer(unsigned long data)
                goto bnx2_restart_timer;
 
        msg = (u32) ++bp->fw_drv_pulse_wr_seq;
-       REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_PULSE_MB, msg);
+       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
 
        if ((bp->phy_flags & PHY_SERDES_FLAG) &&
            (CHIP_NUM(bp) == CHIP_NUM_5706)) {
@@ -4715,11 +4800,7 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct bnx2 *bp = dev->priv;
        int rc;
 
-       if (eeprom->offset > bp->flash_info->total_size)
-               return -EINVAL;
-
-       if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
-               eeprom->len = bp->flash_info->total_size - eeprom->offset;
+       /* parameters already validated in ethtool_get_eeprom */
 
        rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
 
@@ -4733,11 +4814,7 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct bnx2 *bp = dev->priv;
        int rc;
 
-       if (eeprom->offset > bp->flash_info->total_size)
-               return -EINVAL;
-
-       if ((eeprom->offset + eeprom->len) > bp->flash_info->total_size)
-               eeprom->len = bp->flash_info->total_size - eeprom->offset;
+       /* parameters already validated in ethtool_set_eeprom */
 
        rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
 
@@ -5483,10 +5560,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bnx2_init_nvram(bp);
 
+       reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
+
+       if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
+           BNX2_SHM_HDR_SIGNATURE_SIG)
+               bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0);
+       else
+               bp->shmem_base = HOST_VIEW_SHMEM_BASE;
+
        /* Get the permanent MAC address.  First we need to make sure the
         * firmware is actually running.
         */
-       reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DEV_INFO_SIGNATURE);
+       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
 
        if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
            BNX2_DEV_INFO_SIGNATURE_MAGIC) {
@@ -5495,14 +5580,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                goto err_out_unmap;
        }
 
-       bp->fw_ver = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
-                               BNX2_DEV_INFO_BC_REV);
+       bp->fw_ver = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
 
-       reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_UPPER);
+       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
        bp->mac_addr[0] = (u8) (reg >> 8);
        bp->mac_addr[1] = (u8) reg;
 
-       reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_LOWER);
+       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
        bp->mac_addr[2] = (u8) (reg >> 24);
        bp->mac_addr[3] = (u8) (reg >> 16);
        bp->mac_addr[4] = (u8) (reg >> 8);
@@ -5538,7 +5622,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                bp->flags |= NO_WOL_FLAG;
                if (CHIP_NUM(bp) == CHIP_NUM_5708) {
                        bp->phy_addr = 2;
-                       reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
+                       reg = REG_RD_IND(bp, bp->shmem_base +
                                         BNX2_SHARED_HW_CFG_CONFIG);
                        if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
                                bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
@@ -5562,8 +5646,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        if (bp->phy_flags & PHY_SERDES_FLAG) {
                bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
 
-               reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE +
-                                BNX2_PORT_HW_CFG_CONFIG);
+               reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
                reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
                if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
                        bp->autoneg = 0;