Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
[pandora-kernel.git] / drivers / pci / msi.c
index 3ec558d..27a0574 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/config.h>
 #include <linux/ioport.h>
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
@@ -35,7 +34,6 @@ static int nr_msix_devices;
 
 #ifndef CONFIG_X86_IO_APIC
 int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-u8 irq_vector[NR_IRQ_VECTORS];
 #endif
 
 static struct msi_ops *msi_ops;
@@ -47,16 +45,10 @@ msi_register(struct msi_ops *ops)
        return 0;
 }
 
-static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
-{
-       memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
-}
-
 static int msi_cache_init(void)
 {
-       msi_cachep = kmem_cache_create("msi_cache",
-                       NR_IRQS * sizeof(struct msi_desc),
-                       0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
+       msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
+                                       0, SLAB_HWCACHE_ALIGN, NULL, NULL);
        if (!msi_cachep)
                return -ENOMEM;
 
@@ -383,10 +375,6 @@ static int msi_init(void)
                return status;
        }
 
-#ifndef CONFIG_X86_IO_APIC
-       irq_vector[0] = FIRST_DEVICE_VECTOR;
-#endif
-
        if (last_alloc_vector < 0) {
                pci_msi_enable = 0;
                printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
@@ -408,11 +396,10 @@ static struct msi_desc* alloc_msi_entry(void)
 {
        struct msi_desc *entry;
 
-       entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+       entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
        if (!entry)
                return NULL;
 
-       memset(entry, 0, sizeof(struct msi_desc));
        entry->link.tail = entry->link.head = 0;        /* single message */
        entry->dev = NULL;
 
@@ -434,12 +421,12 @@ static void irq_handler_init(int cap_id, int pos, int mask)
 
        spin_lock_irqsave(&irq_desc[pos].lock, flags);
        if (cap_id == PCI_CAP_ID_MSIX)
-               irq_desc[pos].handler = &msix_irq_type;
+               irq_desc[pos].chip = &msix_irq_type;
        else {
                if (!mask)
-                       irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
                else
-                       irq_desc[pos].handler = &msi_irq_w_maskbit_type;
+                       irq_desc[pos].chip = &msi_irq_w_maskbit_type;
        }
        spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
 }
@@ -906,6 +893,33 @@ static int msix_capability_init(struct pci_dev *dev,
        return 0;
 }
 
+/**
+ * pci_msi_supported - check whether MSI may be enabled on device
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * MSI must be globally enabled and supported by the device and its root
+ * bus. But, the root bus is not easy to find since some architectures
+ * have virtual busses on top of the PCI hierarchy (for instance the
+ * hypertransport bus), while the actual bus where MSI must be supported
+ * is below. So we test the MSI flag on all parent busses and assume
+ * that no quirk will ever set the NO_MSI flag on a non-root bus.
+ **/
+static
+int pci_msi_supported(struct pci_dev * dev)
+{
+       struct pci_bus *bus;
+
+       if (!pci_msi_enable || !dev || dev->no_msi)
+               return -EINVAL;
+
+       /* check MSI flags of all parent busses */
+       for (bus = dev->bus; bus; bus = bus->parent)
+               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+                       return -EINVAL;
+
+       return 0;
+}
+
 /**
  * pci_enable_msi - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
@@ -918,19 +932,11 @@ static int msix_capability_init(struct pci_dev *dev,
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-       struct pci_bus *bus;
-       int pos, temp, status = -EINVAL;
+       int pos, temp, status;
        u16 control;
 
-       if (!pci_msi_enable || !dev)
-               return status;
-
-       if (dev->no_msi)
-               return status;
-
-       for (bus = dev->bus; bus; bus = bus->parent)
-               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
-                       return -EINVAL;
+       if (pci_msi_supported(dev) < 0)
+               return -EINVAL;
 
        temp = dev->irq;
 
@@ -1065,33 +1071,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
                                entry_nr * PCI_MSIX_ENTRY_SIZE +
                                PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
 
-               if (head == vector) {
-                       /*
-                        * Detect last MSI-X vector to be released.
-                        * Release the MSI-X memory-mapped table.
-                        */
-#if 0
-                       int pos, nr_entries;
-                       unsigned long phys_addr;
-                       u32 table_offset;
-                       u16 control;
-                       u8 bir;
-
-                       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-                       pci_read_config_word(dev, msi_control_reg(pos),
-                               &control);
-                       nr_entries = multi_msix_capable(control);
-                       pci_read_config_dword(dev, msix_table_offset_reg(pos),
-                               &table_offset);
-                       bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
-                       table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
-                       phys_addr = pci_resource_start(dev, bir) + table_offset;
-/*
- * FIXME!  and what did you want to do with phys_addr?
- */
-#endif
+               if (head == vector)
                        iounmap(base);
-               }
        }
 
        return 0;
@@ -1165,22 +1146,14 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
  **/
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
-       struct pci_bus *bus;
        int status, pos, nr_entries, free_vectors;
        int i, j, temp;
        u16 control;
        unsigned long flags;
 
-       if (!pci_msi_enable || !dev || !entries)
+       if (!entries || pci_msi_supported(dev) < 0)
                return -EINVAL;
 
-       if (dev->no_msi)
-               return -EINVAL;
-
-       for (bus = dev->bus; bus; bus = bus->parent)
-               if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
-                       return -EINVAL;
-
        status = msi_init();
        if (status < 0)
                return status;
@@ -1365,24 +1338,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
                }
                msi_free_vector(dev, vector, 0);
                if (warning) {
-                       /* Force to release the MSI-X memory-mapped table */
-#if 0
-                       unsigned long phys_addr;
-                       u32 table_offset;
-                       u16 control;
-                       u8 bir;
-
-                       pci_read_config_word(dev, msi_control_reg(pos),
-                               &control);
-                       pci_read_config_dword(dev, msix_table_offset_reg(pos),
-                               &table_offset);
-                       bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
-                       table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
-                       phys_addr = pci_resource_start(dev, bir) + table_offset;
-/*
- * FIXME! and what did you want to do with phys_addr?
- */
-#endif
                        iounmap(base);
                        printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
                               "called without free_irq() on all MSI-X vectors\n",