msi: Make MSI useable more architectures
authorEric W. Biederman <ebiederm@xmission.com>
Sun, 28 Jan 2007 19:56:37 +0000 (12:56 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Feb 2007 23:50:08 +0000 (15:50 -0800)
The arch hooks arch_setup_msi_irq and arch_teardown_msi_irq are now
responsible for allocating and freeing the linux irq in addition to
setting up the the linux irq to work with the interrupt.

arch_setup_msi_irq now takes a pci_device and a msi_desc and returns
an irq.

With this change in place this code should be useable by all platforms
except those that won't let the OS touch the hardware like ppc RTAS.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
arch/i386/kernel/io_apic.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/sn/kernel/msi_sn.c
arch/x86_64/kernel/io_apic.c
drivers/pci/msi.c
include/asm-ia64/machvec.h
include/linux/msi.h

index 6a3875f81a0a9ff5c2cce422f0c0f8fbd31410f8..5592fa6e1fa1fa8dfb1adaa7167f706f2016a6d6 100644 (file)
@@ -2606,25 +2606,32 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_msg msg;
-       int ret;
+       int irq, ret;
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        ret = msi_compose_msg(dev, irq, &msg);
-       if (ret < 0)
+       if (ret < 0) {
+               destroy_irq(irq);
                return ret;
+       }
 
        write_msi_msg(irq, &msg);
 
        set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
                                      "edge");
 
-       return 0;
+       return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-       return;
+       destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
index 822e59a1b822fdfe4523628508936d844bd07002..0d05450c91c458211b8f00b72f9e3e169460d601 100644 (file)
@@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 }
 #endif /* CONFIG_SMP */
 
-int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct msi_msg  msg;
        unsigned long   dest_phys_id;
-       unsigned int    vector;
+       unsigned int    irq, vector;
 
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
        vector = irq;
 
@@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        write_msi_msg(irq, &msg);
        set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
 
-       return 0;
+       return irq;
 }
 
 void ia64_teardown_msi_irq(unsigned int irq)
 {
-       return;         /* no-op */
+       destroy_irq(irq);
 }
 
 static void ia64_ack_msi_irq(unsigned int irq)
@@ -126,12 +131,12 @@ static struct irq_chip ia64_msi_chip = {
 };
 
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        if (platform_setup_msi_irq)
-               return platform_setup_msi_irq(irq, pdev);
+               return platform_setup_msi_irq(pdev, desc);
 
-       return ia64_setup_msi_irq(irq, pdev);
+       return ia64_setup_msi_irq(pdev, desc);
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
index 31fbb859b67ea9acce5542f5f105f5a81b3169fc..ea3dc38d73fd49a3a022eee42373d80c8c74065f 100644 (file)
@@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int irq)
        sn_intr_free(nasid, widget, sn_irq_info);
        sn_msi_info[irq].sn_irq_info = NULL;
 
-       return;
+       destroy_irq(irq);
 }
 
-int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
 {
        struct msi_msg msg;
-       struct msi_desc *entry;
        int widget;
        int status;
        nasid_t nasid;
@@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        struct sn_irq_info *sn_irq_info;
        struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+       int irq;
 
-       entry = get_irq_msi(irq);
        if (!entry->msi_attrib.is_64)
                return -EINVAL;
 
@@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        if (provider == NULL || provider->dma_map_consistent == NULL)
                return -EINVAL;
 
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, entry);
        /*
         * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
         * decide which cpu to direct this msi at by default.
@@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
                        SWIN_WIDGETNUM(bussoft->bs_base);
 
        sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (! sn_irq_info)
+       if (! sn_irq_info) {
+               destroy_irq(irq);
                return -ENOMEM;
+       }
 
        status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
        if (status) {
                kfree(sn_irq_info);
+               destroy_irq(irq);
                return -ENOMEM;
        }
 
@@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        if (! bus_addr) {
                sn_intr_free(nasid, widget, sn_irq_info);
                kfree(sn_irq_info);
+               destroy_irq(irq);
                return -ENOMEM;
        }
 
@@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        write_msi_msg(irq, &msg);
        set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
 
-       return 0;
+       return irq;
 }
 
 #ifdef CONFIG_SMP
index d7bad90a5ad80d6b4d651f23d87d30e2dfec8580..6be6730acb5c9039ead2720c1a8219b011f3cde5 100644 (file)
@@ -1956,24 +1956,31 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_msg msg;
-       int ret;
+       int irq, ret;
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        ret = msi_compose_msg(dev, irq, &msg);
-       if (ret < 0)
+       if (ret < 0) {
+               destroy_irq(irq);
                return ret;
+       }
 
        write_msi_msg(irq, &msg);
 
        set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
-       return 0;
+       return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-       return;
+       destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
index 52c253c5ad3dbe84687205c761d522ae79c4abf2..68555c11f55614f8e312a5eb00bc10b18a5a7dca 100644 (file)
@@ -192,37 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
        return entry;
 }
 
-static int create_msi_irq(void)
-{
-       struct msi_desc *entry;
-       int irq;
-
-       entry = alloc_msi_entry();
-       if (!entry)
-               return -ENOMEM;
-
-       irq = create_irq();
-       if (irq < 0) {
-               kmem_cache_free(msi_cachep, entry);
-               return -EBUSY;
-       }
-
-       set_irq_msi(irq, entry);
-
-       return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
-       struct msi_desc *entry;
-
-       entry = get_irq_msi(irq);
-       set_irq_chip(irq, NULL);
-       set_irq_msi(irq, NULL);
-       destroy_irq(irq);
-       kmem_cache_free(msi_cachep, entry);
-}
-
 static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
 {
        u16 control;
@@ -438,7 +407,6 @@ void pci_restore_msi_state(struct pci_dev *dev)
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
-       int status;
        struct msi_desc *entry;
        int pos, irq;
        u16 control;
@@ -446,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        pci_read_config_word(dev, msi_control_reg(pos), &control);
        /* MSI Entry Initialization */
-       irq = create_msi_irq();
-       if (irq < 0)
-               return irq;
+       entry = alloc_msi_entry();
+       if (!entry)
+               return -ENOMEM;
 
-       entry = get_irq_msi(irq);
-       entry->link.head = irq;
-       entry->link.tail = irq;
        entry->msi_attrib.type = PCI_CAP_ID_MSI;
        entry->msi_attrib.is_64 = is_64bit_address(control);
        entry->msi_attrib.entry_nr = 0;
@@ -478,14 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
                        maskbits);
        }
        /* Configure MSI capability structure */
-       status = arch_setup_msi_irq(irq, dev);
-       if (status < 0) {
-               destroy_msi_irq(irq);
-               return status;
+       irq = arch_setup_msi_irq(dev, entry);
+       if (irq < 0) {
+               kmem_cache_free(msi_cachep, entry);
+               return irq;
        }
-
+       entry->link.head = irq;
+       entry->link.tail = irq;
        dev->first_msi_irq = irq;
        set_irq_msi(irq, entry);
+
        /* Set MSI enabled bits  */
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
@@ -507,7 +474,6 @@ 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 status;
        int irq, pos, i, j, nr_entries, temp = 0;
        unsigned long phys_addr;
        u32 table_offset;
@@ -530,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
 
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
-               irq = create_msi_irq();
-               if (irq < 0)
+               entry = alloc_msi_entry();
+               if (!entry)
                        break;
 
-               entry = get_irq_msi(irq);
                j = entries[i].entry;
-               entries[i].vector = irq;
                entry->msi_attrib.type = PCI_CAP_ID_MSIX;
                entry->msi_attrib.is_64 = 1;
                entry->msi_attrib.entry_nr = j;
@@ -545,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
                entry->msi_attrib.pos = pos;
                entry->dev = dev;
                entry->mask_base = base;
+
+               /* Configure MSI-X capability structure */
+               irq = arch_setup_msi_irq(dev, entry);
+               if (irq < 0) {
+                       kmem_cache_free(msi_cachep, entry);
+                       break;
+               }
+               entries[i].vector = irq;
                if (!head) {
                        entry->link.head = irq;
                        entry->link.tail = irq;
@@ -557,12 +529,6 @@ static int msix_capability_init(struct pci_dev *dev,
                }
                temp = irq;
                tail = entry;
-               /* Configure MSI-X capability structure */
-               status = arch_setup_msi_irq(irq, dev);
-               if (status < 0) {
-                       destroy_msi_irq(irq);
-                       break;
-               }
 
                set_irq_msi(irq, entry);
        }
@@ -706,8 +672,6 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
        int head, entry_nr, type;
        void __iomem *base;
 
-       arch_teardown_msi_irq(irq);
-
        entry = get_irq_msi(irq);
        if (!entry || entry->dev != dev) {
                return -EINVAL;
@@ -718,9 +682,9 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
        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;
-       entry->dev = NULL;
 
-       destroy_msi_irq(irq);
+       arch_teardown_msi_irq(irq);
+       kmem_cache_free(msi_cachep, entry);
 
        if (type == PCI_CAP_ID_MSIX) {
                writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
index a3891eb3f217bf1ba54160f780383a130566e1c8..3c96ac19154eaf4113028d5690521fb075adc78b 100644 (file)
@@ -21,6 +21,7 @@ struct mm_struct;
 struct pci_bus;
 struct task_struct;
 struct pci_dev;
+struct msi_desc;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -79,7 +80,7 @@ typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
 
-typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
 typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
 
 static inline void
index b99976b1536ef8c7981bd5097f244c969f9bcf2e..74c8a2ecc9dd0769e172f3f0469f0b1bb26ebf16 100644 (file)
@@ -41,7 +41,7 @@ struct msi_desc {
 /*
  * The arch hook for setup up msi irqs
  */
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);