# 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
|