# HG changeset patch # User Keir Fraser # Date 1229698596 0 # Node ID 2dffa6ceb0af954e7f3a9ad7e993b8aee7b7de65 # Parent 738513b106fa262a11cc3254cd6dd67afb3a63e7 Support S3 for MSI interrupt From: "Jiang, Yunhong" Signed-off-by: Keir Fraser --- 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.