# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1210842209 -3600
# Node ID c3f9cc7789af995b7edfa8a8de4ae099a3750e9e
# Parent a741afb717006a6751044d1d11cd5412f0bbce3c
Do not unmap all MSI-X pirqs when enabling MSI-X
Originally, all existing MSI-X pirqs of that device are unmapped
before mapping the required MSI-X entries. This is actually not
right. This function may be called several times, with each time
requiring enabling different parts of the device MSI-X entry. Former
pirqs should not be unmapped.
Thanks for Neil Turton's comments on this problem.
Signed-off-by: Shan Haitao <Haitao.shan@xxxxxxxxx>
---
drivers/pci/msi-xen.c | 60 ++++++++++++++++++++++++++++++++------------------
1 files changed, 39 insertions(+), 21 deletions(-)
diff -r a741afb71700 -r c3f9cc7789af drivers/pci/msi-xen.c
--- a/drivers/pci/msi-xen.c Thu May 15 09:42:27 2008 +0100
+++ b/drivers/pci/msi-xen.c Thu May 15 10:03:29 2008 +0100
@@ -33,7 +33,6 @@ int msi_register(struct msi_ops *ops)
}
static LIST_HEAD(msi_dev_head);
-static int msi_dev_head_inited = 0;
DEFINE_SPINLOCK(msi_dev_lock);
struct msi_dev_list {
@@ -95,6 +94,23 @@ static int attach_pirq_entry(int pirq, i
list_add_tail(&entry->list, &msi_dev_entry->pirq_list_head);
spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
return 0;
+}
+
+static void detach_pirq_entry(int entry_nr,
+ struct msi_dev_list
*msi_dev_entry)
+{
+ unsigned long flags;
+ struct msi_pirq_entry *pirq_entry;
+
+ list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
+ if (pirq_entry->entry_nr == entry_nr) {
+ spin_lock_irqsave(&msi_dev_entry->pirq_list_lock,
flags);
+ list_del(&pirq_entry->list);
+ spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock,
flags);
+ kfree(pirq_entry);
+ return;
+ }
+ }
}
/*
@@ -379,40 +395,42 @@ static int msix_capability_init(struct p
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- int pirq, i, pos;
+ int pirq, i, j, mapped, pos;
struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
- struct msi_pirq_entry *pirq_entry, *tmp;
- unsigned long flags;
+ struct msi_pirq_entry *pirq_entry;
if (!msi_dev_entry)
return -ENOMEM;
- 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);
-
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
+ mapped = 0;
+ list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head,
list) {
+ if (pirq_entry->entry_nr == entries[i].entry) {
+ printk(KERN_WARNING "msix entry %d for dev
%02x:%02x:%01x are \
+ not freed before acquire again.\n",
entries[i].entry,
+ dev->bus->number,
PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ (entries + i)->vector = pirq_entry->pirq;
+ mapped = 1;
+ break;
+ }
+ }
+ if (mapped)
+ continue;
pirq = msi_map_vector(dev, entries[i].entry, 0);
if (pirq < 0)
break;
attach_pirq_entry(pirq, entries[i].entry, msi_dev_entry);
(entries + i)->vector = pirq;
}
+
if (i != nvec) {
- msi_unmap_pirq(dev, dev->irq);
- (entries + i)->vector = 0;
+ for (j = --i; j >= 0; j--) {
+ msi_unmap_pirq(dev, entries[j].vector);
+ detach_pirq_entry(entries[j].entry, msi_dev_entry);
+ entries[j].vector = 0;
+ }
return -EBUSY;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|