#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))
"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);
}
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) {
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
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,
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;
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;
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++;
}
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++;
}
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++;
}
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;
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 &
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;
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 |
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;
}
/* 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;
bp->tx_prod = 0;
bp->tx_cons = 0;
+ bp->hw_tx_cons = 0;
bp->tx_prod_bseq = 0;
val = BNX2_L2CTX_TYPE_TYPE_L2;
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];
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),
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);
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)) {
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);
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);
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) {
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);
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;
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;