diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 179 |
1 files changed, 88 insertions, 91 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ad141fe8d52..db82f503ba2 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -34,10 +34,15 @@ | |||
34 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
35 | #include <linux/mutex.h> | 35 | #include <linux/mutex.h> |
36 | #include <asm/spu.h> | 36 | #include <asm/spu.h> |
37 | #include <asm/spu_priv1.h> | ||
37 | #include <asm/mmu_context.h> | 38 | #include <asm/mmu_context.h> |
38 | 39 | ||
39 | #include "interrupt.h" | 40 | #include "interrupt.h" |
40 | 41 | ||
42 | const struct spu_priv1_ops *spu_priv1_ops; | ||
43 | |||
44 | EXPORT_SYMBOL_GPL(spu_priv1_ops); | ||
45 | |||
41 | static int __spu_trap_invalid_dma(struct spu *spu) | 46 | static int __spu_trap_invalid_dma(struct spu *spu) |
42 | { | 47 | { |
43 | pr_debug("%s\n", __FUNCTION__); | 48 | pr_debug("%s\n", __FUNCTION__); |
@@ -71,7 +76,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
71 | { | 76 | { |
72 | struct spu_priv2 __iomem *priv2 = spu->priv2; | 77 | struct spu_priv2 __iomem *priv2 = spu->priv2; |
73 | struct mm_struct *mm = spu->mm; | 78 | struct mm_struct *mm = spu->mm; |
74 | u64 esid, vsid; | 79 | u64 esid, vsid, llp; |
75 | 80 | ||
76 | pr_debug("%s\n", __FUNCTION__); | 81 | pr_debug("%s\n", __FUNCTION__); |
77 | 82 | ||
@@ -91,9 +96,14 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
91 | } | 96 | } |
92 | 97 | ||
93 | esid = (ea & ESID_MASK) | SLB_ESID_V; | 98 | esid = (ea & ESID_MASK) | SLB_ESID_V; |
94 | vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER; | 99 | #ifdef CONFIG_HUGETLB_PAGE |
95 | if (in_hugepage_area(mm->context, ea)) | 100 | if (in_hugepage_area(mm->context, ea)) |
96 | vsid |= SLB_VSID_L; | 101 | llp = mmu_psize_defs[mmu_huge_psize].sllp; |
102 | else | ||
103 | #endif | ||
104 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
105 | vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | | ||
106 | SLB_VSID_USER | llp; | ||
97 | 107 | ||
98 | out_be64(&priv2->slb_index_W, spu->slb_replace); | 108 | out_be64(&priv2->slb_index_W, spu->slb_replace); |
99 | out_be64(&priv2->slb_vsid_RW, vsid); | 109 | out_be64(&priv2->slb_vsid_RW, vsid); |
@@ -130,57 +140,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) | |||
130 | spu->dar = ea; | 140 | spu->dar = ea; |
131 | spu->dsisr = dsisr; | 141 | spu->dsisr = dsisr; |
132 | mb(); | 142 | mb(); |
133 | if (spu->stop_callback) | 143 | spu->stop_callback(spu); |
134 | spu->stop_callback(spu); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int __spu_trap_mailbox(struct spu *spu) | ||
139 | { | ||
140 | if (spu->ibox_callback) | ||
141 | spu->ibox_callback(spu); | ||
142 | |||
143 | /* atomically disable SPU mailbox interrupts */ | ||
144 | spin_lock(&spu->register_lock); | ||
145 | spu_int_mask_and(spu, 2, ~0x1); | ||
146 | spin_unlock(&spu->register_lock); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int __spu_trap_stop(struct spu *spu) | ||
151 | { | ||
152 | pr_debug("%s\n", __FUNCTION__); | ||
153 | spu->stop_code = in_be32(&spu->problem->spu_status_R); | ||
154 | if (spu->stop_callback) | ||
155 | spu->stop_callback(spu); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int __spu_trap_halt(struct spu *spu) | ||
160 | { | ||
161 | pr_debug("%s\n", __FUNCTION__); | ||
162 | spu->stop_code = in_be32(&spu->problem->spu_status_R); | ||
163 | if (spu->stop_callback) | ||
164 | spu->stop_callback(spu); | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int __spu_trap_tag_group(struct spu *spu) | ||
169 | { | ||
170 | pr_debug("%s\n", __FUNCTION__); | ||
171 | spu->mfc_callback(spu); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int __spu_trap_spubox(struct spu *spu) | ||
176 | { | ||
177 | if (spu->wbox_callback) | ||
178 | spu->wbox_callback(spu); | ||
179 | |||
180 | /* atomically disable SPU mailbox interrupts */ | ||
181 | spin_lock(&spu->register_lock); | ||
182 | spu_int_mask_and(spu, 2, ~0x10); | ||
183 | spin_unlock(&spu->register_lock); | ||
184 | return 0; | 144 | return 0; |
185 | } | 145 | } |
186 | 146 | ||
@@ -191,8 +151,7 @@ spu_irq_class_0(int irq, void *data, struct pt_regs *regs) | |||
191 | 151 | ||
192 | spu = data; | 152 | spu = data; |
193 | spu->class_0_pending = 1; | 153 | spu->class_0_pending = 1; |
194 | if (spu->stop_callback) | 154 | spu->stop_callback(spu); |
195 | spu->stop_callback(spu); | ||
196 | 155 | ||
197 | return IRQ_HANDLED; | 156 | return IRQ_HANDLED; |
198 | } | 157 | } |
@@ -270,29 +229,38 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) | |||
270 | unsigned long mask; | 229 | unsigned long mask; |
271 | 230 | ||
272 | spu = data; | 231 | spu = data; |
232 | spin_lock(&spu->register_lock); | ||
273 | stat = spu_int_stat_get(spu, 2); | 233 | stat = spu_int_stat_get(spu, 2); |
274 | mask = spu_int_mask_get(spu, 2); | 234 | mask = spu_int_mask_get(spu, 2); |
235 | /* ignore interrupts we're not waiting for */ | ||
236 | stat &= mask; | ||
237 | /* | ||
238 | * mailbox interrupts (0x1 and 0x10) are level triggered. | ||
239 | * mask them now before acknowledging. | ||
240 | */ | ||
241 | if (stat & 0x11) | ||
242 | spu_int_mask_and(spu, 2, ~(stat & 0x11)); | ||
243 | /* acknowledge all interrupts before the callbacks */ | ||
244 | spu_int_stat_clear(spu, 2, stat); | ||
245 | spin_unlock(&spu->register_lock); | ||
275 | 246 | ||
276 | pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); | 247 | pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); |
277 | 248 | ||
278 | stat &= mask; | ||
279 | |||
280 | if (stat & 1) /* PPC core mailbox */ | 249 | if (stat & 1) /* PPC core mailbox */ |
281 | __spu_trap_mailbox(spu); | 250 | spu->ibox_callback(spu); |
282 | 251 | ||
283 | if (stat & 2) /* SPU stop-and-signal */ | 252 | if (stat & 2) /* SPU stop-and-signal */ |
284 | __spu_trap_stop(spu); | 253 | spu->stop_callback(spu); |
285 | 254 | ||
286 | if (stat & 4) /* SPU halted */ | 255 | if (stat & 4) /* SPU halted */ |
287 | __spu_trap_halt(spu); | 256 | spu->stop_callback(spu); |
288 | 257 | ||
289 | if (stat & 8) /* DMA tag group complete */ | 258 | if (stat & 8) /* DMA tag group complete */ |
290 | __spu_trap_tag_group(spu); | 259 | spu->mfc_callback(spu); |
291 | 260 | ||
292 | if (stat & 0x10) /* SPU mailbox threshold */ | 261 | if (stat & 0x10) /* SPU mailbox threshold */ |
293 | __spu_trap_spubox(spu); | 262 | spu->wbox_callback(spu); |
294 | 263 | ||
295 | spu_int_stat_clear(spu, 2, stat); | ||
296 | return stat ? IRQ_HANDLED : IRQ_NONE; | 264 | return stat ? IRQ_HANDLED : IRQ_NONE; |
297 | } | 265 | } |
298 | 266 | ||
@@ -512,14 +480,6 @@ int spu_irq_class_1_bottom(struct spu *spu) | |||
512 | return ret; | 480 | return ret; |
513 | } | 481 | } |
514 | 482 | ||
515 | void spu_irq_setaffinity(struct spu *spu, int cpu) | ||
516 | { | ||
517 | u64 target = iic_get_target_id(cpu); | ||
518 | u64 route = target << 48 | target << 32 | target << 16; | ||
519 | spu_int_route_set(spu, route); | ||
520 | } | ||
521 | EXPORT_SYMBOL_GPL(spu_irq_setaffinity); | ||
522 | |||
523 | static int __init find_spu_node_id(struct device_node *spe) | 483 | static int __init find_spu_node_id(struct device_node *spe) |
524 | { | 484 | { |
525 | unsigned int *id; | 485 | unsigned int *id; |
@@ -649,6 +609,46 @@ out: | |||
649 | return ret; | 609 | return ret; |
650 | } | 610 | } |
651 | 611 | ||
612 | struct sysdev_class spu_sysdev_class = { | ||
613 | set_kset_name("spu") | ||
614 | }; | ||
615 | |||
616 | static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf) | ||
617 | { | ||
618 | struct spu *spu = container_of(sysdev, struct spu, sysdev); | ||
619 | return sprintf(buf, "%d\n", spu->isrc); | ||
620 | |||
621 | } | ||
622 | static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL); | ||
623 | |||
624 | extern int attach_sysdev_to_node(struct sys_device *dev, int nid); | ||
625 | |||
626 | static int spu_create_sysdev(struct spu *spu) | ||
627 | { | ||
628 | int ret; | ||
629 | |||
630 | spu->sysdev.id = spu->number; | ||
631 | spu->sysdev.cls = &spu_sysdev_class; | ||
632 | ret = sysdev_register(&spu->sysdev); | ||
633 | if (ret) { | ||
634 | printk(KERN_ERR "Can't register SPU %d with sysfs\n", | ||
635 | spu->number); | ||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | sysdev_create_file(&spu->sysdev, &attr_isrc); | ||
640 | sysfs_add_device_to_node(&spu->sysdev, spu->nid); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static void spu_destroy_sysdev(struct spu *spu) | ||
646 | { | ||
647 | sysdev_remove_file(&spu->sysdev, &attr_isrc); | ||
648 | sysfs_remove_device_from_node(&spu->sysdev, spu->nid); | ||
649 | sysdev_unregister(&spu->sysdev); | ||
650 | } | ||
651 | |||
652 | static int __init create_spu(struct device_node *spe) | 652 | static int __init create_spu(struct device_node *spe) |
653 | { | 653 | { |
654 | struct spu *spu; | 654 | struct spu *spu; |
@@ -656,7 +656,7 @@ static int __init create_spu(struct device_node *spe) | |||
656 | static int number; | 656 | static int number; |
657 | 657 | ||
658 | ret = -ENOMEM; | 658 | ret = -ENOMEM; |
659 | spu = kmalloc(sizeof (*spu), GFP_KERNEL); | 659 | spu = kzalloc(sizeof (*spu), GFP_KERNEL); |
660 | if (!spu) | 660 | if (!spu) |
661 | goto out; | 661 | goto out; |
662 | 662 | ||
@@ -668,33 +668,20 @@ static int __init create_spu(struct device_node *spe) | |||
668 | spu->nid = of_node_to_nid(spe); | 668 | spu->nid = of_node_to_nid(spe); |
669 | if (spu->nid == -1) | 669 | if (spu->nid == -1) |
670 | spu->nid = 0; | 670 | spu->nid = 0; |
671 | |||
672 | spu->stop_code = 0; | ||
673 | spu->slb_replace = 0; | ||
674 | spu->mm = NULL; | ||
675 | spu->ctx = NULL; | ||
676 | spu->rq = NULL; | ||
677 | spu->pid = 0; | ||
678 | spu->class_0_pending = 0; | ||
679 | spu->flags = 0UL; | ||
680 | spu->dar = 0UL; | ||
681 | spu->dsisr = 0UL; | ||
682 | spin_lock_init(&spu->register_lock); | 671 | spin_lock_init(&spu->register_lock); |
683 | |||
684 | spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); | 672 | spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); |
685 | spu_mfc_sr1_set(spu, 0x33); | 673 | spu_mfc_sr1_set(spu, 0x33); |
686 | |||
687 | spu->ibox_callback = NULL; | ||
688 | spu->wbox_callback = NULL; | ||
689 | spu->stop_callback = NULL; | ||
690 | spu->mfc_callback = NULL; | ||
691 | |||
692 | mutex_lock(&spu_mutex); | 674 | mutex_lock(&spu_mutex); |
675 | |||
693 | spu->number = number++; | 676 | spu->number = number++; |
694 | ret = spu_request_irqs(spu); | 677 | ret = spu_request_irqs(spu); |
695 | if (ret) | 678 | if (ret) |
696 | goto out_unmap; | 679 | goto out_unmap; |
697 | 680 | ||
681 | ret = spu_create_sysdev(spu); | ||
682 | if (ret) | ||
683 | goto out_free_irqs; | ||
684 | |||
698 | list_add(&spu->list, &spu_list); | 685 | list_add(&spu->list, &spu_list); |
699 | mutex_unlock(&spu_mutex); | 686 | mutex_unlock(&spu_mutex); |
700 | 687 | ||
@@ -703,6 +690,9 @@ static int __init create_spu(struct device_node *spe) | |||
703 | spu->problem, spu->priv1, spu->priv2, spu->number); | 690 | spu->problem, spu->priv1, spu->priv2, spu->number); |
704 | goto out; | 691 | goto out; |
705 | 692 | ||
693 | out_free_irqs: | ||
694 | spu_free_irqs(spu); | ||
695 | |||
706 | out_unmap: | 696 | out_unmap: |
707 | mutex_unlock(&spu_mutex); | 697 | mutex_unlock(&spu_mutex); |
708 | spu_unmap(spu); | 698 | spu_unmap(spu); |
@@ -716,6 +706,7 @@ static void destroy_spu(struct spu *spu) | |||
716 | { | 706 | { |
717 | list_del_init(&spu->list); | 707 | list_del_init(&spu->list); |
718 | 708 | ||
709 | spu_destroy_sysdev(spu); | ||
719 | spu_free_irqs(spu); | 710 | spu_free_irqs(spu); |
720 | spu_unmap(spu); | 711 | spu_unmap(spu); |
721 | kfree(spu); | 712 | kfree(spu); |
@@ -728,6 +719,7 @@ static void cleanup_spu_base(void) | |||
728 | list_for_each_entry_safe(spu, tmp, &spu_list, list) | 719 | list_for_each_entry_safe(spu, tmp, &spu_list, list) |
729 | destroy_spu(spu); | 720 | destroy_spu(spu); |
730 | mutex_unlock(&spu_mutex); | 721 | mutex_unlock(&spu_mutex); |
722 | sysdev_class_unregister(&spu_sysdev_class); | ||
731 | } | 723 | } |
732 | module_exit(cleanup_spu_base); | 724 | module_exit(cleanup_spu_base); |
733 | 725 | ||
@@ -736,6 +728,11 @@ static int __init init_spu_base(void) | |||
736 | struct device_node *node; | 728 | struct device_node *node; |
737 | int ret; | 729 | int ret; |
738 | 730 | ||
731 | /* create sysdev class for spus */ | ||
732 | ret = sysdev_class_register(&spu_sysdev_class); | ||
733 | if (ret) | ||
734 | return ret; | ||
735 | |||
739 | ret = -ENODEV; | 736 | ret = -ENODEV; |
740 | for (node = of_find_node_by_type(NULL, "spe"); | 737 | for (node = of_find_node_by_type(NULL, "spe"); |
741 | node; node = of_find_node_by_type(node, "spe")) { | 738 | node; node = of_find_node_by_type(node, "spe")) { |