113 lines
3.0 KiB
Diff
113 lines
3.0 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1229698596 0
|
|
# Node ID 2dffa6ceb0af954e7f3a9ad7e993b8aee7b7de65
|
|
# Parent 738513b106fa262a11cc3254cd6dd67afb3a63e7
|
|
Support S3 for MSI interrupt
|
|
|
|
From: "Jiang, Yunhong" <yunhong.jiang@intel.com>
|
|
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
|
|
|
|
--- a/xen/arch/x86/msi.c
|
|
+++ b/xen/arch/x86/msi.c
|
|
@@ -771,3 +771,41 @@ void pci_cleanup_msi(struct pci_dev *pde
|
|
msi_free_vectors(pdev);
|
|
}
|
|
|
|
+int pci_restore_msi_state(struct pci_dev *pdev)
|
|
+{
|
|
+ unsigned long flags;
|
|
+ int vector;
|
|
+ struct msi_desc *entry, *tmp;
|
|
+ irq_desc_t *desc;
|
|
+
|
|
+ if (!pdev)
|
|
+ return -EINVAL;
|
|
+
|
|
+ list_for_each_entry_safe( entry, tmp, &pdev->msi_list, list )
|
|
+ {
|
|
+ vector = entry->vector;
|
|
+ desc = &irq_desc[vector];
|
|
+
|
|
+ spin_lock_irqsave(&desc->lock, flags);
|
|
+
|
|
+ ASSERT(desc->msi_desc == entry);
|
|
+
|
|
+ if (desc->msi_desc != entry)
|
|
+ {
|
|
+ dprintk(XENLOG_ERR, "Restore MSI for dev %x:%x not set before?\n",
|
|
+ pdev->bus, pdev->devfn);
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ msi_set_enable(pdev, 0);
|
|
+ write_msi_msg(entry, &entry->msg);
|
|
+
|
|
+ msi_set_enable(pdev, 1);
|
|
+ msi_set_mask_bit(vector, entry->msi_attrib.masked);
|
|
+ spin_unlock_irqrestore(&desc->lock, flags);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
--- a/xen/arch/x86/physdev.c
|
|
+++ b/xen/arch/x86/physdev.c
|
|
@@ -427,6 +427,27 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
|
|
break;
|
|
}
|
|
|
|
+ case PHYSDEVOP_restore_msi: {
|
|
+ struct physdev_restore_msi restore_msi;
|
|
+ struct pci_dev *pdev;
|
|
+
|
|
+ ret = -EPERM;
|
|
+ if ( !IS_PRIV(v->domain) )
|
|
+ break;
|
|
+
|
|
+ ret = -EFAULT;
|
|
+ if ( copy_from_guest(&restore_msi, arg, 1) != 0 )
|
|
+ break;
|
|
+
|
|
+ pdev = pci_lock_pdev(restore_msi.bus, restore_msi.devfn);
|
|
+ ret = -ENODEV;
|
|
+ if ( !pdev )
|
|
+ break;
|
|
+
|
|
+ ret = pci_restore_msi_state(pdev);
|
|
+ spin_unlock(&pdev->lock);
|
|
+ break;
|
|
+ }
|
|
default:
|
|
ret = -ENOSYS;
|
|
break;
|
|
--- a/xen/include/asm-x86/msi.h
|
|
+++ b/xen/include/asm-x86/msi.h
|
|
@@ -75,6 +75,7 @@ extern void set_msi_irq_affinity(unsigne
|
|
extern int pci_enable_msi(struct msi_info *msi);
|
|
extern void pci_disable_msi(int vector);
|
|
extern void pci_cleanup_msi(struct pci_dev *pdev);
|
|
+extern int pci_restore_msi_state(struct pci_dev *pdev);
|
|
|
|
struct msi_desc {
|
|
struct {
|
|
--- a/xen/include/public/physdev.h
|
|
+++ b/xen/include/public/physdev.h
|
|
@@ -183,6 +183,15 @@ struct physdev_manage_pci {
|
|
typedef struct physdev_manage_pci physdev_manage_pci_t;
|
|
DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t);
|
|
|
|
+#define PHYSDEVOP_restore_msi 19
|
|
+struct physdev_restore_msi {
|
|
+ /* IN */
|
|
+ uint8_t bus;
|
|
+ uint8_t devfn;
|
|
+};
|
|
+typedef struct physdev_restore_msi physdev_restore_msi_t;
|
|
+DEFINE_XEN_GUEST_HANDLE(physdev_restore_msi_t);
|
|
+
|
|
/*
|
|
* Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
|
|
* hypercall since 0x00030202.
|