Message ID | 20240419035340.608833-2-Jiqian.Chen@amd.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Support device passthrough when dom0 is PVH on Xen | expand |
On 4/18/24 23:53, Jiqian Chen wrote: > When a device has been reset on dom0 side, the vpci on Xen > side won't get notification, so the cached state in vpci is > all out of date compare with the real device state. > To solve that problem, add a new hypercall to clear all vpci > device state. When the state of device is reset on dom0 side, > dom0 can call this hypercall to notify vpci. > > Signed-off-by: Huang Rui <ray.huang@amd.com> > Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com> > Reviewed-by: Stewart Hildebrand <stewart.hildebrand@amd.com> > Reviewed-by: Stefano Stabellini <sstabellini@kernel.org> Could we consider this patch for 4.19? It's independent of the rest of this series, and it fixes a real issue observed on both Arm and x86. The Linux counterpart has already been merged in linux-next [0]. [0] https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20240515&id=b272722511d5e8ae580f01830687b8a6b2717f01
On Wed, 2024-05-15 at 10:27 -0400, Stewart Hildebrand wrote: > On 4/18/24 23:53, Jiqian Chen wrote: > > When a device has been reset on dom0 side, the vpci on Xen > > side won't get notification, so the cached state in vpci is > > all out of date compare with the real device state. > > To solve that problem, add a new hypercall to clear all vpci > > device state. When the state of device is reset on dom0 side, > > dom0 can call this hypercall to notify vpci. > > > > Signed-off-by: Huang Rui <ray.huang@amd.com> > > Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com> > > Reviewed-by: Stewart Hildebrand <stewart.hildebrand@amd.com> > > Reviewed-by: Stefano Stabellini <sstabellini@kernel.org> > > Could we consider this patch for 4.19? It's independent of the rest > of > this series, and it fixes a real issue observed on both Arm and x86. > The > Linux counterpart has already been merged in linux-next [0]. > > [0] > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20240515&id=b272722511d5e8ae580f01830687b8a6b2717f01 Sure! Fixes should be merged. Release-acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> ~ Oleksii
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index 14679dd82971..56fbb69ab201 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -84,6 +84,7 @@ long hvm_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) case PHYSDEVOP_pci_mmcfg_reserved: case PHYSDEVOP_pci_device_add: case PHYSDEVOP_pci_device_remove: + case PHYSDEVOP_pci_device_state_reset: case PHYSDEVOP_dbgp_op: if ( !is_hardware_domain(currd) ) return -ENOSYS; diff --git a/xen/drivers/pci/physdev.c b/xen/drivers/pci/physdev.c index 42db3e6d133c..73dc8f058b0e 100644 --- a/xen/drivers/pci/physdev.c +++ b/xen/drivers/pci/physdev.c @@ -2,6 +2,7 @@ #include <xen/guest_access.h> #include <xen/hypercall.h> #include <xen/init.h> +#include <xen/vpci.h> #ifndef COMPAT typedef long ret_t; @@ -67,6 +68,41 @@ ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) break; } + case PHYSDEVOP_pci_device_state_reset: { + struct physdev_pci_device dev; + struct pci_dev *pdev; + pci_sbdf_t sbdf; + + if ( !is_pci_passthrough_enabled() ) + return -EOPNOTSUPP; + + ret = -EFAULT; + if ( copy_from_guest(&dev, arg, 1) != 0 ) + break; + sbdf = PCI_SBDF(dev.seg, dev.bus, dev.devfn); + + ret = xsm_resource_setup_pci(XSM_PRIV, sbdf.sbdf); + if ( ret ) + break; + + pcidevs_lock(); + pdev = pci_get_pdev(NULL, sbdf); + if ( !pdev ) + { + pcidevs_unlock(); + ret = -ENODEV; + break; + } + + write_lock(&pdev->domain->pci_lock); + ret = vpci_reset_device_state(pdev); + write_unlock(&pdev->domain->pci_lock); + pcidevs_unlock(); + if ( ret ) + printk(XENLOG_ERR "%pp: failed to reset PCI device state\n", &sbdf); + break; + } + default: ret = -ENOSYS; break; diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c index 97e115dc5798..424aec2d5c46 100644 --- a/xen/drivers/vpci/vpci.c +++ b/xen/drivers/vpci/vpci.c @@ -115,6 +115,16 @@ int vpci_assign_device(struct pci_dev *pdev) return rc; } + +int vpci_reset_device_state(struct pci_dev *pdev) +{ + ASSERT(pcidevs_locked()); + ASSERT(rw_is_write_locked(&pdev->domain->pci_lock)); + + vpci_deassign_device(pdev); + return vpci_assign_device(pdev); +} + #endif /* __XEN__ */ static int vpci_register_cmp(const struct vpci_register *r1, diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index f0c0d4727c0b..f5bab1f29779 100644 --- a/xen/include/public/physdev.h +++ b/xen/include/public/physdev.h @@ -296,6 +296,13 @@ DEFINE_XEN_GUEST_HANDLE(physdev_pci_device_add_t); */ #define PHYSDEVOP_prepare_msix 30 #define PHYSDEVOP_release_msix 31 +/* + * Notify the hypervisor that a PCI device has been reset, so that any + * internally cached state is regenerated. Should be called after any + * device reset performed by the hardware domain. + */ +#define PHYSDEVOP_pci_device_state_reset 32 + struct physdev_pci_device { /* IN */ uint16_t seg; diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index e89c571890b2..ea64d94e818b 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -30,6 +30,7 @@ int __must_check vpci_assign_device(struct pci_dev *pdev); /* Remove all handlers and free vpci related structures. */ void vpci_deassign_device(struct pci_dev *pdev); +int __must_check vpci_reset_device_state(struct pci_dev *pdev); /* Add/remove a register handler. */ int __must_check vpci_add_register_mask(struct vpci *vpci, @@ -266,6 +267,11 @@ static inline int vpci_assign_device(struct pci_dev *pdev) static inline void vpci_deassign_device(struct pci_dev *pdev) { } +static inline int __must_check vpci_reset_device_state(struct pci_dev *pdev) +{ + return 0; +} + static inline void vpci_dump_msi(void) { } static inline uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg,