aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt9
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c92
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
277static 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
277static int __devinit fsl_of_msi_probe(struct platform_device *dev, 306static 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