diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2008-05-26 02:47:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-05-29 04:38:24 -0400 |
commit | b02fd9e3ac118037549baeb86fbe0718561db17f (patch) | |
tree | 858f7c763fe0e88a4a9f261eb7ae284413b310db /drivers | |
parent | 158d7abdae85e9ac43d99780c372d79c119f7626 (diff) |
tg3: Add libphy support.
This patch introduces the libphy support.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/tg3.c | 395 | ||||
-rw-r--r-- | drivers/net/tg3.h | 2 |
2 files changed, 352 insertions, 45 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ce04c64a8a6e..028276edd3bc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -1114,11 +1114,17 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) | |||
1114 | 1114 | ||
1115 | static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) | 1115 | static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) |
1116 | { | 1116 | { |
1117 | u8 autoneg; | ||
1117 | u8 flowctrl = 0; | 1118 | u8 flowctrl = 0; |
1118 | u32 old_rx_mode = tp->rx_mode; | 1119 | u32 old_rx_mode = tp->rx_mode; |
1119 | u32 old_tx_mode = tp->tx_mode; | 1120 | u32 old_tx_mode = tp->tx_mode; |
1120 | 1121 | ||
1121 | if (tp->link_config.autoneg == AUTONEG_ENABLE && | 1122 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) |
1123 | autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg; | ||
1124 | else | ||
1125 | autoneg = tp->link_config.autoneg; | ||
1126 | |||
1127 | if (autoneg == AUTONEG_ENABLE && | ||
1122 | (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { | 1128 | (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { |
1123 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) | 1129 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) |
1124 | flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); | 1130 | 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 | tw32_f(MAC_TX_MODE, tp->tx_mode); | 1152 | tw32_f(MAC_TX_MODE, tp->tx_mode); |
1147 | } | 1153 | } |
1148 | 1154 | ||
1155 | static void tg3_adjust_link(struct net_device *dev) | ||
1156 | { | ||
1157 | u8 oldflowctrl, linkmesg = 0; | ||
1158 | u32 mac_mode, lcl_adv, rmt_adv; | ||
1159 | struct tg3 *tp = netdev_priv(dev); | ||
1160 | struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR]; | ||
1161 | |||
1162 | spin_lock(&tp->lock); | ||
1163 | |||
1164 | mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | | ||
1165 | MAC_MODE_HALF_DUPLEX); | ||
1166 | |||
1167 | oldflowctrl = tp->link_config.active_flowctrl; | ||
1168 | |||
1169 | if (phydev->link) { | ||
1170 | lcl_adv = 0; | ||
1171 | rmt_adv = 0; | ||
1172 | |||
1173 | if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10) | ||
1174 | mac_mode |= MAC_MODE_PORT_MODE_MII; | ||
1175 | else | ||
1176 | mac_mode |= MAC_MODE_PORT_MODE_GMII; | ||
1177 | |||
1178 | if (phydev->duplex == DUPLEX_HALF) | ||
1179 | mac_mode |= MAC_MODE_HALF_DUPLEX; | ||
1180 | else { | ||
1181 | lcl_adv = tg3_advert_flowctrl_1000T( | ||
1182 | tp->link_config.flowctrl); | ||
1183 | |||
1184 | if (phydev->pause) | ||
1185 | rmt_adv = LPA_PAUSE_CAP; | ||
1186 | if (phydev->asym_pause) | ||
1187 | rmt_adv |= LPA_PAUSE_ASYM; | ||
1188 | } | ||
1189 | |||
1190 | tg3_setup_flow_control(tp, lcl_adv, rmt_adv); | ||
1191 | } else | ||
1192 | mac_mode |= MAC_MODE_PORT_MODE_GMII; | ||
1193 | |||
1194 | if (mac_mode != tp->mac_mode) { | ||
1195 | tp->mac_mode = mac_mode; | ||
1196 | tw32_f(MAC_MODE, tp->mac_mode); | ||
1197 | udelay(40); | ||
1198 | } | ||
1199 | |||
1200 | if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) | ||
1201 | tw32(MAC_TX_LENGTHS, | ||
1202 | ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | | ||
1203 | (6 << TX_LENGTHS_IPG_SHIFT) | | ||
1204 | (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); | ||
1205 | else | ||
1206 | tw32(MAC_TX_LENGTHS, | ||
1207 | ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | | ||
1208 | (6 << TX_LENGTHS_IPG_SHIFT) | | ||
1209 | (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); | ||
1210 | |||
1211 | if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) || | ||
1212 | (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) || | ||
1213 | phydev->speed != tp->link_config.active_speed || | ||
1214 | phydev->duplex != tp->link_config.active_duplex || | ||
1215 | oldflowctrl != tp->link_config.active_flowctrl) | ||
1216 | linkmesg = 1; | ||
1217 | |||
1218 | tp->link_config.active_speed = phydev->speed; | ||
1219 | tp->link_config.active_duplex = phydev->duplex; | ||
1220 | |||
1221 | spin_unlock(&tp->lock); | ||
1222 | |||
1223 | if (linkmesg) | ||
1224 | tg3_link_report(tp); | ||
1225 | } | ||
1226 | |||
1227 | static int tg3_phy_init(struct tg3 *tp) | ||
1228 | { | ||
1229 | struct phy_device *phydev; | ||
1230 | |||
1231 | if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) | ||
1232 | return 0; | ||
1233 | |||
1234 | /* Bring the PHY back to a known state. */ | ||
1235 | tg3_bmcr_reset(tp); | ||
1236 | |||
1237 | phydev = tp->mdio_bus.phy_map[PHY_ADDR]; | ||
1238 | |||
1239 | /* Attach the MAC to the PHY. */ | ||
1240 | phydev = phy_connect(tp->dev, phydev->dev.bus_id, | ||
1241 | tg3_adjust_link, 0, phydev->interface); | ||
1242 | if (IS_ERR(phydev)) { | ||
1243 | printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); | ||
1244 | return PTR_ERR(phydev); | ||
1245 | } | ||
1246 | |||
1247 | tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; | ||
1248 | |||
1249 | /* Mask with MAC supported features. */ | ||
1250 | phydev->supported &= (PHY_GBIT_FEATURES | | ||
1251 | SUPPORTED_Pause | | ||
1252 | SUPPORTED_Asym_Pause); | ||
1253 | |||
1254 | phydev->advertising = phydev->supported; | ||
1255 | |||
1256 | printk(KERN_INFO | ||
1257 | "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", | ||
1258 | tp->dev->name, phydev->drv->name, phydev->dev.bus_id); | ||
1259 | |||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static void tg3_phy_start(struct tg3 *tp) | ||
1264 | { | ||
1265 | struct phy_device *phydev; | ||
1266 | |||
1267 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) | ||
1268 | return; | ||
1269 | |||
1270 | phydev = tp->mdio_bus.phy_map[PHY_ADDR]; | ||
1271 | |||
1272 | if (tp->link_config.phy_is_low_power) { | ||
1273 | tp->link_config.phy_is_low_power = 0; | ||
1274 | phydev->speed = tp->link_config.orig_speed; | ||
1275 | phydev->duplex = tp->link_config.orig_duplex; | ||
1276 | phydev->autoneg = tp->link_config.orig_autoneg; | ||
1277 | phydev->advertising = tp->link_config.orig_advertising; | ||
1278 | } | ||
1279 | |||
1280 | phy_start(phydev); | ||
1281 | |||
1282 | phy_start_aneg(phydev); | ||
1283 | } | ||
1284 | |||
1285 | static void tg3_phy_stop(struct tg3 *tp) | ||
1286 | { | ||
1287 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) | ||
1288 | return; | ||
1289 | |||
1290 | phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]); | ||
1291 | } | ||
1292 | |||
1293 | static void tg3_phy_fini(struct tg3 *tp) | ||
1294 | { | ||
1295 | if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { | ||
1296 | phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]); | ||
1297 | tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1149 | static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) | 1301 | static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) |
1150 | { | 1302 | { |
1151 | tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); | 1303 | 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 | misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); | 1950 | misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); |
1799 | 1951 | ||
1800 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { | 1952 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { |
1801 | tp->link_config.phy_is_low_power = 1; | 1953 | if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) && |
1954 | !tp->link_config.phy_is_low_power) { | ||
1955 | struct phy_device *phydev; | ||
1956 | u32 advertising; | ||
1957 | |||
1958 | phydev = tp->mdio_bus.phy_map[PHY_ADDR]; | ||
1959 | |||
1960 | tp->link_config.phy_is_low_power = 1; | ||
1961 | |||
1962 | tp->link_config.orig_speed = phydev->speed; | ||
1963 | tp->link_config.orig_duplex = phydev->duplex; | ||
1964 | tp->link_config.orig_autoneg = phydev->autoneg; | ||
1965 | tp->link_config.orig_advertising = phydev->advertising; | ||
1966 | |||
1967 | advertising = ADVERTISED_TP | | ||
1968 | ADVERTISED_Pause | | ||
1969 | ADVERTISED_Autoneg | | ||
1970 | ADVERTISED_10baseT_Half; | ||
1971 | |||
1972 | if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || | ||
1973 | (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { | ||
1974 | if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) | ||
1975 | advertising |= | ||
1976 | ADVERTISED_100baseT_Half | | ||
1977 | ADVERTISED_100baseT_Full | | ||
1978 | ADVERTISED_10baseT_Full; | ||
1979 | else | ||
1980 | advertising |= ADVERTISED_10baseT_Full; | ||
1981 | } | ||
1982 | |||
1983 | phydev->advertising = advertising; | ||
1984 | |||
1985 | phy_start_aneg(phydev); | ||
1986 | } | ||
1802 | } else { | 1987 | } else { |
1803 | if (tp->link_config.phy_is_low_power == 0) { | 1988 | if (tp->link_config.phy_is_low_power == 0) { |
1804 | tp->link_config.phy_is_low_power = 1; | 1989 | tp->link_config.phy_is_low_power = 1; |
@@ -4233,6 +4418,7 @@ static void tg3_poll_controller(struct net_device *dev) | |||
4233 | static void tg3_reset_task(struct work_struct *work) | 4418 | static void tg3_reset_task(struct work_struct *work) |
4234 | { | 4419 | { |
4235 | struct tg3 *tp = container_of(work, struct tg3, reset_task); | 4420 | struct tg3 *tp = container_of(work, struct tg3, reset_task); |
4421 | int err; | ||
4236 | unsigned int restart_timer; | 4422 | unsigned int restart_timer; |
4237 | 4423 | ||
4238 | tg3_full_lock(tp, 0); | 4424 | tg3_full_lock(tp, 0); |
@@ -4244,6 +4430,8 @@ static void tg3_reset_task(struct work_struct *work) | |||
4244 | 4430 | ||
4245 | tg3_full_unlock(tp); | 4431 | tg3_full_unlock(tp); |
4246 | 4432 | ||
4433 | tg3_phy_stop(tp); | ||
4434 | |||
4247 | tg3_netif_stop(tp); | 4435 | tg3_netif_stop(tp); |
4248 | 4436 | ||
4249 | tg3_full_lock(tp, 1); | 4437 | tg3_full_lock(tp, 1); |
@@ -4259,7 +4447,8 @@ static void tg3_reset_task(struct work_struct *work) | |||
4259 | } | 4447 | } |
4260 | 4448 | ||
4261 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); | 4449 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); |
4262 | if (tg3_init_hw(tp, 1)) | 4450 | err = tg3_init_hw(tp, 1); |
4451 | if (err) | ||
4263 | goto out; | 4452 | goto out; |
4264 | 4453 | ||
4265 | tg3_netif_start(tp); | 4454 | tg3_netif_start(tp); |
@@ -4269,6 +4458,9 @@ static void tg3_reset_task(struct work_struct *work) | |||
4269 | 4458 | ||
4270 | out: | 4459 | out: |
4271 | tg3_full_unlock(tp); | 4460 | tg3_full_unlock(tp); |
4461 | |||
4462 | if (!err) | ||
4463 | tg3_phy_start(tp); | ||
4272 | } | 4464 | } |
4273 | 4465 | ||
4274 | static void tg3_dump_short_state(struct tg3 *tp) | 4466 | 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 | return 0; | 4964 | return 0; |
4773 | } | 4965 | } |
4774 | 4966 | ||
4967 | tg3_phy_stop(tp); | ||
4968 | |||
4775 | tg3_netif_stop(tp); | 4969 | tg3_netif_stop(tp); |
4776 | 4970 | ||
4777 | tg3_full_lock(tp, 1); | 4971 | tg3_full_lock(tp, 1); |
@@ -4787,6 +4981,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) | |||
4787 | 4981 | ||
4788 | tg3_full_unlock(tp); | 4982 | tg3_full_unlock(tp); |
4789 | 4983 | ||
4984 | if (!err) | ||
4985 | tg3_phy_start(tp); | ||
4986 | |||
4790 | return err; | 4987 | return err; |
4791 | } | 4988 | } |
4792 | 4989 | ||
@@ -7864,6 +8061,8 @@ static int tg3_open(struct net_device *dev) | |||
7864 | } | 8061 | } |
7865 | } | 8062 | } |
7866 | 8063 | ||
8064 | tg3_phy_start(tp); | ||
8065 | |||
7867 | tg3_full_lock(tp, 0); | 8066 | tg3_full_lock(tp, 0); |
7868 | 8067 | ||
7869 | add_timer(&tp->timer); | 8068 | add_timer(&tp->timer); |
@@ -8665,7 +8864,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | |||
8665 | 8864 | ||
8666 | static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 8865 | static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
8667 | { | 8866 | { |
8668 | struct tg3 *tp = netdev_priv(dev); | 8867 | struct tg3 *tp = netdev_priv(dev); |
8868 | |||
8869 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { | ||
8870 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) | ||
8871 | return -EAGAIN; | ||
8872 | return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); | ||
8873 | } | ||
8669 | 8874 | ||
8670 | cmd->supported = (SUPPORTED_Autoneg); | 8875 | cmd->supported = (SUPPORTED_Autoneg); |
8671 | 8876 | ||
@@ -8702,6 +8907,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
8702 | { | 8907 | { |
8703 | struct tg3 *tp = netdev_priv(dev); | 8908 | struct tg3 *tp = netdev_priv(dev); |
8704 | 8909 | ||
8910 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { | ||
8911 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) | ||
8912 | return -EAGAIN; | ||
8913 | return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); | ||
8914 | } | ||
8915 | |||
8705 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { | 8916 | if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { |
8706 | /* These are the only valid advertisement bits allowed. */ | 8917 | /* These are the only valid advertisement bits allowed. */ |
8707 | if (cmd->autoneg == AUTONEG_ENABLE && | 8918 | if (cmd->autoneg == AUTONEG_ENABLE && |
@@ -8734,7 +8945,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
8734 | tp->link_config.advertising = 0; | 8945 | tp->link_config.advertising = 0; |
8735 | tp->link_config.speed = cmd->speed; | 8946 | tp->link_config.speed = cmd->speed; |
8736 | tp->link_config.duplex = cmd->duplex; | 8947 | tp->link_config.duplex = cmd->duplex; |
8737 | } | 8948 | } |
8738 | 8949 | ||
8739 | tp->link_config.orig_speed = tp->link_config.speed; | 8950 | tp->link_config.orig_speed = tp->link_config.speed; |
8740 | tp->link_config.orig_duplex = tp->link_config.duplex; | 8951 | 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 | static int tg3_nway_reset(struct net_device *dev) | 9039 | static int tg3_nway_reset(struct net_device *dev) |
8829 | { | 9040 | { |
8830 | struct tg3 *tp = netdev_priv(dev); | 9041 | struct tg3 *tp = netdev_priv(dev); |
8831 | u32 bmcr; | ||
8832 | int r; | 9042 | int r; |
8833 | 9043 | ||
8834 | if (!netif_running(dev)) | 9044 | if (!netif_running(dev)) |
@@ -8837,17 +9047,25 @@ static int tg3_nway_reset(struct net_device *dev) | |||
8837 | if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) | 9047 | if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) |
8838 | return -EINVAL; | 9048 | return -EINVAL; |
8839 | 9049 | ||
8840 | spin_lock_bh(&tp->lock); | 9050 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { |
8841 | r = -EINVAL; | 9051 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) |
8842 | tg3_readphy(tp, MII_BMCR, &bmcr); | 9052 | return -EAGAIN; |
8843 | if (!tg3_readphy(tp, MII_BMCR, &bmcr) && | 9053 | r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]); |
8844 | ((bmcr & BMCR_ANENABLE) || | 9054 | } else { |
8845 | (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { | 9055 | u32 bmcr; |
8846 | tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | | 9056 | |
8847 | BMCR_ANENABLE); | 9057 | spin_lock_bh(&tp->lock); |
8848 | r = 0; | 9058 | r = -EINVAL; |
9059 | tg3_readphy(tp, MII_BMCR, &bmcr); | ||
9060 | if (!tg3_readphy(tp, MII_BMCR, &bmcr) && | ||
9061 | ((bmcr & BMCR_ANENABLE) || | ||
9062 | (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) { | ||
9063 | tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART | | ||
9064 | BMCR_ANENABLE); | ||
9065 | r = 0; | ||
9066 | } | ||
9067 | spin_unlock_bh(&tp->lock); | ||
8849 | } | 9068 | } |
8850 | spin_unlock_bh(&tp->lock); | ||
8851 | 9069 | ||
8852 | return r; | 9070 | return r; |
8853 | } | 9071 | } |
@@ -8889,6 +9107,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e | |||
8889 | return -EINVAL; | 9107 | return -EINVAL; |
8890 | 9108 | ||
8891 | if (netif_running(dev)) { | 9109 | if (netif_running(dev)) { |
9110 | tg3_phy_stop(tp); | ||
8892 | tg3_netif_stop(tp); | 9111 | tg3_netif_stop(tp); |
8893 | irq_sync = 1; | 9112 | irq_sync = 1; |
8894 | } | 9113 | } |
@@ -8912,6 +9131,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e | |||
8912 | 9131 | ||
8913 | tg3_full_unlock(tp); | 9132 | tg3_full_unlock(tp); |
8914 | 9133 | ||
9134 | if (irq_sync && !err) | ||
9135 | tg3_phy_start(tp); | ||
9136 | |||
8915 | return err; | 9137 | return err; |
8916 | } | 9138 | } |
8917 | 9139 | ||
@@ -8935,36 +9157,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam | |||
8935 | static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) | 9157 | static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) |
8936 | { | 9158 | { |
8937 | struct tg3 *tp = netdev_priv(dev); | 9159 | struct tg3 *tp = netdev_priv(dev); |
8938 | int irq_sync = 0, err = 0; | 9160 | int err = 0; |
8939 | 9161 | ||
8940 | if (netif_running(dev)) { | 9162 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { |
8941 | tg3_netif_stop(tp); | 9163 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) |
8942 | irq_sync = 1; | 9164 | return -EAGAIN; |
8943 | } | ||
8944 | 9165 | ||
8945 | tg3_full_lock(tp, irq_sync); | 9166 | if (epause->autoneg) { |
9167 | u32 newadv; | ||
9168 | struct phy_device *phydev; | ||
8946 | 9169 | ||
8947 | if (epause->autoneg) | 9170 | phydev = tp->mdio_bus.phy_map[PHY_ADDR]; |
8948 | tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; | ||
8949 | else | ||
8950 | tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; | ||
8951 | if (epause->rx_pause) | ||
8952 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; | ||
8953 | else | ||
8954 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; | ||
8955 | if (epause->tx_pause) | ||
8956 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; | ||
8957 | else | ||
8958 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; | ||
8959 | 9171 | ||
8960 | if (netif_running(dev)) { | 9172 | if (epause->rx_pause) { |
8961 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); | 9173 | if (epause->tx_pause) |
8962 | err = tg3_restart_hw(tp, 1); | 9174 | newadv = ADVERTISED_Pause; |
8963 | if (!err) | 9175 | else |
8964 | tg3_netif_start(tp); | 9176 | newadv = ADVERTISED_Pause | |
8965 | } | 9177 | ADVERTISED_Asym_Pause; |
9178 | } else if (epause->tx_pause) { | ||
9179 | newadv = ADVERTISED_Asym_Pause; | ||
9180 | } else | ||
9181 | newadv = 0; | ||
9182 | |||
9183 | if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { | ||
9184 | u32 oldadv = phydev->advertising & | ||
9185 | (ADVERTISED_Pause | | ||
9186 | ADVERTISED_Asym_Pause); | ||
9187 | if (oldadv != newadv) { | ||
9188 | phydev->advertising &= | ||
9189 | ~(ADVERTISED_Pause | | ||
9190 | ADVERTISED_Asym_Pause); | ||
9191 | phydev->advertising |= newadv; | ||
9192 | err = phy_start_aneg(phydev); | ||
9193 | } | ||
9194 | } else { | ||
9195 | tp->link_config.advertising &= | ||
9196 | ~(ADVERTISED_Pause | | ||
9197 | ADVERTISED_Asym_Pause); | ||
9198 | tp->link_config.advertising |= newadv; | ||
9199 | } | ||
9200 | } else { | ||
9201 | if (epause->rx_pause) | ||
9202 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; | ||
9203 | else | ||
9204 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; | ||
8966 | 9205 | ||
8967 | tg3_full_unlock(tp); | 9206 | if (epause->tx_pause) |
9207 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; | ||
9208 | else | ||
9209 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; | ||
9210 | |||
9211 | if (netif_running(dev)) | ||
9212 | tg3_setup_flow_control(tp, 0, 0); | ||
9213 | } | ||
9214 | } else { | ||
9215 | int irq_sync = 0; | ||
9216 | |||
9217 | if (netif_running(dev)) { | ||
9218 | tg3_netif_stop(tp); | ||
9219 | irq_sync = 1; | ||
9220 | } | ||
9221 | |||
9222 | tg3_full_lock(tp, irq_sync); | ||
9223 | |||
9224 | if (epause->autoneg) | ||
9225 | tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; | ||
9226 | else | ||
9227 | tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; | ||
9228 | if (epause->rx_pause) | ||
9229 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; | ||
9230 | else | ||
9231 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; | ||
9232 | if (epause->tx_pause) | ||
9233 | tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; | ||
9234 | else | ||
9235 | tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; | ||
9236 | |||
9237 | if (netif_running(dev)) { | ||
9238 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); | ||
9239 | err = tg3_restart_hw(tp, 1); | ||
9240 | if (!err) | ||
9241 | tg3_netif_start(tp); | ||
9242 | } | ||
9243 | |||
9244 | tg3_full_unlock(tp); | ||
9245 | } | ||
8968 | 9246 | ||
8969 | return err; | 9247 | return err; |
8970 | } | 9248 | } |
@@ -9799,9 +10077,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, | |||
9799 | data[1] = 1; | 10077 | data[1] = 1; |
9800 | } | 10078 | } |
9801 | if (etest->flags & ETH_TEST_FL_OFFLINE) { | 10079 | if (etest->flags & ETH_TEST_FL_OFFLINE) { |
9802 | int err, irq_sync = 0; | 10080 | int err, err2 = 0, irq_sync = 0; |
9803 | 10081 | ||
9804 | if (netif_running(dev)) { | 10082 | if (netif_running(dev)) { |
10083 | tg3_phy_stop(tp); | ||
9805 | tg3_netif_stop(tp); | 10084 | tg3_netif_stop(tp); |
9806 | irq_sync = 1; | 10085 | irq_sync = 1; |
9807 | } | 10086 | } |
@@ -9842,11 +10121,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, | |||
9842 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); | 10121 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); |
9843 | if (netif_running(dev)) { | 10122 | if (netif_running(dev)) { |
9844 | tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; | 10123 | tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; |
9845 | if (!tg3_restart_hw(tp, 1)) | 10124 | err2 = tg3_restart_hw(tp, 1); |
10125 | if (!err2) | ||
9846 | tg3_netif_start(tp); | 10126 | tg3_netif_start(tp); |
9847 | } | 10127 | } |
9848 | 10128 | ||
9849 | tg3_full_unlock(tp); | 10129 | tg3_full_unlock(tp); |
10130 | |||
10131 | if (irq_sync && !err2) | ||
10132 | tg3_phy_start(tp); | ||
9850 | } | 10133 | } |
9851 | if (tp->link_config.phy_is_low_power) | 10134 | if (tp->link_config.phy_is_low_power) |
9852 | tg3_set_power_state(tp, PCI_D3hot); | 10135 | 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 | struct tg3 *tp = netdev_priv(dev); | 10142 | struct tg3 *tp = netdev_priv(dev); |
9860 | int err; | 10143 | int err; |
9861 | 10144 | ||
10145 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { | ||
10146 | if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) | ||
10147 | return -EAGAIN; | ||
10148 | return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd); | ||
10149 | } | ||
10150 | |||
9862 | switch(cmd) { | 10151 | switch(cmd) { |
9863 | case SIOCGMIIPHY: | 10152 | case SIOCGMIIPHY: |
9864 | data->phy_id = PHY_ADDR; | 10153 | data->phy_id = PHY_ADDR; |
@@ -11110,6 +11399,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) | |||
11110 | u32 hw_phy_id, hw_phy_id_masked; | 11399 | u32 hw_phy_id, hw_phy_id_masked; |
11111 | int err; | 11400 | int err; |
11112 | 11401 | ||
11402 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) | ||
11403 | return tg3_phy_init(tp); | ||
11404 | |||
11113 | /* Reading the PHY ID register can conflict with ASF | 11405 | /* Reading the PHY ID register can conflict with ASF |
11114 | * firwmare access to the PHY hardware. | 11406 | * firwmare access to the PHY hardware. |
11115 | */ | 11407 | */ |
@@ -12043,6 +12335,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) | |||
12043 | printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", | 12335 | printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", |
12044 | pci_name(tp->pdev), err); | 12336 | pci_name(tp->pdev), err); |
12045 | /* ... but do not return immediately ... */ | 12337 | /* ... but do not return immediately ... */ |
12338 | tg3_mdio_fini(tp); | ||
12046 | } | 12339 | } |
12047 | 12340 | ||
12048 | tg3_read_partno(tp); | 12341 | tg3_read_partno(tp); |
@@ -13163,8 +13456,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) | |||
13163 | 13456 | ||
13164 | flush_scheduled_work(); | 13457 | flush_scheduled_work(); |
13165 | 13458 | ||
13166 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) | 13459 | if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { |
13460 | tg3_phy_fini(tp); | ||
13167 | tg3_mdio_fini(tp); | 13461 | tg3_mdio_fini(tp); |
13462 | } | ||
13168 | 13463 | ||
13169 | unregister_netdev(dev); | 13464 | unregister_netdev(dev); |
13170 | if (tp->aperegs) { | 13465 | if (tp->aperegs) { |
@@ -13198,6 +13493,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) | |||
13198 | return 0; | 13493 | return 0; |
13199 | 13494 | ||
13200 | flush_scheduled_work(); | 13495 | flush_scheduled_work(); |
13496 | tg3_phy_stop(tp); | ||
13201 | tg3_netif_stop(tp); | 13497 | tg3_netif_stop(tp); |
13202 | 13498 | ||
13203 | del_timer_sync(&tp->timer); | 13499 | del_timer_sync(&tp->timer); |
@@ -13215,10 +13511,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) | |||
13215 | 13511 | ||
13216 | err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); | 13512 | err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); |
13217 | if (err) { | 13513 | if (err) { |
13514 | int err2; | ||
13515 | |||
13218 | tg3_full_lock(tp, 0); | 13516 | tg3_full_lock(tp, 0); |
13219 | 13517 | ||
13220 | tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; | 13518 | tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; |
13221 | if (tg3_restart_hw(tp, 1)) | 13519 | err2 = tg3_restart_hw(tp, 1); |
13520 | if (err2) | ||
13222 | goto out; | 13521 | goto out; |
13223 | 13522 | ||
13224 | tp->timer.expires = jiffies + tp->timer_offset; | 13523 | tp->timer.expires = jiffies + tp->timer_offset; |
@@ -13229,6 +13528,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) | |||
13229 | 13528 | ||
13230 | out: | 13529 | out: |
13231 | tg3_full_unlock(tp); | 13530 | tg3_full_unlock(tp); |
13531 | |||
13532 | if (!err2) | ||
13533 | tg3_phy_start(tp); | ||
13232 | } | 13534 | } |
13233 | 13535 | ||
13234 | return err; | 13536 | return err; |
@@ -13266,6 +13568,9 @@ static int tg3_resume(struct pci_dev *pdev) | |||
13266 | out: | 13568 | out: |
13267 | tg3_full_unlock(tp); | 13569 | tg3_full_unlock(tp); |
13268 | 13570 | ||
13571 | if (!err) | ||
13572 | tg3_phy_start(tp); | ||
13573 | |||
13269 | return err; | 13574 | return err; |
13270 | } | 13575 | } |
13271 | 13576 | ||
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index e0914fdaf274..48f45c17f60d 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h | |||
@@ -2205,6 +2205,7 @@ struct tg3_link_config { | |||
2205 | u16 orig_speed; | 2205 | u16 orig_speed; |
2206 | u8 orig_duplex; | 2206 | u8 orig_duplex; |
2207 | u8 orig_autoneg; | 2207 | u8 orig_autoneg; |
2208 | u32 orig_advertising; | ||
2208 | }; | 2209 | }; |
2209 | 2210 | ||
2210 | struct tg3_bufmgr_config { | 2211 | struct tg3_bufmgr_config { |
@@ -2483,6 +2484,7 @@ struct tg3 { | |||
2483 | #define TG3_FLG3_USE_PHYLIB 0x00000010 | 2484 | #define TG3_FLG3_USE_PHYLIB 0x00000010 |
2484 | #define TG3_FLG3_MDIOBUS_INITED 0x00000020 | 2485 | #define TG3_FLG3_MDIOBUS_INITED 0x00000020 |
2485 | #define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 | 2486 | #define TG3_FLG3_MDIOBUS_PAUSED 0x00000040 |
2487 | #define TG3_FLG3_PHY_CONNECTED 0x00000080 | ||
2486 | 2488 | ||
2487 | struct timer_list timer; | 2489 | struct timer_list timer; |
2488 | u16 timer_counter; | 2490 | u16 timer_counter; |