aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2006-10-04 11:26:14 -0400
committerPaul Mackerras <paulus@samba.org>2006-10-04 19:21:01 -0400
commit9add11daeee2f6d69f6b86237f197824332a4a3b (patch)
tree526daebd5cac297c288503fe4dafecd02c0f492e
parent28347bce8a837258e737873a55d31f2f424a6ea6 (diff)
[POWERPC] spufs: implement error event delivery to user space
This tries to fix spufs so we have an interface closer to what is specified in the man page for events returned in the third argument of spu_run. Fortunately, libspe has never been using the returned contents of that register, as they were the same as the return code of spu_run (duh!). Unlike the specification that we never implemented correctly, we now require a SPU_CREATE_EVENTS_ENABLED flag passed to spu_create, in order to get the new behavior. When this flag is not passed, spu_run will simply ignore the third argument now. Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c48
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h4
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c7
-rw-r--r--include/asm-powerpc/spu.h14
7 files changed, 68 insertions, 24 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 5931973845b1..bfbd0455d8a7 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -46,21 +46,21 @@ EXPORT_SYMBOL_GPL(spu_priv1_ops);
46static int __spu_trap_invalid_dma(struct spu *spu) 46static int __spu_trap_invalid_dma(struct spu *spu)
47{ 47{
48 pr_debug("%s\n", __FUNCTION__); 48 pr_debug("%s\n", __FUNCTION__);
49 force_sig(SIGBUS, /* info, */ current); 49 spu->dma_callback(spu, SPE_EVENT_INVALID_DMA);
50 return 0; 50 return 0;
51} 51}
52 52
53static int __spu_trap_dma_align(struct spu *spu) 53static int __spu_trap_dma_align(struct spu *spu)
54{ 54{
55 pr_debug("%s\n", __FUNCTION__); 55 pr_debug("%s\n", __FUNCTION__);
56 force_sig(SIGBUS, /* info, */ current); 56 spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT);
57 return 0; 57 return 0;
58} 58}
59 59
60static int __spu_trap_error(struct spu *spu) 60static int __spu_trap_error(struct spu *spu)
61{ 61{
62 pr_debug("%s\n", __FUNCTION__); 62 pr_debug("%s\n", __FUNCTION__);
63 force_sig(SIGILL, /* info, */ current); 63 spu->dma_callback(spu, SPE_EVENT_SPE_ERROR);
64 return 0; 64 return 0;
65} 65}
66 66
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 3950ddccb2c8..8cc615ff3637 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -224,7 +224,8 @@ struct file_operations spufs_context_fops = {
224}; 224};
225 225
226static int 226static int
227spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 227spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
228 int mode)
228{ 229{
229 int ret; 230 int ret;
230 struct inode *inode; 231 struct inode *inode;
@@ -244,6 +245,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
244 if (!ctx) 245 if (!ctx)
245 goto out_iput; 246 goto out_iput;
246 247
248 ctx->flags = flags;
249
247 inode->i_op = &spufs_dir_inode_operations; 250 inode->i_op = &spufs_dir_inode_operations;
248 inode->i_fop = &simple_dir_operations; 251 inode->i_fop = &simple_dir_operations;
249 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 252 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
@@ -304,7 +307,7 @@ long spufs_create_thread(struct nameidata *nd,
304 goto out; 307 goto out;
305 308
306 /* all flags are reserved */ 309 /* all flags are reserved */
307 if (flags) 310 if (flags & (~SPU_CREATE_FLAG_ALL))
308 goto out; 311 goto out;
309 312
310 dentry = lookup_create(nd, 1); 313 dentry = lookup_create(nd, 1);
@@ -317,7 +320,7 @@ long spufs_create_thread(struct nameidata *nd,
317 goto out_dput; 320 goto out_dput;
318 321
319 mode &= ~current->fs->umask; 322 mode &= ~current->fs->umask;
320 ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO); 323 ret = spufs_mkdir(nd->dentry->d_inode, dentry, flags, mode & S_IRWXUGO);
321 if (ret) 324 if (ret)
322 goto out_dput; 325 goto out_dput;
323 326
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 483c8b76232c..63df8cf4ba16 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -14,6 +14,26 @@ void spufs_stop_callback(struct spu *spu)
14 wake_up_all(&ctx->stop_wq); 14 wake_up_all(&ctx->stop_wq);
15} 15}
16 16
17void spufs_dma_callback(struct spu *spu, int type)
18{
19 struct spu_context *ctx = spu->ctx;
20
21 if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
22 ctx->event_return |= type;
23 wake_up_all(&ctx->stop_wq);
24 } else {
25 switch (type) {
26 case SPE_EVENT_DMA_ALIGNMENT:
27 case SPE_EVENT_INVALID_DMA:
28 force_sig(SIGBUS, /* info, */ current);
29 break;
30 case SPE_EVENT_SPE_ERROR:
31 force_sig(SIGILL, /* info */ current);
32 break;
33 }
34 }
35}
36
17static inline int spu_stopped(struct spu_context *ctx, u32 * stat) 37static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
18{ 38{
19 struct spu *spu; 39 struct spu *spu;
@@ -28,8 +48,7 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
28 return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; 48 return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
29} 49}
30 50
31static inline int spu_run_init(struct spu_context *ctx, u32 * npc, 51static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
32 u32 * status)
33{ 52{
34 int ret; 53 int ret;
35 54
@@ -72,7 +91,7 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
72 SPU_STATUS_STOPPED_BY_HALT)) { 91 SPU_STATUS_STOPPED_BY_HALT)) {
73 return *status; 92 return *status;
74 } 93 }
75 if ((ret = spu_run_init(ctx, npc, status)) != 0) 94 if ((ret = spu_run_init(ctx, npc)) != 0)
76 return ret; 95 return ret;
77 return 0; 96 return 0;
78} 97}
@@ -177,46 +196,49 @@ static inline int spu_process_events(struct spu_context *ctx)
177} 196}
178 197
179long spufs_run_spu(struct file *file, struct spu_context *ctx, 198long spufs_run_spu(struct file *file, struct spu_context *ctx,
180 u32 * npc, u32 * status) 199 u32 *npc, u32 *event)
181{ 200{
182 int ret; 201 int ret;
202 u32 status;
183 203
184 if (down_interruptible(&ctx->run_sema)) 204 if (down_interruptible(&ctx->run_sema))
185 return -ERESTARTSYS; 205 return -ERESTARTSYS;
186 206
187 ret = spu_run_init(ctx, npc, status); 207 ctx->event_return = 0;
208 ret = spu_run_init(ctx, npc);
188 if (ret) 209 if (ret)
189 goto out; 210 goto out;
190 211
191 do { 212 do {
192 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); 213 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
193 if (unlikely(ret)) 214 if (unlikely(ret))
194 break; 215 break;
195 if ((*status & SPU_STATUS_STOPPED_BY_STOP) && 216 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
196 (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 217 (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
197 ret = spu_process_callback(ctx); 218 ret = spu_process_callback(ctx);
198 if (ret) 219 if (ret)
199 break; 220 break;
200 *status &= ~SPU_STATUS_STOPPED_BY_STOP; 221 status &= ~SPU_STATUS_STOPPED_BY_STOP;
201 } 222 }
202 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 223 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
203 ret = spu_reacquire_runnable(ctx, npc, status); 224 ret = spu_reacquire_runnable(ctx, npc, &status);
204 if (ret) 225 if (ret)
205 goto out; 226 goto out;
206 continue; 227 continue;
207 } 228 }
208 ret = spu_process_events(ctx); 229 ret = spu_process_events(ctx);
209 230
210 } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | 231 } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
211 SPU_STATUS_STOPPED_BY_HALT))); 232 SPU_STATUS_STOPPED_BY_HALT)));
212 233
213 ctx->ops->runcntl_stop(ctx); 234 ctx->ops->runcntl_stop(ctx);
214 ret = spu_run_fini(ctx, npc, status); 235 ret = spu_run_fini(ctx, npc, &status);
215 if (!ret) 236 if (!ret)
216 ret = *status; 237 ret = status;
217 spu_yield(ctx); 238 spu_yield(ctx);
218 239
219out: 240out:
241 *event = ctx->event_return;
220 up(&ctx->run_sema); 242 up(&ctx->run_sema);
221 return ret; 243 return ret;
222} 244}
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index bd4e2c3d5d08..a824b6051164 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -81,7 +81,6 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
81 spu->number, spu->node); 81 spu->number, spu->node);
82 spu->ctx = ctx; 82 spu->ctx = ctx;
83 spu->flags = 0; 83 spu->flags = 0;
84 ctx->flags = 0;
85 ctx->spu = spu; 84 ctx->spu = spu;
86 ctx->ops = &spu_hw_ops; 85 ctx->ops = &spu_hw_ops;
87 spu->pid = current->pid; 86 spu->pid = current->pid;
@@ -92,6 +91,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
92 spu->wbox_callback = spufs_wbox_callback; 91 spu->wbox_callback = spufs_wbox_callback;
93 spu->stop_callback = spufs_stop_callback; 92 spu->stop_callback = spufs_stop_callback;
94 spu->mfc_callback = spufs_mfc_callback; 93 spu->mfc_callback = spufs_mfc_callback;
94 spu->dma_callback = spufs_dma_callback;
95 mb(); 95 mb();
96 spu_unmap_mappings(ctx); 96 spu_unmap_mappings(ctx);
97 spu_restore(&ctx->csa, spu); 97 spu_restore(&ctx->csa, spu);
@@ -111,12 +111,12 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
111 spu->wbox_callback = NULL; 111 spu->wbox_callback = NULL;
112 spu->stop_callback = NULL; 112 spu->stop_callback = NULL;
113 spu->mfc_callback = NULL; 113 spu->mfc_callback = NULL;
114 spu->dma_callback = NULL;
114 spu->mm = NULL; 115 spu->mm = NULL;
115 spu->pid = 0; 116 spu->pid = 0;
116 spu->prio = MAX_PRIO; 117 spu->prio = MAX_PRIO;
117 ctx->ops = &spu_backing_ops; 118 ctx->ops = &spu_backing_ops;
118 ctx->spu = NULL; 119 ctx->spu = NULL;
119 ctx->flags = 0;
120 spu->flags = 0; 120 spu->flags = 0;
121 spu->ctx = NULL; 121 spu->ctx = NULL;
122} 122}
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 4485738e2102..2fb6a0099112 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -66,7 +66,8 @@ struct spu_context {
66 u32 tagwait; 66 u32 tagwait;
67 struct spu_context_ops *ops; 67 struct spu_context_ops *ops;
68 struct work_struct reap_work; 68 struct work_struct reap_work;
69 u64 flags; 69 unsigned long flags;
70 unsigned long event_return;
70}; 71};
71 72
72struct mfc_dma_command { 73struct mfc_dma_command {
@@ -183,5 +184,6 @@ void spufs_ibox_callback(struct spu *spu);
183void spufs_wbox_callback(struct spu *spu); 184void spufs_wbox_callback(struct spu *spu);
184void spufs_stop_callback(struct spu *spu); 185void spufs_stop_callback(struct spu *spu);
185void spufs_mfc_callback(struct spu *spu); 186void spufs_mfc_callback(struct spu *spu);
187void spufs_dma_callback(struct spu *spu, int type);
186 188
187#endif 189#endif
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index e6565a949ddc..ef33a0ca2036 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -38,7 +38,7 @@ static long do_spu_run(struct file *filp,
38 u32 npc, status; 38 u32 npc, status;
39 39
40 ret = -EFAULT; 40 ret = -EFAULT;
41 if (get_user(npc, unpc) || get_user(status, ustatus)) 41 if (get_user(npc, unpc))
42 goto out; 42 goto out;
43 43
44 /* check if this file was created by spu_create */ 44 /* check if this file was created by spu_create */
@@ -49,7 +49,10 @@ static long do_spu_run(struct file *filp,
49 i = SPUFS_I(filp->f_dentry->d_inode); 49 i = SPUFS_I(filp->f_dentry->d_inode);
50 ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); 50 ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
51 51
52 if (put_user(npc, unpc) || put_user(status, ustatus)) 52 if (put_user(npc, unpc))
53 ret = -EFAULT;
54
55 if (ustatus && put_user(status, ustatus))
53 ret = -EFAULT; 56 ret = -EFAULT;
54out: 57out:
55 return ret; 58 return ret;
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index f6c0a95e8209..87cc21e21946 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -138,6 +138,7 @@ struct spu {
138 void (* ibox_callback)(struct spu *spu); 138 void (* ibox_callback)(struct spu *spu);
139 void (* stop_callback)(struct spu *spu); 139 void (* stop_callback)(struct spu *spu);
140 void (* mfc_callback)(struct spu *spu); 140 void (* mfc_callback)(struct spu *spu);
141 void (* dma_callback)(struct spu *spu, int type);
141 142
142 char irq_c0[8]; 143 char irq_c0[8];
143 char irq_c1[8]; 144 char irq_c1[8];
@@ -169,6 +170,19 @@ extern struct spufs_calls {
169 struct module *owner; 170 struct module *owner;
170} spufs_calls; 171} spufs_calls;
171 172
173/* return status from spu_run, same as in libspe */
174#define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */
175#define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/
176#define SPE_EVENT_SPE_DATA_SEGMENT 0x0020 /*A DMA segmentation error */
177#define SPE_EVENT_SPE_DATA_STORAGE 0x0040 /*A DMA storage error */
178#define SPE_EVENT_INVALID_DMA 0x0800 /* Invalid MFC DMA */
179
180/*
181 * Flags for sys_spu_create.
182 */
183#define SPU_CREATE_EVENTS_ENABLED 0x0001
184#define SPU_CREATE_FLAG_ALL 0x0001 /* mask of all valid flags */
185
172#ifdef CONFIG_SPU_FS_MODULE 186#ifdef CONFIG_SPU_FS_MODULE
173int register_spu_syscalls(struct spufs_calls *calls); 187int register_spu_syscalls(struct spufs_calls *calls);
174void unregister_spu_syscalls(struct spufs_calls *calls); 188void unregister_spu_syscalls(struct spufs_calls *calls);