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>
This commit is contained in:
committed by
David S. Miller
parent
21fc578dca
commit
f5f4cf0846
@@ -332,4 +332,36 @@ extern void igb_free_rx_resources(struct igb_ring *);
|
|||||||
extern void igb_update_stats(struct igb_adapter *);
|
extern void igb_update_stats(struct igb_adapter *);
|
||||||
extern void igb_set_ethtool_ops(struct net_device *);
|
extern void igb_set_ethtool_ops(struct net_device *);
|
||||||
|
|
||||||
|
static inline s32 igb_reset_phy(struct e1000_hw *hw)
|
||||||
|
{
|
||||||
|
if (hw->phy.ops.reset_phy)
|
||||||
|
return hw->phy.ops.reset_phy(hw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
|
||||||
|
{
|
||||||
|
if (hw->phy.ops.read_phy_reg)
|
||||||
|
return hw->phy.ops.read_phy_reg(hw, offset, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
|
||||||
|
{
|
||||||
|
if (hw->phy.ops.write_phy_reg)
|
||||||
|
return hw->phy.ops.write_phy_reg(hw, offset, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline s32 igb_get_phy_info(struct e1000_hw *hw)
|
||||||
|
{
|
||||||
|
if (hw->phy.ops.get_phy_info)
|
||||||
|
return hw->phy.ops.get_phy_info(hw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _IGB_H_ */
|
#endif /* _IGB_H_ */
|
||||||
|
@@ -1376,10 +1376,10 @@ static void igb_phy_disable_receiver(struct igb_adapter *adapter)
|
|||||||
struct e1000_hw *hw = &adapter->hw;
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
|
|
||||||
/* Write out to PHY registers 29 and 30 to disable the Receiver. */
|
/* Write out to PHY registers 29 and 30 to disable the Receiver. */
|
||||||
hw->phy.ops.write_phy_reg(hw, 29, 0x001F);
|
igb_write_phy_reg(hw, 29, 0x001F);
|
||||||
hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC);
|
igb_write_phy_reg(hw, 30, 0x8FFC);
|
||||||
hw->phy.ops.write_phy_reg(hw, 29, 0x001A);
|
igb_write_phy_reg(hw, 29, 0x001A);
|
||||||
hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0);
|
igb_write_phy_reg(hw, 30, 0x8FF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
|
static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
|
||||||
@@ -1392,17 +1392,17 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
|
|||||||
|
|
||||||
if (hw->phy.type == e1000_phy_m88) {
|
if (hw->phy.type == e1000_phy_m88) {
|
||||||
/* Auto-MDI/MDIX Off */
|
/* Auto-MDI/MDIX Off */
|
||||||
hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
|
igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
|
||||||
/* reset to update Auto-MDI/MDIX */
|
/* reset to update Auto-MDI/MDIX */
|
||||||
hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140);
|
igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);
|
||||||
/* autoneg off */
|
/* autoneg off */
|
||||||
hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140);
|
igb_write_phy_reg(hw, PHY_CONTROL, 0x8140);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl_reg = rd32(E1000_CTRL);
|
ctrl_reg = rd32(E1000_CTRL);
|
||||||
|
|
||||||
/* force 1000, set loopback */
|
/* force 1000, set loopback */
|
||||||
hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140);
|
igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
|
||||||
|
|
||||||
/* Now set up the MAC to the same speed/duplex as the PHY. */
|
/* Now set up the MAC to the same speed/duplex as the PHY. */
|
||||||
ctrl_reg = rd32(E1000_CTRL);
|
ctrl_reg = rd32(E1000_CTRL);
|
||||||
@@ -1496,10 +1496,10 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter)
|
|||||||
wr32(E1000_RCTL, rctl);
|
wr32(E1000_RCTL, rctl);
|
||||||
|
|
||||||
hw->mac.autoneg = true;
|
hw->mac.autoneg = true;
|
||||||
hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg);
|
igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg);
|
||||||
if (phy_reg & MII_CR_LOOPBACK) {
|
if (phy_reg & MII_CR_LOOPBACK) {
|
||||||
phy_reg &= ~MII_CR_LOOPBACK;
|
phy_reg &= ~MII_CR_LOOPBACK;
|
||||||
hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg);
|
igb_write_phy_reg(hw, PHY_CONTROL, phy_reg);
|
||||||
igb_phy_sw_reset(hw);
|
igb_phy_sw_reset(hw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -931,8 +931,7 @@ void igb_reset(struct igb_adapter *adapter)
|
|||||||
wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
|
wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
|
||||||
|
|
||||||
igb_reset_adaptive(&adapter->hw);
|
igb_reset_adaptive(&adapter->hw);
|
||||||
if (adapter->hw.phy.ops.get_phy_info)
|
igb_get_phy_info(&adapter->hw);
|
||||||
adapter->hw.phy.ops.get_phy_info(&adapter->hw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1305,7 +1304,7 @@ err_register:
|
|||||||
igb_release_hw_control(adapter);
|
igb_release_hw_control(adapter);
|
||||||
err_eeprom:
|
err_eeprom:
|
||||||
if (!igb_check_reset_block(hw))
|
if (!igb_check_reset_block(hw))
|
||||||
hw->phy.ops.reset_phy(hw);
|
igb_reset_phy(hw);
|
||||||
|
|
||||||
if (hw->flash_address)
|
if (hw->flash_address)
|
||||||
iounmap(hw->flash_address);
|
iounmap(hw->flash_address);
|
||||||
@@ -1365,9 +1364,8 @@ static void __devexit igb_remove(struct pci_dev *pdev)
|
|||||||
|
|
||||||
unregister_netdev(netdev);
|
unregister_netdev(netdev);
|
||||||
|
|
||||||
if (adapter->hw.phy.ops.reset_phy &&
|
if (!igb_check_reset_block(&adapter->hw))
|
||||||
!igb_check_reset_block(&adapter->hw))
|
igb_reset_phy(&adapter->hw);
|
||||||
adapter->hw.phy.ops.reset_phy(&adapter->hw);
|
|
||||||
|
|
||||||
igb_remove_device(&adapter->hw);
|
igb_remove_device(&adapter->hw);
|
||||||
igb_reset_interrupt_capability(adapter);
|
igb_reset_interrupt_capability(adapter);
|
||||||
@@ -2283,8 +2281,7 @@ static void igb_set_multi(struct net_device *netdev)
|
|||||||
static void igb_update_phy_info(unsigned long data)
|
static void igb_update_phy_info(unsigned long data)
|
||||||
{
|
{
|
||||||
struct igb_adapter *adapter = (struct igb_adapter *) data;
|
struct igb_adapter *adapter = (struct igb_adapter *) data;
|
||||||
if (adapter->hw.phy.ops.get_phy_info)
|
igb_get_phy_info(&adapter->hw);
|
||||||
adapter->hw.phy.ops.get_phy_info(&adapter->hw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3258,7 +3255,7 @@ void igb_update_stats(struct igb_adapter *adapter)
|
|||||||
/* Phy Stats */
|
/* Phy Stats */
|
||||||
if (hw->phy.media_type == e1000_media_type_copper) {
|
if (hw->phy.media_type == e1000_media_type_copper) {
|
||||||
if ((adapter->link_speed == SPEED_1000) &&
|
if ((adapter->link_speed == SPEED_1000) &&
|
||||||
(!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
|
(!igb_read_phy_reg(hw, PHY_1000T_STATUS,
|
||||||
&phy_tmp))) {
|
&phy_tmp))) {
|
||||||
phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
|
phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
|
||||||
adapter->phy_stats.idle_errors += phy_tmp;
|
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)
|
|||||||
case SIOCGMIIREG:
|
case SIOCGMIIREG:
|
||||||
if (!capable(CAP_NET_ADMIN))
|
if (!capable(CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw,
|
if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
|
||||||
data->reg_num
|
&data->val_out))
|
||||||
& 0x1F, &data->val_out))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
break;
|
break;
|
||||||
case SIOCSMIIREG:
|
case SIOCSMIIREG:
|
||||||
|
Reference in New Issue
Block a user