Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5f4cf08 authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller
Browse files

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: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 21fc578d
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -332,4 +332,36 @@ extern void igb_free_rx_resources(struct igb_ring *);
extern void igb_update_stats(struct igb_adapter *);
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_ */
+10 −10
Original line number Diff line number Diff line
@@ -1376,10 +1376,10 @@ static void igb_phy_disable_receiver(struct igb_adapter *adapter)
	struct e1000_hw *hw = &adapter->hw;

	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
	hw->phy.ops.write_phy_reg(hw, 29, 0x001F);
	hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC);
	hw->phy.ops.write_phy_reg(hw, 29, 0x001A);
	hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0);
	igb_write_phy_reg(hw, 29, 0x001F);
	igb_write_phy_reg(hw, 30, 0x8FFC);
	igb_write_phy_reg(hw, 29, 0x001A);
	igb_write_phy_reg(hw, 30, 0x8FF0);
}

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) {
		/* 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 */
		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140);
		igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);
		/* 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);

	/* 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. */
	ctrl_reg = rd32(E1000_CTRL);
@@ -1496,10 +1496,10 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter)
	wr32(E1000_RCTL, rctl);

	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) {
		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);
	}
}
+8 −12
Original line number Diff line number Diff line
@@ -931,8 +931,7 @@ void igb_reset(struct igb_adapter *adapter)
	wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);

	igb_reset_adaptive(&adapter->hw);
	if (adapter->hw.phy.ops.get_phy_info)
		adapter->hw.phy.ops.get_phy_info(&adapter->hw);
	igb_get_phy_info(&adapter->hw);
}

/**
@@ -1305,7 +1304,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
	igb_release_hw_control(adapter);
err_eeprom:
	if (!igb_check_reset_block(hw))
		hw->phy.ops.reset_phy(hw);
		igb_reset_phy(hw);

	if (hw->flash_address)
		iounmap(hw->flash_address);
@@ -1365,9 +1364,8 @@ static void __devexit igb_remove(struct pci_dev *pdev)

	unregister_netdev(netdev);

	if (adapter->hw.phy.ops.reset_phy &&
	    !igb_check_reset_block(&adapter->hw))
		adapter->hw.phy.ops.reset_phy(&adapter->hw);
	if (!igb_check_reset_block(&adapter->hw))
		igb_reset_phy(&adapter->hw);

	igb_remove_device(&adapter->hw);
	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)
{
	struct igb_adapter *adapter = (struct igb_adapter *) data;
	if (adapter->hw.phy.ops.get_phy_info)
		adapter->hw.phy.ops.get_phy_info(&adapter->hw);
	igb_get_phy_info(&adapter->hw);
}

/**
@@ -3258,7 +3255,7 @@ void igb_update_stats(struct igb_adapter *adapter)
	/* Phy Stats */
	if (hw->phy.media_type == e1000_media_type_copper) {
		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_IDLE_ERROR_COUNT_MASK;
			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:
		if (!capable(CAP_NET_ADMIN))
			return -EPERM;
		if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw,
						     data->reg_num
						     & 0x1F, &data->val_out))
		if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
		                     &data->val_out))
			return -EIO;
		break;
	case SIOCSMIIREG: