[BNX2]: Remove udelay() in copper PHY code.
[deliverable/linux.git] / drivers / net / bnx2.c
index 6b4edb63c4c485faaf029164bc6b32ea99c9a982..0a46b45f21dd39cfb7d8cb785f351122e777ac0a 100644 (file)
@@ -860,7 +860,7 @@ bnx2_set_link(struct bnx2 *bp)
        u32 bmsr;
        u8 link_up;
 
-       if (bp->loopback == MAC_LOOPBACK) {
+       if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
                bp->link_up = 1;
                return 0;
        }
@@ -902,6 +902,7 @@ bnx2_set_link(struct bnx2 *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);
@@ -988,7 +989,21 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
                u32 new_bmcr;
                int force_link_down = 0;
 
-               if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+               bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+               adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
+
+               bnx2_read_phy(bp, MII_BMCR, &bmcr);
+               new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500);
+               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;
+                       }
+               } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
                        bnx2_read_phy(bp, BCM5708S_UP1, &up1);
                        if (up1 & BCM5708S_UP1_2G5) {
                                up1 &= ~BCM5708S_UP1_2G5;
@@ -997,12 +1012,6 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
                        }
                }
 
-               bnx2_read_phy(bp, MII_ADVERTISE, &adv);
-               adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
-
-               bnx2_read_phy(bp, MII_BMCR, &bmcr);
-               new_bmcr = bmcr & ~BMCR_ANENABLE;
-               new_bmcr |= BMCR_SPEED1000;
                if (bp->req_duplex == DUPLEX_FULL) {
                        adv |= ADVERTISE_1000XFULL;
                        new_bmcr |= BMCR_FULLDPLX;
@@ -1023,6 +1032,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
                                bp->link_up = 0;
                                netif_carrier_off(bp->dev);
                                bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+                               bnx2_report_link(bp);
                        }
                        bnx2_write_phy(bp, MII_ADVERTISE, adv);
                        bnx2_write_phy(bp, MII_BMCR, new_bmcr);
@@ -1048,30 +1058,26 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
        if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
                /* Force a link down visible on the other side */
                if (bp->link_up) {
-                       int i;
-
                        bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
-                       for (i = 0; i < 110; i++) {
-                               udelay(100);
-                       }
+                       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 |
                        BMCR_ANENABLE);
-               if (CHIP_NUM(bp) == CHIP_NUM_5706) {
-                       /* Speed up link-up time when the link partner
-                        * does not autonegotiate which is very common
-                        * in blade servers. Some blade servers use
-                        * IPMI for kerboard input and it's important
-                        * to minimize link disruptions. Autoneg. involves
-                        * exchanging base pages plus 3 next pages and
-                        * normally completes in about 120 msec.
-                        */
-                       bp->current_interval = SERDES_AN_TIMEOUT;
-                       bp->serdes_an_pending = 1;
-                       mod_timer(&bp->timer, jiffies + bp->current_interval);
-               }
+               /* Speed up link-up time when the link partner
+                * does not autonegotiate which is very common
+                * in blade servers. Some blade servers use
+                * IPMI for kerboard input and it's important
+                * to minimize link disruptions. Autoneg. involves
+                * exchanging base pages plus 3 next pages and
+                * normally completes in about 120 msec.
+                */
+               bp->current_interval = SERDES_AN_TIMEOUT;
+               bp->serdes_an_pending = 1;
+               mod_timer(&bp->timer, jiffies + bp->current_interval);
        }
 
        return 0;
@@ -1153,7 +1159,6 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
        }
        if (new_bmcr != bmcr) {
                u32 bmsr;
-               int i = 0;
 
                bnx2_read_phy(bp, MII_BMSR, &bmsr);
                bnx2_read_phy(bp, MII_BMSR, &bmsr);
@@ -1161,12 +1166,12 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
                if (bmsr & BMSR_LSTATUS) {
                        /* Force link down */
                        bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
-                       do {
-                               udelay(100);
-                               bnx2_read_phy(bp, MII_BMSR, &bmsr);
-                               bnx2_read_phy(bp, MII_BMSR, &bmsr);
-                               i++;
-                       } while ((bmsr & BMSR_LSTATUS) && (i < 620));
+                       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_write_phy(bp, MII_BMCR, new_bmcr);
@@ -1397,7 +1402,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp)
        for (i = 0; i < 10; i++) {
                if (bnx2_test_link(bp) == 0)
                        break;
-               udelay(10);
+               msleep(100);
        }
 
        mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
@@ -1888,7 +1893,7 @@ next_rx:
  * is that the MSI interrupt is always serviced.
  */
 static irqreturn_t
-bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
+bnx2_msi(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct bnx2 *bp = netdev_priv(dev);
@@ -1908,7 +1913,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
 }
 
 static irqreturn_t
-bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+bnx2_interrupt(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct bnx2 *bp = netdev_priv(dev);
@@ -2040,7 +2045,8 @@ bnx2_set_rx_mode(struct net_device *dev)
        if (dev->flags & IFF_PROMISC) {
                /* Promiscuous mode. */
                rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
-               sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN;
+               sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
+                            BNX2_RPM_SORT_USER0_PROM_VLAN;
        }
        else if (dev->flags & IFF_ALLMULTI) {
                for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
@@ -3712,7 +3718,9 @@ bnx2_init_nic(struct bnx2 *bp)
        if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
                return rc;
 
+       spin_lock_bh(&bp->phy_lock);
        bnx2_init_phy(bp);
+       spin_unlock_bh(&bp->phy_lock);
        bnx2_set_link(bp);
        return 0;
 }
@@ -3952,7 +3960,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
                bnx2_set_mac_loopback(bp);
        }
        else if (loopback_mode == BNX2_PHY_LOOPBACK) {
-               bp->loopback = 0;
+               bp->loopback = PHY_LOOPBACK;
                bnx2_set_phy_loopback(bp);
        }
        else
@@ -4162,80 +4170,117 @@ bnx2_test_intr(struct bnx2 *bp)
 }
 
 static void
-bnx2_timer(unsigned long data)
+bnx2_5706_serdes_timer(struct bnx2 *bp)
 {
-       struct bnx2 *bp = (struct bnx2 *) data;
-       u32 msg;
+       spin_lock(&bp->phy_lock);
+       if (bp->serdes_an_pending)
+               bp->serdes_an_pending--;
+       else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
+               u32 bmcr;
 
-       if (!netif_running(bp->dev))
-               return;
+               bp->current_interval = bp->timer_interval;
 
-       if (atomic_read(&bp->intr_sem) != 0)
-               goto bnx2_restart_timer;
+               bnx2_read_phy(bp, MII_BMCR, &bmcr);
 
-       msg = (u32) ++bp->fw_drv_pulse_wr_seq;
-       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
+               if (bmcr & BMCR_ANENABLE) {
+                       u32 phy1, phy2;
 
-       bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+                       bnx2_write_phy(bp, 0x1c, 0x7c00);
+                       bnx2_read_phy(bp, 0x1c, &phy1);
 
-       if ((bp->phy_flags & PHY_SERDES_FLAG) &&
-           (CHIP_NUM(bp) == CHIP_NUM_5706)) {
+                       bnx2_write_phy(bp, 0x17, 0x0f01);
+                       bnx2_read_phy(bp, 0x15, &phy2);
+                       bnx2_write_phy(bp, 0x17, 0x0f01);
+                       bnx2_read_phy(bp, 0x15, &phy2);
 
-               spin_lock(&bp->phy_lock);
-               if (bp->serdes_an_pending) {
-                       bp->serdes_an_pending--;
+                       if ((phy1 & 0x10) &&    /* SIGNAL DETECT */
+                               !(phy2 & 0x20)) {       /* no CONFIG */
+
+                               bmcr &= ~BMCR_ANENABLE;
+                               bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
+                               bnx2_write_phy(bp, MII_BMCR, bmcr);
+                               bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
+                       }
                }
-               else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
-                       u32 bmcr;
+       }
+       else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
+                (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
+               u32 phy2;
 
-                       bp->current_interval = bp->timer_interval;
+               bnx2_write_phy(bp, 0x17, 0x0f01);
+               bnx2_read_phy(bp, 0x15, &phy2);
+               if (phy2 & 0x20) {
+                       u32 bmcr;
 
                        bnx2_read_phy(bp, MII_BMCR, &bmcr);
+                       bmcr |= BMCR_ANENABLE;
+                       bnx2_write_phy(bp, MII_BMCR, bmcr);
 
-                       if (bmcr & BMCR_ANENABLE) {
-                               u32 phy1, phy2;
+                       bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+               }
+       } else
+               bp->current_interval = bp->timer_interval;
 
-                               bnx2_write_phy(bp, 0x1c, 0x7c00);
-                               bnx2_read_phy(bp, 0x1c, &phy1);
+       spin_unlock(&bp->phy_lock);
+}
 
-                               bnx2_write_phy(bp, 0x17, 0x0f01);
-                               bnx2_read_phy(bp, 0x15, &phy2);
-                               bnx2_write_phy(bp, 0x17, 0x0f01);
-                               bnx2_read_phy(bp, 0x15, &phy2);
+static void
+bnx2_5708_serdes_timer(struct bnx2 *bp)
+{
+       if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
+               bp->serdes_an_pending = 0;
+               return;
+       }
 
-                               if ((phy1 & 0x10) &&    /* SIGNAL DETECT */
-                                       !(phy2 & 0x20)) {       /* no CONFIG */
+       spin_lock(&bp->phy_lock);
+       if (bp->serdes_an_pending)
+               bp->serdes_an_pending--;
+       else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
+               u32 bmcr;
 
-                                       bmcr &= ~BMCR_ANENABLE;
-                                       bmcr |= BMCR_SPEED1000 |
-                                               BMCR_FULLDPLX;
-                                       bnx2_write_phy(bp, MII_BMCR, bmcr);
-                                       bp->phy_flags |=
-                                               PHY_PARALLEL_DETECT_FLAG;
-                               }
-                       }
+               bnx2_read_phy(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);
+                       bp->current_interval = SERDES_FORCED_TIMEOUT;
+               } else {
+                       bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500);
+                       bmcr |= BMCR_ANENABLE;
+                       bnx2_write_phy(bp, MII_BMCR, bmcr);
+                       bp->serdes_an_pending = 2;
+                       bp->current_interval = bp->timer_interval;
                }
-               else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
-                       (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
-                       u32 phy2;
 
-                       bnx2_write_phy(bp, 0x17, 0x0f01);
-                       bnx2_read_phy(bp, 0x15, &phy2);
-                       if (phy2 & 0x20) {
-                               u32 bmcr;
+       } else
+               bp->current_interval = bp->timer_interval;
 
-                               bnx2_read_phy(bp, MII_BMCR, &bmcr);
-                               bmcr |= BMCR_ANENABLE;
-                               bnx2_write_phy(bp, MII_BMCR, bmcr);
+       spin_unlock(&bp->phy_lock);
+}
 
-                               bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+static void
+bnx2_timer(unsigned long data)
+{
+       struct bnx2 *bp = (struct bnx2 *) data;
+       u32 msg;
 
-                       }
-               }
-               else
-                       bp->current_interval = bp->timer_interval;
+       if (!netif_running(bp->dev))
+               return;
 
-               spin_unlock(&bp->phy_lock);
+       if (atomic_read(&bp->intr_sem) != 0)
+               goto bnx2_restart_timer;
+
+       msg = (u32) ++bp->fw_drv_pulse_wr_seq;
+       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
+
+       bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+
+       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)
+                       bnx2_5708_serdes_timer(bp);
        }
 
 bnx2_restart_timer:
@@ -4743,10 +4788,14 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        }
        else {
                if (bp->phy_flags & PHY_SERDES_FLAG) {
-                       if ((cmd->speed != SPEED_1000) ||
-                               (cmd->duplex != DUPLEX_FULL)) {
+                       if ((cmd->speed != SPEED_1000 &&
+                            cmd->speed != SPEED_2500) ||
+                           (cmd->duplex != DUPLEX_FULL))
+                               return -EINVAL;
+
+                       if (cmd->speed == SPEED_2500 &&
+                           !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
                                return -EINVAL;
-                       }
                }
                else if (cmd->speed == SPEED_1000) {
                        return -EINVAL;
@@ -4903,11 +4952,10 @@ bnx2_nway_reset(struct net_device *dev)
                msleep(20);
 
                spin_lock_bh(&bp->phy_lock);
-               if (CHIP_NUM(bp) == CHIP_NUM_5706) {
-                       bp->current_interval = SERDES_AN_TIMEOUT;
-                       bp->serdes_an_pending = 1;
-                       mod_timer(&bp->timer, jiffies + bp->current_interval);
-               }
+
+               bp->current_interval = SERDES_AN_TIMEOUT;
+               bp->serdes_an_pending = 1;
+               mod_timer(&bp->timer, jiffies + bp->current_interval);
        }
 
        bnx2_read_phy(bp, MII_BMCR, &bmcr);
@@ -5288,6 +5336,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
 
        memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
+               int i;
+
                bnx2_netif_stop(bp);
                bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
                bnx2_free_skbs(bp);
@@ -5312,9 +5362,11 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
                }
 
                /* wait for link up */
-               msleep_interruptible(3000);
-               if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG))
-                       msleep_interruptible(4000);
+               for (i = 0; i < 7; i++) {
+                       if (bp->link_up)
+                               break;
+                       msleep_interruptible(1000);
+               }
        }
 
        if (bnx2_test_nvram(bp) != 0) {
@@ -5554,7 +5606,7 @@ poll_bnx2(struct net_device *dev)
        struct bnx2 *bp = netdev_priv(dev);
 
        disable_irq(bp->pdev->irq);
-       bnx2_interrupt(bp->pdev->irq, dev, NULL);
+       bnx2_interrupt(bp->pdev->irq, dev);
        enable_irq(bp->pdev->irq);
 }
 #endif
This page took 0.050009 seconds and 5 git commands to generate.