/* bnx2.c: Broadcom NX2 network driver.
*
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004-2007 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5.8"
-#define DRV_MODULE_RELDATE "April 24, 2007"
+#define DRV_MODULE_VERSION "1.5.10"
+#define DRV_MODULE_RELDATE "May 1, 2007"
#define RUN_AT(x) (jiffies + (x))
BCM5708,
BCM5708S,
BCM5709,
+ BCM5709S,
} board_t;
/* indexed by board_t, above */
{ "Broadcom NetXtreme II BCM5708 1000Base-T" },
{ "Broadcom NetXtreme II BCM5708 1000Base-SX" },
{ "Broadcom NetXtreme II BCM5709 1000Base-T" },
+ { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
};
static struct pci_device_id bnx2_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
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 },
{ 0, }
};
static u32
bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
{
+ u32 val;
+
+ spin_lock_bh(&bp->indirect_lock);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
- return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
+ val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
+ spin_unlock_bh(&bp->indirect_lock);
+ return val;
}
static void
bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
{
+ spin_lock_bh(&bp->indirect_lock);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
+ spin_unlock_bh(&bp->indirect_lock);
}
static void
bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
{
offset += cid_addr;
+ spin_lock_bh(&bp->indirect_lock);
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
int i;
REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
REG_WR(bp, BNX2_CTX_DATA, val);
}
+ spin_unlock_bh(&bp->indirect_lock);
}
static int
}
}
+static int
+bnx2_5709s_linkup(struct bnx2 *bp)
+{
+ u32 val, speed;
+
+ bp->link_up = 1;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
+ bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ if ((bp->autoneg & AUTONEG_SPEED) == 0) {
+ bp->line_speed = bp->req_line_speed;
+ bp->duplex = bp->req_duplex;
+ return 0;
+ }
+ speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
+ switch (speed) {
+ case MII_BNX2_GP_TOP_AN_SPEED_10:
+ bp->line_speed = SPEED_10;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_100:
+ bp->line_speed = SPEED_100;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_1G:
+ case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
+ bp->line_speed = SPEED_1000;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
+ bp->line_speed = SPEED_2500;
+ break;
+ }
+ if (val & MII_BNX2_GP_TOP_AN_FD)
+ bp->duplex = DUPLEX_FULL;
+ else
+ bp->duplex = DUPLEX_HALF;
+ return 0;
+}
+
static int
bnx2_5708s_linkup(struct bnx2 *bp)
{
return 0;
}
+static void
+bnx2_enable_bmsr1(struct bnx2 *bp)
+{
+ if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+ (CHIP_NUM(bp) == CHIP_NUM_5709))
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_GP_STATUS);
+}
+
+static void
+bnx2_disable_bmsr1(struct bnx2 *bp)
+{
+ if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+ (CHIP_NUM(bp) == CHIP_NUM_5709))
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+}
+
static int
bnx2_test_and_enable_2g5(struct bnx2 *bp)
{
if (bp->autoneg & AUTONEG_SPEED)
bp->advertising |= ADVERTISED_2500baseX_Full;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
bnx2_read_phy(bp, bp->mii_up1, &up1);
if (!(up1 & BCM5708S_UP1_2G5)) {
up1 |= BCM5708S_UP1_2G5;
ret = 0;
}
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
return ret;
}
if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
return 0;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
bnx2_read_phy(bp, bp->mii_up1, &up1);
if (up1 & BCM5708S_UP1_2G5) {
up1 &= ~BCM5708S_UP1_2G5;
ret = 1;
}
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
return ret;
}
if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
return;
- if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ u32 val;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_SERDES_DIG);
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+ val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
+ val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr |= BCM5708S_BMCR_FORCE_2500;
}
if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
return;
- if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ u32 val;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_SERDES_DIG);
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+ val &= ~MII_BNX2_SD_MISC1_FORCE;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr &= ~BCM5708S_BMCR_FORCE_2500;
}
link_up = bp->link_up;
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+ bnx2_enable_bmsr1(bp);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_disable_bmsr1(bp);
if ((bp->phy_flags & PHY_SERDES_FLAG) &&
(CHIP_NUM(bp) == CHIP_NUM_5706)) {
bnx2_5706s_linkup(bp);
else if (CHIP_NUM(bp) == CHIP_NUM_5708)
bnx2_5708s_linkup(bp);
+ else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_5709s_linkup(bp);
}
else {
bnx2_copper_linkup(bp);
new_bmcr = bmcr & ~BMCR_ANENABLE;
new_bmcr |= BMCR_SPEED1000;
- if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ if (bp->req_line_speed == SPEED_2500)
+ bnx2_enable_forced_2g5(bp);
+ else if (bp->req_line_speed == SPEED_1000) {
+ bnx2_disable_forced_2g5(bp);
+ new_bmcr &= ~0x2000;
+ }
+
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
if (bp->req_line_speed == SPEED_2500)
new_bmcr |= BCM5708S_BMCR_FORCE_2500;
else
bnx2_resolve_flow_ctrl(bp);
bnx2_set_mac_link(bp);
}
+ } else {
+ bnx2_resolve_flow_ctrl(bp);
+ bnx2_set_mac_link(bp);
}
return 0;
}
}
}
+static int
+bnx2_init_5709s_phy(struct bnx2 *bp)
+{
+ u32 val;
+
+ bp->mii_bmcr = MII_BMCR + 0x10;
+ bp->mii_bmsr = MII_BMSR + 0x10;
+ bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
+ bp->mii_adv = MII_ADVERTISE + 0x10;
+ bp->mii_lpa = MII_LPA + 0x10;
+ bp->mii_up1 = MII_BNX2_OVER1G_UP1;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
+ 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);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
+
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
+ val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
+ val |= MII_BNX2_SD_1000XCTL1_FIBER;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+ bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
+ if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+ val |= BCM5708S_UP1_2G5;
+ else
+ val &= ~BCM5708S_UP1_2G5;
+ bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
+ bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
+ val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
+ bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
+
+ val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
+ MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
+ bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ return 0;
+}
+
static int
bnx2_init_5708s_phy(struct bnx2 *bp)
{
u32 val;
+ bnx2_reset_phy(bp);
+
+ bp->mii_up1 = BCM5708S_UP1;
+
bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
static int
bnx2_init_5706s_phy(struct bnx2 *bp)
{
+ bnx2_reset_phy(bp);
+
bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
if (CHIP_NUM(bp) == CHIP_NUM_5706)
{
u32 val;
+ bnx2_reset_phy(bp);
+
if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
bnx2_write_phy(bp, 0x18, 0x0c00);
bnx2_write_phy(bp, 0x17, 0x000a);
bp->mii_bmcr = MII_BMCR;
bp->mii_bmsr = MII_BMSR;
+ bp->mii_bmsr1 = MII_BMSR;
bp->mii_adv = MII_ADVERTISE;
bp->mii_lpa = MII_LPA;
REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
- bnx2_reset_phy(bp);
-
bnx2_read_phy(bp, MII_PHYSID1, &val);
bp->phy_id = val << 16;
bnx2_read_phy(bp, MII_PHYSID2, &val);
rc = bnx2_init_5706s_phy(bp);
else if (CHIP_NUM(bp) == CHIP_NUM_5708)
rc = bnx2_init_5708s_phy(bp);
+ else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ rc = bnx2_init_5709s_phy(bp);
}
else {
rc = bnx2_init_copper_phy(bp);
return 0;
}
-static void
-bnx2_phy_int(struct bnx2 *bp)
+static int
+bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
{
+ struct status_block *sblk = bp->status_blk;
u32 new_link_state, old_link_state;
+ int is_set = 1;
- new_link_state = bp->status_blk->status_attn_bits &
- STATUS_ATTN_BITS_LINK_STATE;
- old_link_state = bp->status_blk->status_attn_bits_ack &
- STATUS_ATTN_BITS_LINK_STATE;
+ new_link_state = sblk->status_attn_bits & event;
+ old_link_state = sblk->status_attn_bits_ack & event;
if (new_link_state != old_link_state) {
- if (new_link_state) {
- REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
- STATUS_ATTN_BITS_LINK_STATE);
- }
- else {
- REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
- STATUS_ATTN_BITS_LINK_STATE);
- }
+ if (new_link_state)
+ REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
+ else
+ REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
+ } else
+ is_set = 0;
+
+ return is_set;
+}
+
+static void
+bnx2_phy_int(struct bnx2 *bp)
+{
+ if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
+ spin_lock(&bp->phy_lock);
bnx2_set_link(bp);
+ spin_unlock(&bp->phy_lock);
}
}
return IRQ_HANDLED;
}
+static irqreturn_t
+bnx2_msi_1shot(int irq, void *dev_instance)
+{
+ struct net_device *dev = dev_instance;
+ struct bnx2 *bp = netdev_priv(dev);
+
+ prefetch(bp->status_blk);
+
+ /* Return here if interrupt is disabled. */
+ if (unlikely(atomic_read(&bp->intr_sem) != 0))
+ return IRQ_HANDLED;
+
+ netif_rx_schedule(dev);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t
bnx2_interrupt(int irq, void *dev_instance)
{
return IRQ_HANDLED;
}
+#define STATUS_ATTN_EVENTS STATUS_ATTN_BITS_LINK_STATE
+
static inline int
bnx2_has_work(struct bnx2 *bp)
{
(sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
return 1;
- if ((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
- (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
+ if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
+ (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
return 1;
return 0;
bnx2_poll(struct net_device *dev, int *budget)
{
struct bnx2 *bp = netdev_priv(dev);
+ struct status_block *sblk = bp->status_blk;
+ u32 status_attn_bits = sblk->status_attn_bits;
+ u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
- if ((bp->status_blk->status_attn_bits &
- STATUS_ATTN_BITS_LINK_STATE) !=
- (bp->status_blk->status_attn_bits_ack &
- STATUS_ATTN_BITS_LINK_STATE)) {
+ if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
+ (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
- spin_lock(&bp->phy_lock);
bnx2_phy_int(bp);
- spin_unlock(&bp->phy_lock);
/* This is needed to take care of transient status
* during link changes.
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
- REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
+ val = BNX2_HC_CONFIG_COLLECT_STATS;
else {
- REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
- BNX2_HC_CONFIG_TX_TMR_MODE |
- BNX2_HC_CONFIG_COLLECT_STATS);
+ val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
+ BNX2_HC_CONFIG_COLLECT_STATS;
}
+ if (bp->flags & ONE_SHOT_MSI_FLAG)
+ val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+ REG_WR(bp, BNX2_HC_CONFIG, val);
+
/* Clear internal stats counters. */
REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
- REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
+ REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
BNX2_PORT_FEATURE_ASF_ENABLED)
u32 bmsr;
spin_lock_bh(&bp->phy_lock);
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+ bnx2_enable_bmsr1(bp);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_disable_bmsr1(bp);
spin_unlock_bh(&bp->phy_lock);
if (bmsr & BMSR_LSTATUS) {
if (bp->phy_flags & PHY_SERDES_FLAG) {
if (CHIP_NUM(bp) == CHIP_NUM_5706)
bnx2_5706_serdes_timer(bp);
- else if (CHIP_NUM(bp) == CHIP_NUM_5708)
+ else
bnx2_5708_serdes_timer(bp);
}
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
+static int
+bnx2_request_irq(struct bnx2 *bp)
+{
+ struct net_device *dev = bp->dev;
+ int rc = 0;
+
+ if (bp->flags & USING_MSI_FLAG) {
+ irq_handler_t fn = bnx2_msi;
+
+ if (bp->flags & ONE_SHOT_MSI_FLAG)
+ fn = bnx2_msi_1shot;
+
+ rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
+ } else
+ rc = request_irq(bp->pdev->irq, bnx2_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ return rc;
+}
+
+static void
+bnx2_free_irq(struct bnx2 *bp)
+{
+ struct net_device *dev = bp->dev;
+
+ if (bp->flags & USING_MSI_FLAG) {
+ free_irq(bp->pdev->irq, dev);
+ pci_disable_msi(bp->pdev);
+ bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
+ } else
+ free_irq(bp->pdev->irq, dev);
+}
+
/* Called with rtnl_lock */
static int
bnx2_open(struct net_device *dev)
if (rc)
return rc;
- if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
- (CHIP_ID(bp) != CHIP_ID_5706_A1) &&
- !disable_msi) {
-
+ if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
if (pci_enable_msi(bp->pdev) == 0) {
bp->flags |= USING_MSI_FLAG;
- rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name,
- dev);
- }
- else {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- IRQF_SHARED, dev->name, dev);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bp->flags |= ONE_SHOT_MSI_FLAG;
}
}
- else {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
- dev->name, dev);
- }
+ rc = bnx2_request_irq(bp);
+
if (rc) {
bnx2_free_mem(bp);
return rc;
rc = bnx2_init_nic(bp);
if (rc) {
- free_irq(bp->pdev->irq, dev);
- if (bp->flags & USING_MSI_FLAG) {
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
- }
+ bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
return rc;
bp->dev->name);
bnx2_disable_int(bp);
- free_irq(bp->pdev->irq, dev);
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
+ bnx2_free_irq(bp);
rc = bnx2_init_nic(bp);
- if (!rc) {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- IRQF_SHARED, dev->name, dev);
- }
+ if (!rc)
+ rc = bnx2_request_irq(bp);
+
if (rc) {
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
bnx2_netif_start(bp);
}
-
-/* Called with rtnl_lock */
-static void
-bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- bnx2_netif_stop(bp);
- vlan_group_set_device(bp->vlgrp, vid, NULL);
- bnx2_set_rx_mode(dev);
-
- bnx2_netif_start(bp);
-}
#endif
/* Called with netif_tx_lock.
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
- if ((mss = skb_shinfo(skb)->gso_size) &&
- (skb->len > (bp->dev->mtu + ETH_HLEN))) {
+ if ((mss = skb_shinfo(skb)->gso_size)) {
u32 tcp_opt_len, ip_tcp_len;
struct iphdr *iph;
else
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
bnx2_reset_chip(bp, reset_code);
- free_irq(bp->pdev->irq, dev);
- if (bp->flags & USING_MSI_FLAG) {
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
- }
+ bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
bp->link_up = 0;
advertising = cmd->advertising;
- }
- else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+ } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return -EINVAL;
+ } else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
advertising = cmd->advertising;
}
else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
}
}
+static void __devinit
+bnx2_get_pci_speed(struct bnx2 *bp)
+{
+ u32 reg;
+
+ reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
+ if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
+ u32 clkreg;
+
+ bp->flags |= PCIX_FLAG;
+
+ clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
+
+ clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
+ switch (clkreg) {
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
+ bp->bus_speed_mhz = 133;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
+ bp->bus_speed_mhz = 100;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
+ bp->bus_speed_mhz = 66;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
+ bp->bus_speed_mhz = 50;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
+ bp->bus_speed_mhz = 33;
+ break;
+ }
+ }
+ else {
+ if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
+ bp->bus_speed_mhz = 66;
+ else
+ bp->bus_speed_mhz = 33;
+ }
+
+ if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
+ bp->flags |= PCI_32BIT_FLAG;
+
+}
+
static int __devinit
bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
bp->pdev = pdev;
spin_lock_init(&bp->phy_lock);
+ spin_lock_init(&bp->indirect_lock);
INIT_WORK(&bp->reset_task, bnx2_reset_task);
dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
- if (CHIP_NUM(bp) != CHIP_NUM_5709) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
+ dev_err(&pdev->dev,
+ "Cannot find PCIE capability, aborting.\n");
+ rc = -EIO;
+ goto err_out_unmap;
+ }
+ bp->flags |= PCIE_FLAG;
+ } else {
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
dev_err(&pdev->dev,
}
}
+ if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
+ bp->flags |= MSI_CAP_FLAG;
+ }
+
/* 5708 cannot support DMA addresses > 40-bit. */
if (CHIP_NUM(bp) == CHIP_NUM_5708)
persist_dma_mask = dma_mask = DMA_40BIT_MASK;
goto err_out_unmap;
}
- /* Get bus information. */
- reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
- if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
- u32 clkreg;
-
- bp->flags |= PCIX_FLAG;
-
- clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
-
- clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
- switch (clkreg) {
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
- bp->bus_speed_mhz = 133;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
- bp->bus_speed_mhz = 100;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
- bp->bus_speed_mhz = 66;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
- bp->bus_speed_mhz = 50;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
- bp->bus_speed_mhz = 33;
- break;
- }
- }
- else {
- if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
- bp->bus_speed_mhz = 66;
- else
- bp->bus_speed_mhz = 33;
- }
-
- if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
- bp->flags |= PCI_32BIT_FLAG;
+ if (!(bp->flags & PCIE_FLAG))
+ bnx2_get_pci_speed(bp);
/* 5706A0 may falsely detect SERR and PERR. */
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
return rc;
}
+static char * __devinit
+bnx2_bus_string(struct bnx2 *bp, char *str)
+{
+ char *s = str;
+
+ if (bp->flags & PCIE_FLAG) {
+ s += sprintf(s, "PCI Express");
+ } else {
+ s += sprintf(s, "PCI");
+ if (bp->flags & PCIX_FLAG)
+ s += sprintf(s, "-X");
+ if (bp->flags & PCI_32BIT_FLAG)
+ s += sprintf(s, " 32-bit");
+ else
+ s += sprintf(s, " 64-bit");
+ s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
+ }
+ return str;
+}
+
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct bnx2 *bp;
int rc, i;
+ char str[40];
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef BCM_VLAN
dev->vlan_rx_register = bnx2_vlan_rx_register;
- dev->vlan_rx_kill_vid = bnx2_vlan_rx_kill_vid;
#endif
dev->poll = bnx2_poll;
dev->ethtool_ops = &bnx2_ethtool_ops;
return rc;
}
- printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
+ printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
"IRQ %d, ",
dev->name,
bp->name,
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
((CHIP_ID(bp) & 0x0ff0) >> 4),
- ((bp->flags & PCIX_FLAG) ? "-X" : ""),
- ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
- bp->bus_speed_mhz,
+ bnx2_bus_string(bp, str),
dev->base_addr,
bp->pdev->irq);