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; |
