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

Commit b3eb4e18 authored by Mark Rustad's avatar Mark Rustad Committed by Jeff Kirsher
Browse files

ixgbe: Implement support for firmware-controlled PHYs



Implement support for devices that have firmware-controlled PHYs.

Signed-off-by: default avatarMark Rustad <mark.d.rustad@intel.com>
Tested-by: default avatarKrishneil Singh <krishneil.k.singh@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 12c78ef0
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -661,6 +661,8 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_PHY_INTERRUPT		BIT(11)
#define IXGBE_FLAG2_UDP_TUN_REREG_NEEDED	BIT(12)
#define IXGBE_FLAG2_VLAN_PROMISC		BIT(13)
#define IXGBE_FLAG2_EEE_CAPABLE			BIT(14)
#define IXGBE_FLAG2_EEE_ENABLED			BIT(15)

	/* Tx fast path data */
	int num_tx_queues;
@@ -862,6 +864,7 @@ enum ixgbe_boards {
	board_X550,
	board_X550EM_x,
	board_x550em_a,
	board_x550em_a_fw,
};

extern const struct ixgbe_info ixgbe_82598_info;
@@ -870,6 +873,7 @@ extern const struct ixgbe_info ixgbe_X540_info;
extern const struct ixgbe_info ixgbe_X550_info;
extern const struct ixgbe_info ixgbe_X550EM_x_info;
extern const struct ixgbe_info ixgbe_x550em_a_info;
extern const struct ixgbe_info ixgbe_x550em_a_fw_info;
#ifdef CONFIG_IXGBE_DCB
extern const struct dcbnl_rtnl_ops dcbnl_ops;
#endif
+9 −0
Original line number Diff line number Diff line
@@ -100,6 +100,8 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
		case IXGBE_DEV_ID_X550T1:
		case IXGBE_DEV_ID_X550EM_X_10G_T:
		case IXGBE_DEV_ID_X550EM_A_10G_T:
		case IXGBE_DEV_ID_X550EM_A_1G_T:
		case IXGBE_DEV_ID_X550EM_A_1G_T_L:
			supported = true;
			break;
		default:
@@ -3382,6 +3384,13 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
		else
			*speed = IXGBE_LINK_SPEED_100_FULL;
		break;
	case IXGBE_LINKS_SPEED_10_X550EM_A:
		*speed = IXGBE_LINK_SPEED_UNKNOWN;
		if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T ||
		    hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) {
			*speed = IXGBE_LINK_SPEED_10_FULL;
		}
		break;
	default:
		*speed = IXGBE_LINK_SPEED_UNKNOWN;
	}
+150 −3
Original line number Diff line number Diff line
@@ -197,15 +197,17 @@ static int ixgbe_get_settings(struct net_device *netdev,
				   SUPPORTED_1000baseKX_Full :
				   SUPPORTED_1000baseT_Full;
	if (supported_link & IXGBE_LINK_SPEED_100_FULL)
		ecmd->supported |= ixgbe_isbackplane(hw->phy.media_type) ?
				   SUPPORTED_1000baseKX_Full :
				   SUPPORTED_100baseT_Full;
		ecmd->supported |= SUPPORTED_100baseT_Full;
	if (supported_link & IXGBE_LINK_SPEED_10_FULL)
		ecmd->supported |= SUPPORTED_10baseT_Full;

	/* default advertised speed if phy.autoneg_advertised isn't set */
	ecmd->advertising = ecmd->supported;
	/* set the advertised speeds */
	if (hw->phy.autoneg_advertised) {
		ecmd->advertising = 0;
		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL)
			ecmd->advertising |= ADVERTISED_10baseT_Full;
		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
			ecmd->advertising |= ADVERTISED_100baseT_Full;
		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
@@ -237,6 +239,7 @@ static int ixgbe_get_settings(struct net_device *netdev,
	case ixgbe_phy_tn:
	case ixgbe_phy_aq:
	case ixgbe_phy_x550em_ext_t:
	case ixgbe_phy_fw:
	case ixgbe_phy_cu_unknown:
		ecmd->supported |= SUPPORTED_TP;
		ecmd->advertising |= ADVERTISED_TP;
@@ -346,6 +349,9 @@ static int ixgbe_get_settings(struct net_device *netdev,
		case IXGBE_LINK_SPEED_100_FULL:
			ethtool_cmd_speed_set(ecmd, SPEED_100);
			break;
		case IXGBE_LINK_SPEED_10_FULL:
			ethtool_cmd_speed_set(ecmd, SPEED_10);
			break;
		default:
			break;
		}
@@ -394,6 +400,9 @@ static int ixgbe_set_settings(struct net_device *netdev,
		if (ecmd->advertising & ADVERTISED_100baseT_Full)
			advertised |= IXGBE_LINK_SPEED_100_FULL;

		if (ecmd->advertising & ADVERTISED_10baseT_Full)
			advertised |= IXGBE_LINK_SPEED_10_FULL;

		if (old == advertised)
			return err;
		/* this sets the link speed and restarts auto-neg */
@@ -3173,6 +3182,9 @@ static int ixgbe_get_module_info(struct net_device *dev,
	u8 sff8472_rev, addr_mode;
	bool page_swap = false;

	if (hw->phy.type == ixgbe_phy_fw)
		return -ENXIO;

	/* Check whether we support SFF-8472 or not */
	status = hw->phy.ops.read_i2c_eeprom(hw,
					     IXGBE_SFF_SFF_8472_COMP,
@@ -3218,6 +3230,9 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
	if (ee->len == 0)
		return -EINVAL;

	if (hw->phy.type == ixgbe_phy_fw)
		return -ENXIO;

	for (i = ee->offset; i < ee->offset + ee->len; i++) {
		/* I2C reads can take long time */
		if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
@@ -3237,6 +3252,136 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
	return 0;
}

static const struct {
	ixgbe_link_speed mac_speed;
	u32 supported;
} ixgbe_ls_map[] = {
	{ IXGBE_LINK_SPEED_10_FULL, SUPPORTED_10baseT_Full },
	{ IXGBE_LINK_SPEED_100_FULL, SUPPORTED_100baseT_Full },
	{ IXGBE_LINK_SPEED_1GB_FULL, SUPPORTED_1000baseT_Full },
	{ IXGBE_LINK_SPEED_2_5GB_FULL, SUPPORTED_2500baseX_Full },
	{ IXGBE_LINK_SPEED_10GB_FULL, SUPPORTED_10000baseT_Full },
};

static const struct {
	u32 lp_advertised;
	u32 mac_speed;
} ixgbe_lp_map[] = {
	{ FW_PHY_ACT_UD_2_100M_TX_EEE, SUPPORTED_100baseT_Full },
	{ FW_PHY_ACT_UD_2_1G_T_EEE, SUPPORTED_1000baseT_Full },
	{ FW_PHY_ACT_UD_2_10G_T_EEE, SUPPORTED_10000baseT_Full },
	{ FW_PHY_ACT_UD_2_1G_KX_EEE, SUPPORTED_1000baseKX_Full },
	{ FW_PHY_ACT_UD_2_10G_KX4_EEE, SUPPORTED_10000baseKX4_Full },
	{ FW_PHY_ACT_UD_2_10G_KR_EEE, SUPPORTED_10000baseKR_Full},
};

static int
ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata)
{
	u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
	struct ixgbe_hw *hw = &adapter->hw;
	s32 rc;
	u16 i;

	rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_UD_2, &info);
	if (rc)
		return rc;

	edata->lp_advertised = 0;
	for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) {
		if (info[0] & ixgbe_lp_map[i].lp_advertised)
			edata->lp_advertised |= ixgbe_lp_map[i].mac_speed;
	}

	edata->supported = 0;
	for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) {
		if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed)
			edata->supported |= ixgbe_ls_map[i].supported;
	}

	edata->advertised = 0;
	for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) {
		if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed)
			edata->advertised |= ixgbe_ls_map[i].supported;
	}

	edata->eee_enabled = !!edata->advertised;
	edata->tx_lpi_enabled = edata->eee_enabled;
	if (edata->advertised & edata->lp_advertised)
		edata->eee_active = true;

	return 0;
}

static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
	struct ixgbe_adapter *adapter = netdev_priv(netdev);
	struct ixgbe_hw *hw = &adapter->hw;

	if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
		return -EOPNOTSUPP;

	if (hw->phy.eee_speeds_supported && hw->phy.type == ixgbe_phy_fw)
		return ixgbe_get_eee_fw(adapter, edata);

	return -EOPNOTSUPP;
}

static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
	struct ixgbe_adapter *adapter = netdev_priv(netdev);
	struct ixgbe_hw *hw = &adapter->hw;
	struct ethtool_eee eee_data;
	s32 ret_val;

	if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE))
		return -EOPNOTSUPP;

	memset(&eee_data, 0, sizeof(struct ethtool_eee));

	ret_val = ixgbe_get_eee(netdev, &eee_data);
	if (ret_val)
		return ret_val;

	if (eee_data.eee_enabled && !edata->eee_enabled) {
		if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) {
			e_err(drv, "Setting EEE tx-lpi is not supported\n");
			return -EINVAL;
		}

		if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) {
			e_err(drv,
			      "Setting EEE Tx LPI timer is not supported\n");
			return -EINVAL;
		}

		if (eee_data.advertised != edata->advertised) {
			e_err(drv,
			      "Setting EEE advertised speeds is not supported\n");
			return -EINVAL;
		}
	}

	if (eee_data.eee_enabled != edata->eee_enabled) {
		if (edata->eee_enabled) {
			adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
			hw->phy.eee_speeds_advertised =
						   hw->phy.eee_speeds_supported;
		} else {
			adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
			hw->phy.eee_speeds_advertised = 0;
		}

		/* reset link */
		if (netif_running(netdev))
			ixgbe_reinit_locked(adapter);
		else
			ixgbe_reset(adapter);
	}

	return 0;
}

static const struct ethtool_ops ixgbe_ethtool_ops = {
	.get_settings           = ixgbe_get_settings,
	.set_settings           = ixgbe_set_settings,
@@ -3269,6 +3414,8 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
	.get_rxfh_key_size	= ixgbe_get_rxfh_key_size,
	.get_rxfh		= ixgbe_get_rxfh,
	.set_rxfh		= ixgbe_set_rxfh,
	.get_eee		= ixgbe_get_eee,
	.set_eee		= ixgbe_set_eee,
	.get_channels		= ixgbe_get_channels,
	.set_channels		= ixgbe_set_channels,
	.get_ts_info		= ixgbe_get_ts_info,
+64 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
	[board_X550]		= &ixgbe_X550_info,
	[board_X550EM_x]	= &ixgbe_X550EM_x_info,
	[board_x550em_a]	= &ixgbe_x550em_a_info,
	[board_x550em_a_fw]	= &ixgbe_x550em_a_fw_info,
};

/* ixgbe_pci_tbl - PCI Device ID Table
@@ -140,6 +141,8 @@ static const struct pci_device_id ixgbe_pci_tbl[] = {
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII_L), board_x550em_a },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_10G_T), board_x550em_a},
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), board_x550em_a },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T), board_x550em_a_fw },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L), board_x550em_a_fw },
	/* required last entry */
	{0, }
};
@@ -180,6 +183,7 @@ MODULE_VERSION(DRV_VERSION);
static struct workqueue_struct *ixgbe_wq;

static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *);

static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
					  u32 reg, u16 *value)
@@ -2447,6 +2451,7 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
{
	struct ixgbe_hw *hw = &adapter->hw;
	u32 eicr = adapter->interrupt_event;
	s32 rc;

	if (test_bit(__IXGBE_DOWN, &adapter->state))
		return;
@@ -2485,6 +2490,12 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
			return;

		break;
	case IXGBE_DEV_ID_X550EM_A_1G_T:
	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
		rc = hw->phy.ops.check_overtemp(hw);
		if (rc != IXGBE_ERR_OVERTEMP)
			return;
		break;
	default:
		if (adapter->hw.mac.type >= ixgbe_mac_X540)
			return;
@@ -2531,6 +2542,18 @@ static void ixgbe_check_overtemp_event(struct ixgbe_adapter *adapter, u32 eicr)
			return;
		}
		return;
	case ixgbe_mac_x550em_a:
		if (eicr & IXGBE_EICR_GPI_SDP0_X550EM_a) {
			adapter->interrupt_event = eicr;
			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
			ixgbe_service_event_schedule(adapter);
			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
					IXGBE_EICR_GPI_SDP0_X550EM_a);
			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICR,
					IXGBE_EICR_GPI_SDP0_X550EM_a);
		}
		return;
	case ixgbe_mac_X550:
	case ixgbe_mac_X540:
		if (!(eicr & IXGBE_EICR_TS))
			return;
@@ -5294,6 +5317,8 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)

	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
		usleep_range(1000, 2000);
	if (adapter->hw.phy.type == ixgbe_phy_fw)
		ixgbe_watchdog_link_is_down(adapter);
	ixgbe_down(adapter);
	/*
	 * If SR-IOV enabled then wait a bit before bringing the adapter
@@ -5553,6 +5578,31 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
	ixgbe_clean_all_rx_rings(adapter);
}

/**
 * ixgbe_eee_capable - helper function to determine EEE support on X550
 * @adapter: board private structure
 */
static void ixgbe_set_eee_capable(struct ixgbe_adapter *adapter)
{
	struct ixgbe_hw *hw = &adapter->hw;

	switch (hw->device_id) {
	case IXGBE_DEV_ID_X550EM_A_1G_T:
	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
		if (!hw->phy.eee_speeds_supported)
			break;
		adapter->flags2 |= IXGBE_FLAG2_EEE_CAPABLE;
		if (!hw->phy.eee_speeds_advertised)
			break;
		adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
		break;
	default:
		adapter->flags2 &= ~IXGBE_FLAG2_EEE_CAPABLE;
		adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
		break;
	}
}

/**
 * ixgbe_tx_timeout - Respond to a Tx Hang
 * @netdev: network interface device structure
@@ -5717,6 +5767,14 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
		break;
	case ixgbe_mac_x550em_a:
		adapter->flags |= IXGBE_FLAG_GENEVE_OFFLOAD_CAPABLE;
		switch (hw->device_id) {
		case IXGBE_DEV_ID_X550EM_A_1G_T:
		case IXGBE_DEV_ID_X550EM_A_1G_T_L:
			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
			break;
		default:
			break;
		}
	/* fall through */
	case ixgbe_mac_X550EM_x:
#ifdef CONFIG_IXGBE_DCB
@@ -5730,6 +5788,8 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
#endif /* IXGBE_FCOE */
	/* Fall Through */
	case ixgbe_mac_X550:
		if (hw->mac.type == ixgbe_mac_X550)
			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
#ifdef CONFIG_IXGBE_DCA
		adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE;
#endif
@@ -6807,6 +6867,9 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
	case IXGBE_LINK_SPEED_100_FULL:
		speed_str = "100 Mbps";
		break;
	case IXGBE_LINK_SPEED_10_FULL:
		speed_str = "10 Mbps";
		break;
	default:
		speed_str = "unknown speed";
		break;
@@ -9595,6 +9658,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	hw->phy.reset_if_overtemp = true;
	err = hw->mac.ops.reset_hw(hw);
	hw->phy.reset_if_overtemp = false;
	ixgbe_set_eee_capable(adapter);
	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
		err = 0;
	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+3 −0
Original line number Diff line number Diff line
@@ -784,6 +784,9 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
	if (speed & IXGBE_LINK_SPEED_100_FULL)
		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;

	if (speed & IXGBE_LINK_SPEED_10_FULL)
		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL;

	/* Setup link based on the new speed settings */
	hw->phy.ops.setup_link(hw);

Loading