diff mbox series

[net-next,04/11] sfc: implement vDPA management device operations

Message ID 20221207145428.31544-5-gautam.dawar@amd.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series sfc: add vDPA support for EF100 devices | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 1 this patch: 2
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang fail Errors and warnings before: 0 this patch: 2
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 1 this patch: 2
netdev/checkpatch warning WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
netdev/kdoc success Errors and warnings before: 57 this patch: 57
netdev/source_inline success Was 0 now: 0

Commit Message

Gautam Dawar Dec. 7, 2022, 2:54 p.m. UTC
To allow vDPA device creation and deletion, add a vDPA management
device per function. Currently, the vDPA devices can be created
only on a VF. Also, for now only network class of vDPA devices
are supported.

Signed-off-by: Gautam Dawar <gautam.dawar@amd.com>
---
 drivers/net/ethernet/sfc/Makefile         |   2 +-
 drivers/net/ethernet/sfc/ef10.c           |   2 +-
 drivers/net/ethernet/sfc/ef100_nic.c      |  24 ++-
 drivers/net/ethernet/sfc/ef100_nic.h      |  11 +
 drivers/net/ethernet/sfc/ef100_vdpa.c     | 232 ++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_vdpa.h     |  84 ++++++++
 drivers/net/ethernet/sfc/ef100_vdpa_ops.c |  28 +++
 drivers/net/ethernet/sfc/mcdi_functions.c |   9 +-
 drivers/net/ethernet/sfc/mcdi_functions.h |   3 +-
 drivers/net/ethernet/sfc/net_driver.h     |   6 +
 10 files changed, 394 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/ethernet/sfc/ef100_vdpa_ops.c

Comments

kernel test robot Dec. 7, 2022, 4:31 p.m. UTC | #1
Hi Gautam,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Gautam-Dawar/sfc-add-vDPA-support-for-EF100-devices/20221207-230026
patch link:    https://lore.kernel.org/r/20221207145428.31544-5-gautam.dawar%40amd.com
patch subject: [PATCH net-next 04/11] sfc: implement vDPA management device operations
config: ia64-allyesconfig
compiler: ia64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/ff563410d33798677670893391c1d56ec659d3e3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Gautam-Dawar/sfc-add-vDPA-support-for-EF100-devices/20221207-230026
        git checkout ff563410d33798677670893391c1d56ec659d3e3
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 SHELL=/bin/bash drivers/net/ethernet/sfc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/sfc/ef100_vdpa.c: In function 'ef100_vdpa_create':
>> drivers/net/ethernet/sfc/ef100_vdpa.c:109:24: warning: variable 'dev' set but not used [-Wunused-but-set-variable]
     109 |         struct device *dev;
         |                        ^~~


vim +/dev +109 drivers/net/ethernet/sfc/ef100_vdpa.c

   101	
   102	static struct ef100_vdpa_nic *ef100_vdpa_create(struct efx_nic *efx,
   103							const char *dev_name,
   104							enum ef100_vdpa_class dev_type,
   105							const u8 *mac)
   106	{
   107		struct ef100_nic_data *nic_data = efx->nic_data;
   108		struct ef100_vdpa_nic *vdpa_nic;
 > 109		struct device *dev;
   110		int rc;
   111	
   112		nic_data->vdpa_class = dev_type;
   113		vdpa_nic = vdpa_alloc_device(struct ef100_vdpa_nic,
   114					     vdpa_dev, &efx->pci_dev->dev,
   115					     &ef100_vdpa_config_ops,
   116					     1, 1,
   117					     dev_name, false);
   118		if (!vdpa_nic) {
   119			pci_err(efx->pci_dev,
   120				"vDPA device allocation failed for vf: %u\n",
   121				nic_data->vf_index);
   122			nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
   123			return ERR_PTR(-ENOMEM);
   124		}
   125	
   126		mutex_init(&vdpa_nic->lock);
   127		dev = &vdpa_nic->vdpa_dev.dev;
   128		efx->vdpa_nic = vdpa_nic;
   129		vdpa_nic->vdpa_dev.dma_dev = &efx->pci_dev->dev;
   130		vdpa_nic->vdpa_dev.mdev = efx->mgmt_dev;
   131		vdpa_nic->efx = efx;
   132		vdpa_nic->pf_index = nic_data->pf_index;
   133		vdpa_nic->vf_index = nic_data->vf_index;
   134		vdpa_nic->vdpa_state = EF100_VDPA_STATE_INITIALIZED;
   135		vdpa_nic->mac_address = (u8 *)&vdpa_nic->net_config.mac;
   136		ether_addr_copy(vdpa_nic->mac_address, mac);
   137		vdpa_nic->mac_configured = true;
   138	
   139		rc = get_net_config(vdpa_nic);
   140		if (rc)
   141			goto err_put_device;
   142	
   143		/* _vdpa_register_device when its ready */
   144	
   145		return vdpa_nic;
   146	
   147	err_put_device:
   148		/* put_device invokes ef100_vdpa_free */
   149		put_device(&vdpa_nic->vdpa_dev.dev);
   150		return ERR_PTR(rc);
   151	}
   152
Jason Wang Dec. 14, 2022, 6:43 a.m. UTC | #2
On Wed, Dec 7, 2022 at 10:56 PM Gautam Dawar <gautam.dawar@amd.com> wrote:
>
> To allow vDPA device creation and deletion, add a vDPA management
> device per function. Currently, the vDPA devices can be created
> only on a VF. Also, for now only network class of vDPA devices
> are supported.
>
> Signed-off-by: Gautam Dawar <gautam.dawar@amd.com>
> ---
>  drivers/net/ethernet/sfc/Makefile         |   2 +-
>  drivers/net/ethernet/sfc/ef10.c           |   2 +-
>  drivers/net/ethernet/sfc/ef100_nic.c      |  24 ++-
>  drivers/net/ethernet/sfc/ef100_nic.h      |  11 +
>  drivers/net/ethernet/sfc/ef100_vdpa.c     | 232 ++++++++++++++++++++++
>  drivers/net/ethernet/sfc/ef100_vdpa.h     |  84 ++++++++
>  drivers/net/ethernet/sfc/ef100_vdpa_ops.c |  28 +++
>  drivers/net/ethernet/sfc/mcdi_functions.c |   9 +-
>  drivers/net/ethernet/sfc/mcdi_functions.h |   3 +-
>  drivers/net/ethernet/sfc/net_driver.h     |   6 +
>  10 files changed, 394 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/net/ethernet/sfc/ef100_vdpa_ops.c
>
> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
> index 84c9f0590368..a10eac91ab23 100644
> --- a/drivers/net/ethernet/sfc/Makefile
> +++ b/drivers/net/ethernet/sfc/Makefile
> @@ -11,7 +11,7 @@ sfc-$(CONFIG_SFC_MTD) += mtd.o
>  sfc-$(CONFIG_SFC_SRIOV)        += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>                             mae.o tc.o tc_bindings.o tc_counters.o
>
> -sfc-$(CONFIG_SFC_VDPA) += mcdi_vdpa.o ef100_vdpa.o
> +sfc-$(CONFIG_SFC_VDPA) += mcdi_vdpa.o ef100_vdpa.o ef100_vdpa_ops.o
>  obj-$(CONFIG_SFC)      += sfc.o
>
>  obj-$(CONFIG_SFC_FALCON) += falcon/
> diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
> index 7022fb2005a2..366ecd3c80b1 100644
> --- a/drivers/net/ethernet/sfc/ef10.c
> +++ b/drivers/net/ethernet/sfc/ef10.c
> @@ -589,7 +589,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
>         if (rc)
>                 goto fail4;
>
> -       rc = efx_get_pf_index(efx, &nic_data->pf_index);
> +       rc = efx_get_fn_info(efx, &nic_data->pf_index, NULL);
>         if (rc)
>                 goto fail5;
>
> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
> index 41175eb00326..41811c519275 100644
> --- a/drivers/net/ethernet/sfc/ef100_nic.c
> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
> @@ -1160,7 +1160,7 @@ static int ef100_probe_main(struct efx_nic *efx)
>         if (rc)
>                 goto fail;
>
> -       rc = efx_get_pf_index(efx, &nic_data->pf_index);
> +       rc = efx_get_fn_info(efx, &nic_data->pf_index, &nic_data->vf_index);
>         if (rc)
>                 goto fail;
>
> @@ -1247,13 +1247,33 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>
>  int ef100_probe_vf(struct efx_nic *efx)
>  {
> -       return ef100_probe_main(efx);
> +#if defined(CONFIG_SFC_VDPA)
> +       int err;
> +#endif
> +       int rc;
> +
> +       rc = ef100_probe_main(efx);
> +       if (rc)
> +               return rc;
> +
> +#if defined(CONFIG_SFC_VDPA)
> +       err = ef100_vdpa_register_mgmtdev(efx);
> +       if (err)
> +               pci_warn(efx->pci_dev,
> +                        "vdpa_register_mgmtdev failed, err: %d\n", err);
> +#endif
> +       return 0;
>  }
>
>  void ef100_remove(struct efx_nic *efx)
>  {
>         struct ef100_nic_data *nic_data = efx->nic_data;
>
> +#if defined(CONFIG_SFC_VDPA)
> +       if (efx_vdpa_supported(efx))
> +               ef100_vdpa_unregister_mgmtdev(efx);
> +#endif
> +
>         efx_mcdi_detach(efx);
>         efx_mcdi_fini(efx);
>         if (nic_data) {
> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
> index 5ed693fbe79f..730c8bb932b0 100644
> --- a/drivers/net/ethernet/sfc/ef100_nic.h
> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
> @@ -68,6 +68,13 @@ enum ef100_bar_config {
>         EF100_BAR_CONFIG_VDPA,
>  };
>
> +#ifdef CONFIG_SFC_VDPA
> +enum ef100_vdpa_class {
> +       EF100_VDPA_CLASS_NONE,
> +       EF100_VDPA_CLASS_NET,
> +};
> +#endif
> +
>  struct ef100_nic_data {
>         struct efx_nic *efx;
>         struct efx_buffer mcdi_buf;
> @@ -75,7 +82,11 @@ struct ef100_nic_data {
>         u32 datapath_caps2;
>         u32 datapath_caps3;
>         unsigned int pf_index;
> +       unsigned int vf_index;
>         u16 warm_boot_count;
> +#ifdef CONFIG_SFC_VDPA
> +       enum ef100_vdpa_class vdpa_class;
> +#endif
>         u8 port_id[ETH_ALEN];
>         DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS);
>         enum ef100_bar_config bar_config;
> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.c b/drivers/net/ethernet/sfc/ef100_vdpa.c
> index 5e215cee585a..ff4bb61e598e 100644
> --- a/drivers/net/ethernet/sfc/ef100_vdpa.c
> +++ b/drivers/net/ethernet/sfc/ef100_vdpa.c
> @@ -11,11 +11,17 @@
>  #include <linux/err.h>
>  #include <linux/vdpa.h>
>  #include <linux/virtio_net.h>
> +#include <uapi/linux/vdpa.h>
>  #include "ef100_vdpa.h"
>  #include "mcdi_vdpa.h"
>  #include "mcdi_filters.h"
>  #include "ef100_netdev.h"
>
> +static struct virtio_device_id ef100_vdpa_id_table[] = {
> +       { .device = VIRTIO_ID_NET, .vendor = PCI_VENDOR_ID_REDHAT_QUMRANET },
> +       { 0 },
> +};
> +
>  int ef100_vdpa_init(struct efx_probe_data *probe_data)
>  {
>         struct efx_nic *efx = &probe_data->efx;
> @@ -42,17 +48,243 @@ int ef100_vdpa_init(struct efx_probe_data *probe_data)
>         return rc;
>  }
>
> +static void ef100_vdpa_delete(struct efx_nic *efx)
> +{
> +       if (efx->vdpa_nic) {
> +               /* replace with _vdpa_unregister_device later */
> +               put_device(&efx->vdpa_nic->vdpa_dev.dev);
> +               efx->vdpa_nic = NULL;
> +       }
> +}
> +
>  void ef100_vdpa_fini(struct efx_probe_data *probe_data)
>  {
>         struct efx_nic *efx = &probe_data->efx;
> +       struct ef100_nic_data *nic_data;
>
>         if (efx->state != STATE_VDPA && efx->state != STATE_DISABLED) {
>                 pci_err(efx->pci_dev, "Invalid efx state %u", efx->state);
>                 return;
>         }
>
> +       /* Handle vdpa device deletion, if not done explicitly */
> +       ef100_vdpa_delete(efx);
> +       nic_data = efx->nic_data;
> +       nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
>         efx->state = STATE_PROBED;
>         down_write(&efx->filter_sem);
>         efx_mcdi_filter_table_remove(efx);
>         up_write(&efx->filter_sem);
>  }
> +
> +static int get_net_config(struct ef100_vdpa_nic *vdpa_nic)
> +{
> +       struct efx_nic *efx = vdpa_nic->efx;
> +       u16 mtu;
> +       int rc;
> +
> +       vdpa_nic->net_config.max_virtqueue_pairs =
> +               cpu_to_efx_vdpa16(vdpa_nic, vdpa_nic->max_queue_pairs);
> +
> +       rc = efx_vdpa_get_mtu(efx, &mtu);
> +       if (rc) {
> +               dev_err(&vdpa_nic->vdpa_dev.dev,
> +                       "%s: Get MTU for vf:%u failed:%d\n", __func__,
> +                       vdpa_nic->vf_index, rc);
> +               return rc;
> +       }
> +       vdpa_nic->net_config.mtu = cpu_to_efx_vdpa16(vdpa_nic, mtu);
> +       vdpa_nic->net_config.status = cpu_to_efx_vdpa16(vdpa_nic,
> +                                                       VIRTIO_NET_S_LINK_UP);
> +       return 0;
> +}
> +
> +static struct ef100_vdpa_nic *ef100_vdpa_create(struct efx_nic *efx,
> +                                               const char *dev_name,
> +                                               enum ef100_vdpa_class dev_type,
> +                                               const u8 *mac)
> +{
> +       struct ef100_nic_data *nic_data = efx->nic_data;
> +       struct ef100_vdpa_nic *vdpa_nic;
> +       struct device *dev;
> +       int rc;
> +
> +       nic_data->vdpa_class = dev_type;
> +       vdpa_nic = vdpa_alloc_device(struct ef100_vdpa_nic,
> +                                    vdpa_dev, &efx->pci_dev->dev,
> +                                    &ef100_vdpa_config_ops,
> +                                    1, 1,
> +                                    dev_name, false);
> +       if (!vdpa_nic) {
> +               pci_err(efx->pci_dev,
> +                       "vDPA device allocation failed for vf: %u\n",
> +                       nic_data->vf_index);
> +               nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       mutex_init(&vdpa_nic->lock);
> +       dev = &vdpa_nic->vdpa_dev.dev;
> +       efx->vdpa_nic = vdpa_nic;
> +       vdpa_nic->vdpa_dev.dma_dev = &efx->pci_dev->dev;
> +       vdpa_nic->vdpa_dev.mdev = efx->mgmt_dev;
> +       vdpa_nic->efx = efx;
> +       vdpa_nic->pf_index = nic_data->pf_index;
> +       vdpa_nic->vf_index = nic_data->vf_index;
> +       vdpa_nic->vdpa_state = EF100_VDPA_STATE_INITIALIZED;
> +       vdpa_nic->mac_address = (u8 *)&vdpa_nic->net_config.mac;
> +       ether_addr_copy(vdpa_nic->mac_address, mac);
> +       vdpa_nic->mac_configured = true;
> +
> +       rc = get_net_config(vdpa_nic);
> +       if (rc)
> +               goto err_put_device;
> +
> +       /* _vdpa_register_device when its ready */
> +
> +       return vdpa_nic;
> +
> +err_put_device:
> +       /* put_device invokes ef100_vdpa_free */
> +       put_device(&vdpa_nic->vdpa_dev.dev);
> +       return ERR_PTR(rc);
> +}
> +
> +static void ef100_vdpa_net_dev_del(struct vdpa_mgmt_dev *mgmt_dev,
> +                                  struct vdpa_device *vdev)
> +{
> +       struct ef100_nic_data *nic_data;
> +       struct efx_nic *efx;
> +       int rc;
> +
> +       efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
> +       nic_data = efx->nic_data;
> +
> +       rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
> +       if (rc)
> +               pci_err(efx->pci_dev,
> +                       "set_bar_config EF100 failed, err: %d\n", rc);
> +       else
> +               pci_dbg(efx->pci_dev,
> +                       "vdpa net device deleted, vf: %u\n",
> +                       nic_data->vf_index);
> +}
> +
> +static int ef100_vdpa_net_dev_add(struct vdpa_mgmt_dev *mgmt_dev,
> +                                 const char *name,
> +                                 const struct vdpa_dev_set_config *config)
> +{
> +       struct ef100_vdpa_nic *vdpa_nic;
> +       struct ef100_nic_data *nic_data;
> +       struct efx_nic *efx;
> +       int rc, err;
> +
> +       efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
> +       if (efx->vdpa_nic) {
> +               pci_warn(efx->pci_dev,
> +                        "vDPA device already exists on this VF\n");
> +               return -EEXIST;
> +       }
> +
> +       if (config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
> +               if (!is_valid_ether_addr(config->net.mac)) {
> +                       pci_err(efx->pci_dev, "Invalid MAC address %pM\n",
> +                               config->net.mac);
> +                       return -EINVAL;
> +               }
> +       } else {
> +               pci_err(efx->pci_dev, "MAC address parameter missing\n");

Does this mean ef100 vf doesn't have a given mac address?



> +               return -EIO;
> +       }
> +
> +       nic_data = efx->nic_data;
> +
> +       rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_VDPA);
> +       if (rc) {
> +               pci_err(efx->pci_dev,
> +                       "set_bar_config vDPA failed, err: %d\n", rc);
> +               goto err_set_bar_config;
> +       }
> +
> +       vdpa_nic = ef100_vdpa_create(efx, name, EF100_VDPA_CLASS_NET,
> +                                    (const u8 *)config->net.mac);
> +       if (IS_ERR(vdpa_nic)) {
> +               pci_err(efx->pci_dev,
> +                       "vDPA device creation failed, vf: %u, err: %ld\n",
> +                       nic_data->vf_index, PTR_ERR(vdpa_nic));
> +               rc = PTR_ERR(vdpa_nic);
> +               goto err_set_bar_config;
> +       } else {
> +               pci_dbg(efx->pci_dev,
> +                       "vdpa net device created, vf: %u\n",
> +                       nic_data->vf_index);
> +               pci_warn(efx->pci_dev,
> +                        "Use QEMU versions 6.1.0 and later with vhost-vdpa\n");
> +       }
> +
> +       return 0;
> +
> +err_set_bar_config:
> +       err = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
> +       if (err)
> +               pci_err(efx->pci_dev,
> +                       "set_bar_config EF100 failed, err: %d\n", err);
> +
> +       return rc;
> +}
> +
> +static const struct vdpa_mgmtdev_ops ef100_vdpa_net_mgmtdev_ops = {
> +       .dev_add = ef100_vdpa_net_dev_add,
> +       .dev_del = ef100_vdpa_net_dev_del
> +};
> +
> +int ef100_vdpa_register_mgmtdev(struct efx_nic *efx)
> +{
> +       struct vdpa_mgmt_dev *mgmt_dev;
> +       u64 features;
> +       int rc;
> +
> +       mgmt_dev = kzalloc(sizeof(*mgmt_dev), GFP_KERNEL);
> +       if (!mgmt_dev)
> +               return -ENOMEM;
> +
> +       rc = efx_vdpa_get_features(efx, EF100_VDPA_DEVICE_TYPE_NET, &features);
> +       if (rc) {
> +               pci_err(efx->pci_dev, "%s: MCDI get features error:%d\n",
> +                       __func__, rc);
> +               goto err_get_features;
> +       }
> +
> +       efx->mgmt_dev = mgmt_dev;
> +       mgmt_dev->device = &efx->pci_dev->dev;
> +       mgmt_dev->id_table = ef100_vdpa_id_table;
> +       mgmt_dev->ops = &ef100_vdpa_net_mgmtdev_ops;
> +       mgmt_dev->supported_features = features;
> +       mgmt_dev->max_supported_vqs = EF100_VDPA_MAX_QUEUES_PAIRS * 2;
> +       mgmt_dev->config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR);
> +
> +       rc = vdpa_mgmtdev_register(mgmt_dev);
> +       if (rc) {
> +               pci_err(efx->pci_dev,
> +                       "vdpa_mgmtdev_register failed, err: %d\n", rc);
> +               goto err_mgmtdev_register;
> +       }
> +
> +       return 0;
> +
> +err_mgmtdev_register:
> +err_get_features:
> +       kfree(mgmt_dev);
> +       efx->mgmt_dev = NULL;
> +
> +       return rc;
> +}
> +
> +void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx)
> +{
> +       if (efx->mgmt_dev) {
> +               vdpa_mgmtdev_unregister(efx->mgmt_dev);
> +               kfree(efx->mgmt_dev);
> +               efx->mgmt_dev = NULL;
> +       }
> +}
> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.h b/drivers/net/ethernet/sfc/ef100_vdpa.h
> index 6b51a05becd8..83f6d819f6a5 100644
> --- a/drivers/net/ethernet/sfc/ef100_vdpa.h
> +++ b/drivers/net/ethernet/sfc/ef100_vdpa.h
> @@ -18,6 +18,24 @@
>
>  #if defined(CONFIG_SFC_VDPA)
>
> +/* Max queue pairs currently supported */
> +#define EF100_VDPA_MAX_QUEUES_PAIRS 1
> +
> +/**
> + * enum ef100_vdpa_nic_state - possible states for a vDPA NIC
> + *
> + * @EF100_VDPA_STATE_INITIALIZED: State after vDPA NIC created
> + * @EF100_VDPA_STATE_NEGOTIATED: State after feature negotiation
> + * @EF100_VDPA_STATE_STARTED: State after driver ok
> + * @EF100_VDPA_STATE_NSTATES: Number of VDPA states
> + */
> +enum ef100_vdpa_nic_state {
> +       EF100_VDPA_STATE_INITIALIZED,
> +       EF100_VDPA_STATE_NEGOTIATED,
> +       EF100_VDPA_STATE_STARTED,
> +       EF100_VDPA_STATE_NSTATES
> +};
> +
>  enum ef100_vdpa_device_type {
>         EF100_VDPA_DEVICE_TYPE_NET,
>  };
> @@ -28,7 +46,73 @@ enum ef100_vdpa_vq_type {
>         EF100_VDPA_VQ_NTYPES
>  };
>
> +/**
> + *  struct ef100_vdpa_nic - vDPA NIC data structure
> + *
> + * @vdpa_dev: vdpa_device object which registers on the vDPA bus.
> + * @vdpa_state: NIC state machine governed by ef100_vdpa_nic_state
> + * @efx: pointer to the VF's efx_nic object
> + * @lock: Managing access to vdpa config operations
> + * @pf_index: PF index of the vDPA VF
> + * @vf_index: VF index of the vDPA VF
> + * @status: device status as per VIRTIO spec
> + * @features: negotiated feature bits
> + * @max_queue_pairs: maximum number of queue pairs supported
> + * @net_config: virtio_net_config data
> + * @mac_address: mac address of interface associated with this vdpa device
> + * @mac_configured: true after MAC address is configured
> + */
> +struct ef100_vdpa_nic {
> +       struct vdpa_device vdpa_dev;
> +       enum ef100_vdpa_nic_state vdpa_state;
> +       struct efx_nic *efx;
> +       /* for synchronizing access to vdpa config operations */
> +       struct mutex lock;
> +       u32 pf_index;
> +       u32 vf_index;
> +       u8 status;
> +       u64 features;
> +       u32 max_queue_pairs;
> +       struct virtio_net_config net_config;
> +       u8 *mac_address;
> +       bool mac_configured;
> +};
> +
>  int ef100_vdpa_init(struct efx_probe_data *probe_data);
>  void ef100_vdpa_fini(struct efx_probe_data *probe_data);
> +int ef100_vdpa_register_mgmtdev(struct efx_nic *efx);
> +void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx);
> +
> +static inline bool efx_vdpa_is_little_endian(struct ef100_vdpa_nic *vdpa_nic)
> +{
> +       return virtio_legacy_is_little_endian() ||
> +               (vdpa_nic->features & (1ULL << VIRTIO_F_VERSION_1));
> +}
> +
> +static inline u16 efx_vdpa16_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
> +                                   __virtio16 val)
> +{
> +       return __virtio16_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
> +}
> +
> +static inline __virtio16 cpu_to_efx_vdpa16(struct ef100_vdpa_nic *vdpa_nic,
> +                                          u16 val)
> +{
> +       return __cpu_to_virtio16(efx_vdpa_is_little_endian(vdpa_nic), val);
> +}
> +
> +static inline u32 efx_vdpa32_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
> +                                   __virtio32 val)
> +{
> +       return __virtio32_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
> +}
> +
> +static inline __virtio32 cpu_to_efx_vdpa32(struct ef100_vdpa_nic *vdpa_nic,
> +                                          u32 val)
> +{
> +       return __cpu_to_virtio32(efx_vdpa_is_little_endian(vdpa_nic), val);
> +}
> +
> +extern const struct vdpa_config_ops ef100_vdpa_config_ops;
>  #endif /* CONFIG_SFC_VDPA */
>  #endif /* __EF100_VDPA_H__ */
> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa_ops.c b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
> new file mode 100644
> index 000000000000..31952931c198
> --- /dev/null
> +++ b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
> @@ -0,0 +1,28 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Driver for Xilinx network controllers and boards
> + * Copyright(C) 2020-2022 Xilinx, Inc.
> + * Copyright(C) 2022 Advanced Micro Devices, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation, incorporated herein by reference.
> + */
> +
> +#include <linux/vdpa.h>
> +#include "ef100_vdpa.h"
> +
> +static struct ef100_vdpa_nic *get_vdpa_nic(struct vdpa_device *vdev)
> +{
> +       return container_of(vdev, struct ef100_vdpa_nic, vdpa_dev);
> +}
> +
> +static void ef100_vdpa_free(struct vdpa_device *vdev)
> +{
> +       struct ef100_vdpa_nic *vdpa_nic = get_vdpa_nic(vdev);
> +
> +       mutex_destroy(&vdpa_nic->lock);
> +}
> +
> +const struct vdpa_config_ops ef100_vdpa_config_ops = {
> +       .free                = ef100_vdpa_free,
> +};
> diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c
> index d3e6d8239f5c..4415f19cf68f 100644
> --- a/drivers/net/ethernet/sfc/mcdi_functions.c
> +++ b/drivers/net/ethernet/sfc/mcdi_functions.c
> @@ -413,7 +413,8 @@ int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode)
>         return 0;
>  }
>
> -int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
> +int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
> +                   unsigned int *vf_index)
>  {
>         MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
>         size_t outlen;
> @@ -426,6 +427,10 @@ int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
>         if (outlen < sizeof(outbuf))
>                 return -EIO;
>
> -       *pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
> +       if (pf_index)
> +               *pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
> +
> +       if (efx->type->is_vf && vf_index)
> +               *vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
>         return 0;
>  }
> diff --git a/drivers/net/ethernet/sfc/mcdi_functions.h b/drivers/net/ethernet/sfc/mcdi_functions.h
> index b0e2f53a0d9b..76dc0a13463e 100644
> --- a/drivers/net/ethernet/sfc/mcdi_functions.h
> +++ b/drivers/net/ethernet/sfc/mcdi_functions.h
> @@ -28,6 +28,7 @@ void efx_mcdi_rx_remove(struct efx_rx_queue *rx_queue);
>  void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue);
>  int efx_fini_dmaq(struct efx_nic *efx);
>  int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode);
> -int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index);
> +int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
> +                   unsigned int *vf_index);
>
>  #endif
> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
> index ffda80a95221..79356d614109 100644
> --- a/drivers/net/ethernet/sfc/net_driver.h
> +++ b/drivers/net/ethernet/sfc/net_driver.h
> @@ -1182,6 +1182,12 @@ struct efx_nic {
>
>         unsigned int mem_bar;
>         u32 reg_base;
> +#ifdef CONFIG_SFC_VDPA
> +       /** @mgmt_dev: vDPA Management device */
> +       struct vdpa_mgmt_dev *mgmt_dev;
> +       /** @vdpa_nic: vDPA device structure (EF100) */
> +       struct ef100_vdpa_nic *vdpa_nic;
> +#endif
>
>         /* The following fields may be written more often */
>
> --
> 2.30.1
>
Gautam Dawar Dec. 15, 2022, 7:07 a.m. UTC | #3
On 12/14/22 12:13, Jason Wang wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Wed, Dec 7, 2022 at 10:56 PM Gautam Dawar <gautam.dawar@amd.com> wrote:
>> To allow vDPA device creation and deletion, add a vDPA management
>> device per function. Currently, the vDPA devices can be created
>> only on a VF. Also, for now only network class of vDPA devices
>> are supported.
>>
>> Signed-off-by: Gautam Dawar <gautam.dawar@amd.com>
>> ---
>>   drivers/net/ethernet/sfc/Makefile         |   2 +-
>>   drivers/net/ethernet/sfc/ef10.c           |   2 +-
>>   drivers/net/ethernet/sfc/ef100_nic.c      |  24 ++-
>>   drivers/net/ethernet/sfc/ef100_nic.h      |  11 +
>>   drivers/net/ethernet/sfc/ef100_vdpa.c     | 232 ++++++++++++++++++++++
>>   drivers/net/ethernet/sfc/ef100_vdpa.h     |  84 ++++++++
>>   drivers/net/ethernet/sfc/ef100_vdpa_ops.c |  28 +++
>>   drivers/net/ethernet/sfc/mcdi_functions.c |   9 +-
>>   drivers/net/ethernet/sfc/mcdi_functions.h |   3 +-
>>   drivers/net/ethernet/sfc/net_driver.h     |   6 +
>>   10 files changed, 394 insertions(+), 7 deletions(-)
>>   create mode 100644 drivers/net/ethernet/sfc/ef100_vdpa_ops.c
>>
>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>> index 84c9f0590368..a10eac91ab23 100644
>> --- a/drivers/net/ethernet/sfc/Makefile
>> +++ b/drivers/net/ethernet/sfc/Makefile
>> @@ -11,7 +11,7 @@ sfc-$(CONFIG_SFC_MTD) += mtd.o
>>   sfc-$(CONFIG_SFC_SRIOV)        += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>                              mae.o tc.o tc_bindings.o tc_counters.o
>>
>> -sfc-$(CONFIG_SFC_VDPA) += mcdi_vdpa.o ef100_vdpa.o
>> +sfc-$(CONFIG_SFC_VDPA) += mcdi_vdpa.o ef100_vdpa.o ef100_vdpa_ops.o
>>   obj-$(CONFIG_SFC)      += sfc.o
>>
>>   obj-$(CONFIG_SFC_FALCON) += falcon/
>> diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
>> index 7022fb2005a2..366ecd3c80b1 100644
>> --- a/drivers/net/ethernet/sfc/ef10.c
>> +++ b/drivers/net/ethernet/sfc/ef10.c
>> @@ -589,7 +589,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
>>          if (rc)
>>                  goto fail4;
>>
>> -       rc = efx_get_pf_index(efx, &nic_data->pf_index);
>> +       rc = efx_get_fn_info(efx, &nic_data->pf_index, NULL);
>>          if (rc)
>>                  goto fail5;
>>
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index 41175eb00326..41811c519275 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -1160,7 +1160,7 @@ static int ef100_probe_main(struct efx_nic *efx)
>>          if (rc)
>>                  goto fail;
>>
>> -       rc = efx_get_pf_index(efx, &nic_data->pf_index);
>> +       rc = efx_get_fn_info(efx, &nic_data->pf_index, &nic_data->vf_index);
>>          if (rc)
>>                  goto fail;
>>
>> @@ -1247,13 +1247,33 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>
>>   int ef100_probe_vf(struct efx_nic *efx)
>>   {
>> -       return ef100_probe_main(efx);
>> +#if defined(CONFIG_SFC_VDPA)
>> +       int err;
>> +#endif
>> +       int rc;
>> +
>> +       rc = ef100_probe_main(efx);
>> +       if (rc)
>> +               return rc;
>> +
>> +#if defined(CONFIG_SFC_VDPA)
>> +       err = ef100_vdpa_register_mgmtdev(efx);
>> +       if (err)
>> +               pci_warn(efx->pci_dev,
>> +                        "vdpa_register_mgmtdev failed, err: %d\n", err);
>> +#endif
>> +       return 0;
>>   }
>>
>>   void ef100_remove(struct efx_nic *efx)
>>   {
>>          struct ef100_nic_data *nic_data = efx->nic_data;
>>
>> +#if defined(CONFIG_SFC_VDPA)
>> +       if (efx_vdpa_supported(efx))
>> +               ef100_vdpa_unregister_mgmtdev(efx);
>> +#endif
>> +
>>          efx_mcdi_detach(efx);
>>          efx_mcdi_fini(efx);
>>          if (nic_data) {
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>> index 5ed693fbe79f..730c8bb932b0 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>> @@ -68,6 +68,13 @@ enum ef100_bar_config {
>>          EF100_BAR_CONFIG_VDPA,
>>   };
>>
>> +#ifdef CONFIG_SFC_VDPA
>> +enum ef100_vdpa_class {
>> +       EF100_VDPA_CLASS_NONE,
>> +       EF100_VDPA_CLASS_NET,
>> +};
>> +#endif
>> +
>>   struct ef100_nic_data {
>>          struct efx_nic *efx;
>>          struct efx_buffer mcdi_buf;
>> @@ -75,7 +82,11 @@ struct ef100_nic_data {
>>          u32 datapath_caps2;
>>          u32 datapath_caps3;
>>          unsigned int pf_index;
>> +       unsigned int vf_index;
>>          u16 warm_boot_count;
>> +#ifdef CONFIG_SFC_VDPA
>> +       enum ef100_vdpa_class vdpa_class;
>> +#endif
>>          u8 port_id[ETH_ALEN];
>>          DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS);
>>          enum ef100_bar_config bar_config;
>> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.c b/drivers/net/ethernet/sfc/ef100_vdpa.c
>> index 5e215cee585a..ff4bb61e598e 100644
>> --- a/drivers/net/ethernet/sfc/ef100_vdpa.c
>> +++ b/drivers/net/ethernet/sfc/ef100_vdpa.c
>> @@ -11,11 +11,17 @@
>>   #include <linux/err.h>
>>   #include <linux/vdpa.h>
>>   #include <linux/virtio_net.h>
>> +#include <uapi/linux/vdpa.h>
>>   #include "ef100_vdpa.h"
>>   #include "mcdi_vdpa.h"
>>   #include "mcdi_filters.h"
>>   #include "ef100_netdev.h"
>>
>> +static struct virtio_device_id ef100_vdpa_id_table[] = {
>> +       { .device = VIRTIO_ID_NET, .vendor = PCI_VENDOR_ID_REDHAT_QUMRANET },
>> +       { 0 },
>> +};
>> +
>>   int ef100_vdpa_init(struct efx_probe_data *probe_data)
>>   {
>>          struct efx_nic *efx = &probe_data->efx;
>> @@ -42,17 +48,243 @@ int ef100_vdpa_init(struct efx_probe_data *probe_data)
>>          return rc;
>>   }
>>
>> +static void ef100_vdpa_delete(struct efx_nic *efx)
>> +{
>> +       if (efx->vdpa_nic) {
>> +               /* replace with _vdpa_unregister_device later */
>> +               put_device(&efx->vdpa_nic->vdpa_dev.dev);
>> +               efx->vdpa_nic = NULL;
>> +       }
>> +}
>> +
>>   void ef100_vdpa_fini(struct efx_probe_data *probe_data)
>>   {
>>          struct efx_nic *efx = &probe_data->efx;
>> +       struct ef100_nic_data *nic_data;
>>
>>          if (efx->state != STATE_VDPA && efx->state != STATE_DISABLED) {
>>                  pci_err(efx->pci_dev, "Invalid efx state %u", efx->state);
>>                  return;
>>          }
>>
>> +       /* Handle vdpa device deletion, if not done explicitly */
>> +       ef100_vdpa_delete(efx);
>> +       nic_data = efx->nic_data;
>> +       nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
>>          efx->state = STATE_PROBED;
>>          down_write(&efx->filter_sem);
>>          efx_mcdi_filter_table_remove(efx);
>>          up_write(&efx->filter_sem);
>>   }
>> +
>> +static int get_net_config(struct ef100_vdpa_nic *vdpa_nic)
>> +{
>> +       struct efx_nic *efx = vdpa_nic->efx;
>> +       u16 mtu;
>> +       int rc;
>> +
>> +       vdpa_nic->net_config.max_virtqueue_pairs =
>> +               cpu_to_efx_vdpa16(vdpa_nic, vdpa_nic->max_queue_pairs);
>> +
>> +       rc = efx_vdpa_get_mtu(efx, &mtu);
>> +       if (rc) {
>> +               dev_err(&vdpa_nic->vdpa_dev.dev,
>> +                       "%s: Get MTU for vf:%u failed:%d\n", __func__,
>> +                       vdpa_nic->vf_index, rc);
>> +               return rc;
>> +       }
>> +       vdpa_nic->net_config.mtu = cpu_to_efx_vdpa16(vdpa_nic, mtu);
>> +       vdpa_nic->net_config.status = cpu_to_efx_vdpa16(vdpa_nic,
>> +                                                       VIRTIO_NET_S_LINK_UP);
>> +       return 0;
>> +}
>> +
>> +static struct ef100_vdpa_nic *ef100_vdpa_create(struct efx_nic *efx,
>> +                                               const char *dev_name,
>> +                                               enum ef100_vdpa_class dev_type,
>> +                                               const u8 *mac)
>> +{
>> +       struct ef100_nic_data *nic_data = efx->nic_data;
>> +       struct ef100_vdpa_nic *vdpa_nic;
>> +       struct device *dev;
>> +       int rc;
>> +
>> +       nic_data->vdpa_class = dev_type;
>> +       vdpa_nic = vdpa_alloc_device(struct ef100_vdpa_nic,
>> +                                    vdpa_dev, &efx->pci_dev->dev,
>> +                                    &ef100_vdpa_config_ops,
>> +                                    1, 1,
>> +                                    dev_name, false);
>> +       if (!vdpa_nic) {
>> +               pci_err(efx->pci_dev,
>> +                       "vDPA device allocation failed for vf: %u\n",
>> +                       nic_data->vf_index);
>> +               nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
>> +               return ERR_PTR(-ENOMEM);
>> +       }
>> +
>> +       mutex_init(&vdpa_nic->lock);
>> +       dev = &vdpa_nic->vdpa_dev.dev;
>> +       efx->vdpa_nic = vdpa_nic;
>> +       vdpa_nic->vdpa_dev.dma_dev = &efx->pci_dev->dev;
>> +       vdpa_nic->vdpa_dev.mdev = efx->mgmt_dev;
>> +       vdpa_nic->efx = efx;
>> +       vdpa_nic->pf_index = nic_data->pf_index;
>> +       vdpa_nic->vf_index = nic_data->vf_index;
>> +       vdpa_nic->vdpa_state = EF100_VDPA_STATE_INITIALIZED;
>> +       vdpa_nic->mac_address = (u8 *)&vdpa_nic->net_config.mac;
>> +       ether_addr_copy(vdpa_nic->mac_address, mac);
>> +       vdpa_nic->mac_configured = true;
>> +
>> +       rc = get_net_config(vdpa_nic);
>> +       if (rc)
>> +               goto err_put_device;
>> +
>> +       /* _vdpa_register_device when its ready */
>> +
>> +       return vdpa_nic;
>> +
>> +err_put_device:
>> +       /* put_device invokes ef100_vdpa_free */
>> +       put_device(&vdpa_nic->vdpa_dev.dev);
>> +       return ERR_PTR(rc);
>> +}
>> +
>> +static void ef100_vdpa_net_dev_del(struct vdpa_mgmt_dev *mgmt_dev,
>> +                                  struct vdpa_device *vdev)
>> +{
>> +       struct ef100_nic_data *nic_data;
>> +       struct efx_nic *efx;
>> +       int rc;
>> +
>> +       efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
>> +       nic_data = efx->nic_data;
>> +
>> +       rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
>> +       if (rc)
>> +               pci_err(efx->pci_dev,
>> +                       "set_bar_config EF100 failed, err: %d\n", rc);
>> +       else
>> +               pci_dbg(efx->pci_dev,
>> +                       "vdpa net device deleted, vf: %u\n",
>> +                       nic_data->vf_index);
>> +}
>> +
>> +static int ef100_vdpa_net_dev_add(struct vdpa_mgmt_dev *mgmt_dev,
>> +                                 const char *name,
>> +                                 const struct vdpa_dev_set_config *config)
>> +{
>> +       struct ef100_vdpa_nic *vdpa_nic;
>> +       struct ef100_nic_data *nic_data;
>> +       struct efx_nic *efx;
>> +       int rc, err;
>> +
>> +       efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
>> +       if (efx->vdpa_nic) {
>> +               pci_warn(efx->pci_dev,
>> +                        "vDPA device already exists on this VF\n");
>> +               return -EEXIST;
>> +       }
>> +
>> +       if (config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
>> +               if (!is_valid_ether_addr(config->net.mac)) {
>> +                       pci_err(efx->pci_dev, "Invalid MAC address %pM\n",
>> +                               config->net.mac);
>> +                       return -EINVAL;
>> +               }
>> +       } else {
>> +               pci_err(efx->pci_dev, "MAC address parameter missing\n");
> Does this mean ef100 vf doesn't have a given mac address?
We are working on adding support to configure VF MAC addresses using 
devlink port and once that is available, we can get rid of this 
restriction of specifying the MAC address at vdpa device creation time.
>
>
>
>> +               return -EIO;
>> +       }
>> +
>> +       nic_data = efx->nic_data;
>> +
>> +       rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_VDPA);
>> +       if (rc) {
>> +               pci_err(efx->pci_dev,
>> +                       "set_bar_config vDPA failed, err: %d\n", rc);
>> +               goto err_set_bar_config;
>> +       }
>> +
>> +       vdpa_nic = ef100_vdpa_create(efx, name, EF100_VDPA_CLASS_NET,
>> +                                    (const u8 *)config->net.mac);
>> +       if (IS_ERR(vdpa_nic)) {
>> +               pci_err(efx->pci_dev,
>> +                       "vDPA device creation failed, vf: %u, err: %ld\n",
>> +                       nic_data->vf_index, PTR_ERR(vdpa_nic));
>> +               rc = PTR_ERR(vdpa_nic);
>> +               goto err_set_bar_config;
>> +       } else {
>> +               pci_dbg(efx->pci_dev,
>> +                       "vdpa net device created, vf: %u\n",
>> +                       nic_data->vf_index);
>> +               pci_warn(efx->pci_dev,
>> +                        "Use QEMU versions 6.1.0 and later with vhost-vdpa\n");
>> +       }
>> +
>> +       return 0;
>> +
>> +err_set_bar_config:
>> +       err = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
>> +       if (err)
>> +               pci_err(efx->pci_dev,
>> +                       "set_bar_config EF100 failed, err: %d\n", err);
>> +
>> +       return rc;
>> +}
>> +
>> +static const struct vdpa_mgmtdev_ops ef100_vdpa_net_mgmtdev_ops = {
>> +       .dev_add = ef100_vdpa_net_dev_add,
>> +       .dev_del = ef100_vdpa_net_dev_del
>> +};
>> +
>> +int ef100_vdpa_register_mgmtdev(struct efx_nic *efx)
>> +{
>> +       struct vdpa_mgmt_dev *mgmt_dev;
>> +       u64 features;
>> +       int rc;
>> +
>> +       mgmt_dev = kzalloc(sizeof(*mgmt_dev), GFP_KERNEL);
>> +       if (!mgmt_dev)
>> +               return -ENOMEM;
>> +
>> +       rc = efx_vdpa_get_features(efx, EF100_VDPA_DEVICE_TYPE_NET, &features);
>> +       if (rc) {
>> +               pci_err(efx->pci_dev, "%s: MCDI get features error:%d\n",
>> +                       __func__, rc);
>> +               goto err_get_features;
>> +       }
>> +
>> +       efx->mgmt_dev = mgmt_dev;
>> +       mgmt_dev->device = &efx->pci_dev->dev;
>> +       mgmt_dev->id_table = ef100_vdpa_id_table;
>> +       mgmt_dev->ops = &ef100_vdpa_net_mgmtdev_ops;
>> +       mgmt_dev->supported_features = features;
>> +       mgmt_dev->max_supported_vqs = EF100_VDPA_MAX_QUEUES_PAIRS * 2;
>> +       mgmt_dev->config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR);
>> +
>> +       rc = vdpa_mgmtdev_register(mgmt_dev);
>> +       if (rc) {
>> +               pci_err(efx->pci_dev,
>> +                       "vdpa_mgmtdev_register failed, err: %d\n", rc);
>> +               goto err_mgmtdev_register;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_mgmtdev_register:
>> +err_get_features:
>> +       kfree(mgmt_dev);
>> +       efx->mgmt_dev = NULL;
>> +
>> +       return rc;
>> +}
>> +
>> +void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx)
>> +{
>> +       if (efx->mgmt_dev) {
>> +               vdpa_mgmtdev_unregister(efx->mgmt_dev);
>> +               kfree(efx->mgmt_dev);
>> +               efx->mgmt_dev = NULL;
>> +       }
>> +}
>> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.h b/drivers/net/ethernet/sfc/ef100_vdpa.h
>> index 6b51a05becd8..83f6d819f6a5 100644
>> --- a/drivers/net/ethernet/sfc/ef100_vdpa.h
>> +++ b/drivers/net/ethernet/sfc/ef100_vdpa.h
>> @@ -18,6 +18,24 @@
>>
>>   #if defined(CONFIG_SFC_VDPA)
>>
>> +/* Max queue pairs currently supported */
>> +#define EF100_VDPA_MAX_QUEUES_PAIRS 1
>> +
>> +/**
>> + * enum ef100_vdpa_nic_state - possible states for a vDPA NIC
>> + *
>> + * @EF100_VDPA_STATE_INITIALIZED: State after vDPA NIC created
>> + * @EF100_VDPA_STATE_NEGOTIATED: State after feature negotiation
>> + * @EF100_VDPA_STATE_STARTED: State after driver ok
>> + * @EF100_VDPA_STATE_NSTATES: Number of VDPA states
>> + */
>> +enum ef100_vdpa_nic_state {
>> +       EF100_VDPA_STATE_INITIALIZED,
>> +       EF100_VDPA_STATE_NEGOTIATED,
>> +       EF100_VDPA_STATE_STARTED,
>> +       EF100_VDPA_STATE_NSTATES
>> +};
>> +
>>   enum ef100_vdpa_device_type {
>>          EF100_VDPA_DEVICE_TYPE_NET,
>>   };
>> @@ -28,7 +46,73 @@ enum ef100_vdpa_vq_type {
>>          EF100_VDPA_VQ_NTYPES
>>   };
>>
>> +/**
>> + *  struct ef100_vdpa_nic - vDPA NIC data structure
>> + *
>> + * @vdpa_dev: vdpa_device object which registers on the vDPA bus.
>> + * @vdpa_state: NIC state machine governed by ef100_vdpa_nic_state
>> + * @efx: pointer to the VF's efx_nic object
>> + * @lock: Managing access to vdpa config operations
>> + * @pf_index: PF index of the vDPA VF
>> + * @vf_index: VF index of the vDPA VF
>> + * @status: device status as per VIRTIO spec
>> + * @features: negotiated feature bits
>> + * @max_queue_pairs: maximum number of queue pairs supported
>> + * @net_config: virtio_net_config data
>> + * @mac_address: mac address of interface associated with this vdpa device
>> + * @mac_configured: true after MAC address is configured
>> + */
>> +struct ef100_vdpa_nic {
>> +       struct vdpa_device vdpa_dev;
>> +       enum ef100_vdpa_nic_state vdpa_state;
>> +       struct efx_nic *efx;
>> +       /* for synchronizing access to vdpa config operations */
>> +       struct mutex lock;
>> +       u32 pf_index;
>> +       u32 vf_index;
>> +       u8 status;
>> +       u64 features;
>> +       u32 max_queue_pairs;
>> +       struct virtio_net_config net_config;
>> +       u8 *mac_address;
>> +       bool mac_configured;
>> +};
>> +
>>   int ef100_vdpa_init(struct efx_probe_data *probe_data);
>>   void ef100_vdpa_fini(struct efx_probe_data *probe_data);
>> +int ef100_vdpa_register_mgmtdev(struct efx_nic *efx);
>> +void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx);
>> +
>> +static inline bool efx_vdpa_is_little_endian(struct ef100_vdpa_nic *vdpa_nic)
>> +{
>> +       return virtio_legacy_is_little_endian() ||
>> +               (vdpa_nic->features & (1ULL << VIRTIO_F_VERSION_1));
>> +}
>> +
>> +static inline u16 efx_vdpa16_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
>> +                                   __virtio16 val)
>> +{
>> +       return __virtio16_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
>> +}
>> +
>> +static inline __virtio16 cpu_to_efx_vdpa16(struct ef100_vdpa_nic *vdpa_nic,
>> +                                          u16 val)
>> +{
>> +       return __cpu_to_virtio16(efx_vdpa_is_little_endian(vdpa_nic), val);
>> +}
>> +
>> +static inline u32 efx_vdpa32_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
>> +                                   __virtio32 val)
>> +{
>> +       return __virtio32_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
>> +}
>> +
>> +static inline __virtio32 cpu_to_efx_vdpa32(struct ef100_vdpa_nic *vdpa_nic,
>> +                                          u32 val)
>> +{
>> +       return __cpu_to_virtio32(efx_vdpa_is_little_endian(vdpa_nic), val);
>> +}
>> +
>> +extern const struct vdpa_config_ops ef100_vdpa_config_ops;
>>   #endif /* CONFIG_SFC_VDPA */
>>   #endif /* __EF100_VDPA_H__ */
>> diff --git a/drivers/net/ethernet/sfc/ef100_vdpa_ops.c b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
>> new file mode 100644
>> index 000000000000..31952931c198
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
>> @@ -0,0 +1,28 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Driver for Xilinx network controllers and boards
>> + * Copyright(C) 2020-2022 Xilinx, Inc.
>> + * Copyright(C) 2022 Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#include <linux/vdpa.h>
>> +#include "ef100_vdpa.h"
>> +
>> +static struct ef100_vdpa_nic *get_vdpa_nic(struct vdpa_device *vdev)
>> +{
>> +       return container_of(vdev, struct ef100_vdpa_nic, vdpa_dev);
>> +}
>> +
>> +static void ef100_vdpa_free(struct vdpa_device *vdev)
>> +{
>> +       struct ef100_vdpa_nic *vdpa_nic = get_vdpa_nic(vdev);
>> +
>> +       mutex_destroy(&vdpa_nic->lock);
>> +}
>> +
>> +const struct vdpa_config_ops ef100_vdpa_config_ops = {
>> +       .free                = ef100_vdpa_free,
>> +};
>> diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c
>> index d3e6d8239f5c..4415f19cf68f 100644
>> --- a/drivers/net/ethernet/sfc/mcdi_functions.c
>> +++ b/drivers/net/ethernet/sfc/mcdi_functions.c
>> @@ -413,7 +413,8 @@ int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode)
>>          return 0;
>>   }
>>
>> -int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
>> +int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
>> +                   unsigned int *vf_index)
>>   {
>>          MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
>>          size_t outlen;
>> @@ -426,6 +427,10 @@ int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
>>          if (outlen < sizeof(outbuf))
>>                  return -EIO;
>>
>> -       *pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
>> +       if (pf_index)
>> +               *pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
>> +
>> +       if (efx->type->is_vf && vf_index)
>> +               *vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
>>          return 0;
>>   }
>> diff --git a/drivers/net/ethernet/sfc/mcdi_functions.h b/drivers/net/ethernet/sfc/mcdi_functions.h
>> index b0e2f53a0d9b..76dc0a13463e 100644
>> --- a/drivers/net/ethernet/sfc/mcdi_functions.h
>> +++ b/drivers/net/ethernet/sfc/mcdi_functions.h
>> @@ -28,6 +28,7 @@ void efx_mcdi_rx_remove(struct efx_rx_queue *rx_queue);
>>   void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue);
>>   int efx_fini_dmaq(struct efx_nic *efx);
>>   int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode);
>> -int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index);
>> +int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
>> +                   unsigned int *vf_index);
>>
>>   #endif
>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>> index ffda80a95221..79356d614109 100644
>> --- a/drivers/net/ethernet/sfc/net_driver.h
>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>> @@ -1182,6 +1182,12 @@ struct efx_nic {
>>
>>          unsigned int mem_bar;
>>          u32 reg_base;
>> +#ifdef CONFIG_SFC_VDPA
>> +       /** @mgmt_dev: vDPA Management device */
>> +       struct vdpa_mgmt_dev *mgmt_dev;
>> +       /** @vdpa_nic: vDPA device structure (EF100) */
>> +       struct ef100_vdpa_nic *vdpa_nic;
>> +#endif
>>
>>          /* The following fields may be written more often */
>>
>> --
>> 2.30.1
>>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 84c9f0590368..a10eac91ab23 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -11,7 +11,7 @@  sfc-$(CONFIG_SFC_MTD)	+= mtd.o
 sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
                            mae.o tc.o tc_bindings.o tc_counters.o
 
-sfc-$(CONFIG_SFC_VDPA)	+= mcdi_vdpa.o ef100_vdpa.o
+sfc-$(CONFIG_SFC_VDPA)	+= mcdi_vdpa.o ef100_vdpa.o ef100_vdpa_ops.o
 obj-$(CONFIG_SFC)	+= sfc.o
 
 obj-$(CONFIG_SFC_FALCON) += falcon/
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 7022fb2005a2..366ecd3c80b1 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -589,7 +589,7 @@  static int efx_ef10_probe(struct efx_nic *efx)
 	if (rc)
 		goto fail4;
 
-	rc = efx_get_pf_index(efx, &nic_data->pf_index);
+	rc = efx_get_fn_info(efx, &nic_data->pf_index, NULL);
 	if (rc)
 		goto fail5;
 
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 41175eb00326..41811c519275 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -1160,7 +1160,7 @@  static int ef100_probe_main(struct efx_nic *efx)
 	if (rc)
 		goto fail;
 
-	rc = efx_get_pf_index(efx, &nic_data->pf_index);
+	rc = efx_get_fn_info(efx, &nic_data->pf_index, &nic_data->vf_index);
 	if (rc)
 		goto fail;
 
@@ -1247,13 +1247,33 @@  int ef100_probe_netdev_pf(struct efx_nic *efx)
 
 int ef100_probe_vf(struct efx_nic *efx)
 {
-	return ef100_probe_main(efx);
+#if defined(CONFIG_SFC_VDPA)
+	int err;
+#endif
+	int rc;
+
+	rc = ef100_probe_main(efx);
+	if (rc)
+		return rc;
+
+#if defined(CONFIG_SFC_VDPA)
+	err = ef100_vdpa_register_mgmtdev(efx);
+	if (err)
+		pci_warn(efx->pci_dev,
+			 "vdpa_register_mgmtdev failed, err: %d\n", err);
+#endif
+	return 0;
 }
 
 void ef100_remove(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
 
+#if defined(CONFIG_SFC_VDPA)
+	if (efx_vdpa_supported(efx))
+		ef100_vdpa_unregister_mgmtdev(efx);
+#endif
+
 	efx_mcdi_detach(efx);
 	efx_mcdi_fini(efx);
 	if (nic_data) {
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index 5ed693fbe79f..730c8bb932b0 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -68,6 +68,13 @@  enum ef100_bar_config {
 	EF100_BAR_CONFIG_VDPA,
 };
 
+#ifdef CONFIG_SFC_VDPA
+enum ef100_vdpa_class {
+	EF100_VDPA_CLASS_NONE,
+	EF100_VDPA_CLASS_NET,
+};
+#endif
+
 struct ef100_nic_data {
 	struct efx_nic *efx;
 	struct efx_buffer mcdi_buf;
@@ -75,7 +82,11 @@  struct ef100_nic_data {
 	u32 datapath_caps2;
 	u32 datapath_caps3;
 	unsigned int pf_index;
+	unsigned int vf_index;
 	u16 warm_boot_count;
+#ifdef CONFIG_SFC_VDPA
+	enum ef100_vdpa_class vdpa_class;
+#endif
 	u8 port_id[ETH_ALEN];
 	DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS);
 	enum ef100_bar_config bar_config;
diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.c b/drivers/net/ethernet/sfc/ef100_vdpa.c
index 5e215cee585a..ff4bb61e598e 100644
--- a/drivers/net/ethernet/sfc/ef100_vdpa.c
+++ b/drivers/net/ethernet/sfc/ef100_vdpa.c
@@ -11,11 +11,17 @@ 
 #include <linux/err.h>
 #include <linux/vdpa.h>
 #include <linux/virtio_net.h>
+#include <uapi/linux/vdpa.h>
 #include "ef100_vdpa.h"
 #include "mcdi_vdpa.h"
 #include "mcdi_filters.h"
 #include "ef100_netdev.h"
 
+static struct virtio_device_id ef100_vdpa_id_table[] = {
+	{ .device = VIRTIO_ID_NET, .vendor = PCI_VENDOR_ID_REDHAT_QUMRANET },
+	{ 0 },
+};
+
 int ef100_vdpa_init(struct efx_probe_data *probe_data)
 {
 	struct efx_nic *efx = &probe_data->efx;
@@ -42,17 +48,243 @@  int ef100_vdpa_init(struct efx_probe_data *probe_data)
 	return rc;
 }
 
+static void ef100_vdpa_delete(struct efx_nic *efx)
+{
+	if (efx->vdpa_nic) {
+		/* replace with _vdpa_unregister_device later */
+		put_device(&efx->vdpa_nic->vdpa_dev.dev);
+		efx->vdpa_nic = NULL;
+	}
+}
+
 void ef100_vdpa_fini(struct efx_probe_data *probe_data)
 {
 	struct efx_nic *efx = &probe_data->efx;
+	struct ef100_nic_data *nic_data;
 
 	if (efx->state != STATE_VDPA && efx->state != STATE_DISABLED) {
 		pci_err(efx->pci_dev, "Invalid efx state %u", efx->state);
 		return;
 	}
 
+	/* Handle vdpa device deletion, if not done explicitly */
+	ef100_vdpa_delete(efx);
+	nic_data = efx->nic_data;
+	nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
 	efx->state = STATE_PROBED;
 	down_write(&efx->filter_sem);
 	efx_mcdi_filter_table_remove(efx);
 	up_write(&efx->filter_sem);
 }
+
+static int get_net_config(struct ef100_vdpa_nic *vdpa_nic)
+{
+	struct efx_nic *efx = vdpa_nic->efx;
+	u16 mtu;
+	int rc;
+
+	vdpa_nic->net_config.max_virtqueue_pairs =
+		cpu_to_efx_vdpa16(vdpa_nic, vdpa_nic->max_queue_pairs);
+
+	rc = efx_vdpa_get_mtu(efx, &mtu);
+	if (rc) {
+		dev_err(&vdpa_nic->vdpa_dev.dev,
+			"%s: Get MTU for vf:%u failed:%d\n", __func__,
+			vdpa_nic->vf_index, rc);
+		return rc;
+	}
+	vdpa_nic->net_config.mtu = cpu_to_efx_vdpa16(vdpa_nic, mtu);
+	vdpa_nic->net_config.status = cpu_to_efx_vdpa16(vdpa_nic,
+							VIRTIO_NET_S_LINK_UP);
+	return 0;
+}
+
+static struct ef100_vdpa_nic *ef100_vdpa_create(struct efx_nic *efx,
+						const char *dev_name,
+						enum ef100_vdpa_class dev_type,
+						const u8 *mac)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+	struct ef100_vdpa_nic *vdpa_nic;
+	struct device *dev;
+	int rc;
+
+	nic_data->vdpa_class = dev_type;
+	vdpa_nic = vdpa_alloc_device(struct ef100_vdpa_nic,
+				     vdpa_dev, &efx->pci_dev->dev,
+				     &ef100_vdpa_config_ops,
+				     1, 1,
+				     dev_name, false);
+	if (!vdpa_nic) {
+		pci_err(efx->pci_dev,
+			"vDPA device allocation failed for vf: %u\n",
+			nic_data->vf_index);
+		nic_data->vdpa_class = EF100_VDPA_CLASS_NONE;
+		return ERR_PTR(-ENOMEM);
+	}
+
+	mutex_init(&vdpa_nic->lock);
+	dev = &vdpa_nic->vdpa_dev.dev;
+	efx->vdpa_nic = vdpa_nic;
+	vdpa_nic->vdpa_dev.dma_dev = &efx->pci_dev->dev;
+	vdpa_nic->vdpa_dev.mdev = efx->mgmt_dev;
+	vdpa_nic->efx = efx;
+	vdpa_nic->pf_index = nic_data->pf_index;
+	vdpa_nic->vf_index = nic_data->vf_index;
+	vdpa_nic->vdpa_state = EF100_VDPA_STATE_INITIALIZED;
+	vdpa_nic->mac_address = (u8 *)&vdpa_nic->net_config.mac;
+	ether_addr_copy(vdpa_nic->mac_address, mac);
+	vdpa_nic->mac_configured = true;
+
+	rc = get_net_config(vdpa_nic);
+	if (rc)
+		goto err_put_device;
+
+	/* _vdpa_register_device when its ready */
+
+	return vdpa_nic;
+
+err_put_device:
+	/* put_device invokes ef100_vdpa_free */
+	put_device(&vdpa_nic->vdpa_dev.dev);
+	return ERR_PTR(rc);
+}
+
+static void ef100_vdpa_net_dev_del(struct vdpa_mgmt_dev *mgmt_dev,
+				   struct vdpa_device *vdev)
+{
+	struct ef100_nic_data *nic_data;
+	struct efx_nic *efx;
+	int rc;
+
+	efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
+	nic_data = efx->nic_data;
+
+	rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
+	if (rc)
+		pci_err(efx->pci_dev,
+			"set_bar_config EF100 failed, err: %d\n", rc);
+	else
+		pci_dbg(efx->pci_dev,
+			"vdpa net device deleted, vf: %u\n",
+			nic_data->vf_index);
+}
+
+static int ef100_vdpa_net_dev_add(struct vdpa_mgmt_dev *mgmt_dev,
+				  const char *name,
+				  const struct vdpa_dev_set_config *config)
+{
+	struct ef100_vdpa_nic *vdpa_nic;
+	struct ef100_nic_data *nic_data;
+	struct efx_nic *efx;
+	int rc, err;
+
+	efx = pci_get_drvdata(to_pci_dev(mgmt_dev->device));
+	if (efx->vdpa_nic) {
+		pci_warn(efx->pci_dev,
+			 "vDPA device already exists on this VF\n");
+		return -EEXIST;
+	}
+
+	if (config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
+		if (!is_valid_ether_addr(config->net.mac)) {
+			pci_err(efx->pci_dev, "Invalid MAC address %pM\n",
+				config->net.mac);
+			return -EINVAL;
+		}
+	} else {
+		pci_err(efx->pci_dev, "MAC address parameter missing\n");
+		return -EIO;
+	}
+
+	nic_data = efx->nic_data;
+
+	rc = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_VDPA);
+	if (rc) {
+		pci_err(efx->pci_dev,
+			"set_bar_config vDPA failed, err: %d\n", rc);
+		goto err_set_bar_config;
+	}
+
+	vdpa_nic = ef100_vdpa_create(efx, name, EF100_VDPA_CLASS_NET,
+				     (const u8 *)config->net.mac);
+	if (IS_ERR(vdpa_nic)) {
+		pci_err(efx->pci_dev,
+			"vDPA device creation failed, vf: %u, err: %ld\n",
+			nic_data->vf_index, PTR_ERR(vdpa_nic));
+		rc = PTR_ERR(vdpa_nic);
+		goto err_set_bar_config;
+	} else {
+		pci_dbg(efx->pci_dev,
+			"vdpa net device created, vf: %u\n",
+			nic_data->vf_index);
+		pci_warn(efx->pci_dev,
+			 "Use QEMU versions 6.1.0 and later with vhost-vdpa\n");
+	}
+
+	return 0;
+
+err_set_bar_config:
+	err = efx_ef100_set_bar_config(efx, EF100_BAR_CONFIG_EF100);
+	if (err)
+		pci_err(efx->pci_dev,
+			"set_bar_config EF100 failed, err: %d\n", err);
+
+	return rc;
+}
+
+static const struct vdpa_mgmtdev_ops ef100_vdpa_net_mgmtdev_ops = {
+	.dev_add = ef100_vdpa_net_dev_add,
+	.dev_del = ef100_vdpa_net_dev_del
+};
+
+int ef100_vdpa_register_mgmtdev(struct efx_nic *efx)
+{
+	struct vdpa_mgmt_dev *mgmt_dev;
+	u64 features;
+	int rc;
+
+	mgmt_dev = kzalloc(sizeof(*mgmt_dev), GFP_KERNEL);
+	if (!mgmt_dev)
+		return -ENOMEM;
+
+	rc = efx_vdpa_get_features(efx, EF100_VDPA_DEVICE_TYPE_NET, &features);
+	if (rc) {
+		pci_err(efx->pci_dev, "%s: MCDI get features error:%d\n",
+			__func__, rc);
+		goto err_get_features;
+	}
+
+	efx->mgmt_dev = mgmt_dev;
+	mgmt_dev->device = &efx->pci_dev->dev;
+	mgmt_dev->id_table = ef100_vdpa_id_table;
+	mgmt_dev->ops = &ef100_vdpa_net_mgmtdev_ops;
+	mgmt_dev->supported_features = features;
+	mgmt_dev->max_supported_vqs = EF100_VDPA_MAX_QUEUES_PAIRS * 2;
+	mgmt_dev->config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR);
+
+	rc = vdpa_mgmtdev_register(mgmt_dev);
+	if (rc) {
+		pci_err(efx->pci_dev,
+			"vdpa_mgmtdev_register failed, err: %d\n", rc);
+		goto err_mgmtdev_register;
+	}
+
+	return 0;
+
+err_mgmtdev_register:
+err_get_features:
+	kfree(mgmt_dev);
+	efx->mgmt_dev = NULL;
+
+	return rc;
+}
+
+void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx)
+{
+	if (efx->mgmt_dev) {
+		vdpa_mgmtdev_unregister(efx->mgmt_dev);
+		kfree(efx->mgmt_dev);
+		efx->mgmt_dev = NULL;
+	}
+}
diff --git a/drivers/net/ethernet/sfc/ef100_vdpa.h b/drivers/net/ethernet/sfc/ef100_vdpa.h
index 6b51a05becd8..83f6d819f6a5 100644
--- a/drivers/net/ethernet/sfc/ef100_vdpa.h
+++ b/drivers/net/ethernet/sfc/ef100_vdpa.h
@@ -18,6 +18,24 @@ 
 
 #if defined(CONFIG_SFC_VDPA)
 
+/* Max queue pairs currently supported */
+#define EF100_VDPA_MAX_QUEUES_PAIRS 1
+
+/**
+ * enum ef100_vdpa_nic_state - possible states for a vDPA NIC
+ *
+ * @EF100_VDPA_STATE_INITIALIZED: State after vDPA NIC created
+ * @EF100_VDPA_STATE_NEGOTIATED: State after feature negotiation
+ * @EF100_VDPA_STATE_STARTED: State after driver ok
+ * @EF100_VDPA_STATE_NSTATES: Number of VDPA states
+ */
+enum ef100_vdpa_nic_state {
+	EF100_VDPA_STATE_INITIALIZED,
+	EF100_VDPA_STATE_NEGOTIATED,
+	EF100_VDPA_STATE_STARTED,
+	EF100_VDPA_STATE_NSTATES
+};
+
 enum ef100_vdpa_device_type {
 	EF100_VDPA_DEVICE_TYPE_NET,
 };
@@ -28,7 +46,73 @@  enum ef100_vdpa_vq_type {
 	EF100_VDPA_VQ_NTYPES
 };
 
+/**
+ *  struct ef100_vdpa_nic - vDPA NIC data structure
+ *
+ * @vdpa_dev: vdpa_device object which registers on the vDPA bus.
+ * @vdpa_state: NIC state machine governed by ef100_vdpa_nic_state
+ * @efx: pointer to the VF's efx_nic object
+ * @lock: Managing access to vdpa config operations
+ * @pf_index: PF index of the vDPA VF
+ * @vf_index: VF index of the vDPA VF
+ * @status: device status as per VIRTIO spec
+ * @features: negotiated feature bits
+ * @max_queue_pairs: maximum number of queue pairs supported
+ * @net_config: virtio_net_config data
+ * @mac_address: mac address of interface associated with this vdpa device
+ * @mac_configured: true after MAC address is configured
+ */
+struct ef100_vdpa_nic {
+	struct vdpa_device vdpa_dev;
+	enum ef100_vdpa_nic_state vdpa_state;
+	struct efx_nic *efx;
+	/* for synchronizing access to vdpa config operations */
+	struct mutex lock;
+	u32 pf_index;
+	u32 vf_index;
+	u8 status;
+	u64 features;
+	u32 max_queue_pairs;
+	struct virtio_net_config net_config;
+	u8 *mac_address;
+	bool mac_configured;
+};
+
 int ef100_vdpa_init(struct efx_probe_data *probe_data);
 void ef100_vdpa_fini(struct efx_probe_data *probe_data);
+int ef100_vdpa_register_mgmtdev(struct efx_nic *efx);
+void ef100_vdpa_unregister_mgmtdev(struct efx_nic *efx);
+
+static inline bool efx_vdpa_is_little_endian(struct ef100_vdpa_nic *vdpa_nic)
+{
+	return virtio_legacy_is_little_endian() ||
+		(vdpa_nic->features & (1ULL << VIRTIO_F_VERSION_1));
+}
+
+static inline u16 efx_vdpa16_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
+				    __virtio16 val)
+{
+	return __virtio16_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
+}
+
+static inline __virtio16 cpu_to_efx_vdpa16(struct ef100_vdpa_nic *vdpa_nic,
+					   u16 val)
+{
+	return __cpu_to_virtio16(efx_vdpa_is_little_endian(vdpa_nic), val);
+}
+
+static inline u32 efx_vdpa32_to_cpu(struct ef100_vdpa_nic *vdpa_nic,
+				    __virtio32 val)
+{
+	return __virtio32_to_cpu(efx_vdpa_is_little_endian(vdpa_nic), val);
+}
+
+static inline __virtio32 cpu_to_efx_vdpa32(struct ef100_vdpa_nic *vdpa_nic,
+					   u32 val)
+{
+	return __cpu_to_virtio32(efx_vdpa_is_little_endian(vdpa_nic), val);
+}
+
+extern const struct vdpa_config_ops ef100_vdpa_config_ops;
 #endif /* CONFIG_SFC_VDPA */
 #endif /* __EF100_VDPA_H__ */
diff --git a/drivers/net/ethernet/sfc/ef100_vdpa_ops.c b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
new file mode 100644
index 000000000000..31952931c198
--- /dev/null
+++ b/drivers/net/ethernet/sfc/ef100_vdpa_ops.c
@@ -0,0 +1,28 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Driver for Xilinx network controllers and boards
+ * Copyright(C) 2020-2022 Xilinx, Inc.
+ * Copyright(C) 2022 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/vdpa.h>
+#include "ef100_vdpa.h"
+
+static struct ef100_vdpa_nic *get_vdpa_nic(struct vdpa_device *vdev)
+{
+	return container_of(vdev, struct ef100_vdpa_nic, vdpa_dev);
+}
+
+static void ef100_vdpa_free(struct vdpa_device *vdev)
+{
+	struct ef100_vdpa_nic *vdpa_nic = get_vdpa_nic(vdev);
+
+	mutex_destroy(&vdpa_nic->lock);
+}
+
+const struct vdpa_config_ops ef100_vdpa_config_ops = {
+	.free	             = ef100_vdpa_free,
+};
diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c
index d3e6d8239f5c..4415f19cf68f 100644
--- a/drivers/net/ethernet/sfc/mcdi_functions.c
+++ b/drivers/net/ethernet/sfc/mcdi_functions.c
@@ -413,7 +413,8 @@  int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode)
 	return 0;
 }
 
-int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
+int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
+		    unsigned int *vf_index)
 {
 	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
 	size_t outlen;
@@ -426,6 +427,10 @@  int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index)
 	if (outlen < sizeof(outbuf))
 		return -EIO;
 
-	*pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
+	if (pf_index)
+		*pf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_PF);
+
+	if (efx->type->is_vf && vf_index)
+		*vf_index = MCDI_DWORD(outbuf, GET_FUNCTION_INFO_OUT_VF);
 	return 0;
 }
diff --git a/drivers/net/ethernet/sfc/mcdi_functions.h b/drivers/net/ethernet/sfc/mcdi_functions.h
index b0e2f53a0d9b..76dc0a13463e 100644
--- a/drivers/net/ethernet/sfc/mcdi_functions.h
+++ b/drivers/net/ethernet/sfc/mcdi_functions.h
@@ -28,6 +28,7 @@  void efx_mcdi_rx_remove(struct efx_rx_queue *rx_queue);
 void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue);
 int efx_fini_dmaq(struct efx_nic *efx);
 int efx_mcdi_window_mode_to_stride(struct efx_nic *efx, u8 vi_window_mode);
-int efx_get_pf_index(struct efx_nic *efx, unsigned int *pf_index);
+int efx_get_fn_info(struct efx_nic *efx, unsigned int *pf_index,
+		    unsigned int *vf_index);
 
 #endif
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index ffda80a95221..79356d614109 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1182,6 +1182,12 @@  struct efx_nic {
 
 	unsigned int mem_bar;
 	u32 reg_base;
+#ifdef CONFIG_SFC_VDPA
+	/** @mgmt_dev: vDPA Management device */
+	struct vdpa_mgmt_dev *mgmt_dev;
+	/** @vdpa_nic: vDPA device structure (EF100) */
+	struct ef100_vdpa_nic *vdpa_nic;
+#endif
 
 	/* The following fields may be written more often */