summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c39
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h3
2 files changed, 42 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index e5c344d336ea..89548e07ddeb 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -148,14 +148,47 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ struct device_node *np;
+ phandle phandle = 0;
int rc, hwirq = -ENOMEM;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
struct fsl_msi *msi_data;
+ /*
+ * If the PCI node has an fsl,msi property, then we need to use it
+ * to find the specific MSI.
+ */
+ np = of_parse_phandle(hose->dn, "fsl,msi", 0);
+ if (np) {
+ if (of_device_is_compatible(np, "fsl,mpic-msi"))
+ phandle = np->phandle;
+ else {
+ dev_err(&pdev->dev, "node %s has an invalid fsl,msi"
+ " phandle\n", hose->dn->full_name);
+ return -EINVAL;
+ }
+ }
+
list_for_each_entry(entry, &pdev->msi_list, list) {
+ /*
+ * Loop over all the MSI devices until we find one that has an
+ * available interrupt.
+ */
list_for_each_entry(msi_data, &msi_head, list) {
+ /*
+ * If the PCI node has an fsl,msi property, then we
+ * restrict our search to the corresponding MSI node.
+ * The simplest way is to skip over MSI nodes with the
+ * wrong phandle. Under the Freescale hypervisor, this
+ * has the additional benefit of skipping over MSI
+ * nodes that are not mapped in the PAMU.
+ */
+ if (phandle && (phandle != msi_data->phandle))
+ continue;
+
hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
if (hwirq >= 0)
break;
@@ -370,6 +403,12 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
msi->msiir_offset = features->msiir_offset + (res.start & 0xfffff);
+ /*
+ * Remember the phandle, so that we can match with any PCI nodes
+ * that have an "fsl,msi" property.
+ */
+ msi->phandle = dev->dev.of_node->phandle;
+
rc = fsl_msi_init_allocator(msi);
if (rc) {
dev_err(&dev->dev, "Error allocating MSI bitmap\n");
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index 1313abbc5200..b5d25ba51311 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -13,6 +13,7 @@
#ifndef _POWERPC_SYSDEV_FSL_MSI_H
#define _POWERPC_SYSDEV_FSL_MSI_H
+#include <linux/of.h>
#include <asm/msi_bitmap.h>
#define NR_MSI_REG 8
@@ -36,6 +37,8 @@ struct fsl_msi {
struct msi_bitmap bitmap;
struct list_head list; /* support multiple MSI banks */
+
+ phandle phandle;
};
#endif /* _POWERPC_SYSDEV_FSL_MSI_H */