aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/msi.c66
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c2
-rw-r--r--include/linux/msi.h8
-rw-r--r--include/linux/pci.h1
5 files changed, 33 insertions, 46 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 5902c00f4fc..434c7182d92 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -218,7 +218,8 @@ static struct msi_desc* alloc_msi_entry(void)
if (!entry)
return NULL;
- entry->link.tail = entry->link.head = 0; /* single message */
+ INIT_LIST_HEAD(&entry->list);
+ entry->irq = 0;
entry->dev = NULL;
return entry;
@@ -253,7 +254,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
static void __pci_restore_msix_state(struct pci_dev *dev)
{
int pos;
- int irq, head, tail = 0;
struct msi_desc *entry;
u16 control;
@@ -263,18 +263,14 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
/* route the table */
pci_intx(dev, 0); /* disable intx */
msix_set_enable(dev, 0);
- irq = head = dev->first_msi_irq;
- entry = get_irq_msi(irq);
- pos = entry->msi_attrib.pos;
- while (head != tail) {
- entry = get_irq_msi(irq);
- write_msi_msg(irq, &entry->msg);
- msi_set_mask_bit(irq, entry->msi_attrib.masked);
- tail = entry->link.tail;
- irq = tail;
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ write_msi_msg(entry->irq, &entry->msg);
+ msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
}
+ entry = get_irq_msi(dev->first_msi_irq);
+ pos = entry->msi_attrib.pos;
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
control &= ~PCI_MSIX_FLAGS_MASKALL;
control |= PCI_MSIX_FLAGS_ENABLE;
@@ -343,8 +339,8 @@ static int msi_capability_init(struct pci_dev *dev)
kfree(entry);
return irq;
}
- entry->link.head = irq;
- entry->link.tail = irq;
+ entry->irq = irq;
+ list_add(&entry->list, &dev->msi_list);
dev->first_msi_irq = irq;
set_irq_msi(irq, entry);
@@ -370,8 +366,8 @@ static int msi_capability_init(struct pci_dev *dev)
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int irq, pos, i, j, nr_entries, temp = 0;
+ struct msi_desc *entry;
+ int irq, pos, i, j, nr_entries;
unsigned long phys_addr;
u32 table_offset;
u16 control;
@@ -416,19 +412,9 @@ static int msix_capability_init(struct pci_dev *dev,
kfree(entry);
break;
}
+ entry->irq = irq;
entries[i].vector = irq;
- if (!head) {
- entry->link.head = irq;
- entry->link.tail = irq;
- head = entry;
- } else {
- entry->link.head = temp;
- entry->link.tail = tail->link.tail;
- tail->link.tail = irq;
- head->link.head = irq;
- }
- temp = irq;
- tail = entry;
+ list_add(&entry->list, &dev->msi_list);
set_irq_msi(irq, entry);
}
@@ -557,7 +543,7 @@ EXPORT_SYMBOL(pci_disable_msi);
static int msi_free_irq(struct pci_dev* dev, int irq)
{
struct msi_desc *entry;
- int head, entry_nr, type;
+ int entry_nr, type;
void __iomem *base;
BUG_ON(irq_has_action(irq));
@@ -568,10 +554,8 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
}
type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr;
- head = entry->link.head;
base = entry->mask_base;
- get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
- get_irq_msi(entry->link.tail)->link.head = entry->link.head;
+ list_del(&entry->list);
arch_teardown_msi_irq(irq);
kfree(entry);
@@ -580,7 +564,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
- if (head == irq)
+ if (list_empty(&dev->msi_list))
iounmap(base);
}
@@ -646,17 +630,10 @@ EXPORT_SYMBOL(pci_enable_msix);
static void msix_free_all_irqs(struct pci_dev *dev)
{
- int irq, head, tail = 0;
-
- irq = head = dev->first_msi_irq;
- while (head != tail) {
- tail = get_irq_msi(irq)->link.tail;
+ struct msi_desc *entry;
- if (irq != head)
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
+ list_for_each_entry(entry, &dev->msi_list, list)
+ msi_free_irq(dev, entry->irq);
dev->first_msi_irq = 0;
}
@@ -699,6 +676,11 @@ void pci_no_msi(void)
pci_msi_enable = 0;
}
+void pci_msi_init_pci_dev(struct pci_dev *dev)
+{
+ INIT_LIST_HEAD(&dev->msi_list);
+}
+
/* Arch hooks */
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 62ea04c8af6..3fec13d3add 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
+extern void pci_msi_init_pci_dev(struct pci_dev *dev);
#else
static inline void pci_no_msi(void) { }
+static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c659f8ae441..e48fcf08962 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -857,6 +857,8 @@ struct pci_dev *alloc_pci_dev(void)
INIT_LIST_HEAD(&dev->global_list);
INIT_LIST_HEAD(&dev->bus_list);
+ pci_msi_init_pci_dev(dev);
+
return dev;
}
EXPORT_SYMBOL(alloc_pci_dev);
diff --git a/include/linux/msi.h b/include/linux/msi.h
index d2a200048b2..931e013f1db 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -1,6 +1,8 @@
#ifndef LINUX_MSI_H
#define LINUX_MSI_H
+#include <linux/list.h>
+
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
@@ -24,10 +26,8 @@ struct msi_desc {
unsigned default_irq; /* default pre-assigned irq */
}msi_attrib;
- struct {
- __u16 head;
- __u16 tail;
- }link;
+ unsigned int irq;
+ struct list_head list;
void __iomem *mask_base;
struct pci_dev *dev;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c02074785d4..d43097dc867 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -190,6 +190,7 @@ struct pci_dev {
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
#ifdef CONFIG_PCI_MSI
unsigned int first_msi_irq;
+ struct list_head msi_list;
#endif
};