[Intel-wired-lan] [PATCH net-next V2 2/2] intel: ixgbevf: Support Windows hosts (Hyper-V)

KY Srinivasan kys at microsoft.com
Mon Apr 18 16:52:54 UTC 2016



> -----Original Message-----
> From: Alexander Duyck [mailto:alexander.duyck at gmail.com]
> Sent: Monday, April 18, 2016 9:18 AM
> To: KY Srinivasan <kys at microsoft.com>
> Cc: David Miller <davem at davemloft.net>; Netdev
> <netdev at vger.kernel.org>; linux-kernel at vger.kernel.org;
> devel at linuxdriverproject.org; olaf at aepfle.de; Robo Bot
> <apw at canonical.com>; Jason Wang <jasowang at redhat.com>;
> eli at mellanox.com; jackm at mellanox.com; yevgenyp at mellanox.com; John
> Ronciak <john.ronciak at intel.com>; intel-wired-lan <intel-wired-
> lan at lists.osuosl.org>
> Subject: Re: [Intel-wired-lan] [PATCH net-next V2 2/2] intel: ixgbevf: Support
> Windows hosts (Hyper-V)
> 
> On Sun, Apr 17, 2016 at 10:22 PM, K. Y. Srinivasan <kys at microsoft.com>
> wrote:
> > 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 at microsoft.com>
> > ---
> >         V2: Addressed most of the comments from
> >             Alexander Duyck <alexander.duyck at gmail.com>
> >             and Rustad, Mark D <mark.d.rustad at intel.com>.
> >
> >  drivers/net/ethernet/intel/ixgbevf/ixgbevf.h      |   12 ++
> >  drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c |   16 ++-
> >  drivers/net/ethernet/intel/ixgbevf/mbx.c          |   12 ++
> >  drivers/net/ethernet/intel/ixgbevf/vf.c           |  201
> +++++++++++++++++++++
> >  4 files changed, 237 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
> b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
> > index 5ac60ee..3296d27 100644
> > --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
> > +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
> > @@ -460,9 +460,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 {
> > @@ -477,6 +481,13 @@ 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[];
> > @@ -494,6 +505,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);
> >
> > diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
> b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
> > index 007cbe0..c761d80 100644
> > --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
> > +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
> > @@ -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, }
> >  };
> > diff --git a/drivers/net/ethernet/intel/ixgbevf/mbx.c
> b/drivers/net/ethernet/intel/ixgbevf/mbx.c
> > index dc68fea..298a0da 100644
> > --- a/drivers/net/ethernet/intel/ixgbevf/mbx.c
> > +++ b/drivers/net/ethernet/intel/ixgbevf/mbx.c
> > @@ -346,3 +346,15 @@ 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 communiction 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,
> > +};
> > diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c
> b/drivers/net/ethernet/intel/ixgbevf/vf.c
> > index 4d613a4..1ec13c1 100644
> > --- a/drivers/net/ethernet/intel/ixgbevf/vf.c
> > +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
> > @@ -27,6 +27,13 @@
> >  #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
> > @@ -126,6 +133,23 @@ static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw
> *hw)
> >  }
> >
> >  /**
> > + * Hyper-V variant; the VF/PF communication is through the PCI
> > + * config space.
> > + */
> > +static s32 ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
> > +{
> > +       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;
> > +}
> > +
> 
> I'm still not seeing anything that protects the HyperV VF from being
> built with MM_CONFIG disabled.  As such this driver will just fail
> with no explanation in such a case.  If nothing else you could add
> some code here that printed an error message if MM_CONFIG is disabled
> at the very least.
I will add the error message.

> 
> > +/**
> >   *  ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
> >   *  @hw: pointer to hardware structure
> >   *
> > @@ -258,6 +282,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 +445,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)
> >  {
> > @@ -473,6 +522,15 @@ static s32 ixgbevf_update_mc_addr_list_vf(struct
> ixgbe_hw *hw,
> >  }
> >
> >  /**
> > + * 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
> >   *  @netdev: pointer to net device structure
> > @@ -513,6 +571,15 @@ static s32 ixgbevf_update_xcast_mode(struct
> ixgbe_hw *hw,
> >  }
> >
> >  /**
> > + * 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
> >   *  @vlan: 12 bit VLAN ID
> > @@ -551,6 +618,15 @@ mbx_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
> >   *  @speed: Unused in this implementation
> > @@ -656,6 +732,67 @@ out:
> >  }
> >
> >  /**
> > + * 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
> >   *  @max_size: value to assign to max frame size
> > @@ -663,6 +800,18 @@ out:
> >  void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size)
> >  {
> >         u32 msgbuf[2];
> > +       u32 reg;
> > +
> > +       if (ixgbevf_on_hyperv(hw)) {
> > +               /* 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);
> > +               return;
> > +       }
> >
> >         msgbuf[0] = IXGBE_VF_SET_LPE;
> >         msgbuf[1] = max_size;
> 
> There is no point in making this one function.  You should split this
> code out and create a HyperV version of the function that you can call
> instead.  It would help to make this more readable anyway since you
> can then drop one level of indentation.

I will split the function as you have suggested.

> 
> > @@ -679,6 +828,15 @@ int ixgbevf_negotiate_api_version(struct
> ixgbe_hw *hw, int api)
> >         int err;
> >         u32 msg[3];
> >
> > +       if (ixgbevf_on_hyperv(hw)) {
> > +               /* Hyper-V only supports api version ixgbe_mbox_api_10
> > +                */
> > +               if (api != ixgbe_mbox_api_10)
> > +                       return IXGBE_ERR_INVALID_ARGUMENT;
> > +
> > +               return 0;
> > +       }
> > +
> >         /* Negotiate the mailbox API version */
> >         msg[0] = IXGBE_VF_API_NEGOTIATE;
> >         msg[1] = api;
> 
> Same thing here.  You can just create a new function and avoid having
> to mess with the mailbox based approach.

I will split the function as you have suggested.
> 
> > @@ -776,22 +934,65 @@ 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)
> > +{
> > +       if (hw->mbx.ops.check_for_msg == NULL)
> > +               return true;
> > +       else
> > +               return false;
> > +}
> > --
> > 1.7.4.1

Thank you.

K. Y
> >
> > _______________________________________________
> > Intel-wired-lan mailing list
> > Intel-wired-lan at lists.osuosl.org
> >
> https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2flists.osu
> osl.org%2fmailman%2flistinfo%2fintel-wired-
> lan&data=01%7c01%7ckys%40microsoft.com%7cfdaf85b858e240c2e38108d3
> 67a4f2d7%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=Vf%2fXiRxqiEa
> OaUMQNN9kM1A12IV5JCkEXVILgAEFbYI%3d


More information about the devel mailing list