aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
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