[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] Fix buggy mask_base in saving/restoring MSI-X table during S3



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1228218887 0
# Node ID 63a878f8851b3b15c21e83ddda4aa36fe3bd9a80
# Parent  cdc6729dc7025594b902ef01795bfafd4c14ea3c
Fix buggy mask_base in saving/restoring MSI-X table during S3

Fix mask_base (actually MSI-X table base, copy name from native) to be
a virtual address rather than a physical address. And remove wrong
printk in pci_disable_msix.

Signed-off-by: Shan Haitao <haitao.shan@xxxxxxxxx>
---
 drivers/pci/msi-xen.c |   52 ++++++++++++++++++++++++--------------------------
 1 files changed, 25 insertions(+), 27 deletions(-)

diff -r cdc6729dc702 -r 63a878f8851b drivers/pci/msi-xen.c
--- a/drivers/pci/msi-xen.c     Fri Nov 28 13:41:38 2008 +0000
+++ b/drivers/pci/msi-xen.c     Tue Dec 02 11:54:47 2008 +0000
@@ -42,6 +42,8 @@ struct msi_dev_list {
        struct list_head list;
        spinlock_t pirq_list_lock;
        struct list_head pirq_list_head;
+       /* Used for saving/restoring MSI-X tables */
+       void __iomem *mask_base;
 };
 
 struct msi_pirq_entry {
@@ -50,7 +52,6 @@ struct msi_pirq_entry {
        int entry_nr;
 #ifdef CONFIG_PM
        /* PM save area for MSIX address/data */
-       void __iomem *mask_base;
        u32     address_hi_save;
        u32     address_lo_save;
        u32     data_save;
@@ -90,7 +91,7 @@ static struct msi_dev_list *get_msi_dev_
        return ret;
 }
 
-static int attach_pirq_entry(int pirq, int entry_nr, u64 table_base,
+static int attach_pirq_entry(int pirq, int entry_nr,
                              struct msi_dev_list *msi_dev_entry)
 {
        struct msi_pirq_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
@@ -100,9 +101,6 @@ static int attach_pirq_entry(int pirq, i
                return -ENOMEM;
        entry->pirq = pirq;
        entry->entry_nr = entry_nr;
-#ifdef COMFIG_PM
-       entry->mask_base = table_base;
-#endif
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
        list_add_tail(&entry->list, &msi_dev_entry->pirq_list_head);
        spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
@@ -381,17 +379,24 @@ int pci_save_msix_state(struct pci_dev *
        unsigned long flags;
        struct msi_dev_list *msi_dev_entry;
        struct msi_pirq_entry *pirq_entry;
+       void __iomem *base;
 
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
        if (pos <= 0 || dev->no_msi)
                return 0;
-
-       printk(KERN_CRIT "Saving MSIX cap\n");
 
        /* save the capability */
        pci_read_config_word(dev, msi_control_reg(pos), &control);
        if (!(control & PCI_MSIX_FLAGS_ENABLE))
                return 0;
+
+       msi_dev_entry = get_msi_dev_pirq_list(dev);
+       /* If we failed to map the MSI-X table at pci_enable_msix,
+        * We could not support saving them here.
+        */
+       if (!(base = msi_dev_entry->mask_base))
+               return -ENOMEM;
+
        save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
                GFP_KERNEL);
        if (!save_state) {
@@ -400,19 +405,12 @@ int pci_save_msix_state(struct pci_dev *
        }
        *((u16 *)&save_state->data[0]) = control;
 
-       msi_dev_entry = get_msi_dev_pirq_list(dev);
-
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
        list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
                int j;
-               void __iomem *base;
 
                /* save the table */
-               base = pirq_entry->mask_base;
                j = pirq_entry->entry_nr;
-               printk(KERN_CRIT "Save msix table entry %d pirq %x base %p\n",
-                      j, pirq_entry->pirq, base);
-
                pirq_entry->address_lo_save =
                        readl(base + j * PCI_MSIX_ENTRY_SIZE +
                              PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
@@ -443,7 +441,6 @@ void pci_restore_msix_state(struct pci_d
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
        if (!save_state)
                return;
-       printk(KERN_CRIT "Restoring MSIX cap\n");
 
        save = *((u16 *)&save_state->data[0]);
        pci_remove_saved_cap(save_state);
@@ -454,15 +451,12 @@ void pci_restore_msix_state(struct pci_d
                return;
 
        msi_dev_entry = get_msi_dev_pirq_list(dev);
+       base = msi_dev_entry->mask_base;
 
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
        list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
                /* route the table */
-               base = pirq_entry->mask_base;
                j = pirq_entry->entry_nr;
-
-               printk(KERN_CRIT "Restore msix table entry %d pirq %x base 
%p\n",
-                      j, pirq_entry->pirq, base);
                writel(pirq_entry->address_lo_save,
                        base + j * PCI_MSIX_ENTRY_SIZE +
                        PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
@@ -523,7 +517,8 @@ static int msix_capability_init(struct p
                                struct msix_entry *entries, int nvec)
 {
        u64 table_base;
-       int pirq, i, j, mapped, pos;
+       u16 control;
+       int pirq, i, j, mapped, pos, nr_entries;
        struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
        struct msi_pirq_entry *pirq_entry;
 
@@ -534,6 +529,12 @@ static int msix_capability_init(struct p
        table_base = find_table_base(dev, pos);
        if (!table_base)
                return -ENODEV;
+
+       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       nr_entries = multi_msix_capable(control);
+       if (!msi_dev_entry->mask_base)
+               msi_dev_entry->mask_base = 
+                       ioremap_nocache(table_base, nr_entries * 
PCI_MSIX_ENTRY_SIZE);
 
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
@@ -554,7 +555,7 @@ static int msix_capability_init(struct p
                pirq = msi_map_vector(dev, entries[i].entry, table_base);
                if (pirq < 0)
                        break;
-               attach_pirq_entry(pirq, entries[i].entry, table_base, 
msi_dev_entry);
+               attach_pirq_entry(pirq, entries[i].entry, msi_dev_entry);
                (entries + i)->vector = pirq;
        }
 
@@ -739,7 +740,7 @@ int pci_enable_msix(struct pci_dev* dev,
                        if (mapped)
                                continue;
                        irq = evtchn_map_pirq(-1, entries[i].vector);
-                       attach_pirq_entry(irq, entries[i].entry, 0, 
msi_dev_entry);
+                       attach_pirq_entry(irq, entries[i].entry, msi_dev_entry);
                        entries[i].vector = irq;
                }
         return 0;
@@ -857,18 +858,15 @@ void msi_remove_pci_irq_vectors(struct p
 
        spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
        if (!list_empty(&msi_dev_entry->pirq_list_head))
-       {
-               printk(KERN_WARNING "msix pirqs for dev %02x:%02x:%01x are not 
freed \
-                      before acquire again.\n", dev->bus->number, 
PCI_SLOT(dev->devfn),
-                          PCI_FUNC(dev->devfn));
                list_for_each_entry_safe(pirq_entry, tmp,
                                         &msi_dev_entry->pirq_list_head, list) {
                        msi_unmap_pirq(dev, pirq_entry->pirq);
                        list_del(&pirq_entry->list);
                        kfree(pirq_entry);
                }
-       }
        spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
+       iounmap(msi_dev_entry->mask_base);
+       msi_dev_entry->mask_base = NULL;
        dev->irq = dev->irq_old;
 }
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.