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 | 50 ++++++++++++++++++++++++++++++++ include/linux/vfio_pci_core.h | 10 +++++++ 4 files changed, 64 insertions(+) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 322060a75d9f..fdcc95b36edb 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> @@ -194,6 +195,7 @@ struct zpci_dev { /* IOMMU and passthrough */ struct s390_domain *s390_domain; /* s390 IOMMU domain data */ struct kvm_zdev *kzdev; + 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..112c1f820f8e 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,52 @@ 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); + int (*fn)(struct zpci_dev *zdev, struct kvm *kvm); + int rc = NOTIFY_OK; + + if (action == VFIO_GROUP_NOTIFY_SET_KVM) { + if (!zdev) + return NOTIFY_DONE; + + fn = symbol_get(kvm_s390_pci_register_kvm); + if (!fn) + return NOTIFY_DONE; + + if (fn(zdev, (struct kvm *)data)) + rc = NOTIFY_BAD; + + symbol_put(kvm_s390_pci_register_kvm); + } + + return rc; +} + +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); +} diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 48f2dd3c568c..b1b285421c18 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_S390 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