mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-30 08:04:13 +08:00
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: K. Y. Srinivasan <kys@microsoft.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
b4363fbd8d
commit
c6d45171d7
@ -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);
|
||||
|
||||
|
@ -62,10 +62,14 @@ static char ixgbevf_copyright[] =
|
||||
"Copyright (c) 2009 - 2015 Intel Corporation.";
|
||||
|
||||
static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
|
||||
[board_82599_vf] = &ixgbevf_82599_vf_info,
|
||||
[board_X540_vf] = &ixgbevf_X540_vf_info,
|
||||
[board_X550_vf] = &ixgbevf_X550_vf_info,
|
||||
[board_X550EM_x_vf] = &ixgbevf_X550EM_x_vf_info,
|
||||
[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 */
|
||||
ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
|
||||
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) {
|
||||
err = hw->mac.ops.negotiate_api_version(hw, api[idx]);
|
||||
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 */
|
||||
ixgbevf_rlpml_set_vf(hw, max_frame);
|
||||
if (!ixgbevf_on_hyperv(hw))
|
||||
ixgbevf_rlpml_set_vf(hw, max_frame);
|
||||
else
|
||||
ixgbevf_hv_rlpml_set_vf(hw, max_frame);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 @@ mbx_err:
|
||||
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 @@ out:
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user