From: Keir Fraser Date: Fri, 19 Dec 2008 14:56:36 +0000 (+0000) Subject: Support S3 for MSI interrupt X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14026^2~4 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=9913ea3300493461dbadf167b7bc5f0308f20d8c;p=xen.git Support S3 for MSI interrupt From: "Jiang, Yunhong" Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c index 30bf9052c4..fdca2453ce 100644 --- a/xen/arch/x86/msi.c +++ b/xen/arch/x86/msi.c @@ -741,3 +741,43 @@ void pci_cleanup_msi(struct pci_dev *pdev) 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; + + ASSERT(spin_is_locked(&pcidevs_lock)); + + 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; +} + diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index fafe74f546..89a1d686fa 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -415,6 +415,24 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) 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; + + spin_lock(&pcidevs_lock); + pdev = pci_get_pdev(restore_msi.bus, restore_msi.devfn); + ret = pdev ? pci_restore_msi_state(pdev) : -ENODEV; + spin_unlock(&pcidevs_lock); + break; + } default: ret = -ENOSYS; break; diff --git a/xen/include/asm-x86/msi.h b/xen/include/asm-x86/msi.h index 779ee8d46b..1f18b7c5e3 100644 --- a/xen/include/asm-x86/msi.h +++ b/xen/include/asm-x86/msi.h @@ -79,6 +79,7 @@ extern void pci_cleanup_msi(struct pci_dev *pdev); extern int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); extern void teardown_msi_vector(int vector); extern int msi_free_vector(struct msi_desc *entry); +extern int pci_restore_msi_state(struct pci_dev *pdev); struct msi_desc { struct { diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index b4d303ffe3..72a42cf265 100644 --- 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.