@@ -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_reset:
case PHYSDEVOP_dbgp_op:
if ( !is_hardware_domain(currd) )
return -ENOSYS;
@@ -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,57 @@ ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
break;
}
+ case PHYSDEVOP_pci_device_reset:
+ {
+ struct pci_device_reset dev_reset;
+ struct pci_dev *pdev;
+ pci_sbdf_t sbdf;
+
+ ret = -EFAULT;
+ if ( copy_from_guest(&dev_reset, arg, 1) != 0 )
+ break;
+
+ ret = -EINVAL;
+ if ( dev_reset.flags & ~PCI_DEVICE_RESET_MASK )
+ break;
+
+ sbdf = PCI_SBDF(dev_reset.dev.seg,
+ dev_reset.dev.bus,
+ dev_reset.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);
+ pcidevs_unlock();
+ switch ( dev_reset.flags & PCI_DEVICE_RESET_MASK )
+ {
+ case PCI_DEVICE_RESET_COLD:
+ case PCI_DEVICE_RESET_WARM:
+ case PCI_DEVICE_RESET_HOT:
+ case PCI_DEVICE_RESET_FLR:
+ ret = vpci_reset_device(pdev);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ write_unlock(&pdev->domain->pci_lock);
+
+ break;
+ }
+
default:
ret = -ENOSYS;
break;
@@ -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_reset 32
+
struct physdev_pci_device {
/* IN */
uint16_t seg;
@@ -305,6 +312,16 @@ struct physdev_pci_device {
typedef struct physdev_pci_device physdev_pci_device_t;
DEFINE_XEN_GUEST_HANDLE(physdev_pci_device_t);
+struct pci_device_reset {
+ physdev_pci_device_t dev;
+#define PCI_DEVICE_RESET_COLD 0x0
+#define PCI_DEVICE_RESET_WARM 0x1
+#define PCI_DEVICE_RESET_HOT 0x2
+#define PCI_DEVICE_RESET_FLR 0x3
+#define PCI_DEVICE_RESET_MASK 0x3
+ uint32_t flags;
+};
+
#define PHYSDEVOP_DBGP_RESET_PREPARE 1
#define PHYSDEVOP_DBGP_RESET_DONE 2
@@ -304,6 +304,12 @@ static inline bool __must_check vpci_process_pending(struct vcpu *v)
}
#endif
+static inline int __must_check vpci_reset_device(struct pci_dev *pdev)
+{
+ vpci_deassign_device(pdev);
+ return vpci_assign_device(pdev);
+}
+
#endif
/*