During vfio-pci open_device, register a notifier for the zPCI device to catch KVM registration. This is needed in order to pass a special indicator (GISA) to firmware to allow zPCI interpretation facilities to be used for only the specific KVM associated with the vfio-pci device. During vfio-pci close_device, unregister the notifier. Signed-off-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx> --- arch/s390/include/asm/pci.h | 2 ++ drivers/vfio/pci/vfio_pci_core.c | 2 ++ drivers/vfio/pci/vfio_pci_zdev.c | 54 ++++++++++++++++++++++++++++++++ include/linux/vfio_pci_core.h | 10 ++++++ 4 files changed, 68 insertions(+) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 85eb0ef9d4c3..67fbce1ea0c9 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/mutex.h> #include <linux/iommu.h> +#include <linux/notifier.h> #include <linux/pci_hotplug.h> #include <asm-generic/pci.h> #include <asm/pci_clp.h> @@ -195,6 +196,7 @@ struct zpci_dev { struct s390_domain *s390_domain; /* s390 IOMMU domain data */ struct kvm_zdev *kzdev; struct mutex kzdev_lock; + struct notifier_block nb; /* vfio notifications */ }; static inline bool zdev_enabled(struct zpci_dev *zdev) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 06b6f3594a13..d53125b308f0 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -449,6 +449,7 @@ void vfio_pci_core_close_device(struct vfio_device *core_vdev) vdev->sriov_pf_core_dev->vf_token->users--; mutex_unlock(&vdev->sriov_pf_core_dev->vf_token->lock); } + vfio_pci_zdev_release(vdev); vfio_spapr_pci_eeh_release(vdev->pdev); vfio_pci_core_disable(vdev); @@ -469,6 +470,7 @@ void vfio_pci_core_finish_enable(struct vfio_pci_core_device *vdev) { vfio_pci_probe_mmaps(vdev); vfio_spapr_pci_eeh_open(vdev->pdev); + vfio_pci_zdev_open(vdev); if (vdev->sriov_pf_core_dev) { mutex_lock(&vdev->sriov_pf_core_dev->vf_token->lock); diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c index ea4c0d2b0663..130ab298ab98 100644 --- a/drivers/vfio/pci/vfio_pci_zdev.c +++ b/drivers/vfio/pci/vfio_pci_zdev.c @@ -11,6 +11,7 @@ #include <linux/uaccess.h> #include <linux/vfio.h> #include <linux/vfio_zdev.h> +#include <linux/kvm_host.h> #include <asm/pci_clp.h> #include <asm/pci_io.h> @@ -136,3 +137,56 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, return ret; } + +static int vfio_pci_zdev_group_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct zpci_dev *zdev = container_of(nb, struct zpci_dev, nb); + + if (action == VFIO_GROUP_NOTIFY_SET_KVM) { + if (!zdev) + return NOTIFY_DONE; + + if (data) { + if (kvm_s390_pci_register_kvm(zdev, (struct kvm *)data)) + return NOTIFY_BAD; + } else { + if (kvm_s390_pci_unregister_kvm(zdev)) + return NOTIFY_BAD; + } + + } + + return NOTIFY_OK; +} + +void vfio_pci_zdev_open(struct vfio_pci_core_device *vdev) +{ + unsigned long events = VFIO_GROUP_NOTIFY_SET_KVM; + struct zpci_dev *zdev = to_zpci(vdev->pdev); + + if (!zdev) + return; + + zdev->nb.notifier_call = vfio_pci_zdev_group_notifier; + + vfio_register_notifier(vdev->vdev.dev, VFIO_GROUP_NOTIFY, + &events, &zdev->nb); +} + +void vfio_pci_zdev_release(struct vfio_pci_core_device *vdev) +{ + struct zpci_dev *zdev = to_zpci(vdev->pdev); + + if (!zdev) + return; + + vfio_unregister_notifier(vdev->vdev.dev, VFIO_GROUP_NOTIFY, + &zdev->nb); + + /* + * It's possible that the notifier is unregistered and we still have a + * kvm association registered -- clean it up now. + */ + kvm_s390_pci_unregister_kvm(zdev); +} diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index cfc9eb1f0b27..68ab01b592d3 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -209,12 +209,22 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) #ifdef CONFIG_VFIO_PCI_ZDEV_KVM extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps); +void vfio_pci_zdev_open(struct vfio_pci_core_device *vdev); +void vfio_pci_zdev_release(struct vfio_pci_core_device *vdev); #else static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps) { return -ENODEV; } + +static inline void vfio_pci_zdev_open(struct vfio_pci_core_device *vdev) +{ +} + +static inline void vfio_pci_zdev_release(struct vfio_pci_core_device *vdev) +{ +} #endif /* Will be exported for vfio pci drivers usage */ -- 2.27.0