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

Commit c6d45171 authored by KY Srinivasan's avatar KY Srinivasan Committed by Jeff Kirsher
Browse files

ixgbevf: Support Windows hosts (Hyper-V)



On Hyper-V, the VF/PF communication is a via software mediated path
as opposed to the hardware mailbox. Make the necessary
adjustments to support Hyper-V.

Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b4363fbd
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -450,9 +450,13 @@ enum ixbgevf_state_t {

enum ixgbevf_boards {
	board_82599_vf,
	board_82599_vf_hv,
	board_X540_vf,
	board_X540_vf_hv,
	board_X550_vf,
	board_X550_vf_hv,
	board_X550EM_x_vf,
	board_X550EM_x_vf_hv,
};

enum ixgbevf_xcast_modes {
@@ -467,6 +471,12 @@ extern const struct ixgbevf_info ixgbevf_X550_vf_info;
extern const struct ixgbevf_info ixgbevf_X550EM_x_vf_info;
extern const struct ixgbe_mbx_operations ixgbevf_mbx_ops;

extern const struct ixgbevf_info ixgbevf_82599_vf_hv_info;
extern const struct ixgbevf_info ixgbevf_X540_vf_hv_info;
extern const struct ixgbevf_info ixgbevf_X550_vf_hv_info;
extern const struct ixgbevf_info ixgbevf_X550EM_x_vf_hv_info;
extern const struct ixgbe_mbx_operations ixgbevf_hv_mbx_ops;

/* needed by ethtool.c */
extern const char ixgbevf_driver_name[];
extern const char ixgbevf_driver_version[];
@@ -484,6 +494,7 @@ void ixgbevf_free_rx_resources(struct ixgbevf_ring *);
void ixgbevf_free_tx_resources(struct ixgbevf_ring *);
void ixgbevf_update_stats(struct ixgbevf_adapter *adapter);
int ethtool_ioctl(struct ifreq *ifr);
bool ixgbevf_on_hyperv(struct ixgbe_hw *hw);

extern void ixgbevf_write_eitr(struct ixgbevf_q_vector *q_vector);

+24 −7
Original line number Diff line number Diff line
@@ -63,9 +63,13 @@ static char ixgbevf_copyright[] =

static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
	[board_82599_vf]	= &ixgbevf_82599_vf_info,
	[board_82599_vf_hv]	= &ixgbevf_82599_vf_hv_info,
	[board_X540_vf]		= &ixgbevf_X540_vf_info,
	[board_X540_vf_hv]	= &ixgbevf_X540_vf_hv_info,
	[board_X550_vf]		= &ixgbevf_X550_vf_info,
	[board_X550_vf_hv]	= &ixgbevf_X550_vf_hv_info,
	[board_X550EM_x_vf]	= &ixgbevf_X550EM_x_vf_info,
	[board_X550EM_x_vf_hv]	= &ixgbevf_X550EM_x_vf_hv_info,
};

/* ixgbevf_pci_tbl - PCI Device ID Table
@@ -78,9 +82,13 @@ static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
 */
static const struct pci_device_id ixgbevf_pci_tbl[] = {
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF), board_82599_vf },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF_HV), board_82599_vf_hv },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF), board_X540_vf },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF_HV), board_X540_vf_hv },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF), board_X550_vf },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550_VF_HV), board_X550_vf_hv },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF), board_X550EM_x_vf },
	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_VF_HV), board_X550EM_x_vf_hv},
	/* required last entry */
	{0, }
};
@@ -1795,7 +1803,10 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)
		ixgbevf_setup_vfmrqc(adapter);

	/* notify the PF of our intent to use this size of frame */
	if (!ixgbevf_on_hyperv(hw))
		ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
	else
		ixgbevf_hv_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);

	/* Setup the HW Rx Head and Tail Descriptor Pointers and
	 * the Base and Length of the Rx Descriptor Ring
@@ -2056,7 +2067,10 @@ static void ixgbevf_negotiate_api(struct ixgbevf_adapter *adapter)
	spin_lock_bh(&adapter->mbx_lock);

	while (api[idx] != ixgbe_mbox_api_unknown) {
		if (!ixgbevf_on_hyperv(hw))
			err = hw->mac.ops.negotiate_api_version(hw, api[idx]);
		else
			err = ixgbevf_hv_negotiate_api_version(hw, api[idx]);
		if (!err)
			break;
		idx++;
@@ -3740,7 +3754,10 @@ static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu)
	netdev->mtu = new_mtu;

	/* notify the PF of our intent to use this size of frame */
	if (!ixgbevf_on_hyperv(hw))
		ixgbevf_rlpml_set_vf(hw, max_frame);
	else
		ixgbevf_hv_rlpml_set_vf(hw, max_frame);

	return 0;
}
+11 −0
Original line number Diff line number Diff line
@@ -346,3 +346,14 @@ const struct ixgbe_mbx_operations ixgbevf_mbx_ops = {
	.check_for_rst	= ixgbevf_check_for_rst_vf,
};

/* Mailbox operations when running on Hyper-V.
 * On Hyper-V, PF/VF communication is not through the
 * hardware mailbox; this communication is through
 * a software mediated path.
 * Most mail box operations are noop while running on
 * Hyper-V.
 */
const struct ixgbe_mbx_operations ixgbevf_hv_mbx_ops = {
	.init_params	= ixgbevf_init_mbx_params_vf,
	.check_for_rst	= ixgbevf_check_for_rst_vf,
};
+215 −0
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@
#include "vf.h"
#include "ixgbevf.h"

/* On Hyper-V, to reset, we need to read from this offset
 * from the PCI config space. This is the mechanism used on
 * Hyper-V to support PF/VF communication.
 */
#define IXGBE_HV_RESET_OFFSET           0x201

/**
 *  ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx
 *  @hw: pointer to hardware structure
@@ -125,6 +131,27 @@ static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
	return 0;
}

/**
 * Hyper-V variant; the VF/PF communication is through the PCI
 * config space.
 */
static s32 ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
{
#if IS_ENABLED(CONFIG_PCI_MMCONFIG)
	struct ixgbevf_adapter *adapter = hw->back;
	int i;

	for (i = 0; i < 6; i++)
		pci_read_config_byte(adapter->pdev,
				     (i + IXGBE_HV_RESET_OFFSET),
				     &hw->mac.perm_addr[i]);
	return 0;
#else
	pr_err("PCI_MMCONFIG needs to be enabled for Hyper-V\n");
	return -EOPNOTSUPP;
#endif
}

/**
 *  ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
 *  @hw: pointer to hardware structure
@@ -258,6 +285,11 @@ static s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
	return ret_val;
}

static s32 ixgbevf_hv_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
{
	return -EOPNOTSUPP;
}

/**
 * ixgbevf_get_reta_locked - get the RSS redirection table (RETA) contents.
 * @adapter: pointer to the port handle
@@ -416,6 +448,26 @@ static s32 ixgbevf_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
	return ret_val;
}

/**
 *  ixgbevf_hv_set_rar_vf - set device MAC address Hyper-V variant
 *  @hw: pointer to hardware structure
 *  @index: Receive address register to write
 *  @addr: Address to put into receive address register
 *  @vmdq: Unused in this implementation
 *
 * We don't really allow setting the device MAC address. However,
 * if the address being set is the permanent MAC address we will
 * permit that.
 **/
static s32 ixgbevf_hv_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
				 u32 vmdq)
{
	if (ether_addr_equal(addr, hw->mac.perm_addr))
		return 0;

	return -EOPNOTSUPP;
}

static void ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw,
				       u32 *msg, u16 size)
{
@@ -472,6 +524,15 @@ static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw,
	return 0;
}

/**
 * Hyper-V variant - just a stub.
 */
static s32 ixgbevf_hv_update_mc_addr_list_vf(struct ixgbe_hw *hw,
					     struct net_device *netdev)
{
	return -EOPNOTSUPP;
}

/**
 *  ixgbevf_update_xcast_mode - Update Multicast mode
 *  @hw: pointer to the HW structure
@@ -512,6 +573,16 @@ static s32 ixgbevf_update_xcast_mode(struct ixgbe_hw *hw,
	return 0;
}

/**
 * Hyper-V variant - just a stub.
 */
static s32 ixgbevf_hv_update_xcast_mode(struct ixgbe_hw *hw,
					struct net_device *netdev,
					int xcast_mode)
{
	return -EOPNOTSUPP;
}

/**
 *  ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
 *  @hw: pointer to the HW structure
@@ -550,6 +621,15 @@ static s32 ixgbevf_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
	return err;
}

/**
 * Hyper-V variant - just a stub.
 */
static s32 ixgbevf_hv_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
				  bool vlan_on)
{
	return -EOPNOTSUPP;
}

/**
 *  ixgbevf_setup_mac_link_vf - Setup MAC link settings
 *  @hw: pointer to hardware structure
@@ -655,6 +735,67 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
	return ret_val;
}

/**
 * Hyper-V variant; there is no mailbox communication.
 */
static s32 ixgbevf_hv_check_mac_link_vf(struct ixgbe_hw *hw,
					ixgbe_link_speed *speed,
					bool *link_up,
					bool autoneg_wait_to_complete)
{
	struct ixgbe_mbx_info *mbx = &hw->mbx;
	struct ixgbe_mac_info *mac = &hw->mac;
	u32 links_reg;

	/* If we were hit with a reset drop the link */
	if (!mbx->ops.check_for_rst(hw) || !mbx->timeout)
		mac->get_link_status = true;

	if (!mac->get_link_status)
		goto out;

	/* if link status is down no point in checking to see if pf is up */
	links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
	if (!(links_reg & IXGBE_LINKS_UP))
		goto out;

	/* for SFP+ modules and DA cables on 82599 it can take up to 500usecs
	 * before the link status is correct
	 */
	if (mac->type == ixgbe_mac_82599_vf) {
		int i;

		for (i = 0; i < 5; i++) {
			udelay(100);
			links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);

			if (!(links_reg & IXGBE_LINKS_UP))
				goto out;
		}
	}

	switch (links_reg & IXGBE_LINKS_SPEED_82599) {
	case IXGBE_LINKS_SPEED_10G_82599:
		*speed = IXGBE_LINK_SPEED_10GB_FULL;
		break;
	case IXGBE_LINKS_SPEED_1G_82599:
		*speed = IXGBE_LINK_SPEED_1GB_FULL;
		break;
	case IXGBE_LINKS_SPEED_100_82599:
		*speed = IXGBE_LINK_SPEED_100_FULL;
		break;
	}

	/* if we passed all the tests above then the link is up and we no
	 * longer need to check for link
	 */
	mac->get_link_status = false;

out:
	*link_up = !mac->get_link_status;
	return 0;
}

/**
 *  ixgbevf_rlpml_set_vf - Set the maximum receive packet length
 *  @hw: pointer to the HW structure
@@ -669,6 +810,25 @@ void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size)
	ixgbevf_write_msg_read_ack(hw, msgbuf, 2);
}

/**
 * ixgbevf_hv_rlpml_set_vf - Set the maximum receive packet length
 * @hw: pointer to the HW structure
 * @max_size: value to assign to max frame size
 * Hyper-V variant.
 **/
void ixgbevf_hv_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size)
{
	u32 reg;

	/* If we are on Hyper-V, we implement this functionality
	 * differently.
	 */
	reg =  IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(0));
	/* CRC == 4 */
	reg |= ((max_size + 4) | IXGBE_RXDCTL_RLPML_EN);
	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(0), reg);
}

/**
 *  ixgbevf_negotiate_api_version_vf - Negotiate supported API version
 *  @hw: pointer to the HW structure
@@ -703,6 +863,21 @@ static int ixgbevf_negotiate_api_version_vf(struct ixgbe_hw *hw, int api)
	return err;
}

/**
 *  ixgbevf_hv_negotiate_api_version - Negotiate supported API version
 *  @hw: pointer to the HW structure
 *  @api: integer containing requested API version
 *  Hyper-V version - only ixgbe_mbox_api_10 supported.
 **/
int ixgbevf_hv_negotiate_api_version(struct ixgbe_hw *hw, int api)
{
	/* Hyper-V only supports api version ixgbe_mbox_api_10 */
	if (api != ixgbe_mbox_api_10)
		return IXGBE_ERR_INVALID_ARGUMENT;

	return 0;
}

int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
		       unsigned int *default_tc)
{
@@ -777,22 +952,62 @@ static const struct ixgbe_mac_operations ixgbevf_mac_ops = {
	.set_vfta		= ixgbevf_set_vfta_vf,
};

static const struct ixgbe_mac_operations ixgbevf_hv_mac_ops = {
	.init_hw		= ixgbevf_init_hw_vf,
	.reset_hw		= ixgbevf_hv_reset_hw_vf,
	.start_hw		= ixgbevf_start_hw_vf,
	.get_mac_addr		= ixgbevf_get_mac_addr_vf,
	.stop_adapter		= ixgbevf_stop_hw_vf,
	.setup_link		= ixgbevf_setup_mac_link_vf,
	.check_link		= ixgbevf_hv_check_mac_link_vf,
	.set_rar		= ixgbevf_hv_set_rar_vf,
	.update_mc_addr_list	= ixgbevf_hv_update_mc_addr_list_vf,
	.update_xcast_mode	= ixgbevf_hv_update_xcast_mode,
	.set_uc_addr		= ixgbevf_hv_set_uc_addr_vf,
	.set_vfta		= ixgbevf_hv_set_vfta_vf,
};

const struct ixgbevf_info ixgbevf_82599_vf_info = {
	.mac = ixgbe_mac_82599_vf,
	.mac_ops = &ixgbevf_mac_ops,
};

const struct ixgbevf_info ixgbevf_82599_vf_hv_info = {
	.mac = ixgbe_mac_82599_vf,
	.mac_ops = &ixgbevf_hv_mac_ops,
};

const struct ixgbevf_info ixgbevf_X540_vf_info = {
	.mac = ixgbe_mac_X540_vf,
	.mac_ops = &ixgbevf_mac_ops,
};

const struct ixgbevf_info ixgbevf_X540_vf_hv_info = {
	.mac = ixgbe_mac_X540_vf,
	.mac_ops = &ixgbevf_hv_mac_ops,
};

const struct ixgbevf_info ixgbevf_X550_vf_info = {
	.mac = ixgbe_mac_X550_vf,
	.mac_ops = &ixgbevf_mac_ops,
};

const struct ixgbevf_info ixgbevf_X550_vf_hv_info = {
	.mac = ixgbe_mac_X550_vf,
	.mac_ops = &ixgbevf_hv_mac_ops,
};

const struct ixgbevf_info ixgbevf_X550EM_x_vf_info = {
	.mac = ixgbe_mac_X550EM_x_vf,
	.mac_ops = &ixgbevf_mac_ops,
};

const struct ixgbevf_info ixgbevf_X550EM_x_vf_hv_info = {
	.mac = ixgbe_mac_X550EM_x_vf,
	.mac_ops = &ixgbevf_hv_mac_ops,
};

bool ixgbevf_on_hyperv(struct ixgbe_hw *hw)
{
	return hw->mbx.ops.check_for_msg == NULL;
}
+2 −0
Original line number Diff line number Diff line
@@ -209,6 +209,8 @@ static inline u32 ixgbe_read_reg_array(struct ixgbe_hw *hw, u32 reg,
#define IXGBE_READ_REG_ARRAY(h, r, o) ixgbe_read_reg_array(h, r, o)

void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size);
void ixgbevf_hv_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size);
int ixgbevf_hv_negotiate_api_version(struct ixgbe_hw *hw, int api);
int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
		       unsigned int *default_tc);
int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues);