[POWERPC] spufs: Add spu stats in sysfs
[linux-2.6] / 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         if (ctx->flags & SPU_CREATE_ISOLATE) {
130                 unsigned long runcntl;
131
132                 if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
133                         int ret = spu_setup_isolated(ctx);
134                         if (ret)
135                                 return ret;
136                 }
137
138                 /* if userspace has set the runcntrl register (eg, to issue an
139                  * isolated exit), we need to re-set it here */
140                 runcntl = ctx->ops->runcntl_read(ctx) &
141                         (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
142                 if (runcntl == 0)
143                         runcntl = SPU_RUNCNTL_RUNNABLE;
144                 ctx->ops->runcntl_write(ctx, runcntl);
145         } else {
146                 unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL;
147                 ctx->ops->npc_write(ctx, *npc);
148                 if (test_thread_flag(TIF_SINGLESTEP))
149                         mode = SPU_PRIVCNTL_MODE_SINGLE_STEP;
150                 out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode);
151                 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
152         }
153
154         return 0;
155 }
156
157 static int spu_run_fini(struct spu_context *ctx, u32 * npc,
158                                u32 * status)
159 {
160         int ret = 0;
161
162         *status = ctx->ops->status_read(ctx);
163         *npc = ctx->ops->npc_read(ctx);
164         spu_release(ctx);
165
166         if (signal_pending(current))
167                 ret = -ERESTARTSYS;
168
169         return ret;
170 }
171
172 static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
173                                          u32 *status)
174 {
175         int ret;
176
177         ret = spu_run_fini(ctx, npc, status);
178         if (ret)
179                 return ret;
180
181         if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
182                 return *status;
183
184         ret = spu_acquire_runnable(ctx, 0);
185         if (ret)
186                 return ret;
187
188         ret = spu_run_init(ctx, npc);
189         if (ret) {
190                 spu_release(ctx);
191                 return ret;
192         }
193         return 0;
194 }
195
196 /*
197  * SPU syscall restarting is tricky because we violate the basic
198  * assumption that the signal handler is running on the interrupted
199  * thread. Here instead, the handler runs on PowerPC user space code,
200  * while the syscall was called from the SPU.
201  * This means we can only do a very rough approximation of POSIX
202  * signal semantics.
203  */
204 int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
205                           unsigned int *npc)
206 {
207         int ret;
208
209         switch (*spu_ret) {
210         case -ERESTARTSYS:
211         case -ERESTARTNOINTR:
212                 /*
213                  * Enter the regular syscall restarting for
214                  * sys_spu_run, then restart the SPU syscall
215                  * callback.
216                  */
217                 *npc -= 8;
218                 ret = -ERESTARTSYS;
219                 break;
220         case -ERESTARTNOHAND:
221         case -ERESTART_RESTARTBLOCK:
222                 /*
223                  * Restart block is too hard for now, just return -EINTR
224                  * to the SPU.
225                  * ERESTARTNOHAND comes from sys_pause, we also return
226                  * -EINTR from there.
227                  * Assume that we need to be restarted ourselves though.
228                  */
229                 *spu_ret = -EINTR;
230                 ret = -ERESTARTSYS;
231                 break;
232         default:
233                 printk(KERN_WARNING "%s: unexpected return code %ld\n",
234                         __FUNCTION__, *spu_ret);
235                 ret = 0;
236         }
237         return ret;
238 }
239
240 int spu_process_callback(struct spu_context *ctx)
241 {
242         struct spu_syscall_block s;
243         u32 ls_pointer, npc;
244         void __iomem *ls;
245         long spu_ret;
246         int ret;
247
248         /* get syscall block from local store */
249         npc = ctx->ops->npc_read(ctx) & ~3;
250         ls = (void __iomem *)ctx->ops->get_ls(ctx);
251         ls_pointer = in_be32(ls + npc);
252         if (ls_pointer > (LS_SIZE - sizeof(s)))
253                 return -EFAULT;
254         memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
255
256         /* do actual syscall without pinning the spu */
257         ret = 0;
258         spu_ret = -ENOSYS;
259         npc += 4;
260
261         if (s.nr_ret < __NR_syscalls) {
262                 spu_release(ctx);
263                 /* do actual system call from here */
264                 spu_ret = spu_sys_callback(&s);
265                 if (spu_ret <= -ERESTARTSYS) {
266                         ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
267                 }
268                 spu_acquire(ctx);
269                 if (ret == -ERESTARTSYS)
270                         return ret;
271         }
272
273         /* write result, jump over indirect pointer */
274         memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
275         ctx->ops->npc_write(ctx, npc);
276         ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
277         return ret;
278 }
279
280 static inline int spu_process_events(struct spu_context *ctx)
281 {
282         struct spu *spu = ctx->spu;
283         int ret = 0;
284
285         if (spu->class_0_pending)
286                 ret = spu_irq_class_0_bottom(spu);
287         if (!ret && signal_pending(current))
288                 ret = -ERESTARTSYS;
289         return ret;
290 }
291
292 long spufs_run_spu(struct file *file, struct spu_context *ctx,
293                    u32 *npc, u32 *event)
294 {
295         int ret;
296         u32 status;
297
298         if (mutex_lock_interruptible(&ctx->run_mutex))
299                 return -ERESTARTSYS;
300
301         ctx->ops->master_start(ctx);
302         ctx->event_return = 0;
303
304         spu_acquire(ctx);
305         if (ctx->state == SPU_STATE_SAVED) {
306                 __spu_update_sched_info(ctx);
307
308                 ret = spu_activate(ctx, 0);
309                 if (ret) {
310                         spu_release(ctx);
311                         goto out;
312                 }
313         } else {
314                 /*
315                  * We have to update the scheduling priority under active_mutex
316                  * to protect against find_victim().
317                  */
318                 spu_update_sched_info(ctx);
319         }
320
321         ret = spu_run_init(ctx, npc);
322         if (ret) {
323                 spu_release(ctx);
324                 goto out;
325         }
326
327         do {
328                 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
329                 if (unlikely(ret))
330                         break;
331                 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
332                     (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
333                         ret = spu_process_callback(ctx);
334                         if (ret)
335                                 break;
336                         status &= ~SPU_STATUS_STOPPED_BY_STOP;
337                 }
338                 ret = spufs_handle_class1(ctx);
339                 if (ret)
340                         break;
341
342                 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
343                         ret = spu_reacquire_runnable(ctx, npc, &status);
344                         if (ret)
345                                 goto out2;
346                         continue;
347                 }
348                 ret = spu_process_events(ctx);
349
350         } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
351                                       SPU_STATUS_STOPPED_BY_HALT |
352                                        SPU_STATUS_SINGLE_STEP)));
353
354         if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
355             (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) &&
356             (ctx->state == SPU_STATE_RUNNABLE))
357                 ctx->stats.libassist++;
358
359         ctx->ops->master_stop(ctx);
360         ret = spu_run_fini(ctx, npc, &status);
361         spu_yield(ctx);
362
363 out2:
364         if ((ret == 0) ||
365             ((ret == -ERESTARTSYS) &&
366              ((status & SPU_STATUS_STOPPED_BY_HALT) ||
367               (status & SPU_STATUS_SINGLE_STEP) ||
368               ((status & SPU_STATUS_STOPPED_BY_STOP) &&
369                (status >> SPU_STOP_STATUS_SHIFT != 0x2104)))))
370                 ret = status;
371
372         /* Note: we don't need to force_sig SIGTRAP on single-step
373          * since we have TIF_SINGLESTEP set, thus the kernel will do
374          * it upon return from the syscall anyawy
375          */
376         if ((status & SPU_STATUS_STOPPED_BY_STOP)
377             && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
378                 force_sig(SIGTRAP, current);
379                 ret = -ERESTARTSYS;
380         }
381
382 out:
383         *event = ctx->event_return;
384         mutex_unlock(&ctx->run_mutex);
385         return ret;
386 }