]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/platforms/cell/spufs/run.c
[CELL] spufs: remove unused file argument from spufs_run_spu()
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / cell / spufs / run.c
1 #define DEBUG
2
3 #include <linux/wait.h>
4 #include <linux/ptrace.h>
5
6 #include <asm/spu.h>
7 #include <asm/spu_priv1.h>
8 #include <asm/io.h>
9 #include <asm/unistd.h>
10
11 #include "spufs.h"
12
13 /* interrupt-level stop callback function. */
14 void spufs_stop_callback(struct spu *spu)
15 {
16         struct spu_context *ctx = spu->ctx;
17
18         wake_up_all(&ctx->stop_wq);
19 }
20
21 static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
22 {
23         struct spu *spu;
24         u64 pte_fault;
25
26         *stat = ctx->ops->status_read(ctx);
27         if (ctx->state != SPU_STATE_RUNNABLE)
28                 return 1;
29         spu = ctx->spu;
30         pte_fault = spu->dsisr &
31             (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
32         return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
33                 1 : 0;
34 }
35
36 static int spu_setup_isolated(struct spu_context *ctx)
37 {
38         int ret;
39         u64 __iomem *mfc_cntl;
40         u64 sr1;
41         u32 status;
42         unsigned long timeout;
43         const u32 status_loading = SPU_STATUS_RUNNING
44                 | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
45
46         ret = -ENODEV;
47         if (!isolated_loader)
48                 goto out;
49
50         /*
51          * We need to exclude userspace access to the context.
52          *
53          * To protect against memory access we invalidate all ptes
54          * and make sure the pagefault handlers block on the mutex.
55          */
56         spu_unmap_mappings(ctx);
57
58         mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
59
60         /* purge the MFC DMA queue to ensure no spurious accesses before we
61          * enter kernel mode */
62         timeout = jiffies + HZ;
63         out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST);
64         while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK)
65                         != MFC_CNTL_PURGE_DMA_COMPLETE) {
66                 if (time_after(jiffies, timeout)) {
67                         printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
68                                         __FUNCTION__);
69                         ret = -EIO;
70                         goto out;
71                 }
72                 cond_resched();
73         }
74
75         /* put the SPE in kernel mode to allow access to the loader */
76         sr1 = spu_mfc_sr1_get(ctx->spu);
77         sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
78         spu_mfc_sr1_set(ctx->spu, sr1);
79
80         /* start the loader */
81         ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32);
82         ctx->ops->signal2_write(ctx,
83                         (unsigned long)isolated_loader & 0xffffffff);
84
85         ctx->ops->runcntl_write(ctx,
86                         SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
87
88         ret = 0;
89         timeout = jiffies + HZ;
90         while (((status = ctx->ops->status_read(ctx)) & status_loading) ==
91                                 status_loading) {
92                 if (time_after(jiffies, timeout)) {
93                         printk(KERN_ERR "%s: timeout waiting for loader\n",
94                                         __FUNCTION__);
95                         ret = -EIO;
96                         goto out_drop_priv;
97                 }
98                 cond_resched();
99         }
100
101         if (!(status & SPU_STATUS_RUNNING)) {
102                 /* If isolated LOAD has failed: run SPU, we will get a stop-and
103                  * signal later. */
104                 pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
105                 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
106                 ret = -EACCES;
107                 goto out_drop_priv;
108         }
109
110         if (!(status & SPU_STATUS_ISOLATED_STATE)) {
111                 /* This isn't allowed by the CBEA, but check anyway */
112                 pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
113                 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
114                 ret = -EINVAL;
115                 goto out_drop_priv;
116         }
117
118 out_drop_priv:
119         /* Finished accessing the loader. Drop kernel mode */
120         sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
121         spu_mfc_sr1_set(ctx->spu, sr1);
122
123 out:
124         return ret;
125 }
126
127 static int spu_run_init(struct spu_context *ctx, u32 * npc)
128 {
129         spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
130
131         if (ctx->flags & SPU_CREATE_ISOLATE) {
132                 unsigned long runcntl;
133
134                 if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
135                         int ret = spu_setup_isolated(ctx);
136                         if (ret)
137                                 return ret;
138                 }
139
140                 /* if userspace has set the runcntrl register (eg, to issue an
141                  * isolated exit), we need to re-set it here */
142                 runcntl = ctx->ops->runcntl_read(ctx) &
143                         (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
144                 if (runcntl == 0)
145                         runcntl = SPU_RUNCNTL_RUNNABLE;
146                 ctx->ops->runcntl_write(ctx, runcntl);
147         } else {
148                 unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL;
149                 ctx->ops->npc_write(ctx, *npc);
150                 if (test_thread_flag(TIF_SINGLESTEP))
151                         mode = SPU_PRIVCNTL_MODE_SINGLE_STEP;
152                 out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode);
153                 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
154         }
155
156         spuctx_switch_state(ctx, SPU_UTIL_USER);
157
158         return 0;
159 }
160
161 static int spu_run_fini(struct spu_context *ctx, u32 * npc,
162                                u32 * status)
163 {
164         int ret = 0;
165
166         *status = ctx->ops->status_read(ctx);
167         *npc = ctx->ops->npc_read(ctx);
168
169         spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
170         spu_release(ctx);
171
172         if (signal_pending(current))
173                 ret = -ERESTARTSYS;
174
175         return ret;
176 }
177
178 static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
179                                          u32 *status)
180 {
181         int ret;
182
183         ret = spu_run_fini(ctx, npc, status);
184         if (ret)
185                 return ret;
186
187         if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
188                 return *status;
189
190         ret = spu_acquire_runnable(ctx, 0);
191         if (ret)
192                 return ret;
193
194         ret = spu_run_init(ctx, npc);
195         if (ret) {
196                 spu_release(ctx);
197                 return ret;
198         }
199         return 0;
200 }
201
202 /*
203  * SPU syscall restarting is tricky because we violate the basic
204  * assumption that the signal handler is running on the interrupted
205  * thread. Here instead, the handler runs on PowerPC user space code,
206  * while the syscall was called from the SPU.
207  * This means we can only do a very rough approximation of POSIX
208  * signal semantics.
209  */
210 int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
211                           unsigned int *npc)
212 {
213         int ret;
214
215         switch (*spu_ret) {
216         case -ERESTARTSYS:
217         case -ERESTARTNOINTR:
218                 /*
219                  * Enter the regular syscall restarting for
220                  * sys_spu_run, then restart the SPU syscall
221                  * callback.
222                  */
223                 *npc -= 8;
224                 ret = -ERESTARTSYS;
225                 break;
226         case -ERESTARTNOHAND:
227         case -ERESTART_RESTARTBLOCK:
228                 /*
229                  * Restart block is too hard for now, just return -EINTR
230                  * to the SPU.
231                  * ERESTARTNOHAND comes from sys_pause, we also return
232                  * -EINTR from there.
233                  * Assume that we need to be restarted ourselves though.
234                  */
235                 *spu_ret = -EINTR;
236                 ret = -ERESTARTSYS;
237                 break;
238         default:
239                 printk(KERN_WARNING "%s: unexpected return code %ld\n",
240                         __FUNCTION__, *spu_ret);
241                 ret = 0;
242         }
243         return ret;
244 }
245
246 int spu_process_callback(struct spu_context *ctx)
247 {
248         struct spu_syscall_block s;
249         u32 ls_pointer, npc;
250         void __iomem *ls;
251         long spu_ret;
252         int ret;
253
254         /* get syscall block from local store */
255         npc = ctx->ops->npc_read(ctx) & ~3;
256         ls = (void __iomem *)ctx->ops->get_ls(ctx);
257         ls_pointer = in_be32(ls + npc);
258         if (ls_pointer > (LS_SIZE - sizeof(s)))
259                 return -EFAULT;
260         memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
261
262         /* do actual syscall without pinning the spu */
263         ret = 0;
264         spu_ret = -ENOSYS;
265         npc += 4;
266
267         if (s.nr_ret < __NR_syscalls) {
268                 spu_release(ctx);
269                 /* do actual system call from here */
270                 spu_ret = spu_sys_callback(&s);
271                 if (spu_ret <= -ERESTARTSYS) {
272                         ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
273                 }
274                 spu_acquire(ctx);
275                 if (ret == -ERESTARTSYS)
276                         return ret;
277         }
278
279         /* write result, jump over indirect pointer */
280         memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
281         ctx->ops->npc_write(ctx, npc);
282         ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
283         return ret;
284 }
285
286 static inline int spu_process_events(struct spu_context *ctx)
287 {
288         struct spu *spu = ctx->spu;
289         int ret = 0;
290
291         if (spu->class_0_pending)
292                 ret = spu_irq_class_0_bottom(spu);
293         if (!ret && signal_pending(current))
294                 ret = -ERESTARTSYS;
295         return ret;
296 }
297
298 long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
299 {
300         int ret;
301         u32 status;
302
303         if (mutex_lock_interruptible(&ctx->run_mutex))
304                 return -ERESTARTSYS;
305
306         ctx->ops->master_start(ctx);
307         ctx->event_return = 0;
308
309         spu_acquire(ctx);
310         if (ctx->state == SPU_STATE_SAVED) {
311                 __spu_update_sched_info(ctx);
312
313                 ret = spu_activate(ctx, 0);
314                 if (ret) {
315                         spu_release(ctx);
316                         goto out;
317                 }
318         } else {
319                 /*
320                  * We have to update the scheduling priority under active_mutex
321                  * to protect against find_victim().
322                  */
323                 spu_update_sched_info(ctx);
324         }
325
326         ret = spu_run_init(ctx, npc);
327         if (ret) {
328                 spu_release(ctx);
329                 goto out;
330         }
331
332         do {
333                 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
334                 if (unlikely(ret))
335                         break;
336
337                 spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
338
339                 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
340                     (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
341                         ret = spu_process_callback(ctx);
342                         if (ret)
343                                 break;
344                         status &= ~SPU_STATUS_STOPPED_BY_STOP;
345                 }
346                 ret = spufs_handle_class1(ctx);
347                 if (ret)
348                         break;
349
350                 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
351                         ret = spu_reacquire_runnable(ctx, npc, &status);
352                         if (ret)
353                                 goto out2;
354                         continue;
355                 }
356                 ret = spu_process_events(ctx);
357
358         } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
359                                       SPU_STATUS_STOPPED_BY_HALT |
360                                        SPU_STATUS_SINGLE_STEP)));
361
362         if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
363             (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) &&
364             (ctx->state == SPU_STATE_RUNNABLE))
365                 ctx->stats.libassist++;
366
367
368         ctx->ops->master_stop(ctx);
369         ret = spu_run_fini(ctx, npc, &status);
370         spu_yield(ctx);
371
372 out2:
373         if ((ret == 0) ||
374             ((ret == -ERESTARTSYS) &&
375              ((status & SPU_STATUS_STOPPED_BY_HALT) ||
376               (status & SPU_STATUS_SINGLE_STEP) ||
377               ((status & SPU_STATUS_STOPPED_BY_STOP) &&
378                (status >> SPU_STOP_STATUS_SHIFT != 0x2104)))))
379                 ret = status;
380
381         /* Note: we don't need to force_sig SIGTRAP on single-step
382          * since we have TIF_SINGLESTEP set, thus the kernel will do
383          * it upon return from the syscall anyawy
384          */
385         if ((status & SPU_STATUS_STOPPED_BY_STOP)
386             && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
387                 force_sig(SIGTRAP, current);
388                 ret = -ERESTARTSYS;
389         }
390
391 out:
392         *event = ctx->event_return;
393         mutex_unlock(&ctx->run_mutex);
394         return ret;
395 }