diff options
-rw-r--r-- | Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt | 9 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 92 |
2 files changed, 64 insertions, 37 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt index bcc30bac6831..70558c3f3682 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt | |||
@@ -5,14 +5,21 @@ Required properties: | |||
5 | first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572, | 5 | first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572, |
6 | etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on | 6 | etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on |
7 | the parent type. | 7 | the parent type. |
8 | |||
8 | - reg : should contain the address and the length of the shared message | 9 | - reg : should contain the address and the length of the shared message |
9 | interrupt register set. | 10 | interrupt register set. |
11 | |||
10 | - msi-available-ranges: use <start count> style section to define which | 12 | - msi-available-ranges: use <start count> style section to define which |
11 | msi interrupt can be used in the 256 msi interrupts. This property is | 13 | msi interrupt can be used in the 256 msi interrupts. This property is |
12 | optional, without this, all the 256 MSI interrupts can be used. | 14 | optional, without this, all the 256 MSI interrupts can be used. |
15 | Each available range must begin and end on a multiple of 32 (i.e. | ||
16 | no splitting an individual MSI register or the associated PIC interrupt). | ||
17 | |||
13 | - interrupts : each one of the interrupts here is one entry per 32 MSIs, | 18 | - interrupts : each one of the interrupts here is one entry per 32 MSIs, |
14 | and routed to the host interrupt controller. the interrupts should | 19 | and routed to the host interrupt controller. the interrupts should |
15 | be set as edge sensitive. | 20 | be set as edge sensitive. If msi-available-ranges is present, only |
21 | the interrupts that correspond to available ranges shall be present. | ||
22 | |||
16 | - interrupt-parent: the phandle for the interrupt controller | 23 | - interrupt-parent: the phandle for the interrupt controller |
17 | that services interrupts for this device. for 83xx cpu, the interrupts | 24 | that services interrupts for this device. for 83xx cpu, the interrupts |
18 | are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed | 25 | are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed |
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index f6051d7de3ed..8d6b074bb3e9 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. | 2 | * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. |
3 | * | 3 | * |
4 | * Author: Tony Li <tony.li@freescale.com> | 4 | * Author: Tony Li <tony.li@freescale.com> |
5 | * Jason Jin <Jason.jin@freescale.com> | 5 | * Jason Jin <Jason.jin@freescale.com> |
@@ -274,19 +274,47 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) | |||
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, | ||
278 | struct platform_device *dev, | ||
279 | int offset, int irq_index) | ||
280 | { | ||
281 | struct fsl_msi_cascade_data *cascade_data = NULL; | ||
282 | int virt_msir; | ||
283 | |||
284 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); | ||
285 | if (virt_msir == NO_IRQ) { | ||
286 | dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n", | ||
287 | __func__, irq_index); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | cascade_data = kzalloc(sizeof(struct fsl_msi_cascade_data), GFP_KERNEL); | ||
292 | if (!cascade_data) { | ||
293 | dev_err(&dev->dev, "No memory for MSI cascade data\n"); | ||
294 | return -ENOMEM; | ||
295 | } | ||
296 | |||
297 | msi->msi_virqs[irq_index] = virt_msir; | ||
298 | cascade_data->index = offset + irq_index; | ||
299 | cascade_data->msi_data = msi; | ||
300 | set_irq_data(virt_msir, cascade_data); | ||
301 | set_irq_chained_handler(virt_msir, fsl_msi_cascade); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
277 | static int __devinit fsl_of_msi_probe(struct platform_device *dev, | 306 | static int __devinit fsl_of_msi_probe(struct platform_device *dev, |
278 | const struct of_device_id *match) | 307 | const struct of_device_id *match) |
279 | { | 308 | { |
280 | struct fsl_msi *msi; | 309 | struct fsl_msi *msi; |
281 | struct resource res; | 310 | struct resource res; |
282 | int err, i, count; | 311 | int err, i, j, irq_index, count; |
283 | int rc; | 312 | int rc; |
284 | int virt_msir; | ||
285 | const u32 *p; | 313 | const u32 *p; |
286 | struct fsl_msi_feature *features = match->data; | 314 | struct fsl_msi_feature *features = match->data; |
287 | struct fsl_msi_cascade_data *cascade_data = NULL; | ||
288 | int len; | 315 | int len; |
289 | u32 offset; | 316 | u32 offset; |
317 | static const u32 all_avail[] = { 0, NR_MSI_IRQS }; | ||
290 | 318 | ||
291 | printk(KERN_DEBUG "Setting up Freescale MSI support\n"); | 319 | printk(KERN_DEBUG "Setting up Freescale MSI support\n"); |
292 | 320 | ||
@@ -333,42 +361,34 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev, | |||
333 | goto error_out; | 361 | goto error_out; |
334 | } | 362 | } |
335 | 363 | ||
336 | p = of_get_property(dev->dev.of_node, "interrupts", &count); | 364 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); |
337 | if (!p) { | 365 | if (p && len % (2 * sizeof(u32)) != 0) { |
338 | dev_err(&dev->dev, "no interrupts property found on %s\n", | 366 | dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", |
339 | dev->dev.of_node->full_name); | 367 | __func__); |
340 | err = -ENODEV; | ||
341 | goto error_out; | ||
342 | } | ||
343 | if (count % 8 != 0) { | ||
344 | dev_err(&dev->dev, "Malformed interrupts property on %s\n", | ||
345 | dev->dev.of_node->full_name); | ||
346 | err = -EINVAL; | 368 | err = -EINVAL; |
347 | goto error_out; | 369 | goto error_out; |
348 | } | 370 | } |
349 | offset = 0; | 371 | |
350 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); | 372 | if (!p) |
351 | if (p) | 373 | p = all_avail; |
352 | offset = *p / IRQS_PER_MSI_REG; | 374 | |
353 | 375 | for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) { | |
354 | count /= sizeof(u32); | 376 | if (p[i * 2] % IRQS_PER_MSI_REG || |
355 | for (i = 0; i < min(count / 2, NR_MSI_REG); i++) { | 377 | p[i * 2 + 1] % IRQS_PER_MSI_REG) { |
356 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, i); | 378 | printk(KERN_WARNING "%s: %s: msi available range of %u at %u is not IRQ-aligned\n", |
357 | if (virt_msir != NO_IRQ) { | 379 | __func__, dev->dev.of_node->full_name, |
358 | cascade_data = kzalloc( | 380 | p[i * 2 + 1], p[i * 2]); |
359 | sizeof(struct fsl_msi_cascade_data), | 381 | err = -EINVAL; |
360 | GFP_KERNEL); | 382 | goto error_out; |
361 | if (!cascade_data) { | 383 | } |
362 | dev_err(&dev->dev, | 384 | |
363 | "No memory for MSI cascade data\n"); | 385 | offset = p[i * 2] / IRQS_PER_MSI_REG; |
364 | err = -ENOMEM; | 386 | count = p[i * 2 + 1] / IRQS_PER_MSI_REG; |
387 | |||
388 | for (j = 0; j < count; j++, irq_index++) { | ||
389 | err = fsl_msi_setup_hwirq(msi, dev, offset, irq_index); | ||
390 | if (err) | ||
365 | goto error_out; | 391 | goto error_out; |
366 | } | ||
367 | msi->msi_virqs[i] = virt_msir; | ||
368 | cascade_data->index = i + offset; | ||
369 | cascade_data->msi_data = msi; | ||
370 | set_irq_data(virt_msir, (void *)cascade_data); | ||
371 | set_irq_chained_handler(virt_msir, fsl_msi_cascade); | ||
372 | } | 392 | } |
373 | } | 393 | } |
374 | 394 | ||