The pds_core driver will create auxiliary devices for each PCI device supported by pds_vfio. In order to communicate with the device, the pds_vfio driver needs to register as an auxiliary driver for the previously mentioned auxiliary device. Once the auxiliary device is probed, the pds_vfio driver can send admin queue commands and receive events from the device by way of pds_core. Use the following commands to enable a VF and tell pds_core to create its corresponding auxiliary device: echo 1 > /sys/bus/pci/drivers/pds_core/$PF_BDF/sriov_numvfs devlink dev param set pci/$PF_BDF name enable_migration value true cmode runtime This functionality is needed to support live migration commands, which are added later in the series. Signed-off-by: Brett Creeley <brett.creeley@xxxxxxx> Signed-off-by: Shannon Nelson <shannon.nelson@xxxxxxx> --- drivers/vfio/pci/pds/Makefile | 2 + drivers/vfio/pci/pds/aux_drv.c | 154 ++++++++++++++++++++++++++++++++ drivers/vfio/pci/pds/aux_drv.h | 29 ++++++ drivers/vfio/pci/pds/cmds.c | 30 +++++++ drivers/vfio/pci/pds/cmds.h | 14 +++ drivers/vfio/pci/pds/pci_drv.c | 18 +++- drivers/vfio/pci/pds/pci_drv.h | 11 +++ drivers/vfio/pci/pds/vfio_dev.c | 8 ++ drivers/vfio/pci/pds/vfio_dev.h | 1 + include/linux/pds/pds_lm.h | 12 +++ 10 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 drivers/vfio/pci/pds/aux_drv.c create mode 100644 drivers/vfio/pci/pds/aux_drv.h create mode 100644 drivers/vfio/pci/pds/cmds.c create mode 100644 drivers/vfio/pci/pds/cmds.h create mode 100644 drivers/vfio/pci/pds/pci_drv.h create mode 100644 include/linux/pds/pds_lm.h diff --git a/drivers/vfio/pci/pds/Makefile b/drivers/vfio/pci/pds/Makefile index dcc8f6beffe2..49bf8289739b 100644 --- a/drivers/vfio/pci/pds/Makefile +++ b/drivers/vfio/pci/pds/Makefile @@ -2,5 +2,7 @@ obj-$(CONFIG_PDS_VFIO_PCI) += pds_vfio.o pds_vfio-y := \ + aux_drv.o \ + cmds.o \ pci_drv.o \ vfio_dev.o diff --git a/drivers/vfio/pci/pds/aux_drv.c b/drivers/vfio/pci/pds/aux_drv.c new file mode 100644 index 000000000000..494551894926 --- /dev/null +++ b/drivers/vfio/pci/pds/aux_drv.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Pensando Systems, Inc */ + +#include <linux/auxiliary_bus.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +#include <linux/pds/pds_core_if.h> +#include <linux/pds/pds_adminq.h> +#include <linux/pds/pds_auxbus.h> +#include <linux/pds/pds_lm.h> + +#include "aux_drv.h" +#include "vfio_dev.h" +#include "pci_drv.h" +#include "cmds.h" + +static const +struct auxiliary_device_id pds_vfio_aux_id_table[] = { + { .name = PDS_LM_DEV_NAME, }, + {}, +}; + +static void +pds_vfio_aux_notify_handler(struct pds_auxiliary_dev *padev, + union pds_core_notifyq_comp *event) +{ + struct device *dev = &padev->aux_dev.dev; + u16 ecode = le16_to_cpu(event->ecode); + + dev_dbg(dev, "%s: event code %d\n", __func__, ecode); +} + +static int +pds_vfio_aux_probe(struct auxiliary_device *aux_dev, + const struct auxiliary_device_id *id) + +{ + struct pds_auxiliary_dev *padev = + container_of(aux_dev, struct pds_auxiliary_dev, aux_dev); + struct pds_vfio_pci_device *pds_vfio; + struct device *dev = &aux_dev->dev; + struct pds_vfio_aux *vfio_aux; + struct pci_dev *pdev; + struct pci_bus *bus; + int busnr; + u16 devfn; + int err; + + /* Find our VF PCI device */ + busnr = PCI_BUS_NUM(padev->id); + devfn = padev->id & 0xff; + bus = pci_find_bus(0, busnr); + pdev = pci_get_slot(bus, devfn); + + if (!pds_vfio_is_vfio_pci_driver(pdev)) { + dev_dbg(&aux_dev->dev, "unbind %s from %s driver and bind to %s driver for live migration support\n", + pci_name(pdev), dev_driver_string(&pdev->dev), PDS_VFIO_DRV_NAME); + return -EPROBE_DEFER; + } + + pds_vfio = pci_get_drvdata(pdev); + if (!pds_vfio) { + dev_dbg(&pdev->dev, "PCI device not probed yet, defer until PCI device is probed by %s driver\n", + PDS_VFIO_DRV_NAME); + return -EPROBE_DEFER; + } + + vfio_aux = kzalloc(sizeof(*vfio_aux), GFP_KERNEL); + if (!vfio_aux) + return -ENOMEM; + + vfio_aux->padev = padev; + vfio_aux->pds_vfio = pds_vfio; + auxiliary_set_drvdata(aux_dev, vfio_aux); + + dev_dbg(dev, "%s: id %#04x busnr %#x devfn %#x bus %p pds_vfio %p\n", + __func__, padev->id, busnr, devfn, bus, vfio_aux->pds_vfio); + + vfio_aux->pds_vfio->vfio_aux = vfio_aux; + + vfio_aux->padrv.event_handler = pds_vfio_aux_notify_handler; + err = pds_vfio_register_client_cmd(vfio_aux->pds_vfio); + if (err) { + dev_err(dev, "failed to register as client: %pe\n", + ERR_PTR(err)); + goto err_out; + } + + return 0; + +err_out: + auxiliary_set_drvdata(aux_dev, NULL); + kfree(vfio_aux); + + return err; +} + +static void +pds_vfio_aux_remove(struct auxiliary_device *aux_dev) +{ + struct pds_vfio_aux *vfio_aux = auxiliary_get_drvdata(aux_dev); + struct pds_vfio_pci_device *pds_vfio = vfio_aux->pds_vfio; + + if (pds_vfio) { + pds_vfio_unregister_client_cmd(pds_vfio); + vfio_aux->pds_vfio->vfio_aux = NULL; + pci_dev_put(pds_vfio->pdev); + } + + kfree(vfio_aux); + auxiliary_set_drvdata(aux_dev, NULL); +} + +static struct auxiliary_driver +pds_vfio_aux_driver = { + .name = PDS_DEV_TYPE_LM_STR, + .probe = pds_vfio_aux_probe, + .remove = pds_vfio_aux_remove, + .id_table = pds_vfio_aux_id_table, +}; + +struct auxiliary_driver * +pds_vfio_aux_driver_info(void) +{ + return &pds_vfio_aux_driver; +} + +static int +pds_vfio_aux_match_id(struct device *dev, const void *data) +{ + dev_dbg(dev, "%s: %s\n", __func__, (char *)data); + return !strcmp(dev_name(dev), data); +} + +struct pds_vfio_aux * +pds_vfio_aux_get_drvdata(int vf_pci_id) +{ + struct auxiliary_device *aux_dev; + char name[32]; + + snprintf(name, sizeof(name), "%s.%d", PDS_LM_DEV_NAME, vf_pci_id); + aux_dev = auxiliary_find_device(NULL, name, pds_vfio_aux_match_id); + if (!aux_dev) + return NULL; + + return auxiliary_get_drvdata(aux_dev); +} + +void +pds_vfio_put_aux_dev(struct pds_vfio_aux *vfio_aux) +{ + put_device(&vfio_aux->padev->aux_dev.dev); +} diff --git a/drivers/vfio/pci/pds/aux_drv.h b/drivers/vfio/pci/pds/aux_drv.h new file mode 100644 index 000000000000..0f05a968bb00 --- /dev/null +++ b/drivers/vfio/pci/pds/aux_drv.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Pensando Systems, Inc */ + +#ifndef _AUX_DRV_H_ +#define _AUX_DRV_H_ + +#include <linux/auxiliary_bus.h> + +#include <linux/pds/pds_intr.h> +#include <linux/pds/pds_common.h> +#include <linux/pds/pds_adminq.h> +#include <linux/pds/pds_auxbus.h> + +struct pds_vfio_pci_device; + +struct pds_vfio_aux { + struct pds_auxiliary_dev *padev; + struct pds_auxiliary_drv padrv; + struct pds_vfio_pci_device *pds_vfio; +}; + +struct auxiliary_driver * +pds_vfio_aux_driver_info(void); +struct pds_vfio_aux * +pds_vfio_aux_get_drvdata(int vf_pci_id); +void +pds_vfio_put_aux_dev(struct pds_vfio_aux *vfio_aux); + +#endif /* _AUX_DRV_H_ */ diff --git a/drivers/vfio/pci/pds/cmds.c b/drivers/vfio/pci/pds/cmds.c new file mode 100644 index 000000000000..5a3fadcd38d8 --- /dev/null +++ b/drivers/vfio/pci/pds/cmds.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Pensando Systems, Inc */ + +#include <linux/io.h> +#include <linux/types.h> + +#include <linux/pds/pds_core_if.h> +#include <linux/pds/pds_adminq.h> +#include <linux/pds/pds_auxbus.h> + +#include "vfio_dev.h" +#include "aux_drv.h" +#include "cmds.h" + +int +pds_vfio_register_client_cmd(struct pds_vfio_pci_device *pds_vfio) +{ + struct pds_vfio_aux *vfio_aux = pds_vfio->vfio_aux; + struct pds_auxiliary_dev *padev = vfio_aux->padev; + + return padev->ops->register_client(padev, &vfio_aux->padrv); +} + +void +pds_vfio_unregister_client_cmd(struct pds_vfio_pci_device *pds_vfio) +{ + struct pds_auxiliary_dev *padev = pds_vfio->vfio_aux->padev; + + padev->ops->unregister_client(padev); +} diff --git a/drivers/vfio/pci/pds/cmds.h b/drivers/vfio/pci/pds/cmds.h new file mode 100644 index 000000000000..7fe2d1efd894 --- /dev/null +++ b/drivers/vfio/pci/pds/cmds.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Pensando Systems, Inc */ + +#ifndef _CMDS_H_ +#define _CMDS_H_ + +struct pds_vfio_pci_device; + +int +pds_vfio_register_client_cmd(struct pds_vfio_pci_device *pds_vfio); +void +pds_vfio_unregister_client_cmd(struct pds_vfio_pci_device *pds_vfio); + +#endif /* _CMDS_H_ */ diff --git a/drivers/vfio/pci/pds/pci_drv.c b/drivers/vfio/pci/pds/pci_drv.c index 09cab0dbb0e9..d6ad15719ec4 100644 --- a/drivers/vfio/pci/pds/pci_drv.c +++ b/drivers/vfio/pci/pds/pci_drv.c @@ -11,8 +11,9 @@ #include <linux/pds/pds_core_if.h> #include "vfio_dev.h" +#include "aux_drv.h" +#include "pci_drv.h" -#define PDS_VFIO_DRV_NAME "pds_vfio" #define PDS_VFIO_DRV_DESCRIPTION "Pensando VFIO Device Driver" #define PCI_VENDOR_ID_PENSANDO 0x1dd8 @@ -75,9 +76,17 @@ pds_vfio_pci_driver = { .driver_managed_dma = true, }; +bool +pds_vfio_is_vfio_pci_driver(struct pci_dev *pdev) +{ + return (to_pci_driver(pdev->dev.driver) == &pds_vfio_pci_driver); +} + static void __exit pds_vfio_pci_cleanup(void) { + auxiliary_driver_unregister(pds_vfio_aux_driver_info()); + pci_unregister_driver(&pds_vfio_pci_driver); } module_exit(pds_vfio_pci_cleanup); @@ -93,6 +102,13 @@ pds_vfio_pci_init(void) return err; } + err = auxiliary_driver_register(pds_vfio_aux_driver_info()); + if (err) { + pr_err("aux driver register failed: %pe\n", ERR_PTR(err)); + pci_unregister_driver(&pds_vfio_pci_driver); + return err; + } + return 0; } module_init(pds_vfio_pci_init); diff --git a/drivers/vfio/pci/pds/pci_drv.h b/drivers/vfio/pci/pds/pci_drv.h new file mode 100644 index 000000000000..549092f40f5a --- /dev/null +++ b/drivers/vfio/pci/pds/pci_drv.h @@ -0,0 +1,11 @@ +#ifndef _PCI_DRV_H +#define _PCI_DRV_H + +#include <linux/pci.h> + +#define PDS_VFIO_DRV_NAME "pds_vfio" + +bool +pds_vfio_is_vfio_pci_driver(struct pci_dev *pdev); + +#endif /* _PCI_DRV_H */ diff --git a/drivers/vfio/pci/pds/vfio_dev.c b/drivers/vfio/pci/pds/vfio_dev.c index f8f4006c0915..30c3bb47a2be 100644 --- a/drivers/vfio/pci/pds/vfio_dev.c +++ b/drivers/vfio/pci/pds/vfio_dev.c @@ -5,6 +5,7 @@ #include <linux/vfio_pci_core.h> #include "vfio_dev.h" +#include "aux_drv.h" struct pds_vfio_pci_device * pds_vfio_pci_drvdata(struct pci_dev *pdev) @@ -22,6 +23,7 @@ pds_vfio_init_device(struct vfio_device *vdev) container_of(vdev, struct pds_vfio_pci_device, vfio_coredev.vdev); struct pci_dev *pdev = to_pci_dev(vdev->dev); + struct pds_vfio_aux *vfio_aux; int err; err = vfio_pci_core_init_dev(vdev); @@ -30,6 +32,12 @@ pds_vfio_init_device(struct vfio_device *vdev) pds_vfio->vf_id = pci_iov_vf_id(pdev); pds_vfio->pci_id = PCI_DEVID(pdev->bus->number, pdev->devfn); + vfio_aux = pds_vfio_aux_get_drvdata(pds_vfio->pci_id); + if (vfio_aux) { + vfio_aux->pds_vfio = pds_vfio; + pds_vfio->vfio_aux = vfio_aux; + pds_vfio_put_aux_dev(vfio_aux); + } return 0; } diff --git a/drivers/vfio/pci/pds/vfio_dev.h b/drivers/vfio/pci/pds/vfio_dev.h index 289479a08dce..b16668693e1f 100644 --- a/drivers/vfio/pci/pds/vfio_dev.h +++ b/drivers/vfio/pci/pds/vfio_dev.h @@ -10,6 +10,7 @@ struct pds_vfio_pci_device { struct vfio_pci_core_device vfio_coredev; struct pci_dev *pdev; + struct pds_vfio_aux *vfio_aux; int vf_id; int pci_id; diff --git a/include/linux/pds/pds_lm.h b/include/linux/pds/pds_lm.h new file mode 100644 index 000000000000..fdaf2bf71d35 --- /dev/null +++ b/include/linux/pds/pds_lm.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Pensando Systems, Inc */ + +#ifndef _PDS_LM_H_ +#define _PDS_LM_H_ + +#include "pds_common.h" + +#define PDS_DEV_TYPE_LM_STR "LM" +#define PDS_LM_DEV_NAME PDS_CORE_DRV_NAME "." PDS_DEV_TYPE_LM_STR + +#endif /* _PDS_LM_H_ */ -- 2.17.1