Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
[pandora-kernel.git] / drivers / pci / msi.c
index 36bc7c4..27a0574 100644 (file)
@@ -45,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;
 
@@ -402,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;
 
@@ -900,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
@@ -912,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;
 
@@ -1134,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;