MSI: Use a list instead of the custom link structure
authorMichael Ellerman <michael@ellerman.id.au>
Thu, 5 Apr 2007 07:19:10 +0000 (17:19 +1000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 3 May 2007 02:02:37 +0000 (19:02 -0700)
The msi descriptors are linked together with what looks a lot like
a linked list, but isn't a struct list_head list. Make it one.

The only complication is that previously we walked a list of irqs, and
got the descriptor for each with get_irq_msi(). Now we have a list of
descriptors and need to get the irq out of it, so it needs to be in the
actual struct msi_desc. We use 0 to indicate no irq is setup.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/msi.c
drivers/pci/pci.h
drivers/pci/probe.c
include/linux/msi.h
include/linux/pci.h

index 5902c00f4fcec53586a60e1cbc043ae36d1f9b4b..434c7182d9261e5af0ec2086f8cebde17a74a174 100644 (file)
@@ -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 */
 
index 62ea04c8af648415b43c188ece4b645bf3cff7c2..3fec13d3add7cbdd72d94516deb4236ca6dcb76f 100644 (file)
@@ -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)
index c659f8ae441acf57789bed7d9c1e6d73fc66355d..e48fcf0896212193ace241d8f066fb8de9100feb 100644 (file)
@@ -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);
index d2a200048b22bda776beb1eba424a19d20a7c24e..931e013f1db547716eca186f5f7eb5254c248aff 100644 (file)
@@ -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;
index c02074785d4098cb053ae390e144595ef6d6f18f..d43097dc86728858def3f28360c3e9bd6966f9a6 100644 (file)
@@ -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
 };