From: Jiang Liu <[email protected]>

Enhance PCI MSI core to support hierarchy irqdomain, so the common
code can be shared across architectures.

[ tglx: Extracted and combined from several patches ]

Signed-off-by: Jiang Liu <[email protected]>
Cc: Bjorn Helgaas <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Yingjoe Chen <[email protected]>
Cc: Yijing Wang <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
---
 drivers/pci/Kconfig |    5 ++++
 drivers/pci/msi.c   |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/msi.h |    8 ++++++
 3 files changed, 75 insertions(+)

Index: tip/drivers/pci/Kconfig
===================================================================
--- tip.orig/drivers/pci/Kconfig
+++ tip/drivers/pci/Kconfig
@@ -17,6 +17,11 @@ config PCI_MSI
 
           If you don't know what to do here, say Y.
 
+config PCI_MSI_IRQ_DOMAIN
+       bool
+       depends on PCI_MSI
+       select GENERIC_MSI_IRQ_DOMAIN
+
 config PCI_DEBUG
        bool "PCI Debugging"
        depends on PCI && DEBUG_KERNEL
Index: tip/drivers/pci/msi.c
===================================================================
--- tip.orig/drivers/pci/msi.c
+++ tip/drivers/pci/msi.c
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/irqdomain.h>
 
 #include "pci.h"
 
@@ -1072,3 +1073,64 @@ int pci_enable_msix_range(struct pci_dev
        return nvec;
 }
 EXPORT_SYMBOL(pci_enable_msix_range);
+
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+       struct msi_desc *desc = irq_data->msi_desc;
+
+       /*
+        * MSI-X message is written per-IRQ.
+        * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+        */
+       if (desc->irq == irq_data->irq)
+               pci_write_msi_msg(desc, msg);
+}
+
+/*
+ * Generate a unique ID number for each possible MSI source, the ID number
+ * is only used within the irqdomain.
+ */
+irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
+                                         struct msi_desc *desc)
+{
+       return (irq_hw_number_t)desc->msi_attrib.entry_nr |
+               PCI_DEVID(dev->bus->number, dev->devfn) << 11 |
+               (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
+}
+
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
+                             struct pci_dev *dev, void *arg)
+{
+       struct msi_domain_info *info = domain->host_data;
+       int node = dev_to_node(&dev->dev);
+       struct msi_desc *desc;
+       int i, virq;
+
+       list_for_each_entry(desc, &dev->msi_list, list) {
+               if (info->ops->calc_hwirq)
+                       info->ops->calc_hwirq(info, arg, desc);
+
+               virq = irq_domain_alloc_irqs(domain, desc->nvec_used,
+                                            node, arg);
+               if (virq < 0) {
+                       /* Special handling for pci_enable_msi_range(). */
+                       if (type == PCI_CAP_ID_MSI && desc->nvec_used > 1)
+                               return 1;
+                       else
+                               return -ENOSPC;
+               }
+               for (i = 0; i < desc->nvec_used; i++)
+                       irq_set_msi_desc_off(virq, i, desc);
+       }
+
+       list_for_each_entry(desc, &dev->msi_list, list)
+               if (desc->nvec_used == 1)
+                       dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", virq);
+               else
+                       dev_dbg(&dev->dev, "irq [%d-%d] for MSI/MSI-X\n",
+                               virq, virq + desc->nvec_used - 1);
+
+       return 0;
+}
+#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
Index: tip/include/linux/msi.h
===================================================================
--- tip.orig/include/linux/msi.h
+++ tip/include/linux/msi.h
@@ -112,4 +112,12 @@ struct msi_domain_info *msi_get_domain_i
 
 #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
 
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
+                             struct pci_dev *dev, void *arg);
+irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
+                                         struct msi_desc *desc);
+#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
+
 #endif /* LINUX_MSI_H */


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to