diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 415 |
1 files changed, 94 insertions, 321 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 7aa809d5a244..bd7bffc3ddd0 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -25,22 +25,17 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/pci.h> | ||
29 | #include <linux/poll.h> | ||
30 | #include <linux/ptrace.h> | 28 | #include <linux/ptrace.h> |
31 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
32 | #include <linux/wait.h> | 30 | #include <linux/wait.h> |
33 | 31 | #include <linux/mm.h> | |
34 | #include <asm/firmware.h> | 32 | #include <linux/io.h> |
35 | #include <asm/io.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
38 | #include <asm/spu.h> | 34 | #include <asm/spu.h> |
39 | #include <asm/spu_priv1.h> | 35 | #include <asm/spu_priv1.h> |
40 | #include <asm/mmu_context.h> | 36 | #include <asm/xmon.h> |
41 | |||
42 | #include "interrupt.h" | ||
43 | 37 | ||
38 | const struct spu_management_ops *spu_management_ops; | ||
44 | const struct spu_priv1_ops *spu_priv1_ops; | 39 | const struct spu_priv1_ops *spu_priv1_ops; |
45 | 40 | ||
46 | EXPORT_SYMBOL_GPL(spu_priv1_ops); | 41 | EXPORT_SYMBOL_GPL(spu_priv1_ops); |
@@ -89,7 +84,30 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
89 | printk("%s: invalid access during switch!\n", __func__); | 84 | printk("%s: invalid access during switch!\n", __func__); |
90 | return 1; | 85 | return 1; |
91 | } | 86 | } |
92 | if (!mm || (REGION_ID(ea) != USER_REGION_ID)) { | 87 | esid = (ea & ESID_MASK) | SLB_ESID_V; |
88 | |||
89 | switch(REGION_ID(ea)) { | ||
90 | case USER_REGION_ID: | ||
91 | #ifdef CONFIG_HUGETLB_PAGE | ||
92 | if (in_hugepage_area(mm->context, ea)) | ||
93 | llp = mmu_psize_defs[mmu_huge_psize].sllp; | ||
94 | else | ||
95 | #endif | ||
96 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
97 | vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | | ||
98 | SLB_VSID_USER | llp; | ||
99 | break; | ||
100 | case VMALLOC_REGION_ID: | ||
101 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
102 | vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | | ||
103 | SLB_VSID_KERNEL | llp; | ||
104 | break; | ||
105 | case KERNEL_REGION_ID: | ||
106 | llp = mmu_psize_defs[mmu_linear_psize].sllp; | ||
107 | vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | | ||
108 | SLB_VSID_KERNEL | llp; | ||
109 | break; | ||
110 | default: | ||
93 | /* Future: support kernel segments so that drivers | 111 | /* Future: support kernel segments so that drivers |
94 | * can use SPUs. | 112 | * can use SPUs. |
95 | */ | 113 | */ |
@@ -97,16 +115,6 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
97 | return 1; | 115 | return 1; |
98 | } | 116 | } |
99 | 117 | ||
100 | esid = (ea & ESID_MASK) | SLB_ESID_V; | ||
101 | #ifdef CONFIG_HUGETLB_PAGE | ||
102 | if (in_hugepage_area(mm->context, ea)) | ||
103 | llp = mmu_psize_defs[mmu_huge_psize].sllp; | ||
104 | else | ||
105 | #endif | ||
106 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
107 | vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | | ||
108 | SLB_VSID_USER | llp; | ||
109 | |||
110 | out_be64(&priv2->slb_index_W, spu->slb_replace); | 118 | out_be64(&priv2->slb_index_W, spu->slb_replace); |
111 | out_be64(&priv2->slb_vsid_RW, vsid); | 119 | out_be64(&priv2->slb_vsid_RW, vsid); |
112 | out_be64(&priv2->slb_esid_RW, esid); | 120 | out_be64(&priv2->slb_esid_RW, esid); |
@@ -320,6 +328,7 @@ static void spu_free_irqs(struct spu *spu) | |||
320 | } | 328 | } |
321 | 329 | ||
322 | static struct list_head spu_list[MAX_NUMNODES]; | 330 | static struct list_head spu_list[MAX_NUMNODES]; |
331 | static LIST_HEAD(spu_full_list); | ||
323 | static DEFINE_MUTEX(spu_mutex); | 332 | static DEFINE_MUTEX(spu_mutex); |
324 | 333 | ||
325 | static void spu_init_channels(struct spu *spu) | 334 | static void spu_init_channels(struct spu *spu) |
@@ -364,8 +373,7 @@ struct spu *spu_alloc_node(int node) | |||
364 | if (!list_empty(&spu_list[node])) { | 373 | if (!list_empty(&spu_list[node])) { |
365 | spu = list_entry(spu_list[node].next, struct spu, list); | 374 | spu = list_entry(spu_list[node].next, struct spu, list); |
366 | list_del_init(&spu->list); | 375 | list_del_init(&spu->list); |
367 | pr_debug("Got SPU %x %d %d\n", | 376 | pr_debug("Got SPU %d %d\n", spu->number, spu->node); |
368 | spu->isrc, spu->number, spu->node); | ||
369 | spu_init_channels(spu); | 377 | spu_init_channels(spu); |
370 | } | 378 | } |
371 | mutex_unlock(&spu_mutex); | 379 | mutex_unlock(&spu_mutex); |
@@ -493,280 +501,65 @@ int spu_irq_class_1_bottom(struct spu *spu) | |||
493 | if (!error) { | 501 | if (!error) { |
494 | spu_restart_dma(spu); | 502 | spu_restart_dma(spu); |
495 | } else { | 503 | } else { |
496 | __spu_trap_invalid_dma(spu); | 504 | spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE); |
497 | } | 505 | } |
498 | return ret; | 506 | return ret; |
499 | } | 507 | } |
500 | 508 | ||
501 | static int __init find_spu_node_id(struct device_node *spe) | 509 | struct sysdev_class spu_sysdev_class = { |
502 | { | 510 | set_kset_name("spu") |
503 | const unsigned int *id; | 511 | }; |
504 | struct device_node *cpu; | ||
505 | cpu = spe->parent->parent; | ||
506 | id = get_property(cpu, "node-id", NULL); | ||
507 | return id ? *id : 0; | ||
508 | } | ||
509 | |||
510 | static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe, | ||
511 | const char *prop) | ||
512 | { | ||
513 | static DEFINE_MUTEX(add_spumem_mutex); | ||
514 | |||
515 | const struct address_prop { | ||
516 | unsigned long address; | ||
517 | unsigned int len; | ||
518 | } __attribute__((packed)) *p; | ||
519 | int proplen; | ||
520 | |||
521 | unsigned long start_pfn, nr_pages; | ||
522 | struct pglist_data *pgdata; | ||
523 | struct zone *zone; | ||
524 | int ret; | ||
525 | |||
526 | p = get_property(spe, prop, &proplen); | ||
527 | WARN_ON(proplen != sizeof (*p)); | ||
528 | |||
529 | start_pfn = p->address >> PAGE_SHIFT; | ||
530 | nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
531 | |||
532 | pgdata = NODE_DATA(spu->nid); | ||
533 | zone = pgdata->node_zones; | ||
534 | |||
535 | /* XXX rethink locking here */ | ||
536 | mutex_lock(&add_spumem_mutex); | ||
537 | ret = __add_pages(zone, start_pfn, nr_pages); | ||
538 | mutex_unlock(&add_spumem_mutex); | ||
539 | |||
540 | return ret; | ||
541 | } | ||
542 | 512 | ||
543 | static void __iomem * __init map_spe_prop(struct spu *spu, | 513 | int spu_add_sysdev_attr(struct sysdev_attribute *attr) |
544 | struct device_node *n, const char *name) | ||
545 | { | 514 | { |
546 | const struct address_prop { | 515 | struct spu *spu; |
547 | unsigned long address; | 516 | mutex_lock(&spu_mutex); |
548 | unsigned int len; | ||
549 | } __attribute__((packed)) *prop; | ||
550 | |||
551 | const void *p; | ||
552 | int proplen; | ||
553 | void __iomem *ret = NULL; | ||
554 | int err = 0; | ||
555 | |||
556 | p = get_property(n, name, &proplen); | ||
557 | if (proplen != sizeof (struct address_prop)) | ||
558 | return NULL; | ||
559 | |||
560 | prop = p; | ||
561 | |||
562 | err = cell_spuprop_present(spu, n, name); | ||
563 | if (err && (err != -EEXIST)) | ||
564 | goto out; | ||
565 | |||
566 | ret = ioremap(prop->address, prop->len); | ||
567 | |||
568 | out: | ||
569 | return ret; | ||
570 | } | ||
571 | 517 | ||
572 | static void spu_unmap(struct spu *spu) | 518 | list_for_each_entry(spu, &spu_full_list, full_list) |
573 | { | 519 | sysdev_create_file(&spu->sysdev, attr); |
574 | iounmap(spu->priv2); | ||
575 | iounmap(spu->priv1); | ||
576 | iounmap(spu->problem); | ||
577 | iounmap((__force u8 __iomem *)spu->local_store); | ||
578 | } | ||
579 | 520 | ||
580 | /* This function shall be abstracted for HV platforms */ | 521 | mutex_unlock(&spu_mutex); |
581 | static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np) | 522 | return 0; |
582 | { | ||
583 | unsigned int isrc; | ||
584 | const u32 *tmp; | ||
585 | |||
586 | /* Get the interrupt source unit from the device-tree */ | ||
587 | tmp = get_property(np, "isrc", NULL); | ||
588 | if (!tmp) | ||
589 | return -ENODEV; | ||
590 | isrc = tmp[0]; | ||
591 | |||
592 | /* Add the node number */ | ||
593 | isrc |= spu->node << IIC_IRQ_NODE_SHIFT; | ||
594 | spu->isrc = isrc; | ||
595 | |||
596 | /* Now map interrupts of all 3 classes */ | ||
597 | spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); | ||
598 | spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); | ||
599 | spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); | ||
600 | |||
601 | /* Right now, we only fail if class 2 failed */ | ||
602 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | ||
603 | } | 523 | } |
524 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr); | ||
604 | 525 | ||
605 | static int __init spu_map_device_old(struct spu *spu, struct device_node *node) | 526 | int spu_add_sysdev_attr_group(struct attribute_group *attrs) |
606 | { | 527 | { |
607 | const char *prop; | 528 | struct spu *spu; |
608 | int ret; | 529 | mutex_lock(&spu_mutex); |
609 | |||
610 | ret = -ENODEV; | ||
611 | spu->name = get_property(node, "name", NULL); | ||
612 | if (!spu->name) | ||
613 | goto out; | ||
614 | |||
615 | prop = get_property(node, "local-store", NULL); | ||
616 | if (!prop) | ||
617 | goto out; | ||
618 | spu->local_store_phys = *(unsigned long *)prop; | ||
619 | |||
620 | /* we use local store as ram, not io memory */ | ||
621 | spu->local_store = (void __force *) | ||
622 | map_spe_prop(spu, node, "local-store"); | ||
623 | if (!spu->local_store) | ||
624 | goto out; | ||
625 | |||
626 | prop = get_property(node, "problem", NULL); | ||
627 | if (!prop) | ||
628 | goto out_unmap; | ||
629 | spu->problem_phys = *(unsigned long *)prop; | ||
630 | |||
631 | spu->problem= map_spe_prop(spu, node, "problem"); | ||
632 | if (!spu->problem) | ||
633 | goto out_unmap; | ||
634 | |||
635 | spu->priv1= map_spe_prop(spu, node, "priv1"); | ||
636 | /* priv1 is not available on a hypervisor */ | ||
637 | |||
638 | spu->priv2= map_spe_prop(spu, node, "priv2"); | ||
639 | if (!spu->priv2) | ||
640 | goto out_unmap; | ||
641 | ret = 0; | ||
642 | goto out; | ||
643 | |||
644 | out_unmap: | ||
645 | spu_unmap(spu); | ||
646 | out: | ||
647 | return ret; | ||
648 | } | ||
649 | 530 | ||
650 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | 531 | list_for_each_entry(spu, &spu_full_list, full_list) |
651 | { | 532 | sysfs_create_group(&spu->sysdev.kobj, attrs); |
652 | struct of_irq oirq; | ||
653 | int ret; | ||
654 | int i; | ||
655 | 533 | ||
656 | for (i=0; i < 3; i++) { | 534 | mutex_unlock(&spu_mutex); |
657 | ret = of_irq_map_one(np, i, &oirq); | ||
658 | if (ret) { | ||
659 | pr_debug("spu_new: failed to get irq %d\n", i); | ||
660 | goto err; | ||
661 | } | ||
662 | ret = -EINVAL; | ||
663 | pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0], | ||
664 | oirq.controller->full_name); | ||
665 | spu->irqs[i] = irq_create_of_mapping(oirq.controller, | ||
666 | oirq.specifier, oirq.size); | ||
667 | if (spu->irqs[i] == NO_IRQ) { | ||
668 | pr_debug("spu_new: failed to map it !\n"); | ||
669 | goto err; | ||
670 | } | ||
671 | } | ||
672 | return 0; | 535 | return 0; |
673 | |||
674 | err: | ||
675 | pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name); | ||
676 | for (; i >= 0; i--) { | ||
677 | if (spu->irqs[i] != NO_IRQ) | ||
678 | irq_dispose_mapping(spu->irqs[i]); | ||
679 | } | ||
680 | return ret; | ||
681 | } | 536 | } |
537 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); | ||
682 | 538 | ||
683 | static int spu_map_resource(struct device_node *node, int nr, | ||
684 | void __iomem** virt, unsigned long *phys) | ||
685 | { | ||
686 | struct resource resource = { }; | ||
687 | int ret; | ||
688 | |||
689 | ret = of_address_to_resource(node, nr, &resource); | ||
690 | if (ret) | ||
691 | goto out; | ||
692 | 539 | ||
693 | if (phys) | 540 | void spu_remove_sysdev_attr(struct sysdev_attribute *attr) |
694 | *phys = resource.start; | ||
695 | *virt = ioremap(resource.start, resource.end - resource.start); | ||
696 | if (!*virt) | ||
697 | ret = -EINVAL; | ||
698 | |||
699 | out: | ||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | static int __init spu_map_device(struct spu *spu, struct device_node *node) | ||
704 | { | 541 | { |
705 | int ret = -ENODEV; | 542 | struct spu *spu; |
706 | spu->name = get_property(node, "name", NULL); | 543 | mutex_lock(&spu_mutex); |
707 | if (!spu->name) | ||
708 | goto out; | ||
709 | |||
710 | ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store, | ||
711 | &spu->local_store_phys); | ||
712 | if (ret) { | ||
713 | pr_debug("spu_new: failed to map %s resource 0\n", | ||
714 | node->full_name); | ||
715 | goto out; | ||
716 | } | ||
717 | ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem, | ||
718 | &spu->problem_phys); | ||
719 | if (ret) { | ||
720 | pr_debug("spu_new: failed to map %s resource 1\n", | ||
721 | node->full_name); | ||
722 | goto out_unmap; | ||
723 | } | ||
724 | ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2, | ||
725 | NULL); | ||
726 | if (ret) { | ||
727 | pr_debug("spu_new: failed to map %s resource 2\n", | ||
728 | node->full_name); | ||
729 | goto out_unmap; | ||
730 | } | ||
731 | |||
732 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | ||
733 | ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1, | ||
734 | NULL); | ||
735 | if (ret) { | ||
736 | pr_debug("spu_new: failed to map %s resource 3\n", | ||
737 | node->full_name); | ||
738 | goto out_unmap; | ||
739 | } | ||
740 | pr_debug("spu_new: %s maps:\n", node->full_name); | ||
741 | pr_debug(" local store : 0x%016lx -> 0x%p\n", | ||
742 | spu->local_store_phys, spu->local_store); | ||
743 | pr_debug(" problem state : 0x%016lx -> 0x%p\n", | ||
744 | spu->problem_phys, spu->problem); | ||
745 | pr_debug(" priv2 : 0x%p\n", spu->priv2); | ||
746 | pr_debug(" priv1 : 0x%p\n", spu->priv1); | ||
747 | 544 | ||
748 | return 0; | 545 | list_for_each_entry(spu, &spu_full_list, full_list) |
546 | sysdev_remove_file(&spu->sysdev, attr); | ||
749 | 547 | ||
750 | out_unmap: | 548 | mutex_unlock(&spu_mutex); |
751 | spu_unmap(spu); | ||
752 | out: | ||
753 | pr_debug("failed to map spe %s: %d\n", spu->name, ret); | ||
754 | return ret; | ||
755 | } | 549 | } |
550 | EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr); | ||
756 | 551 | ||
757 | struct sysdev_class spu_sysdev_class = { | 552 | void spu_remove_sysdev_attr_group(struct attribute_group *attrs) |
758 | set_kset_name("spu") | ||
759 | }; | ||
760 | |||
761 | static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf) | ||
762 | { | 553 | { |
763 | struct spu *spu = container_of(sysdev, struct spu, sysdev); | 554 | struct spu *spu; |
764 | return sprintf(buf, "%d\n", spu->isrc); | 555 | mutex_lock(&spu_mutex); |
765 | 556 | ||
766 | } | 557 | list_for_each_entry(spu, &spu_full_list, full_list) |
767 | static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL); | 558 | sysfs_remove_group(&spu->sysdev.kobj, attrs); |
768 | 559 | ||
769 | extern int attach_sysdev_to_node(struct sys_device *dev, int nid); | 560 | mutex_unlock(&spu_mutex); |
561 | } | ||
562 | EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group); | ||
770 | 563 | ||
771 | static int spu_create_sysdev(struct spu *spu) | 564 | static int spu_create_sysdev(struct spu *spu) |
772 | { | 565 | { |
@@ -781,21 +574,18 @@ static int spu_create_sysdev(struct spu *spu) | |||
781 | return ret; | 574 | return ret; |
782 | } | 575 | } |
783 | 576 | ||
784 | if (spu->isrc != 0) | 577 | sysfs_add_device_to_node(&spu->sysdev, spu->node); |
785 | sysdev_create_file(&spu->sysdev, &attr_isrc); | ||
786 | sysfs_add_device_to_node(&spu->sysdev, spu->nid); | ||
787 | 578 | ||
788 | return 0; | 579 | return 0; |
789 | } | 580 | } |
790 | 581 | ||
791 | static void spu_destroy_sysdev(struct spu *spu) | 582 | static void spu_destroy_sysdev(struct spu *spu) |
792 | { | 583 | { |
793 | sysdev_remove_file(&spu->sysdev, &attr_isrc); | 584 | sysfs_remove_device_from_node(&spu->sysdev, spu->node); |
794 | sysfs_remove_device_from_node(&spu->sysdev, spu->nid); | ||
795 | sysdev_unregister(&spu->sysdev); | 585 | sysdev_unregister(&spu->sysdev); |
796 | } | 586 | } |
797 | 587 | ||
798 | static int __init create_spu(struct device_node *spe) | 588 | static int __init create_spu(void *data) |
799 | { | 589 | { |
800 | struct spu *spu; | 590 | struct spu *spu; |
801 | int ret; | 591 | int ret; |
@@ -806,57 +596,37 @@ static int __init create_spu(struct device_node *spe) | |||
806 | if (!spu) | 596 | if (!spu) |
807 | goto out; | 597 | goto out; |
808 | 598 | ||
809 | spu->node = find_spu_node_id(spe); | 599 | spin_lock_init(&spu->register_lock); |
810 | if (spu->node >= MAX_NUMNODES) { | 600 | mutex_lock(&spu_mutex); |
811 | printk(KERN_WARNING "SPE %s on node %d ignored," | 601 | spu->number = number++; |
812 | " node number too big\n", spe->full_name, spu->node); | 602 | mutex_unlock(&spu_mutex); |
813 | printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); | 603 | |
814 | return -ENODEV; | 604 | ret = spu_create_spu(spu, data); |
815 | } | ||
816 | spu->nid = of_node_to_nid(spe); | ||
817 | if (spu->nid == -1) | ||
818 | spu->nid = 0; | ||
819 | 605 | ||
820 | ret = spu_map_device(spu, spe); | ||
821 | /* try old method */ | ||
822 | if (ret) | ||
823 | ret = spu_map_device_old(spu, spe); | ||
824 | if (ret) | 606 | if (ret) |
825 | goto out_free; | 607 | goto out_free; |
826 | 608 | ||
827 | ret = spu_map_interrupts(spu, spe); | 609 | spu_mfc_sdr_setup(spu); |
828 | if (ret) | ||
829 | ret = spu_map_interrupts_old(spu, spe); | ||
830 | if (ret) | ||
831 | goto out_unmap; | ||
832 | spin_lock_init(&spu->register_lock); | ||
833 | spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); | ||
834 | spu_mfc_sr1_set(spu, 0x33); | 610 | spu_mfc_sr1_set(spu, 0x33); |
835 | mutex_lock(&spu_mutex); | ||
836 | |||
837 | spu->number = number++; | ||
838 | ret = spu_request_irqs(spu); | 611 | ret = spu_request_irqs(spu); |
839 | if (ret) | 612 | if (ret) |
840 | goto out_unlock; | 613 | goto out_destroy; |
841 | 614 | ||
842 | ret = spu_create_sysdev(spu); | 615 | ret = spu_create_sysdev(spu); |
843 | if (ret) | 616 | if (ret) |
844 | goto out_free_irqs; | 617 | goto out_free_irqs; |
845 | 618 | ||
619 | mutex_lock(&spu_mutex); | ||
846 | list_add(&spu->list, &spu_list[spu->node]); | 620 | list_add(&spu->list, &spu_list[spu->node]); |
621 | list_add(&spu->full_list, &spu_full_list); | ||
847 | mutex_unlock(&spu_mutex); | 622 | mutex_unlock(&spu_mutex); |
848 | 623 | ||
849 | pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n", | ||
850 | spu->name, spu->isrc, spu->local_store, | ||
851 | spu->problem, spu->priv1, spu->priv2, spu->number); | ||
852 | goto out; | 624 | goto out; |
853 | 625 | ||
854 | out_free_irqs: | 626 | out_free_irqs: |
855 | spu_free_irqs(spu); | 627 | spu_free_irqs(spu); |
856 | out_unlock: | 628 | out_destroy: |
857 | mutex_unlock(&spu_mutex); | 629 | spu_destroy_spu(spu); |
858 | out_unmap: | ||
859 | spu_unmap(spu); | ||
860 | out_free: | 630 | out_free: |
861 | kfree(spu); | 631 | kfree(spu); |
862 | out: | 632 | out: |
@@ -866,10 +636,11 @@ out: | |||
866 | static void destroy_spu(struct spu *spu) | 636 | static void destroy_spu(struct spu *spu) |
867 | { | 637 | { |
868 | list_del_init(&spu->list); | 638 | list_del_init(&spu->list); |
639 | list_del_init(&spu->full_list); | ||
869 | 640 | ||
870 | spu_destroy_sysdev(spu); | 641 | spu_destroy_sysdev(spu); |
871 | spu_free_irqs(spu); | 642 | spu_free_irqs(spu); |
872 | spu_unmap(spu); | 643 | spu_destroy_spu(spu); |
873 | kfree(spu); | 644 | kfree(spu); |
874 | } | 645 | } |
875 | 646 | ||
@@ -890,9 +661,11 @@ module_exit(cleanup_spu_base); | |||
890 | 661 | ||
891 | static int __init init_spu_base(void) | 662 | static int __init init_spu_base(void) |
892 | { | 663 | { |
893 | struct device_node *node; | ||
894 | int i, ret; | 664 | int i, ret; |
895 | 665 | ||
666 | if (!spu_management_ops) | ||
667 | return 0; | ||
668 | |||
896 | /* create sysdev class for spus */ | 669 | /* create sysdev class for spus */ |
897 | ret = sysdev_class_register(&spu_sysdev_class); | 670 | ret = sysdev_class_register(&spu_sysdev_class); |
898 | if (ret) | 671 | if (ret) |
@@ -901,17 +674,17 @@ static int __init init_spu_base(void) | |||
901 | for (i = 0; i < MAX_NUMNODES; i++) | 674 | for (i = 0; i < MAX_NUMNODES; i++) |
902 | INIT_LIST_HEAD(&spu_list[i]); | 675 | INIT_LIST_HEAD(&spu_list[i]); |
903 | 676 | ||
904 | ret = -ENODEV; | 677 | ret = spu_enumerate_spus(create_spu); |
905 | for (node = of_find_node_by_type(NULL, "spe"); | 678 | |
906 | node; node = of_find_node_by_type(node, "spe")) { | 679 | if (ret) { |
907 | ret = create_spu(node); | 680 | printk(KERN_WARNING "%s: Error initializing spus\n", |
908 | if (ret) { | 681 | __FUNCTION__); |
909 | printk(KERN_WARNING "%s: Error initializing %s\n", | 682 | cleanup_spu_base(); |
910 | __FUNCTION__, node->name); | 683 | return ret; |
911 | cleanup_spu_base(); | ||
912 | break; | ||
913 | } | ||
914 | } | 684 | } |
685 | |||
686 | xmon_register_spus(&spu_full_list); | ||
687 | |||
915 | return ret; | 688 | return ret; |
916 | } | 689 | } |
917 | module_init(init_spu_base); | 690 | module_init(init_spu_base); |