]> xenbits.xensource.com Git - legacy/linux-2.6.18-xen.git/commitdiff
Fix buggy mask_base in saving/restoring MSI-X table during S3
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 2 Dec 2008 11:54:47 +0000 (11:54 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 2 Dec 2008 11:54:47 +0000 (11:54 +0000)
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@intel.com>
drivers/pci/msi-xen.c

index 0d1b48a702caa631745c6de704a5a18b3a8e44bc..759bf547325d249605b3ddc6a30e4db883c3b6f8 100644 (file)
@@ -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_pirq_list(struct pci_dev *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, int entry_nr, u64 table_base,
                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 *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 *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_dev *dev)
        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_dev *dev)
                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 pci_dev *dev,
                                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;
 
@@ -535,6 +530,12 @@ static int msix_capability_init(struct pci_dev *dev,
        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++) {
                mapped = 0;
@@ -554,7 +555,7 @@ static int msix_capability_init(struct pci_dev *dev,
                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, struct msix_entry *entries, int nvec)
                        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 pci_dev* dev)
 
        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;
 }