diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2008-11-22 00:30:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-22 00:30:24 -0500 |
commit | f5f4cf08467db10de061a1b90037a56a360d3554 (patch) | |
tree | f590f5a39dca1a57012f5eb62302ca56b7d3e27a | |
parent | 21fc578dcaa66dd30bad3c2f2cd7578e2865e8f2 (diff) |
igb: do not use phy ops in ethtool test cleanup for non-copper parts
Currently the igb driver is experiencing a panic due to a null function
pointer being used during the cleanup of the ethtool looback test on
fiber/serdes parts. This patch prevents that and adds a check prior to
calling any phy function.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/igb/igb.h | 32 | ||||
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 20 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 20 |
3 files changed, 50 insertions, 22 deletions
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index acf2569b98f4..2121b8bc6ea7 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h | |||
@@ -332,4 +332,36 @@ extern void igb_free_rx_resources(struct igb_ring *); | |||
332 | extern void igb_update_stats(struct igb_adapter *); | 332 | extern void igb_update_stats(struct igb_adapter *); |
333 | extern void igb_set_ethtool_ops(struct net_device *); | 333 | extern void igb_set_ethtool_ops(struct net_device *); |
334 | 334 | ||
335 | static inline s32 igb_reset_phy(struct e1000_hw *hw) | ||
336 | { | ||
337 | if (hw->phy.ops.reset_phy) | ||
338 | return hw->phy.ops.reset_phy(hw); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data) | ||
344 | { | ||
345 | if (hw->phy.ops.read_phy_reg) | ||
346 | return hw->phy.ops.read_phy_reg(hw, offset, data); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data) | ||
352 | { | ||
353 | if (hw->phy.ops.write_phy_reg) | ||
354 | return hw->phy.ops.write_phy_reg(hw, offset, data); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static inline s32 igb_get_phy_info(struct e1000_hw *hw) | ||
360 | { | ||
361 | if (hw->phy.ops.get_phy_info) | ||
362 | return hw->phy.ops.get_phy_info(hw); | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
335 | #endif /* _IGB_H_ */ | 367 | #endif /* _IGB_H_ */ |
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index a661159a097b..8e9d295034ff 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c | |||
@@ -1376,10 +1376,10 @@ static void igb_phy_disable_receiver(struct igb_adapter *adapter) | |||
1376 | struct e1000_hw *hw = &adapter->hw; | 1376 | struct e1000_hw *hw = &adapter->hw; |
1377 | 1377 | ||
1378 | /* Write out to PHY registers 29 and 30 to disable the Receiver. */ | 1378 | /* Write out to PHY registers 29 and 30 to disable the Receiver. */ |
1379 | hw->phy.ops.write_phy_reg(hw, 29, 0x001F); | 1379 | igb_write_phy_reg(hw, 29, 0x001F); |
1380 | hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC); | 1380 | igb_write_phy_reg(hw, 30, 0x8FFC); |
1381 | hw->phy.ops.write_phy_reg(hw, 29, 0x001A); | 1381 | igb_write_phy_reg(hw, 29, 0x001A); |
1382 | hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0); | 1382 | igb_write_phy_reg(hw, 30, 0x8FF0); |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | static int igb_integrated_phy_loopback(struct igb_adapter *adapter) | 1385 | static int igb_integrated_phy_loopback(struct igb_adapter *adapter) |
@@ -1392,17 +1392,17 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) | |||
1392 | 1392 | ||
1393 | if (hw->phy.type == e1000_phy_m88) { | 1393 | if (hw->phy.type == e1000_phy_m88) { |
1394 | /* Auto-MDI/MDIX Off */ | 1394 | /* Auto-MDI/MDIX Off */ |
1395 | hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); | 1395 | igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); |
1396 | /* reset to update Auto-MDI/MDIX */ | 1396 | /* reset to update Auto-MDI/MDIX */ |
1397 | hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140); | 1397 | igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); |
1398 | /* autoneg off */ | 1398 | /* autoneg off */ |
1399 | hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140); | 1399 | igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); |
1400 | } | 1400 | } |
1401 | 1401 | ||
1402 | ctrl_reg = rd32(E1000_CTRL); | 1402 | ctrl_reg = rd32(E1000_CTRL); |
1403 | 1403 | ||
1404 | /* force 1000, set loopback */ | 1404 | /* force 1000, set loopback */ |
1405 | hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140); | 1405 | igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); |
1406 | 1406 | ||
1407 | /* Now set up the MAC to the same speed/duplex as the PHY. */ | 1407 | /* Now set up the MAC to the same speed/duplex as the PHY. */ |
1408 | ctrl_reg = rd32(E1000_CTRL); | 1408 | ctrl_reg = rd32(E1000_CTRL); |
@@ -1496,10 +1496,10 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter) | |||
1496 | wr32(E1000_RCTL, rctl); | 1496 | wr32(E1000_RCTL, rctl); |
1497 | 1497 | ||
1498 | hw->mac.autoneg = true; | 1498 | hw->mac.autoneg = true; |
1499 | hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg); | 1499 | igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg); |
1500 | if (phy_reg & MII_CR_LOOPBACK) { | 1500 | if (phy_reg & MII_CR_LOOPBACK) { |
1501 | phy_reg &= ~MII_CR_LOOPBACK; | 1501 | phy_reg &= ~MII_CR_LOOPBACK; |
1502 | hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg); | 1502 | igb_write_phy_reg(hw, PHY_CONTROL, phy_reg); |
1503 | igb_phy_sw_reset(hw); | 1503 | igb_phy_sw_reset(hw); |
1504 | } | 1504 | } |
1505 | } | 1505 | } |
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index eca5684d5655..b64c41a44dfc 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c | |||
@@ -931,8 +931,7 @@ void igb_reset(struct igb_adapter *adapter) | |||
931 | wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); | 931 | wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); |
932 | 932 | ||
933 | igb_reset_adaptive(&adapter->hw); | 933 | igb_reset_adaptive(&adapter->hw); |
934 | if (adapter->hw.phy.ops.get_phy_info) | 934 | igb_get_phy_info(&adapter->hw); |
935 | adapter->hw.phy.ops.get_phy_info(&adapter->hw); | ||
936 | } | 935 | } |
937 | 936 | ||
938 | /** | 937 | /** |
@@ -1305,7 +1304,7 @@ err_register: | |||
1305 | igb_release_hw_control(adapter); | 1304 | igb_release_hw_control(adapter); |
1306 | err_eeprom: | 1305 | err_eeprom: |
1307 | if (!igb_check_reset_block(hw)) | 1306 | if (!igb_check_reset_block(hw)) |
1308 | hw->phy.ops.reset_phy(hw); | 1307 | igb_reset_phy(hw); |
1309 | 1308 | ||
1310 | if (hw->flash_address) | 1309 | if (hw->flash_address) |
1311 | iounmap(hw->flash_address); | 1310 | iounmap(hw->flash_address); |
@@ -1365,9 +1364,8 @@ static void __devexit igb_remove(struct pci_dev *pdev) | |||
1365 | 1364 | ||
1366 | unregister_netdev(netdev); | 1365 | unregister_netdev(netdev); |
1367 | 1366 | ||
1368 | if (adapter->hw.phy.ops.reset_phy && | 1367 | if (!igb_check_reset_block(&adapter->hw)) |
1369 | !igb_check_reset_block(&adapter->hw)) | 1368 | igb_reset_phy(&adapter->hw); |
1370 | adapter->hw.phy.ops.reset_phy(&adapter->hw); | ||
1371 | 1369 | ||
1372 | igb_remove_device(&adapter->hw); | 1370 | igb_remove_device(&adapter->hw); |
1373 | igb_reset_interrupt_capability(adapter); | 1371 | igb_reset_interrupt_capability(adapter); |
@@ -2283,8 +2281,7 @@ static void igb_set_multi(struct net_device *netdev) | |||
2283 | static void igb_update_phy_info(unsigned long data) | 2281 | static void igb_update_phy_info(unsigned long data) |
2284 | { | 2282 | { |
2285 | struct igb_adapter *adapter = (struct igb_adapter *) data; | 2283 | struct igb_adapter *adapter = (struct igb_adapter *) data; |
2286 | if (adapter->hw.phy.ops.get_phy_info) | 2284 | igb_get_phy_info(&adapter->hw); |
2287 | adapter->hw.phy.ops.get_phy_info(&adapter->hw); | ||
2288 | } | 2285 | } |
2289 | 2286 | ||
2290 | /** | 2287 | /** |
@@ -3258,7 +3255,7 @@ void igb_update_stats(struct igb_adapter *adapter) | |||
3258 | /* Phy Stats */ | 3255 | /* Phy Stats */ |
3259 | if (hw->phy.media_type == e1000_media_type_copper) { | 3256 | if (hw->phy.media_type == e1000_media_type_copper) { |
3260 | if ((adapter->link_speed == SPEED_1000) && | 3257 | if ((adapter->link_speed == SPEED_1000) && |
3261 | (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, | 3258 | (!igb_read_phy_reg(hw, PHY_1000T_STATUS, |
3262 | &phy_tmp))) { | 3259 | &phy_tmp))) { |
3263 | phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; | 3260 | phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; |
3264 | adapter->phy_stats.idle_errors += phy_tmp; | 3261 | adapter->phy_stats.idle_errors += phy_tmp; |
@@ -4111,9 +4108,8 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | |||
4111 | case SIOCGMIIREG: | 4108 | case SIOCGMIIREG: |
4112 | if (!capable(CAP_NET_ADMIN)) | 4109 | if (!capable(CAP_NET_ADMIN)) |
4113 | return -EPERM; | 4110 | return -EPERM; |
4114 | if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw, | 4111 | if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, |
4115 | data->reg_num | 4112 | &data->val_out)) |
4116 | & 0x1F, &data->val_out)) | ||
4117 | return -EIO; | 4113 | return -EIO; |
4118 | break; | 4114 | break; |
4119 | case SIOCSMIIREG: | 4115 | case SIOCSMIIREG: |