aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell/spu_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c119
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
267static int 267static int spu_request_irqs(struct spu *spu)
268spu_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
294out2: 300bail2:
295 free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); 301 if (spu->irqs[1] != NO_IRQ)
296out1: 302 free_irq(spu->irqs[1], spu);
297 free_irq(irq_base + spu->isrc, spu); 303bail1:
298out: 304 if (spu->irqs[0] != NO_IRQ)
305 free_irq(spu->irqs[0], spu);
306bail0:
299 return ret; 307 return ret;
300} 308}
301 309
302static void 310static void spu_free_irqs(struct spu *spu)
303spu_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
314static LIST_HEAD(spu_list); 320static 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 */
569static 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
562static int __init spu_map_device(struct spu *spu, struct device_node *node) 594static 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);