diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 119 |
1 files changed, 75 insertions, 44 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 656c1ef5f4ad..5d2313a6c82b 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -264,51 +264,57 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) | |||
264 | return stat ? IRQ_HANDLED : IRQ_NONE; | 264 | return stat ? IRQ_HANDLED : IRQ_NONE; |
265 | } | 265 | } |
266 | 266 | ||
267 | static int | 267 | static int spu_request_irqs(struct spu *spu) |
268 | spu_request_irqs(struct spu *spu) | ||
269 | { | 268 | { |
270 | int ret; | 269 | int ret = 0; |
271 | int irq_base; | ||
272 | |||
273 | irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET; | ||
274 | |||
275 | snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number); | ||
276 | ret = request_irq(irq_base + spu->isrc, | ||
277 | spu_irq_class_0, IRQF_DISABLED, spu->irq_c0, spu); | ||
278 | if (ret) | ||
279 | goto out; | ||
280 | |||
281 | snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); | ||
282 | ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, | ||
283 | spu_irq_class_1, IRQF_DISABLED, spu->irq_c1, spu); | ||
284 | if (ret) | ||
285 | goto out1; | ||
286 | 270 | ||
287 | snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); | 271 | if (spu->irqs[0] != NO_IRQ) { |
288 | ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, | 272 | snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", |
289 | spu_irq_class_2, IRQF_DISABLED, spu->irq_c2, spu); | 273 | spu->number); |
290 | if (ret) | 274 | ret = request_irq(spu->irqs[0], spu_irq_class_0, |
291 | goto out2; | 275 | IRQF_DISABLED, |
292 | goto out; | 276 | spu->irq_c0, spu); |
277 | if (ret) | ||
278 | goto bail0; | ||
279 | } | ||
280 | if (spu->irqs[1] != NO_IRQ) { | ||
281 | snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", | ||
282 | spu->number); | ||
283 | ret = request_irq(spu->irqs[1], spu_irq_class_1, | ||
284 | IRQF_DISABLED, | ||
285 | spu->irq_c1, spu); | ||
286 | if (ret) | ||
287 | goto bail1; | ||
288 | } | ||
289 | if (spu->irqs[2] != NO_IRQ) { | ||
290 | snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", | ||
291 | spu->number); | ||
292 | ret = request_irq(spu->irqs[2], spu_irq_class_2, | ||
293 | IRQF_DISABLED, | ||
294 | spu->irq_c2, spu); | ||
295 | if (ret) | ||
296 | goto bail2; | ||
297 | } | ||
298 | return 0; | ||
293 | 299 | ||
294 | out2: | 300 | bail2: |
295 | free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); | 301 | if (spu->irqs[1] != NO_IRQ) |
296 | out1: | 302 | free_irq(spu->irqs[1], spu); |
297 | free_irq(irq_base + spu->isrc, spu); | 303 | bail1: |
298 | out: | 304 | if (spu->irqs[0] != NO_IRQ) |
305 | free_irq(spu->irqs[0], spu); | ||
306 | bail0: | ||
299 | return ret; | 307 | return ret; |
300 | } | 308 | } |
301 | 309 | ||
302 | static void | 310 | static void spu_free_irqs(struct spu *spu) |
303 | spu_free_irqs(struct spu *spu) | ||
304 | { | 311 | { |
305 | int irq_base; | 312 | if (spu->irqs[0] != NO_IRQ) |
306 | 313 | free_irq(spu->irqs[0], spu); | |
307 | irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET; | 314 | if (spu->irqs[1] != NO_IRQ) |
308 | 315 | free_irq(spu->irqs[1], spu); | |
309 | free_irq(irq_base + spu->isrc, spu); | 316 | if (spu->irqs[2] != NO_IRQ) |
310 | free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); | 317 | free_irq(spu->irqs[2], spu); |
311 | free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu); | ||
312 | } | 318 | } |
313 | 319 | ||
314 | static LIST_HEAD(spu_list); | 320 | static LIST_HEAD(spu_list); |
@@ -559,17 +565,38 @@ static void spu_unmap(struct spu *spu) | |||
559 | iounmap((u8 __iomem *)spu->local_store); | 565 | iounmap((u8 __iomem *)spu->local_store); |
560 | } | 566 | } |
561 | 567 | ||
568 | /* This function shall be abstracted for HV platforms */ | ||
569 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | ||
570 | { | ||
571 | struct irq_host *host; | ||
572 | unsigned int isrc; | ||
573 | u32 *tmp; | ||
574 | |||
575 | host = iic_get_irq_host(spu->node); | ||
576 | if (host == NULL) | ||
577 | return -ENODEV; | ||
578 | |||
579 | /* Get the interrupt source from the device-tree */ | ||
580 | tmp = (u32 *)get_property(np, "isrc", NULL); | ||
581 | if (!tmp) | ||
582 | return -ENODEV; | ||
583 | spu->isrc = isrc = tmp[0]; | ||
584 | |||
585 | /* Now map interrupts of all 3 classes */ | ||
586 | spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc, 0); | ||
587 | spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc, 0); | ||
588 | spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc, 0); | ||
589 | |||
590 | /* Right now, we only fail if class 2 failed */ | ||
591 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | ||
592 | } | ||
593 | |||
562 | static int __init spu_map_device(struct spu *spu, struct device_node *node) | 594 | static int __init spu_map_device(struct spu *spu, struct device_node *node) |
563 | { | 595 | { |
564 | char *prop; | 596 | char *prop; |
565 | int ret; | 597 | int ret; |
566 | 598 | ||
567 | ret = -ENODEV; | 599 | ret = -ENODEV; |
568 | prop = get_property(node, "isrc", NULL); | ||
569 | if (!prop) | ||
570 | goto out; | ||
571 | spu->isrc = *(unsigned int *)prop; | ||
572 | |||
573 | spu->name = get_property(node, "name", NULL); | 600 | spu->name = get_property(node, "name", NULL); |
574 | if (!spu->name) | 601 | if (!spu->name) |
575 | goto out; | 602 | goto out; |
@@ -636,7 +663,8 @@ static int spu_create_sysdev(struct spu *spu) | |||
636 | return ret; | 663 | return ret; |
637 | } | 664 | } |
638 | 665 | ||
639 | sysdev_create_file(&spu->sysdev, &attr_isrc); | 666 | if (spu->isrc != 0) |
667 | sysdev_create_file(&spu->sysdev, &attr_isrc); | ||
640 | sysfs_add_device_to_node(&spu->sysdev, spu->nid); | 668 | sysfs_add_device_to_node(&spu->sysdev, spu->nid); |
641 | 669 | ||
642 | return 0; | 670 | return 0; |
@@ -668,6 +696,9 @@ static int __init create_spu(struct device_node *spe) | |||
668 | spu->nid = of_node_to_nid(spe); | 696 | spu->nid = of_node_to_nid(spe); |
669 | if (spu->nid == -1) | 697 | if (spu->nid == -1) |
670 | spu->nid = 0; | 698 | spu->nid = 0; |
699 | ret = spu_map_interrupts(spu, spe); | ||
700 | if (ret) | ||
701 | goto out_unmap; | ||
671 | spin_lock_init(&spu->register_lock); | 702 | spin_lock_init(&spu->register_lock); |
672 | spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); | 703 | spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); |
673 | spu_mfc_sr1_set(spu, 0x33); | 704 | spu_mfc_sr1_set(spu, 0x33); |