diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 8 | ||||
-rw-r--r-- | drivers/net/bnx2.c | 974 | ||||
-rw-r--r-- | drivers/net/bnx2.h | 65 | ||||
-rw-r--r-- | drivers/net/bnx2_fw.h | 1697 | ||||
-rw-r--r-- | drivers/net/bnx2_fw2.h | 7868 | ||||
-rw-r--r-- | drivers/net/wireless/strip.c | 4 | ||||
-rw-r--r-- | drivers/parisc/led.c | 2 |
7 files changed, 5740 insertions, 4878 deletions
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 1a6aeac5a1c..01fbdd38e3b 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -194,15 +194,15 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) sl = sl_tail = NULL; read_lock(&dev_base_lock); - for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) { + for_each_netdev(ifp) { dev_hold(ifp); if (!is_aoe_netif(ifp)) - continue; + goto cont; skb = new_skb(sizeof *h + sizeof *ch); if (skb == NULL) { printk(KERN_INFO "aoe: skb alloc failure\n"); - continue; + goto cont; } skb_put(skb, sizeof *h + sizeof *ch); skb->dev = ifp; @@ -221,6 +221,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) skb->next = sl; sl = skb; +cont: + dev_put(ifp); } read_unlock(&dev_base_lock); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index f98a2205a09..88b33c6ddda 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1,6 +1,6 @@ /* 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 @@ -54,8 +54,8 @@ #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)) @@ -84,6 +84,7 @@ typedef enum { BCM5708, BCM5708S, BCM5709, + BCM5709S, } board_t; /* indexed by board_t, above */ @@ -98,6 +99,7 @@ static const struct { { "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[] = { @@ -117,6 +119,8 @@ 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, } }; @@ -230,21 +234,29 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp) 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; @@ -262,6 +274,7 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) REG_WR(bp, BNX2_CTX_DATA_ADR, offset); REG_WR(bp, BNX2_CTX_DATA, val); } + spin_unlock_bh(&bp->indirect_lock); } static int @@ -572,8 +585,8 @@ bnx2_report_fw_link(struct bnx2 *bp) 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); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); if (!(bmsr & BMSR_ANEGCOMPLETE) || bp->phy_flags & PHY_PARALLEL_DETECT_FLAG) @@ -654,8 +667,8 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) return; } - bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); - bnx2_read_phy(bp, MII_LPA, &remote_adv); + bnx2_read_phy(bp, bp->mii_adv, &local_adv); + bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); if (bp->phy_flags & PHY_SERDES_FLAG) { u32 new_local_adv = 0; @@ -700,6 +713,45 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) } 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) { u32 val; @@ -736,7 +788,7 @@ bnx2_5706s_linkup(struct bnx2 *bp) bp->link_up = 1; bp->line_speed = SPEED_1000; - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_FULLDPLX) { bp->duplex = DUPLEX_FULL; } @@ -748,8 +800,8 @@ bnx2_5706s_linkup(struct bnx2 *bp) return 0; } - bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); - bnx2_read_phy(bp, MII_LPA, &remote_adv); + bnx2_read_phy(bp, bp->mii_adv, &local_adv); + bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); common = local_adv & remote_adv; if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) { @@ -770,7 +822,7 @@ bnx2_copper_linkup(struct bnx2 *bp) { u32 bmcr; - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { u32 local_adv, remote_adv, common; @@ -787,8 +839,8 @@ bnx2_copper_linkup(struct bnx2 *bp) bp->duplex = DUPLEX_HALF; } else { - bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); - bnx2_read_phy(bp, MII_LPA, &remote_adv); + bnx2_read_phy(bp, bp->mii_adv, &local_adv); + bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); common = local_adv & remote_adv; if (common & ADVERTISE_100FULL) { @@ -898,6 +950,145 @@ bnx2_set_mac_link(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) +{ + u32 up1; + int ret = 1; + + if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + return 0; + + 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; + bnx2_write_phy(bp, bp->mii_up1, up1); + 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; +} + +static int +bnx2_test_and_disable_2g5(struct bnx2 *bp) +{ + u32 up1; + int ret = 0; + + 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; + bnx2_write_phy(bp, bp->mii_up1, up1); + 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; +} + +static void +bnx2_enable_forced_2g5(struct bnx2 *bp) +{ + u32 bmcr; + + if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + return; + + 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->autoneg & AUTONEG_SPEED) { + bmcr &= ~BMCR_ANENABLE; + if (bp->req_duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + } + bnx2_write_phy(bp, bp->mii_bmcr, bmcr); +} + +static void +bnx2_disable_forced_2g5(struct bnx2 *bp) +{ + u32 bmcr; + + if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + return; + + 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; + } + + if (bp->autoneg & AUTONEG_SPEED) + bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART; + bnx2_write_phy(bp, bp->mii_bmcr, bmcr); +} + static int bnx2_set_link(struct bnx2 *bp) { @@ -911,8 +1102,10 @@ bnx2_set_link(struct bnx2 *bp) link_up = bp->link_up; - bnx2_read_phy(bp, MII_BMSR, &bmsr); - bnx2_read_phy(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)) { @@ -933,6 +1126,8 @@ bnx2_set_link(struct bnx2 *bp) 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); @@ -941,17 +1136,9 @@ bnx2_set_link(struct bnx2 *bp) } else { if ((bp->phy_flags & PHY_SERDES_FLAG) && - (bp->autoneg & AUTONEG_SPEED)) { + (bp->autoneg & AUTONEG_SPEED)) + bnx2_disable_forced_2g5(bp); - u32 bmcr; - - bnx2_read_phy(bp, MII_BMCR, &bmcr); - bmcr &= ~BCM5708S_BMCR_FORCE_2500; - if (!(bmcr & BMCR_ANENABLE)) { - bnx2_write_phy(bp, MII_BMCR, bmcr | - BMCR_ANENABLE); - } - } bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; bp->link_up = 0; } @@ -971,13 +1158,13 @@ bnx2_reset_phy(struct bnx2 *bp) int i; u32 reg; - bnx2_write_phy(bp, MII_BMCR, BMCR_RESET); + bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET); #define PHY_RESET_MAX_WAIT 100 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) { udelay(10); - bnx2_read_phy(bp, MII_BMCR, ®); + bnx2_read_phy(bp, bp->mii_bmcr, ®); if (!(reg & BMCR_RESET)) { udelay(20); break; @@ -1026,34 +1213,40 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) static int bnx2_setup_serdes_phy(struct bnx2 *bp) { - u32 adv, bmcr, up1; + u32 adv, bmcr; u32 new_adv = 0; if (!(bp->autoneg & AUTONEG_SPEED)) { u32 new_bmcr; int force_link_down = 0; - bnx2_read_phy(bp, MII_ADVERTISE, &adv); + if (bp->req_line_speed == SPEED_2500) { + if (!bnx2_test_and_enable_2g5(bp)) + force_link_down = 1; + } else if (bp->req_line_speed == SPEED_1000) { + if (bnx2_test_and_disable_2g5(bp)) + force_link_down = 1; + } + bnx2_read_phy(bp, bp->mii_adv, &adv); adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); - bnx2_read_phy(bp, MII_BMCR, &bmcr); - new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + new_bmcr = bmcr & ~BMCR_ANENABLE; new_bmcr |= BMCR_SPEED1000; - if (bp->req_line_speed == SPEED_2500) { - new_bmcr |= BCM5708S_BMCR_FORCE_2500; - bnx2_read_phy(bp, BCM5708S_UP1, &up1); - if (!(up1 & BCM5708S_UP1_2G5)) { - up1 |= BCM5708S_UP1_2G5; - bnx2_write_phy(bp, BCM5708S_UP1, up1); - force_link_down = 1; + + 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) { - bnx2_read_phy(bp, BCM5708S_UP1, &up1); - if (up1 & BCM5708S_UP1_2G5) { - up1 &= ~BCM5708S_UP1_2G5; - bnx2_write_phy(bp, BCM5708S_UP1, up1); - force_link_down = 1; - } + if (bp->req_line_speed == SPEED_2500) + new_bmcr |= BCM5708S_BMCR_FORCE_2500; + else + new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500; } if (bp->req_duplex == DUPLEX_FULL) { @@ -1067,49 +1260,48 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) if ((new_bmcr != bmcr) || (force_link_down)) { /* Force a link down visible on the other side */ if (bp->link_up) { - bnx2_write_phy(bp, MII_ADVERTISE, adv & + bnx2_write_phy(bp, bp->mii_adv, adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF)); - bnx2_write_phy(bp, MII_BMCR, bmcr | + bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); bp->link_up = 0; netif_carrier_off(bp->dev); - bnx2_write_phy(bp, MII_BMCR, new_bmcr); + bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); bnx2_report_link(bp); } - bnx2_write_phy(bp, MII_ADVERTISE, adv); - bnx2_write_phy(bp, MII_BMCR, new_bmcr); + bnx2_write_phy(bp, bp->mii_adv, adv); + bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); + } else { + bnx2_resolve_flow_ctrl(bp); + bnx2_set_mac_link(bp); } return 0; } - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { - bnx2_read_phy(bp, BCM5708S_UP1, &up1); - up1 |= BCM5708S_UP1_2G5; - bnx2_write_phy(bp, BCM5708S_UP1, up1); - } + bnx2_test_and_enable_2g5(bp); if (bp->advertising & ADVERTISED_1000baseT_Full) new_adv |= ADVERTISE_1000XFULL; new_adv |= bnx2_phy_get_pause_adv(bp); - bnx2_read_phy(bp, MII_ADVERTISE, &adv); - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_adv, &adv); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); bp->serdes_an_pending = 0; if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) { /* Force a link down visible on the other side */ if (bp->link_up) { - bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); + bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); msleep(20); spin_lock_bh(&bp->phy_lock); } - bnx2_write_phy(bp, MII_ADVERTISE, new_adv); - bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | + bnx2_write_phy(bp, bp->mii_adv, new_adv); + bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); /* Speed up link-up time when the link partner * does not autonegotiate which is very common @@ -1122,6 +1314,9 @@ bnx2_setup_serdes_phy(struct bnx2 *bp) bp->current_interval = SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); + } else { + bnx2_resolve_flow_ctrl(bp); + bnx2_set_mac_link(bp); } return 0; @@ -1146,14 +1341,14 @@ bnx2_setup_copper_phy(struct bnx2 *bp) u32 bmcr; u32 new_bmcr; - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bp->autoneg & AUTONEG_SPEED) { u32 adv_reg, adv1000_reg; u32 new_adv_reg = 0; u32 new_adv1000_reg = 0; - bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg); + bnx2_read_phy(bp, bp->mii_adv, &adv_reg); adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -1179,9 +1374,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp) (adv_reg != new_adv_reg) || ((bmcr & BMCR_ANENABLE) == 0)) { - bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg); + bnx2_write_phy(bp, bp->mii_adv, new_adv_reg); bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg); - bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART | + bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART | BMCR_ANENABLE); } else if (bp->link_up) { @@ -1204,21 +1399,21 @@ bnx2_setup_copper_phy(struct bnx2 *bp) if (new_bmcr != bmcr) { u32 bmsr; - bnx2_read_phy(bp, MII_BMSR, &bmsr); - bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); if (bmsr & BMSR_LSTATUS) { /* Force link down */ - bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); + bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); msleep(50); spin_lock_bh(&bp->phy_lock); - bnx2_read_phy(bp, MII_BMSR, &bmsr); - bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); + bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); } - bnx2_write_phy(bp, MII_BMCR, new_bmcr); + bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); /* Normally, the new speed is setup after the link has * gone down and up again. In some cases, link will not go @@ -1230,6 +1425,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp) bnx2_resolve_flow_ctrl(bp); bnx2_set_mac_link(bp); } + } else { + bnx2_resolve_flow_ctrl(bp); + bnx2_set_mac_link(bp); } return 0; } @@ -1249,10 +1447,63 @@ bnx2_setup_phy(struct bnx2 *bp) } 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); @@ -1305,6 +1556,8 @@ bnx2_init_5708s_phy(struct bnx2 *bp) 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) @@ -1342,6 +1595,8 @@ bnx2_init_copper_phy(struct bnx2 *bp) { 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); @@ -1396,9 +1651,13 @@ bnx2_init_phy(struct bnx2 *bp) bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG; bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG; - REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); + 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; - bnx2_reset_phy(bp); + REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); bnx2_read_phy(bp, MII_PHYSID1, &val); bp->phy_id = val << 16; @@ -1410,6 +1669,8 @@ bnx2_init_phy(struct bnx2 *bp) 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); @@ -1442,7 +1703,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp) int rc, i; spin_lock_bh(&bp->phy_lock); - rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX | + rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000); spin_unlock_bh(&bp->phy_lock); if (rc) @@ -1681,25 +1942,33 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) 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); } } @@ -1993,6 +2262,23 @@ bnx2_msi(int irq, void *dev_instance) } 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) { struct net_device *dev = dev_instance; @@ -2022,6 +2308,8 @@ 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) { @@ -2031,8 +2319,8 @@ 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; @@ -2042,15 +2330,14 @@ static int 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. @@ -3489,17 +3776,21 @@ bnx2_init_chip(struct bnx2 *bp) 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) @@ -3763,10 +4054,11 @@ static int bnx2_test_registers(struct bnx2 *bp) { int ret; - int i; + int i, is_5709; static const struct { u16 offset; u16 flags; +#define BNX2_FL_NOT_5709 1 u32 rw_mask; u32 ro_mask; } reg_tbl[] = { @@ -3774,26 +4066,26 @@ bnx2_test_registers(struct bnx2 *bp) { 0x0090, 0, 0xffffffff, 0x00000000 }, { 0x0094, 0, 0x00000000, 0x00000000 }, - { 0x0404, 0, 0x00003f00, 0x00000000 }, - { 0x0418, 0, 0x00000000, 0xffffffff }, - { 0x041c, 0, 0x00000000, 0xffffffff }, - { 0x0420, 0, 0x00000000, 0x80ffffff }, - { 0x0424, 0, 0x00000000, 0x00000000 }, - { 0x0428, 0, 0x00000000, 0x00000001 }, - { 0x0450, 0, 0x00000000, 0x0000ffff }, - { 0x0454, 0, 0x00000000, 0xffffffff }, - { 0x0458, 0, 0x00000000, 0xffffffff }, - - { 0x0808, 0, 0x00000000, 0xffffffff }, - { 0x0854, 0, 0x00000000, 0xffffffff }, - { 0x0868, 0, 0x00000000, 0x77777777 }, - { 0x086c, 0, 0x00000000, 0x77777777 }, - { 0x0870, 0, 0x00000000, 0x77777777 }, - { 0x0874, 0, 0x00000000, 0x77777777 }, - - { 0x0c00, 0, 0x00000000, 0x00000001 }, - { 0x0c04, 0, 0x00000000, 0x03ff0001 }, - { 0x0c08, 0, 0x0f0ff073, 0x00000000 }, + { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 }, + { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff }, + { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 }, + { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, + { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff }, + { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + + { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, + { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, + { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, + { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, + { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, + + { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, + { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 }, + { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 }, { 0x1000, 0, 0x00000000, 0x00000001 }, { 0x1004, 0, 0x00000000, 0x000f0001 }, @@ -3840,7 +4132,6 @@ bnx2_test_registers(struct bnx2 *bp) { 0x5004, 0, 0x00000000, 0x0000007f }, { 0x5008, 0, 0x0f0007ff, 0x00000000 }, - { 0x500c, 0, 0xf800f800, 0x07ff07ff }, { 0x5c00, 0, 0x00000000, 0x00000001 }, { 0x5c04, 0, 0x00000000, 0x0003000f }, @@ -3880,8 +4171,16 @@ bnx2_test_registers(struct bnx2 *bp) }; ret = 0; + is_5709 = 0; + if (CHIP_NUM(bp) == CHIP_NUM_5709) + is_5709 = 1; + for (i = 0; reg_tbl[i].offset != 0xffff; i++) { u32 offset, rw_mask, ro_mask, save_val, val; + u16 flags = reg_tbl[i].flags; + + if (is_5709 && (flags & BNX2_FL_NOT_5709)) + continue; offset = (u32) reg_tbl[i].offset; rw_mask = reg_tbl[i].rw_mask; @@ -3950,10 +4249,10 @@ bnx2_test_memory(struct bnx2 *bp) { int ret = 0; int i; - static const struct { + static struct mem_entry { u32 offset; u32 len; - } mem_tbl[] = { + } mem_tbl_5706[] = { { 0x60000, 0x4000 }, { 0xa0000, 0x3000 }, { 0xe0000, 0x4000 }, @@ -3961,7 +4260,21 @@ bnx2_test_memory(struct bnx2 *bp) { 0x1a0000, 0x4000 }, { 0x160000, 0x4000 }, { 0xffffffff, 0 }, + }, + mem_tbl_5709[] = { + { 0x60000, 0x4000 }, + { 0xa0000, 0x3000 }, + { 0xe0000, 0x4000 }, + { 0x120000, 0x4000 }, + { 0x1a0000, 0x4000 }, + { 0xffffffff, 0 }, }; + struct mem_entry *mem_tbl; + + if (CHIP_NUM(bp) == CHIP_NUM_5709) + mem_tbl = mem_tbl_5709; + else + mem_tbl = mem_tbl_5706; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset, @@ -4163,8 +4476,10 @@ bnx2_test_link(struct bnx2 *bp) u32 bmsr; spin_lock_bh(&bp->phy_lock); - bnx2_read_phy(bp, MII_BMSR, &bmsr); - bnx2_read_phy(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) { @@ -4214,7 +4529,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bp->current_interval = bp->timer_interval; - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { u32 phy1, phy2; @@ -4232,7 +4547,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bmcr &= ~BMCR_ANENABLE; bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX; - bnx2_write_phy(bp, MII_BMCR, bmcr); + bnx2_write_phy(bp, bp->mii_bmcr, bmcr); bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG; } } @@ -4246,9 +4561,9 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) if (phy2 & 0x20) { u32 bmcr; - bnx2_read_phy(bp, MII_BMCR, &bmcr); + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); bmcr |= BMCR_ANENABLE; - bnx2_write_phy(bp, MII_BMCR, bmcr); + bnx2_write_phy(bp, bp->mii_bmcr, bmcr); bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; } @@ -4272,17 +4587,12 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { u32 bmcr; - bnx2_read_phy(bp, MII_BMCR, &bmcr); - + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { - bmcr &= ~BMCR_ANENABLE; - bmcr |= BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500; - bnx2_write_phy(bp, MII_BMCR, bmcr); + bnx2_enable_forced_2g5(bp); bp->current_interval = SERDES_FORCED_TIMEOUT; } else { - bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500); - bmcr |= BMCR_ANENABLE; - bnx2_write_phy(bp, MII_BMCR, bmcr); + bnx2_disable_forced_2g5(bp); bp->serdes_an_pending = 2; bp->current_interval = bp->timer_interval; } @@ -4313,7 +4623,7 @@ bnx2_timer(unsigned long data) 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); } @@ -4321,6 +4631,38 @@ bnx2_restart_timer: 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; |