powerpc/fsl: add MSI support for the Freescale hypervisor
Add support for vmpic-msi nodes to the fsl_msi driver. The MSI is
virtualized by the hypervisor, so the vmpic-msi does not contain a 'reg'
property. Instead, the driver uses hcalls.
Add support for the "msi-address-64" property to the fsl_pci driver.
The Freescale hypervisor typically puts the virtualized MSIIR register
in the page after the end of DDR, so we extend the DDR ATMU to cover it.
Any other location for MSIIR is not supported, for now.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 89548e0..ecb5c19 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -23,6 +23,8 @@
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/mpic.h>
+#include <asm/fsl_hcalls.h>
+
#include "fsl_msi.h"
#include "fsl_pci.h"
@@ -163,11 +165,13 @@
*/
np = of_parse_phandle(hose->dn, "fsl,msi", 0);
if (np) {
- if (of_device_is_compatible(np, "fsl,mpic-msi"))
+ if (of_device_is_compatible(np, "fsl,mpic-msi") ||
+ of_device_is_compatible(np, "fsl,vmpic-msi"))
phandle = np->phandle;
else {
- dev_err(&pdev->dev, "node %s has an invalid fsl,msi"
- " phandle\n", hose->dn->full_name);
+ dev_err(&pdev->dev,
+ "node %s has an invalid fsl,msi phandle %u\n",
+ hose->dn->full_name, np->phandle);
return -EINVAL;
}
}
@@ -196,16 +200,14 @@
if (hwirq < 0) {
rc = hwirq;
- pr_debug("%s: fail allocating msi interrupt\n",
- __func__);
+ dev_err(&pdev->dev, "could not allocate MSI interrupt\n");
goto out_free;
}
virq = irq_create_mapping(msi_data->irqhost, hwirq);
if (virq == NO_IRQ) {
- pr_debug("%s: fail mapping hwirq 0x%x\n",
- __func__, hwirq);
+ dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq);
msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
rc = -ENOSPC;
goto out_free;
@@ -234,6 +236,7 @@
u32 intr_index;
u32 have_shift = 0;
struct fsl_msi_cascade_data *cascade_data;
+ unsigned int ret;
cascade_data = irq_get_handler_data(irq);
msi_data = cascade_data->msi_data;
@@ -265,6 +268,14 @@
case FSL_PIC_IP_IPIC:
msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4);
break;
+ case FSL_PIC_IP_VMPIC:
+ ret = fh_vmpic_get_msir(virq_to_hw(irq), &msir_value);
+ if (ret) {
+ pr_err("fsl-msi: fh_vmpic_get_msir() failed for "
+ "irq %u (ret=%u)\n", irq, ret);
+ msir_value = 0;
+ }
+ break;
}
while (msir_value) {
@@ -282,6 +293,7 @@
switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
+ case FSL_PIC_IP_VMPIC:
chip->irq_eoi(idata);
break;
case FSL_PIC_IP_IPIC:
@@ -311,7 +323,8 @@
}
if (msi->bitmap.bitmap)
msi_bitmap_free(&msi->bitmap);
- iounmap(msi->msi_regs);
+ if ((msi->feature & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC)
+ iounmap(msi->msi_regs);
kfree(msi);
return 0;
@@ -383,26 +396,32 @@
goto error_out;
}
- /* Get the MSI reg base */
- err = of_address_to_resource(dev->dev.of_node, 0, &res);
- if (err) {
- dev_err(&dev->dev, "%s resource error!\n",
+ /*
+ * Under the Freescale hypervisor, the msi nodes don't have a 'reg'
+ * property. Instead, we use hypercalls to access the MSI.
+ */
+ if ((features->fsl_pic_ip & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC) {
+ err = of_address_to_resource(dev->dev.of_node, 0, &res);
+ if (err) {
+ dev_err(&dev->dev, "invalid resource for node %s\n",
dev->dev.of_node->full_name);
- goto error_out;
- }
+ goto error_out;
+ }
- msi->msi_regs = ioremap(res.start, resource_size(&res));
- if (!msi->msi_regs) {
- dev_err(&dev->dev, "ioremap problem failed\n");
- goto error_out;
+ msi->msi_regs = ioremap(res.start, resource_size(&res));
+ if (!msi->msi_regs) {
+ dev_err(&dev->dev, "could not map node %s\n",
+ dev->dev.of_node->full_name);
+ goto error_out;
+ }
+ msi->msiir_offset =
+ features->msiir_offset + (res.start & 0xfffff);
}
msi->feature = features->fsl_pic_ip;
msi->irqhost->host_data = msi;
- 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.
@@ -476,6 +495,11 @@
.msiir_offset = 0x38,
};
+static const struct fsl_msi_feature vmpic_msi_feature = {
+ .fsl_pic_ip = FSL_PIC_IP_VMPIC,
+ .msiir_offset = 0,
+};
+
static const struct of_device_id fsl_of_msi_ids[] = {
{
.compatible = "fsl,mpic-msi",
@@ -485,6 +509,10 @@
.compatible = "fsl,ipic-msi",
.data = (void *)&ipic_msi_feature,
},
+ {
+ .compatible = "fsl,vmpic-msi",
+ .data = (void *)&vmpic_msi_feature,
+ },
{}
};