提交 b02fd9e3 编写于 作者: M Matt Carlson 提交者: David S. Miller

tg3: Add libphy support.

This patch introduces the libphy support.
Signed-off-by: NMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: NMichael Chan <mchan@broadcom.com>
Signed-off-by: NBenjamin Li <benli@broadcom.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 158d7abd
...@@ -1114,11 +1114,17 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) ...@@ -1114,11 +1114,17 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
{ {
u8 autoneg;
u8 flowctrl = 0; u8 flowctrl = 0;
u32 old_rx_mode = tp->rx_mode; u32 old_rx_mode = tp->rx_mode;
u32 old_tx_mode = tp->tx_mode; u32 old_tx_mode = tp->tx_mode;
if (tp->link_config.autoneg == AUTONEG_ENABLE && if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg;
else
autoneg = tp->link_config.autoneg;
if (autoneg == AUTONEG_ENABLE &&
(tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
...@@ -1146,6 +1152,152 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) ...@@ -1146,6 +1152,152 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
tw32_f(MAC_TX_MODE, tp->tx_mode); tw32_f(MAC_TX_MODE, tp->tx_mode);
} }
static void tg3_adjust_link(struct net_device *dev)
{
u8 oldflowctrl, linkmesg = 0;
u32 mac_mode, lcl_adv, rmt_adv;
struct tg3 *tp = netdev_priv(dev);
struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR];
spin_lock(&tp->lock);
mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK |
MAC_MODE_HALF_DUPLEX);
oldflowctrl = tp->link_config.active_flowctrl;
if (phydev->link) {
lcl_adv = 0;
rmt_adv = 0;
if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
mac_mode |= MAC_MODE_PORT_MODE_MII;
else
mac_mode |= MAC_MODE_PORT_MODE_GMII;
if (phydev->duplex == DUPLEX_HALF)
mac_mode |= MAC_MODE_HALF_DUPLEX;
else {
lcl_adv = tg3_advert_flowctrl_1000T(
tp->link_config.flowctrl);
if (phydev->pause)
rmt_adv = LPA_PAUSE_CAP;
if (phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
}
tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
} else
mac_mode |= MAC_MODE_PORT_MODE_GMII;
if (mac_mode != tp->mac_mode) {
tp->mac_mode = mac_mode;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
}
if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF)
tw32(MAC_TX_LENGTHS,
((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
(6 << TX_LENGTHS_IPG_SHIFT) |
(0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
else
tw32(MAC_TX_LENGTHS,
((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
(6 << TX_LENGTHS_IPG_SHIFT) |
(32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
(!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
phydev->speed != tp->link_config.active_speed ||
phydev->duplex != tp->link_config.active_duplex ||
oldflowctrl != tp->link_config.active_flowctrl)
linkmesg = 1;
tp->link_config.active_speed = phydev->speed;
tp->link_config.active_duplex = phydev->duplex;
spin_unlock(&tp->lock);
if (linkmesg)
tg3_link_report(tp);
}
static int tg3_phy_init(struct tg3 *tp)
{
struct phy_device *phydev;
if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
return 0;
/* Bring the PHY back to a known state. */
tg3_bmcr_reset(tp);
phydev = tp->mdio_bus.phy_map[PHY_ADDR];
/* Attach the MAC to the PHY. */
phydev = phy_connect(tp->dev, phydev->dev.bus_id,
tg3_adjust_link, 0, phydev->interface);
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
return PTR_ERR(phydev);
}
tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
/* Mask with MAC supported features. */
phydev->supported &= (PHY_GBIT_FEATURES |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
phydev->advertising = phydev->supported;
printk(KERN_INFO
"%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
tp->dev->name, phydev->drv->name, phydev->dev.bus_id);
return 0;
}
static void tg3_phy_start(struct tg3 *tp)
{
struct phy_device *phydev;
if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
return;
phydev = tp->mdio_bus.phy_map[PHY_ADDR];
if (tp->link_config.phy_is_low_power) {
tp->link_config.phy_is_low_power = 0;
phydev->speed = tp->link_config.orig_speed;
phydev->duplex = tp->link_config.orig_duplex;
phydev->autoneg = tp->link_config.orig_autoneg;
phydev->advertising = tp->link_config.orig_advertising;
}
phy_start(phydev);
phy_start_aneg(phydev);
}
static void tg3_phy_stop(struct tg3 *tp)
{
if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
return;
phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]);
}
static void tg3_phy_fini(struct tg3 *tp)
{
if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]);
tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
}
}
static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
{ {
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
...@@ -1798,7 +1950,40 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) ...@@ -1798,7 +1950,40 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
tp->link_config.phy_is_low_power = 1; if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
!tp->link_config.phy_is_low_power) {
struct phy_device *phydev;
u32 advertising;
phydev = tp->mdio_bus.phy_map[PHY_ADDR];
tp->link_config.phy_is_low_power = 1;
tp->link_config.orig_speed = phydev->speed;
tp->link_config.orig_duplex = phydev->duplex;
tp->link_config.orig_autoneg = phydev->autoneg;
tp->link_config.orig_advertising = phydev->advertising;
advertising = ADVERTISED_TP |
ADVERTISED_Pause |
ADVERTISED_Autoneg |
ADVERTISED_10baseT_Half;
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
(tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
advertising |=
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_10baseT_Full;
else
advertising |= ADVERTISED_10baseT_Full;
}
phydev->advertising = advertising;
phy_start_aneg(phydev);
}
} else { } else {
if (tp->link_config.phy_is_low_power == 0) { if (tp->link_config.phy_is_low_power == 0) {
tp->link_config.phy_is_low_power = 1; tp->link_config.phy_is_low_power = 1;
...@@ -4233,6 +4418,7 @@ static void tg3_poll_controller(struct net_device *dev) ...@@ -4233,6 +4418,7 @@ static void tg3_poll_controller(struct net_device *dev)
static void tg3_reset_task(struct work_struct *work) static void tg3_reset_task(struct work_struct *work)
{ {
struct tg3 *tp = container_of(work, struct tg3, reset_task); struct tg3 *tp = container_of(work, struct tg3, reset_task);
int err;
unsigned int restart_timer; unsigned int restart_timer;
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
...@@ -4244,6 +4430,8 @@ static void tg3_reset_task(struct work_struct *work) ...@@ -4244,6 +4430,8 @@ static void tg3_reset_task(struct work_struct *work)
tg3_full_unlock(tp); tg3_full_unlock(tp);
tg3_phy_stop(tp);
tg3_netif_stop(tp); tg3_netif_stop(tp);
tg3_full_lock(tp, 1); tg3_full_lock(tp, 1);
...@@ -4259,7 +4447,8 @@ static void tg3_reset_task(struct work_struct *work) ...@@ -4259,7 +4447,8 @@ static void tg3_reset_task(struct work_struct *work)
} }
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
if (tg3_init_hw(tp, 1)) err = tg3_init_hw(tp, 1);
if (err)
goto out; goto out;
tg3_netif_start(tp); tg3_netif_start(tp);
...@@ -4269,6 +4458,9 @@ static void tg3_reset_task(struct work_struct *work) ...@@ -4269,6 +4458,9 @@ static void tg3_reset_task(struct work_struct *work)
out: out:
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (!err)
tg3_phy_start(tp);
} }
static void tg3_dump_short_state(struct tg3 *tp) static void tg3_dump_short_state(struct tg3 *tp)
...@@ -4772,6 +4964,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) ...@@ -4772,6 +4964,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
tg3_phy_stop(tp);
tg3_netif_stop(tp); tg3_netif_stop(tp);
tg3_full_lock(tp, 1); tg3_full_lock(tp, 1);
...@@ -4787,6 +4981,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) ...@@ -4787,6 +4981,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (!err)
tg3_phy_start(tp);
return err; return err;
} }
...@@ -7864,6 +8061,8 @@ static int tg3_open(struct net_device *dev) ...@@ -7864,6 +8061,8 @@ static int tg3_open(struct net_device *dev)
} }
} }
tg3_phy_start(tp);
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
add_timer(&tp->timer); add_timer(&tp->timer);
...@@ -8665,7 +8864,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, ...@@ -8665,7 +8864,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
return -EAGAIN;
return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
}
cmd->supported = (SUPPORTED_Autoneg); cmd->supported = (SUPPORTED_Autoneg);
...@@ -8702,6 +8907,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -8702,6 +8907,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
return -EAGAIN;
return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
}
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
/* These are the only valid advertisement bits allowed. */ /* These are the only valid advertisement bits allowed. */
if (cmd->autoneg == AUTONEG_ENABLE && if (cmd->autoneg == AUTONEG_ENABLE &&
...@@ -8734,7 +8945,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -8734,7 +8945,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.advertising = 0; tp->link_config.advertising = 0;
tp->link_config.speed = cmd->speed; tp->link_config.speed = cmd->speed;
tp->link_config.duplex = cmd->duplex; tp->link_config.duplex = cmd->duplex;
} }
tp->link_config.orig_speed = tp->link_config.speed; tp->link_config.orig_speed = tp->link_config.speed;
tp->link_config.orig_duplex = tp->link_config.duplex; tp->link_config.orig_duplex = tp->link_config.duplex;
...@@ -8828,7 +9039,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value) ...@@ -8828,7 +9039,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
static int tg3_nway_reset(struct net_device *dev) static int tg3_nway_reset(struct net_device *dev)
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
u32 bmcr;
int r; int r;
if (!netif_running(dev)) if (!netif_running(dev))
...@@ -8837,17 +9047,25 @@ static int tg3_nway_reset(struct net_device *dev) ...@@ -8837,17 +9047,25 @@ static int tg3_nway_reset(struct net_device *dev)
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
return -EINVAL; return -EINVAL;
spin_lock_bh(&tp->lock); if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
r = -EINVAL; if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
tg3_readphy(tp, MII_BMCR, &bmcr); return -EAGAIN;
if (!tg3_readphy(tp, MII_BMCR, &bmcr) && r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]);
((bmcr & BMCR_ANENABLE) || } else {
(tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { u32 bmcr;
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
BMCR_ANENABLE); spin_lock_bh(&tp->lock);
r = 0; r = -EINVAL;
tg3_readphy(tp, MII_BMCR, &bmcr);
if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
((bmcr & BMCR_ANENABLE) ||
(tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
BMCR_ANENABLE);
r = 0;
}
spin_unlock_bh(&tp->lock);
} }
spin_unlock_bh(&tp->lock);
return r; return r;
} }
...@@ -8889,6 +9107,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e ...@@ -8889,6 +9107,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
return -EINVAL; return -EINVAL;
if (netif_running(dev)) { if (netif_running(dev)) {
tg3_phy_stop(tp);
tg3_netif_stop(tp); tg3_netif_stop(tp);
irq_sync = 1; irq_sync = 1;
} }
...@@ -8912,6 +9131,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e ...@@ -8912,6 +9131,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (irq_sync && !err)
tg3_phy_start(tp);
return err; return err;
} }
...@@ -8935,36 +9157,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam ...@@ -8935,36 +9157,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{ {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
int irq_sync = 0, err = 0; int err = 0;
if (netif_running(dev)) { if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
tg3_netif_stop(tp); if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
irq_sync = 1; return -EAGAIN;
}
tg3_full_lock(tp, irq_sync); if (epause->autoneg) {
u32 newadv;
struct phy_device *phydev;
if (epause->autoneg) phydev = tp->mdio_bus.phy_map[PHY_ADDR];
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
if (epause->rx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
if (epause->tx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
if (netif_running(dev)) { if (epause->rx_pause) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (epause->tx_pause)
err = tg3_restart_hw(tp, 1); newadv = ADVERTISED_Pause;
if (!err) else
tg3_netif_start(tp); newadv = ADVERTISED_Pause |
} ADVERTISED_Asym_Pause;
} else if (epause->tx_pause) {
newadv = ADVERTISED_Asym_Pause;
} else
newadv = 0;
if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
u32 oldadv = phydev->advertising &
(ADVERTISED_Pause |
ADVERTISED_Asym_Pause);
if (oldadv != newadv) {
phydev->advertising &=
~(ADVERTISED_Pause |
ADVERTISED_Asym_Pause);
phydev->advertising |= newadv;
err = phy_start_aneg(phydev);
}
} else {
tp->link_config.advertising &=
~(ADVERTISED_Pause |
ADVERTISED_Asym_Pause);
tp->link_config.advertising |= newadv;
}
} else {
if (epause->rx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
tg3_full_unlock(tp); if (epause->tx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
if (netif_running(dev))
tg3_setup_flow_control(tp, 0, 0);
}
} else {
int irq_sync = 0;
if (netif_running(dev)) {
tg3_netif_stop(tp);
irq_sync = 1;
}
tg3_full_lock(tp, irq_sync);
if (epause->autoneg)
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
if (epause->rx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
if (epause->tx_pause)
tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
else
tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
err = tg3_restart_hw(tp, 1);
if (!err)
tg3_netif_start(tp);
}
tg3_full_unlock(tp);
}
return err; return err;
} }
...@@ -9799,9 +10077,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, ...@@ -9799,9 +10077,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
data[1] = 1; data[1] = 1;
} }
if (etest->flags & ETH_TEST_FL_OFFLINE) { if (etest->flags & ETH_TEST_FL_OFFLINE) {
int err, irq_sync = 0; int err, err2 = 0, irq_sync = 0;
if (netif_running(dev)) { if (netif_running(dev)) {
tg3_phy_stop(tp);
tg3_netif_stop(tp); tg3_netif_stop(tp);
irq_sync = 1; irq_sync = 1;
} }
...@@ -9842,11 +10121,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, ...@@ -9842,11 +10121,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) { if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
if (!tg3_restart_hw(tp, 1)) err2 = tg3_restart_hw(tp, 1);
if (!err2)
tg3_netif_start(tp); tg3_netif_start(tp);
} }
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (irq_sync && !err2)
tg3_phy_start(tp);
} }
if (tp->link_config.phy_is_low_power) if (tp->link_config.phy_is_low_power)
tg3_set_power_state(tp, PCI_D3hot); tg3_set_power_state(tp, PCI_D3hot);
...@@ -9859,6 +10142,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -9859,6 +10142,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
int err; int err;
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
return -EAGAIN;
return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd);
}
switch(cmd) { switch(cmd) {
case SIOCGMIIPHY: case SIOCGMIIPHY:
data->phy_id = PHY_ADDR; data->phy_id = PHY_ADDR;
...@@ -11110,6 +11399,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) ...@@ -11110,6 +11399,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
u32 hw_phy_id, hw_phy_id_masked; u32 hw_phy_id, hw_phy_id_masked;
int err; int err;
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
return tg3_phy_init(tp);
/* Reading the PHY ID register can conflict with ASF /* Reading the PHY ID register can conflict with ASF
* firwmare access to the PHY hardware. * firwmare access to the PHY hardware.
*/ */
...@@ -12043,6 +12335,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) ...@@ -12043,6 +12335,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
pci_name(tp->pdev), err); pci_name(tp->pdev), err);
/* ... but do not return immediately ... */ /* ... but do not return immediately ... */
tg3_mdio_fini(tp);
} }
tg3_read_partno(tp); tg3_read_partno(tp);
...@@ -13163,8 +13456,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) ...@@ -13163,8 +13456,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
flush_scheduled_work(); flush_scheduled_work();
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
tg3_phy_fini(tp);
tg3_mdio_fini(tp); tg3_mdio_fini(tp);
}
unregister_netdev(dev); unregister_netdev(dev);
if (tp->aperegs) { if (tp->aperegs) {
...@@ -13198,6 +13493,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -13198,6 +13493,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
return 0; return 0;
flush_scheduled_work(); flush_scheduled_work();
tg3_phy_stop(tp);
tg3_netif_stop(tp); tg3_netif_stop(tp);
del_timer_sync(&tp->timer); del_timer_sync(&tp->timer);
...@@ -13215,10 +13511,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -13215,10 +13511,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
if (err) { if (err) {
int err2;
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
if (tg3_restart_hw(tp, 1)) err2 = tg3_restart_hw(tp, 1);
if (err2)
goto out; goto out;
tp->timer.expires = jiffies + tp->timer_offset; tp->timer.expires = jiffies + tp->timer_offset;
...@@ -13229,6 +13528,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -13229,6 +13528,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
out: out:
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (!err2)
tg3_phy_start(tp);
} }
return err; return err;
...@@ -13266,6 +13568,9 @@ static int tg3_resume(struct pci_dev *pdev) ...@@ -13266,6 +13568,9 @@ static int tg3_resume(struct pci_dev *pdev)
out: out:
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (!err)
tg3_phy_start(tp);
return err; return err;
} }
......
...@@ -2205,6 +2205,7 @@ struct tg3_link_config { ...@@ -2205,6 +2205,7 @@ struct tg3_link_config {
u16 orig_speed; u16 orig_speed;
u8 orig_duplex; u8 orig_duplex;
u8 orig_autoneg; u8 orig_autoneg;
u32 orig_advertising;
}; };
struct tg3_bufmgr_config { struct tg3_bufmgr_config {
...@@ -2483,6 +2484,7 @@ struct tg3 { ...@@ -2483,6 +2484,7 @@ struct tg3 {
#define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_USE_PHYLIB 0x00000010
#define TG3_FLG3_MDIOBUS_INITED 0x00000020 #define TG3_FLG3_MDIOBUS_INITED 0x00000020
#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 #define TG3_FLG3_MDIOBUS_PAUSED 0x00000040
#define TG3_FLG3_PHY_CONNECTED 0x00000080
struct timer_list timer; struct timer_list timer;
u16 timer_counter; u16 timer_counter;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册