aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-01-17 15:25:28 -0500
committerKumar Gala <galak@kernel.crashing.org>2011-03-15 14:48:16 -0400
commit6820fead714d57012428c96266e86105e39075e0 (patch)
treee24753dc62ab33a4d4c14236fe06d26cd69ba862 /arch/powerpc
parent48a10cdfc0262ee7b5ccd4cbb673957e320ec563 (diff)
powerpc/fsl_msi: Handle msi-available-ranges better
Now handles multiple ranges, doesn't make assumptions about interrupt specifier format, and doesn't claim interrupts that don't correspond to an available range. Also has some better error checking. The device tree binding is updated to clarify some existing assumptions. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c92
1 files changed, 56 insertions, 36 deletions
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