mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
[BNX2]: speedup serdes linkup
This speeds up link-up time on 5706 SerDes if the link partner does not autoneg, a rather common scenario in blade servers. Some blade servers use IPMI for keyboard input and it's important to minimize link disruptions. The speedup is achieved by shortening the timer to (HZ / 3) during the transient period right after initiating a SerDes autoneg. If autoneg does not complete, parallel detect can be done sooner. After the transient period is over, the timer goes back to its normal HZ interval. As suggested by Jeff Garzik, the timer initialization is moved to bnx2_init_board() from bnx2_open(). An eeprom bit is also added to allow default forced SerDes speed for even faster link-up time. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
afdc08b9f9
commit
cd339a0ed6
2 changed files with 45 additions and 13 deletions
|
@ -806,7 +806,19 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
|
||||||
bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
|
bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
|
||||||
bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
|
bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
|
||||||
BMCR_ANENABLE);
|
BMCR_ANENABLE);
|
||||||
bp->serdes_an_pending = SERDES_AN_TIMEOUT / bp->timer_interval;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3800,6 +3812,9 @@ bnx2_timer(unsigned long data)
|
||||||
struct bnx2 *bp = (struct bnx2 *) data;
|
struct bnx2 *bp = (struct bnx2 *) data;
|
||||||
u32 msg;
|
u32 msg;
|
||||||
|
|
||||||
|
if (!netif_running(bp->dev))
|
||||||
|
return;
|
||||||
|
|
||||||
if (atomic_read(&bp->intr_sem) != 0)
|
if (atomic_read(&bp->intr_sem) != 0)
|
||||||
goto bnx2_restart_timer;
|
goto bnx2_restart_timer;
|
||||||
|
|
||||||
|
@ -3817,6 +3832,8 @@ bnx2_timer(unsigned long data)
|
||||||
else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
|
else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
|
||||||
u32 bmcr;
|
u32 bmcr;
|
||||||
|
|
||||||
|
bp->current_interval = bp->timer_interval;
|
||||||
|
|
||||||
bnx2_read_phy(bp, MII_BMCR, &bmcr);
|
bnx2_read_phy(bp, MII_BMCR, &bmcr);
|
||||||
|
|
||||||
if (bmcr & BMCR_ANENABLE) {
|
if (bmcr & BMCR_ANENABLE) {
|
||||||
|
@ -3859,14 +3876,14 @@ bnx2_timer(unsigned long data)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
bp->current_interval = bp->timer_interval;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&bp->phy_lock, flags);
|
spin_unlock_irqrestore(&bp->phy_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bnx2_restart_timer:
|
bnx2_restart_timer:
|
||||||
bp->timer.expires = RUN_AT(bp->timer_interval);
|
mod_timer(&bp->timer, jiffies + bp->current_interval);
|
||||||
|
|
||||||
add_timer(&bp->timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called with rtnl_lock */
|
/* Called with rtnl_lock */
|
||||||
|
@ -3919,12 +3936,7 @@ bnx2_open(struct net_device *dev)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_timer(&bp->timer);
|
mod_timer(&bp->timer, jiffies + bp->current_interval);
|
||||||
|
|
||||||
bp->timer.expires = RUN_AT(bp->timer_interval);
|
|
||||||
bp->timer.data = (unsigned long) bp;
|
|
||||||
bp->timer.function = bnx2_timer;
|
|
||||||
add_timer(&bp->timer);
|
|
||||||
|
|
||||||
atomic_set(&bp->intr_sem, 0);
|
atomic_set(&bp->intr_sem, 0);
|
||||||
|
|
||||||
|
@ -4485,8 +4497,9 @@ bnx2_nway_reset(struct net_device *dev)
|
||||||
|
|
||||||
spin_lock_irq(&bp->phy_lock);
|
spin_lock_irq(&bp->phy_lock);
|
||||||
if (CHIP_NUM(bp) == CHIP_NUM_5706) {
|
if (CHIP_NUM(bp) == CHIP_NUM_5706) {
|
||||||
bp->serdes_an_pending = SERDES_AN_TIMEOUT /
|
bp->current_interval = SERDES_AN_TIMEOUT;
|
||||||
bp->timer_interval;
|
bp->serdes_an_pending = 1;
|
||||||
|
mod_timer(&bp->timer, jiffies + bp->current_interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5315,6 +5328,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||||
bp->stats_ticks = 1000000 & 0xffff00;
|
bp->stats_ticks = 1000000 & 0xffff00;
|
||||||
|
|
||||||
bp->timer_interval = HZ;
|
bp->timer_interval = HZ;
|
||||||
|
bp->current_interval = HZ;
|
||||||
|
|
||||||
/* Disable WOL support if we are running on a SERDES chip. */
|
/* Disable WOL support if we are running on a SERDES chip. */
|
||||||
if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
|
if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
|
||||||
|
@ -5338,6 +5352,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||||
bp->req_line_speed = 0;
|
bp->req_line_speed = 0;
|
||||||
if (bp->phy_flags & PHY_SERDES_FLAG) {
|
if (bp->phy_flags & PHY_SERDES_FLAG) {
|
||||||
bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
|
bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
|
||||||
|
|
||||||
|
reg = REG_RD_IND(bp, HOST_VIEW_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;
|
||||||
|
bp->req_line_speed = bp->line_speed = SPEED_1000;
|
||||||
|
bp->req_duplex = DUPLEX_FULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
|
bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
|
||||||
|
@ -5345,6 +5368,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||||
|
|
||||||
bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
|
bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
|
||||||
|
|
||||||
|
init_timer(&bp->timer);
|
||||||
|
bp->timer.expires = RUN_AT(bp->timer_interval);
|
||||||
|
bp->timer.data = (unsigned long) bp;
|
||||||
|
bp->timer.function = bnx2_timer;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_unmap:
|
err_out_unmap:
|
||||||
|
|
|
@ -3872,6 +3872,7 @@ struct bnx2 {
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
int timer_interval;
|
int timer_interval;
|
||||||
|
int current_interval;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
struct work_struct reset_task;
|
struct work_struct reset_task;
|
||||||
int in_reset_task;
|
int in_reset_task;
|
||||||
|
@ -3986,7 +3987,7 @@ struct bnx2 {
|
||||||
#define PHY_LOOPBACK 2
|
#define PHY_LOOPBACK 2
|
||||||
|
|
||||||
u8 serdes_an_pending;
|
u8 serdes_an_pending;
|
||||||
#define SERDES_AN_TIMEOUT (2 * HZ)
|
#define SERDES_AN_TIMEOUT (HZ / 3)
|
||||||
|
|
||||||
u8 mac_addr[8];
|
u8 mac_addr[8];
|
||||||
|
|
||||||
|
@ -4172,6 +4173,9 @@ struct fw_info {
|
||||||
|
|
||||||
#define BNX2_PORT_HW_CFG_MAC_LOWER 0x00000054
|
#define BNX2_PORT_HW_CFG_MAC_LOWER 0x00000054
|
||||||
#define BNX2_PORT_HW_CFG_CONFIG 0x00000058
|
#define BNX2_PORT_HW_CFG_CONFIG 0x00000058
|
||||||
|
#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK 0x001f0000
|
||||||
|
#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_AN 0x00000000
|
||||||
|
#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G 0x00030000
|
||||||
|
|
||||||
#define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER 0x00000068
|
#define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER 0x00000068
|
||||||
#define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER 0x0000006c
|
#define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER 0x0000006c
|
||||||
|
|
Loading…
Reference in a new issue