|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (C) 2007-2010 Freescale Semiconductor, Inc.
|
|
|
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc.
|
|
|
*
|
|
|
* Author: Tony Li <tony.li@freescale.com>
|
|
|
* Jason Jin <Jason.jin@freescale.com>
|
|
@@ -274,19 +274,47 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi,
|
|
|
+ struct platform_device *dev,
|
|
|
+ int offset, int irq_index)
|
|
|
+{
|
|
|
+ struct fsl_msi_cascade_data *cascade_data = NULL;
|
|
|
+ int virt_msir;
|
|
|
+
|
|
|
+ virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index);
|
|
|
+ if (virt_msir == NO_IRQ) {
|
|
|
+ dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n",
|
|
|
+ __func__, irq_index);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ cascade_data = kzalloc(sizeof(struct fsl_msi_cascade_data), GFP_KERNEL);
|
|
|
+ if (!cascade_data) {
|
|
|
+ dev_err(&dev->dev, "No memory for MSI cascade data\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ msi->msi_virqs[irq_index] = virt_msir;
|
|
|
+ cascade_data->index = offset + irq_index;
|
|
|
+ cascade_data->msi_data = msi;
|
|
|
+ set_irq_data(virt_msir, cascade_data);
|
|
|
+ set_irq_chained_handler(virt_msir, fsl_msi_cascade);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int __devinit fsl_of_msi_probe(struct platform_device *dev,
|
|
|
const struct of_device_id *match)
|
|
|
{
|
|
|
struct fsl_msi *msi;
|
|
|
struct resource res;
|
|
|
- int err, i, count;
|
|
|
+ int err, i, j, irq_index, count;
|
|
|
int rc;
|
|
|
- int virt_msir;
|
|
|
const u32 *p;
|
|
|
struct fsl_msi_feature *features = match->data;
|
|
|
- struct fsl_msi_cascade_data *cascade_data = NULL;
|
|
|
int len;
|
|
|
u32 offset;
|
|
|
+ static const u32 all_avail[] = { 0, NR_MSI_IRQS };
|
|
|
|
|
|
printk(KERN_DEBUG "Setting up Freescale MSI support\n");
|
|
|
|
|
@@ -333,42 +361,34 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev,
|
|
|
goto error_out;
|
|
|
}
|
|
|
|
|
|
- p = of_get_property(dev->dev.of_node, "interrupts", &count);
|
|
|
- if (!p) {
|
|
|
- dev_err(&dev->dev, "no interrupts property found on %s\n",
|
|
|
- dev->dev.of_node->full_name);
|
|
|
- err = -ENODEV;
|
|
|
- goto error_out;
|
|
|
- }
|
|
|
- if (count % 8 != 0) {
|
|
|
- dev_err(&dev->dev, "Malformed interrupts property on %s\n",
|
|
|
- dev->dev.of_node->full_name);
|
|
|
+ p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
|
|
|
+ if (p && len % (2 * sizeof(u32)) != 0) {
|
|
|
+ dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n",
|
|
|
+ __func__);
|
|
|
err = -EINVAL;
|
|
|
goto error_out;
|
|
|
}
|
|
|
- offset = 0;
|
|
|
- p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
|
|
|
- if (p)
|
|
|
- offset = *p / IRQS_PER_MSI_REG;
|
|
|
-
|
|
|
- count /= sizeof(u32);
|
|
|
- for (i = 0; i < min(count / 2, NR_MSI_REG); i++) {
|
|
|
- virt_msir = irq_of_parse_and_map(dev->dev.of_node, i);
|
|
|
- if (virt_msir != NO_IRQ) {
|
|
|
- cascade_data = kzalloc(
|
|
|
- sizeof(struct fsl_msi_cascade_data),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!cascade_data) {
|
|
|
- dev_err(&dev->dev,
|
|
|
- "No memory for MSI cascade data\n");
|
|
|
- err = -ENOMEM;
|
|
|
+
|
|
|
+ if (!p)
|
|
|
+ p = all_avail;
|
|
|
+
|
|
|
+ for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) {
|
|
|
+ if (p[i * 2] % IRQS_PER_MSI_REG ||
|
|
|
+ p[i * 2 + 1] % IRQS_PER_MSI_REG) {
|
|
|
+ printk(KERN_WARNING "%s: %s: msi available range of %u at %u is not IRQ-aligned\n",
|
|
|
+ __func__, dev->dev.of_node->full_name,
|
|
|
+ p[i * 2 + 1], p[i * 2]);
|
|
|
+ err = -EINVAL;
|
|
|
+ goto error_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ offset = p[i * 2] / IRQS_PER_MSI_REG;
|
|
|
+ count = p[i * 2 + 1] / IRQS_PER_MSI_REG;
|
|
|
+
|
|
|
+ for (j = 0; j < count; j++, irq_index++) {
|
|
|
+ err = fsl_msi_setup_hwirq(msi, dev, offset, irq_index);
|
|
|
+ if (err)
|
|
|
goto error_out;
|
|
|
- }
|
|
|
- msi->msi_virqs[i] = virt_msir;
|
|
|
- cascade_data->index = i + offset;
|
|
|
- cascade_data->msi_data = msi;
|
|
|
- set_irq_data(virt_msir, (void *)cascade_data);
|
|
|
- set_irq_chained_handler(virt_msir, fsl_msi_cascade);
|
|
|
}
|
|
|
}
|
|
|
|