diff options
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 152 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 131 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 28 |
4 files changed, 160 insertions, 153 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index 9bfaba8791e3..a7cddf40e3d9 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | obj-$(CONFIG_SPU_FS) += spufs.o | 1 | obj-$(CONFIG_SPU_FS) += spufs.o |
2 | spufs-y += inode.o file.o context.o switch.o syscalls.o | 2 | spufs-y += inode.o file.o context.o switch.o syscalls.o |
3 | spufs-y += sched.o backing_ops.o hw_ops.o | 3 | spufs-y += sched.o backing_ops.o hw_ops.o run.o |
4 | 4 | ||
5 | # Rules to build switch.o with the help of SPU tool chain | 5 | # Rules to build switch.o with the help of SPU tool chain |
6 | SPU_CROSS := spu- | 6 | SPU_CROSS := spu- |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index e63426822fd5..dfa649c9b956 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -304,34 +304,6 @@ static struct file_operations spufs_mbox_stat_fops = { | |||
304 | .read = spufs_mbox_stat_read, | 304 | .read = spufs_mbox_stat_read, |
305 | }; | 305 | }; |
306 | 306 | ||
307 | /* | ||
308 | * spufs_wait | ||
309 | * Same as wait_event_interruptible(), except that here | ||
310 | * we need to call spu_release(ctx) before sleeping, and | ||
311 | * then spu_acquire(ctx) when awoken. | ||
312 | */ | ||
313 | |||
314 | #define spufs_wait(wq, condition) \ | ||
315 | ({ \ | ||
316 | int __ret = 0; \ | ||
317 | DEFINE_WAIT(__wait); \ | ||
318 | for (;;) { \ | ||
319 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | ||
320 | if (condition) \ | ||
321 | break; \ | ||
322 | if (!signal_pending(current)) { \ | ||
323 | spu_release(ctx); \ | ||
324 | schedule(); \ | ||
325 | spu_acquire(ctx); \ | ||
326 | continue; \ | ||
327 | } \ | ||
328 | __ret = -ERESTARTSYS; \ | ||
329 | break; \ | ||
330 | } \ | ||
331 | finish_wait(&(wq), &__wait); \ | ||
332 | __ret; \ | ||
333 | }) | ||
334 | |||
335 | /* low-level ibox access function */ | 307 | /* low-level ibox access function */ |
336 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data) | 308 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data) |
337 | { | 309 | { |
@@ -529,130 +501,6 @@ static struct file_operations spufs_wbox_stat_fops = { | |||
529 | .read = spufs_wbox_stat_read, | 501 | .read = spufs_wbox_stat_read, |
530 | }; | 502 | }; |
531 | 503 | ||
532 | /* interrupt-level stop callback function. */ | ||
533 | void spufs_stop_callback(struct spu *spu) | ||
534 | { | ||
535 | struct spu_context *ctx = spu->ctx; | ||
536 | |||
537 | wake_up_all(&ctx->stop_wq); | ||
538 | } | ||
539 | |||
540 | static inline int spu_stopped(struct spu_context *ctx, u32 * stat) | ||
541 | { | ||
542 | struct spu *spu; | ||
543 | u64 pte_fault; | ||
544 | |||
545 | *stat = ctx->ops->status_read(ctx); | ||
546 | if (ctx->state != SPU_STATE_RUNNABLE) | ||
547 | return 1; | ||
548 | spu = ctx->spu; | ||
549 | pte_fault = spu->dsisr & | ||
550 | (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); | ||
551 | return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; | ||
552 | } | ||
553 | |||
554 | static inline int spu_run_init(struct spu_context *ctx, u32 * npc, | ||
555 | u32 * status) | ||
556 | { | ||
557 | int ret; | ||
558 | |||
559 | if ((ret = spu_acquire_runnable(ctx)) != 0) | ||
560 | return ret; | ||
561 | ctx->ops->npc_write(ctx, *npc); | ||
562 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, | ||
567 | u32 * status) | ||
568 | { | ||
569 | int ret = 0; | ||
570 | |||
571 | *status = ctx->ops->status_read(ctx); | ||
572 | *npc = ctx->ops->npc_read(ctx); | ||
573 | spu_release(ctx); | ||
574 | |||
575 | if (signal_pending(current)) | ||
576 | ret = -ERESTARTSYS; | ||
577 | if (unlikely(current->ptrace & PT_PTRACED)) { | ||
578 | if ((*status & SPU_STATUS_STOPPED_BY_STOP) | ||
579 | && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { | ||
580 | force_sig(SIGTRAP, current); | ||
581 | ret = -ERESTARTSYS; | ||
582 | } | ||
583 | } | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, | ||
588 | u32 *status) | ||
589 | { | ||
590 | int ret; | ||
591 | |||
592 | if ((ret = spu_run_fini(ctx, npc, status)) != 0) | ||
593 | return ret; | ||
594 | if (*status & (SPU_STATUS_STOPPED_BY_STOP | | ||
595 | SPU_STATUS_STOPPED_BY_HALT)) { | ||
596 | return *status; | ||
597 | } | ||
598 | if ((ret = spu_run_init(ctx, npc, status)) != 0) | ||
599 | return ret; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static inline int spu_process_events(struct spu_context *ctx) | ||
604 | { | ||
605 | struct spu *spu = ctx->spu; | ||
606 | u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; | ||
607 | int ret = 0; | ||
608 | |||
609 | if (spu->dsisr & pte_fault) | ||
610 | ret = spu_irq_class_1_bottom(spu); | ||
611 | if (spu->class_0_pending) | ||
612 | ret = spu_irq_class_0_bottom(spu); | ||
613 | if (!ret && signal_pending(current)) | ||
614 | ret = -ERESTARTSYS; | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | long spufs_run_spu(struct file *file, struct spu_context *ctx, | ||
619 | u32 * npc, u32 * status) | ||
620 | { | ||
621 | int ret; | ||
622 | |||
623 | if (down_interruptible(&ctx->run_sema)) | ||
624 | return -ERESTARTSYS; | ||
625 | |||
626 | ret = spu_run_init(ctx, npc, status); | ||
627 | if (ret) | ||
628 | goto out; | ||
629 | |||
630 | do { | ||
631 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); | ||
632 | if (unlikely(ret)) | ||
633 | break; | ||
634 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | ||
635 | ret = spu_reacquire_runnable(ctx, npc, status); | ||
636 | if (ret) | ||
637 | goto out; | ||
638 | continue; | ||
639 | } | ||
640 | ret = spu_process_events(ctx); | ||
641 | |||
642 | } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | | ||
643 | SPU_STATUS_STOPPED_BY_HALT))); | ||
644 | |||
645 | ctx->ops->runcntl_stop(ctx); | ||
646 | ret = spu_run_fini(ctx, npc, status); | ||
647 | if (!ret) | ||
648 | ret = *status; | ||
649 | spu_yield(ctx); | ||
650 | |||
651 | out: | ||
652 | up(&ctx->run_sema); | ||
653 | return ret; | ||
654 | } | ||
655 | |||
656 | static ssize_t spufs_signal1_read(struct file *file, char __user *buf, | 504 | static ssize_t spufs_signal1_read(struct file *file, char __user *buf, |
657 | size_t len, loff_t *pos) | 505 | size_t len, loff_t *pos) |
658 | { | 506 | { |
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c new file mode 100644 index 000000000000..18ea8866c61a --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -0,0 +1,131 @@ | |||
1 | #include <linux/wait.h> | ||
2 | #include <linux/ptrace.h> | ||
3 | |||
4 | #include <asm/spu.h> | ||
5 | |||
6 | #include "spufs.h" | ||
7 | |||
8 | /* interrupt-level stop callback function. */ | ||
9 | void spufs_stop_callback(struct spu *spu) | ||
10 | { | ||
11 | struct spu_context *ctx = spu->ctx; | ||
12 | |||
13 | wake_up_all(&ctx->stop_wq); | ||
14 | } | ||
15 | |||
16 | static inline int spu_stopped(struct spu_context *ctx, u32 * stat) | ||
17 | { | ||
18 | struct spu *spu; | ||
19 | u64 pte_fault; | ||
20 | |||
21 | *stat = ctx->ops->status_read(ctx); | ||
22 | if (ctx->state != SPU_STATE_RUNNABLE) | ||
23 | return 1; | ||
24 | spu = ctx->spu; | ||
25 | pte_fault = spu->dsisr & | ||
26 | (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); | ||
27 | return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; | ||
28 | } | ||
29 | |||
30 | static inline int spu_run_init(struct spu_context *ctx, u32 * npc, | ||
31 | u32 * status) | ||
32 | { | ||
33 | int ret; | ||
34 | |||
35 | if ((ret = spu_acquire_runnable(ctx)) != 0) | ||
36 | return ret; | ||
37 | ctx->ops->npc_write(ctx, *npc); | ||
38 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, | ||
43 | u32 * status) | ||
44 | { | ||
45 | int ret = 0; | ||
46 | |||
47 | *status = ctx->ops->status_read(ctx); | ||
48 | *npc = ctx->ops->npc_read(ctx); | ||
49 | spu_release(ctx); | ||
50 | |||
51 | if (signal_pending(current)) | ||
52 | ret = -ERESTARTSYS; | ||
53 | if (unlikely(current->ptrace & PT_PTRACED)) { | ||
54 | if ((*status & SPU_STATUS_STOPPED_BY_STOP) | ||
55 | && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { | ||
56 | force_sig(SIGTRAP, current); | ||
57 | ret = -ERESTARTSYS; | ||
58 | } | ||
59 | } | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, | ||
64 | u32 *status) | ||
65 | { | ||
66 | int ret; | ||
67 | |||
68 | if ((ret = spu_run_fini(ctx, npc, status)) != 0) | ||
69 | return ret; | ||
70 | if (*status & (SPU_STATUS_STOPPED_BY_STOP | | ||
71 | SPU_STATUS_STOPPED_BY_HALT)) { | ||
72 | return *status; | ||
73 | } | ||
74 | if ((ret = spu_run_init(ctx, npc, status)) != 0) | ||
75 | return ret; | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static inline int spu_process_events(struct spu_context *ctx) | ||
80 | { | ||
81 | struct spu *spu = ctx->spu; | ||
82 | u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; | ||
83 | int ret = 0; | ||
84 | |||
85 | if (spu->dsisr & pte_fault) | ||
86 | ret = spu_irq_class_1_bottom(spu); | ||
87 | if (spu->class_0_pending) | ||
88 | ret = spu_irq_class_0_bottom(spu); | ||
89 | if (!ret && signal_pending(current)) | ||
90 | ret = -ERESTARTSYS; | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | long spufs_run_spu(struct file *file, struct spu_context *ctx, | ||
95 | u32 * npc, u32 * status) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | if (down_interruptible(&ctx->run_sema)) | ||
100 | return -ERESTARTSYS; | ||
101 | |||
102 | ret = spu_run_init(ctx, npc, status); | ||
103 | if (ret) | ||
104 | goto out; | ||
105 | |||
106 | do { | ||
107 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); | ||
108 | if (unlikely(ret)) | ||
109 | break; | ||
110 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | ||
111 | ret = spu_reacquire_runnable(ctx, npc, status); | ||
112 | if (ret) | ||
113 | goto out; | ||
114 | continue; | ||
115 | } | ||
116 | ret = spu_process_events(ctx); | ||
117 | |||
118 | } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | | ||
119 | SPU_STATUS_STOPPED_BY_HALT))); | ||
120 | |||
121 | ctx->ops->runcntl_stop(ctx); | ||
122 | ret = spu_run_fini(ctx, npc, status); | ||
123 | if (!ret) | ||
124 | ret = *status; | ||
125 | spu_yield(ctx); | ||
126 | |||
127 | out: | ||
128 | up(&ctx->run_sema); | ||
129 | return ret; | ||
130 | } | ||
131 | |||
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 48961ac584a1..c715ed0c4014 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -124,6 +124,34 @@ void spu_yield(struct spu_context *ctx); | |||
124 | int __init spu_sched_init(void); | 124 | int __init spu_sched_init(void); |
125 | void __exit spu_sched_exit(void); | 125 | void __exit spu_sched_exit(void); |
126 | 126 | ||
127 | /* | ||
128 | * spufs_wait | ||
129 | * Same as wait_event_interruptible(), except that here | ||
130 | * we need to call spu_release(ctx) before sleeping, and | ||
131 | * then spu_acquire(ctx) when awoken. | ||
132 | */ | ||
133 | |||
134 | #define spufs_wait(wq, condition) \ | ||
135 | ({ \ | ||
136 | int __ret = 0; \ | ||
137 | DEFINE_WAIT(__wait); \ | ||
138 | for (;;) { \ | ||
139 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | ||
140 | if (condition) \ | ||
141 | break; \ | ||
142 | if (!signal_pending(current)) { \ | ||
143 | spu_release(ctx); \ | ||
144 | schedule(); \ | ||
145 | spu_acquire(ctx); \ | ||
146 | continue; \ | ||
147 | } \ | ||
148 | __ret = -ERESTARTSYS; \ | ||
149 | break; \ | ||
150 | } \ | ||
151 | finish_wait(&(wq), &__wait); \ | ||
152 | __ret; \ | ||
153 | }) | ||
154 | |||
127 | size_t spu_wbox_write(struct spu_context *ctx, u32 data); | 155 | size_t spu_wbox_write(struct spu_context *ctx, u32 data); |
128 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data); | 156 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data); |
129 | 157 | ||