Commit | Line | Data |
---|---|---|
67207b96 AB |
1 | /* |
2 | * SPU file system -- file contents | |
3 | * | |
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | |
5 | * | |
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2, or (at your option) | |
11 | * any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | */ | |
22 | ||
23 | #include <linux/fs.h> | |
24 | #include <linux/ioctl.h> | |
25 | #include <linux/module.h> | |
d88cfffa | 26 | #include <linux/pagemap.h> |
67207b96 AB |
27 | #include <linux/poll.h> |
28 | ||
29 | #include <asm/io.h> | |
30 | #include <asm/semaphore.h> | |
31 | #include <asm/spu.h> | |
32 | #include <asm/uaccess.h> | |
33 | ||
34 | #include "spufs.h" | |
35 | ||
8b3d6663 | 36 | |
67207b96 AB |
37 | static int |
38 | spufs_mem_open(struct inode *inode, struct file *file) | |
39 | { | |
40 | struct spufs_inode_info *i = SPUFS_I(inode); | |
41 | file->private_data = i->i_ctx; | |
8b3d6663 | 42 | file->f_mapping = i->i_ctx->local_store; |
67207b96 AB |
43 | return 0; |
44 | } | |
45 | ||
46 | static ssize_t | |
47 | spufs_mem_read(struct file *file, char __user *buffer, | |
48 | size_t size, loff_t *pos) | |
49 | { | |
8b3d6663 AB |
50 | struct spu_context *ctx = file->private_data; |
51 | char *local_store; | |
67207b96 AB |
52 | int ret; |
53 | ||
8b3d6663 | 54 | spu_acquire(ctx); |
67207b96 | 55 | |
8b3d6663 AB |
56 | local_store = ctx->ops->get_ls(ctx); |
57 | ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); | |
67207b96 | 58 | |
8b3d6663 | 59 | spu_release(ctx); |
67207b96 AB |
60 | return ret; |
61 | } | |
62 | ||
63 | static ssize_t | |
64 | spufs_mem_write(struct file *file, const char __user *buffer, | |
65 | size_t size, loff_t *pos) | |
66 | { | |
67 | struct spu_context *ctx = file->private_data; | |
8b3d6663 AB |
68 | char *local_store; |
69 | int ret; | |
67207b96 AB |
70 | |
71 | size = min_t(ssize_t, LS_SIZE - *pos, size); | |
72 | if (size <= 0) | |
73 | return -EFBIG; | |
74 | *pos += size; | |
8b3d6663 AB |
75 | |
76 | spu_acquire(ctx); | |
77 | ||
78 | local_store = ctx->ops->get_ls(ctx); | |
79 | ret = copy_from_user(local_store + *pos - size, | |
80 | buffer, size) ? -EFAULT : size; | |
81 | ||
82 | spu_release(ctx); | |
83 | return ret; | |
67207b96 AB |
84 | } |
85 | ||
8b3d6663 AB |
86 | #ifdef CONFIG_SPARSEMEM |
87 | static struct page * | |
88 | spufs_mem_mmap_nopage(struct vm_area_struct *vma, | |
89 | unsigned long address, int *type) | |
90 | { | |
91 | struct page *page = NOPAGE_SIGBUS; | |
92 | ||
93 | struct spu_context *ctx = vma->vm_file->private_data; | |
94 | unsigned long offset = address - vma->vm_start; | |
95 | offset += vma->vm_pgoff << PAGE_SHIFT; | |
96 | ||
97 | spu_acquire(ctx); | |
98 | ||
99 | if (ctx->state == SPU_STATE_SAVED) | |
100 | page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); | |
101 | else | |
102 | page = pfn_to_page((ctx->spu->local_store_phys + offset) | |
103 | >> PAGE_SHIFT); | |
104 | ||
105 | spu_release(ctx); | |
106 | ||
107 | if (type) | |
108 | *type = VM_FAULT_MINOR; | |
109 | ||
d88cfffa | 110 | page_cache_get(page); |
8b3d6663 AB |
111 | return page; |
112 | } | |
113 | ||
114 | static struct vm_operations_struct spufs_mem_mmap_vmops = { | |
115 | .nopage = spufs_mem_mmap_nopage, | |
116 | }; | |
117 | ||
67207b96 AB |
118 | static int |
119 | spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) | |
120 | { | |
8b3d6663 AB |
121 | if (!(vma->vm_flags & VM_SHARED)) |
122 | return -EINVAL; | |
67207b96 | 123 | |
8b3d6663 | 124 | /* FIXME: */ |
8b3d6663 AB |
125 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
126 | | _PAGE_NO_CACHE); | |
127 | ||
128 | vma->vm_ops = &spufs_mem_mmap_vmops; | |
67207b96 AB |
129 | return 0; |
130 | } | |
8b3d6663 | 131 | #endif |
67207b96 AB |
132 | |
133 | static struct file_operations spufs_mem_fops = { | |
134 | .open = spufs_mem_open, | |
135 | .read = spufs_mem_read, | |
136 | .write = spufs_mem_write, | |
8b3d6663 AB |
137 | .llseek = generic_file_llseek, |
138 | #ifdef CONFIG_SPARSEMEM | |
67207b96 | 139 | .mmap = spufs_mem_mmap, |
8b3d6663 AB |
140 | #endif |
141 | }; | |
142 | ||
143 | static int | |
144 | spufs_regs_open(struct inode *inode, struct file *file) | |
145 | { | |
146 | struct spufs_inode_info *i = SPUFS_I(inode); | |
147 | file->private_data = i->i_ctx; | |
148 | return 0; | |
149 | } | |
150 | ||
151 | static ssize_t | |
152 | spufs_regs_read(struct file *file, char __user *buffer, | |
153 | size_t size, loff_t *pos) | |
154 | { | |
155 | struct spu_context *ctx = file->private_data; | |
156 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
157 | int ret; | |
158 | ||
159 | spu_acquire_saved(ctx); | |
160 | ||
161 | ret = simple_read_from_buffer(buffer, size, pos, | |
162 | lscsa->gprs, sizeof lscsa->gprs); | |
163 | ||
164 | spu_release(ctx); | |
165 | return ret; | |
166 | } | |
167 | ||
168 | static ssize_t | |
169 | spufs_regs_write(struct file *file, const char __user *buffer, | |
170 | size_t size, loff_t *pos) | |
171 | { | |
172 | struct spu_context *ctx = file->private_data; | |
173 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
174 | int ret; | |
175 | ||
176 | size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); | |
177 | if (size <= 0) | |
178 | return -EFBIG; | |
179 | *pos += size; | |
180 | ||
181 | spu_acquire_saved(ctx); | |
182 | ||
183 | ret = copy_from_user(lscsa->gprs + *pos - size, | |
184 | buffer, size) ? -EFAULT : size; | |
185 | ||
186 | spu_release(ctx); | |
187 | return ret; | |
188 | } | |
189 | ||
190 | static struct file_operations spufs_regs_fops = { | |
191 | .open = spufs_regs_open, | |
192 | .read = spufs_regs_read, | |
193 | .write = spufs_regs_write, | |
67207b96 AB |
194 | .llseek = generic_file_llseek, |
195 | }; | |
196 | ||
8b3d6663 AB |
197 | static ssize_t |
198 | spufs_fpcr_read(struct file *file, char __user * buffer, | |
199 | size_t size, loff_t * pos) | |
200 | { | |
201 | struct spu_context *ctx = file->private_data; | |
202 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
203 | int ret; | |
204 | ||
205 | spu_acquire_saved(ctx); | |
206 | ||
207 | ret = simple_read_from_buffer(buffer, size, pos, | |
208 | &lscsa->fpcr, sizeof(lscsa->fpcr)); | |
209 | ||
210 | spu_release(ctx); | |
211 | return ret; | |
212 | } | |
213 | ||
214 | static ssize_t | |
215 | spufs_fpcr_write(struct file *file, const char __user * buffer, | |
216 | size_t size, loff_t * pos) | |
217 | { | |
218 | struct spu_context *ctx = file->private_data; | |
219 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
220 | int ret; | |
221 | ||
222 | size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); | |
223 | if (size <= 0) | |
224 | return -EFBIG; | |
225 | *pos += size; | |
226 | ||
227 | spu_acquire_saved(ctx); | |
228 | ||
229 | ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, | |
230 | buffer, size) ? -EFAULT : size; | |
231 | ||
232 | spu_release(ctx); | |
233 | return ret; | |
234 | } | |
235 | ||
236 | static struct file_operations spufs_fpcr_fops = { | |
237 | .open = spufs_regs_open, | |
238 | .read = spufs_fpcr_read, | |
239 | .write = spufs_fpcr_write, | |
240 | .llseek = generic_file_llseek, | |
241 | }; | |
242 | ||
67207b96 AB |
243 | /* generic open function for all pipe-like files */ |
244 | static int spufs_pipe_open(struct inode *inode, struct file *file) | |
245 | { | |
246 | struct spufs_inode_info *i = SPUFS_I(inode); | |
247 | file->private_data = i->i_ctx; | |
248 | ||
249 | return nonseekable_open(inode, file); | |
250 | } | |
251 | ||
252 | static ssize_t spufs_mbox_read(struct file *file, char __user *buf, | |
253 | size_t len, loff_t *pos) | |
254 | { | |
8b3d6663 | 255 | struct spu_context *ctx = file->private_data; |
67207b96 | 256 | u32 mbox_data; |
8b3d6663 | 257 | int ret; |
67207b96 AB |
258 | |
259 | if (len < 4) | |
260 | return -EINVAL; | |
261 | ||
8b3d6663 AB |
262 | spu_acquire(ctx); |
263 | ret = ctx->ops->mbox_read(ctx, &mbox_data); | |
264 | spu_release(ctx); | |
67207b96 | 265 | |
8b3d6663 AB |
266 | if (!ret) |
267 | return -EAGAIN; | |
67207b96 AB |
268 | |
269 | if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) | |
270 | return -EFAULT; | |
271 | ||
272 | return 4; | |
273 | } | |
274 | ||
275 | static struct file_operations spufs_mbox_fops = { | |
276 | .open = spufs_pipe_open, | |
277 | .read = spufs_mbox_read, | |
278 | }; | |
279 | ||
280 | static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, | |
281 | size_t len, loff_t *pos) | |
282 | { | |
8b3d6663 | 283 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
284 | u32 mbox_stat; |
285 | ||
286 | if (len < 4) | |
287 | return -EINVAL; | |
288 | ||
8b3d6663 AB |
289 | spu_acquire(ctx); |
290 | ||
291 | mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; | |
292 | ||
293 | spu_release(ctx); | |
67207b96 AB |
294 | |
295 | if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) | |
296 | return -EFAULT; | |
297 | ||
298 | return 4; | |
299 | } | |
300 | ||
301 | static struct file_operations spufs_mbox_stat_fops = { | |
302 | .open = spufs_pipe_open, | |
303 | .read = spufs_mbox_stat_read, | |
304 | }; | |
305 | ||
8b3d6663 AB |
306 | /* |
307 | * spufs_wait | |
308 | * Same as wait_event_interruptible(), except that here | |
309 | * we need to call spu_release(ctx) before sleeping, and | |
310 | * then spu_acquire(ctx) when awoken. | |
311 | */ | |
312 | ||
313 | #define spufs_wait(wq, condition) \ | |
314 | ({ \ | |
315 | int __ret = 0; \ | |
316 | DEFINE_WAIT(__wait); \ | |
317 | for (;;) { \ | |
318 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | |
319 | if (condition) \ | |
320 | break; \ | |
321 | if (!signal_pending(current)) { \ | |
322 | spu_release(ctx); \ | |
323 | schedule(); \ | |
324 | spu_acquire(ctx); \ | |
325 | continue; \ | |
326 | } \ | |
327 | __ret = -ERESTARTSYS; \ | |
328 | break; \ | |
329 | } \ | |
330 | finish_wait(&(wq), &__wait); \ | |
331 | __ret; \ | |
332 | }) | |
333 | ||
67207b96 | 334 | /* low-level ibox access function */ |
8b3d6663 | 335 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data) |
67207b96 | 336 | { |
8b3d6663 AB |
337 | return ctx->ops->ibox_read(ctx, data); |
338 | } | |
67207b96 | 339 | |
8b3d6663 AB |
340 | static int spufs_ibox_fasync(int fd, struct file *file, int on) |
341 | { | |
342 | struct spu_context *ctx = file->private_data; | |
67207b96 | 343 | |
8b3d6663 | 344 | return fasync_helper(fd, file, on, &ctx->ibox_fasync); |
67207b96 | 345 | } |
67207b96 | 346 | |
8b3d6663 AB |
347 | /* interrupt-level ibox callback function. */ |
348 | void spufs_ibox_callback(struct spu *spu) | |
67207b96 | 349 | { |
8b3d6663 AB |
350 | struct spu_context *ctx = spu->ctx; |
351 | ||
352 | wake_up_all(&ctx->ibox_wq); | |
353 | kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); | |
67207b96 AB |
354 | } |
355 | ||
356 | static ssize_t spufs_ibox_read(struct file *file, char __user *buf, | |
357 | size_t len, loff_t *pos) | |
358 | { | |
8b3d6663 | 359 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
360 | u32 ibox_data; |
361 | ssize_t ret; | |
362 | ||
363 | if (len < 4) | |
364 | return -EINVAL; | |
365 | ||
8b3d6663 | 366 | spu_acquire(ctx); |
67207b96 AB |
367 | |
368 | ret = 0; | |
369 | if (file->f_flags & O_NONBLOCK) { | |
8b3d6663 | 370 | if (!spu_ibox_read(ctx, &ibox_data)) |
67207b96 AB |
371 | ret = -EAGAIN; |
372 | } else { | |
8b3d6663 | 373 | ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); |
67207b96 AB |
374 | } |
375 | ||
8b3d6663 AB |
376 | spu_release(ctx); |
377 | ||
67207b96 AB |
378 | if (ret) |
379 | return ret; | |
380 | ||
381 | ret = 4; | |
382 | if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) | |
383 | ret = -EFAULT; | |
384 | ||
385 | return ret; | |
386 | } | |
387 | ||
388 | static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) | |
389 | { | |
8b3d6663 | 390 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
391 | u32 mbox_stat; |
392 | unsigned int mask; | |
393 | ||
8b3d6663 AB |
394 | spu_acquire(ctx); |
395 | ||
396 | mbox_stat = ctx->ops->mbox_stat_read(ctx); | |
397 | ||
398 | spu_release(ctx); | |
67207b96 | 399 | |
8b3d6663 | 400 | poll_wait(file, &ctx->ibox_wq, wait); |
67207b96 AB |
401 | |
402 | mask = 0; | |
403 | if (mbox_stat & 0xff0000) | |
404 | mask |= POLLIN | POLLRDNORM; | |
405 | ||
406 | return mask; | |
407 | } | |
408 | ||
409 | static struct file_operations spufs_ibox_fops = { | |
410 | .open = spufs_pipe_open, | |
411 | .read = spufs_ibox_read, | |
412 | .poll = spufs_ibox_poll, | |
413 | .fasync = spufs_ibox_fasync, | |
414 | }; | |
415 | ||
416 | static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, | |
417 | size_t len, loff_t *pos) | |
418 | { | |
8b3d6663 | 419 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
420 | u32 ibox_stat; |
421 | ||
422 | if (len < 4) | |
423 | return -EINVAL; | |
424 | ||
8b3d6663 AB |
425 | spu_acquire(ctx); |
426 | ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; | |
427 | spu_release(ctx); | |
67207b96 AB |
428 | |
429 | if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) | |
430 | return -EFAULT; | |
431 | ||
432 | return 4; | |
433 | } | |
434 | ||
435 | static struct file_operations spufs_ibox_stat_fops = { | |
436 | .open = spufs_pipe_open, | |
437 | .read = spufs_ibox_stat_read, | |
438 | }; | |
439 | ||
440 | /* low-level mailbox write */ | |
8b3d6663 | 441 | size_t spu_wbox_write(struct spu_context *ctx, u32 data) |
67207b96 | 442 | { |
8b3d6663 AB |
443 | return ctx->ops->wbox_write(ctx, data); |
444 | } | |
67207b96 | 445 | |
8b3d6663 AB |
446 | static int spufs_wbox_fasync(int fd, struct file *file, int on) |
447 | { | |
448 | struct spu_context *ctx = file->private_data; | |
449 | int ret; | |
67207b96 | 450 | |
8b3d6663 | 451 | ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); |
67207b96 | 452 | |
67207b96 AB |
453 | return ret; |
454 | } | |
67207b96 | 455 | |
8b3d6663 AB |
456 | /* interrupt-level wbox callback function. */ |
457 | void spufs_wbox_callback(struct spu *spu) | |
67207b96 | 458 | { |
8b3d6663 AB |
459 | struct spu_context *ctx = spu->ctx; |
460 | ||
461 | wake_up_all(&ctx->wbox_wq); | |
462 | kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); | |
67207b96 AB |
463 | } |
464 | ||
465 | static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, | |
466 | size_t len, loff_t *pos) | |
467 | { | |
8b3d6663 | 468 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
469 | u32 wbox_data; |
470 | int ret; | |
471 | ||
472 | if (len < 4) | |
473 | return -EINVAL; | |
474 | ||
67207b96 AB |
475 | if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) |
476 | return -EFAULT; | |
477 | ||
8b3d6663 AB |
478 | spu_acquire(ctx); |
479 | ||
67207b96 AB |
480 | ret = 0; |
481 | if (file->f_flags & O_NONBLOCK) { | |
8b3d6663 | 482 | if (!spu_wbox_write(ctx, wbox_data)) |
67207b96 AB |
483 | ret = -EAGAIN; |
484 | } else { | |
8b3d6663 | 485 | ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); |
67207b96 AB |
486 | } |
487 | ||
8b3d6663 AB |
488 | spu_release(ctx); |
489 | ||
67207b96 AB |
490 | return ret ? ret : sizeof wbox_data; |
491 | } | |
492 | ||
493 | static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) | |
494 | { | |
8b3d6663 | 495 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
496 | u32 mbox_stat; |
497 | unsigned int mask; | |
498 | ||
8b3d6663 AB |
499 | spu_acquire(ctx); |
500 | mbox_stat = ctx->ops->mbox_stat_read(ctx); | |
501 | spu_release(ctx); | |
67207b96 | 502 | |
8b3d6663 | 503 | poll_wait(file, &ctx->wbox_wq, wait); |
67207b96 AB |
504 | |
505 | mask = 0; | |
506 | if (mbox_stat & 0x00ff00) | |
507 | mask = POLLOUT | POLLWRNORM; | |
508 | ||
509 | return mask; | |
510 | } | |
511 | ||
512 | static struct file_operations spufs_wbox_fops = { | |
513 | .open = spufs_pipe_open, | |
514 | .write = spufs_wbox_write, | |
515 | .poll = spufs_wbox_poll, | |
516 | .fasync = spufs_wbox_fasync, | |
517 | }; | |
518 | ||
519 | static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, | |
520 | size_t len, loff_t *pos) | |
521 | { | |
8b3d6663 | 522 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
523 | u32 wbox_stat; |
524 | ||
525 | if (len < 4) | |
526 | return -EINVAL; | |
527 | ||
8b3d6663 AB |
528 | spu_acquire(ctx); |
529 | wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; | |
530 | spu_release(ctx); | |
67207b96 AB |
531 | |
532 | if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) | |
533 | return -EFAULT; | |
534 | ||
535 | return 4; | |
536 | } | |
537 | ||
538 | static struct file_operations spufs_wbox_stat_fops = { | |
539 | .open = spufs_pipe_open, | |
540 | .read = spufs_wbox_stat_read, | |
541 | }; | |
542 | ||
543 | long spufs_run_spu(struct file *file, struct spu_context *ctx, | |
8b3d6663 | 544 | u32 *npc, u32 *status) |
67207b96 | 545 | { |
67207b96 AB |
546 | int ret; |
547 | ||
8b3d6663 AB |
548 | ret = spu_acquire_runnable(ctx); |
549 | if (ret) | |
550 | return ret; | |
67207b96 | 551 | |
8b3d6663 | 552 | ctx->ops->npc_write(ctx, *npc); |
67207b96 AB |
553 | |
554 | ret = spu_run(ctx->spu); | |
555 | ||
8b3d6663 AB |
556 | if (!ret) |
557 | ret = ctx->ops->status_read(ctx); | |
67207b96 | 558 | |
8b3d6663 | 559 | *npc = ctx->ops->npc_read(ctx); |
67207b96 | 560 | |
8b3d6663 AB |
561 | spu_release(ctx); |
562 | spu_yield(ctx); | |
67207b96 AB |
563 | return ret; |
564 | } | |
565 | ||
566 | static ssize_t spufs_signal1_read(struct file *file, char __user *buf, | |
567 | size_t len, loff_t *pos) | |
568 | { | |
8b3d6663 | 569 | struct spu_context *ctx = file->private_data; |
67207b96 AB |
570 | u32 data; |
571 | ||
67207b96 AB |
572 | if (len < 4) |
573 | return -EINVAL; | |
574 | ||
8b3d6663 AB |
575 | spu_acquire(ctx); |
576 | data = ctx->ops->signal1_read(ctx); | |
577 | spu_release(ctx); | |
578 | ||
67207b96 AB |
579 | if (copy_to_user(buf, &data, 4)) |
580 | return -EFAULT; | |
581 | ||
582 | return 4; | |
583 | } | |
584 | ||
585 | static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | |
586 | size_t len, loff_t *pos) | |
587 | { | |
588 | struct spu_context *ctx; | |
67207b96 AB |
589 | u32 data; |
590 | ||
591 | ctx = file->private_data; | |
67207b96 AB |
592 | |
593 | if (len < 4) | |
594 | return -EINVAL; | |
595 | ||
596 | if (copy_from_user(&data, buf, 4)) | |
597 | return -EFAULT; | |
598 | ||
8b3d6663 AB |
599 | spu_acquire(ctx); |
600 | ctx->ops->signal1_write(ctx, data); | |
601 | spu_release(ctx); | |
67207b96 AB |
602 | |
603 | return 4; | |
604 | } | |
605 | ||
606 | static struct file_operations spufs_signal1_fops = { | |
607 | .open = spufs_pipe_open, | |
608 | .read = spufs_signal1_read, | |
609 | .write = spufs_signal1_write, | |
610 | }; | |
611 | ||
612 | static ssize_t spufs_signal2_read(struct file *file, char __user *buf, | |
613 | size_t len, loff_t *pos) | |
614 | { | |
615 | struct spu_context *ctx; | |
67207b96 AB |
616 | u32 data; |
617 | ||
618 | ctx = file->private_data; | |
67207b96 AB |
619 | |
620 | if (len < 4) | |
621 | return -EINVAL; | |
622 | ||
8b3d6663 AB |
623 | spu_acquire(ctx); |
624 | data = ctx->ops->signal2_read(ctx); | |
625 | spu_release(ctx); | |
626 | ||
67207b96 AB |
627 | if (copy_to_user(buf, &data, 4)) |
628 | return -EFAULT; | |
629 | ||
630 | return 4; | |
631 | } | |
632 | ||
633 | static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | |
634 | size_t len, loff_t *pos) | |
635 | { | |
636 | struct spu_context *ctx; | |
67207b96 AB |
637 | u32 data; |
638 | ||
639 | ctx = file->private_data; | |
67207b96 AB |
640 | |
641 | if (len < 4) | |
642 | return -EINVAL; | |
643 | ||
644 | if (copy_from_user(&data, buf, 4)) | |
645 | return -EFAULT; | |
646 | ||
8b3d6663 AB |
647 | spu_acquire(ctx); |
648 | ctx->ops->signal2_write(ctx, data); | |
649 | spu_release(ctx); | |
67207b96 AB |
650 | |
651 | return 4; | |
652 | } | |
653 | ||
654 | static struct file_operations spufs_signal2_fops = { | |
655 | .open = spufs_pipe_open, | |
656 | .read = spufs_signal2_read, | |
657 | .write = spufs_signal2_write, | |
658 | }; | |
659 | ||
660 | static void spufs_signal1_type_set(void *data, u64 val) | |
661 | { | |
662 | struct spu_context *ctx = data; | |
67207b96 | 663 | |
8b3d6663 AB |
664 | spu_acquire(ctx); |
665 | ctx->ops->signal1_type_set(ctx, val); | |
666 | spu_release(ctx); | |
67207b96 AB |
667 | } |
668 | ||
669 | static u64 spufs_signal1_type_get(void *data) | |
670 | { | |
671 | struct spu_context *ctx = data; | |
8b3d6663 AB |
672 | u64 ret; |
673 | ||
674 | spu_acquire(ctx); | |
675 | ret = ctx->ops->signal1_type_get(ctx); | |
676 | spu_release(ctx); | |
677 | ||
678 | return ret; | |
67207b96 AB |
679 | } |
680 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, | |
681 | spufs_signal1_type_set, "%llu"); | |
682 | ||
683 | static void spufs_signal2_type_set(void *data, u64 val) | |
684 | { | |
685 | struct spu_context *ctx = data; | |
67207b96 | 686 | |
8b3d6663 AB |
687 | spu_acquire(ctx); |
688 | ctx->ops->signal2_type_set(ctx, val); | |
689 | spu_release(ctx); | |
67207b96 AB |
690 | } |
691 | ||
692 | static u64 spufs_signal2_type_get(void *data) | |
693 | { | |
694 | struct spu_context *ctx = data; | |
8b3d6663 AB |
695 | u64 ret; |
696 | ||
697 | spu_acquire(ctx); | |
698 | ret = ctx->ops->signal2_type_get(ctx); | |
699 | spu_release(ctx); | |
700 | ||
701 | return ret; | |
67207b96 AB |
702 | } |
703 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, | |
704 | spufs_signal2_type_set, "%llu"); | |
705 | ||
706 | static void spufs_npc_set(void *data, u64 val) | |
707 | { | |
708 | struct spu_context *ctx = data; | |
8b3d6663 AB |
709 | spu_acquire(ctx); |
710 | ctx->ops->npc_write(ctx, val); | |
711 | spu_release(ctx); | |
67207b96 AB |
712 | } |
713 | ||
714 | static u64 spufs_npc_get(void *data) | |
715 | { | |
716 | struct spu_context *ctx = data; | |
717 | u64 ret; | |
8b3d6663 AB |
718 | spu_acquire(ctx); |
719 | ret = ctx->ops->npc_read(ctx); | |
720 | spu_release(ctx); | |
67207b96 AB |
721 | return ret; |
722 | } | |
723 | DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") | |
724 | ||
8b3d6663 AB |
725 | static void spufs_decr_set(void *data, u64 val) |
726 | { | |
727 | struct spu_context *ctx = data; | |
728 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
729 | spu_acquire_saved(ctx); | |
730 | lscsa->decr.slot[0] = (u32) val; | |
731 | spu_release(ctx); | |
732 | } | |
733 | ||
734 | static u64 spufs_decr_get(void *data) | |
735 | { | |
736 | struct spu_context *ctx = data; | |
737 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
738 | u64 ret; | |
739 | spu_acquire_saved(ctx); | |
740 | ret = lscsa->decr.slot[0]; | |
741 | spu_release(ctx); | |
742 | return ret; | |
743 | } | |
744 | DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, | |
745 | "%llx\n") | |
746 | ||
747 | static void spufs_decr_status_set(void *data, u64 val) | |
748 | { | |
749 | struct spu_context *ctx = data; | |
750 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
751 | spu_acquire_saved(ctx); | |
752 | lscsa->decr_status.slot[0] = (u32) val; | |
753 | spu_release(ctx); | |
754 | } | |
755 | ||
756 | static u64 spufs_decr_status_get(void *data) | |
757 | { | |
758 | struct spu_context *ctx = data; | |
759 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
760 | u64 ret; | |
761 | spu_acquire_saved(ctx); | |
762 | ret = lscsa->decr_status.slot[0]; | |
763 | spu_release(ctx); | |
764 | return ret; | |
765 | } | |
766 | DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, | |
767 | spufs_decr_status_set, "%llx\n") | |
768 | ||
769 | static void spufs_spu_tag_mask_set(void *data, u64 val) | |
770 | { | |
771 | struct spu_context *ctx = data; | |
772 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
773 | spu_acquire_saved(ctx); | |
774 | lscsa->tag_mask.slot[0] = (u32) val; | |
775 | spu_release(ctx); | |
776 | } | |
777 | ||
778 | static u64 spufs_spu_tag_mask_get(void *data) | |
779 | { | |
780 | struct spu_context *ctx = data; | |
781 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
782 | u64 ret; | |
783 | spu_acquire_saved(ctx); | |
784 | ret = lscsa->tag_mask.slot[0]; | |
785 | spu_release(ctx); | |
786 | return ret; | |
787 | } | |
788 | DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get, | |
789 | spufs_spu_tag_mask_set, "%llx\n") | |
790 | ||
791 | static void spufs_event_mask_set(void *data, u64 val) | |
792 | { | |
793 | struct spu_context *ctx = data; | |
794 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
795 | spu_acquire_saved(ctx); | |
796 | lscsa->event_mask.slot[0] = (u32) val; | |
797 | spu_release(ctx); | |
798 | } | |
799 | ||
800 | static u64 spufs_event_mask_get(void *data) | |
801 | { | |
802 | struct spu_context *ctx = data; | |
803 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
804 | u64 ret; | |
805 | spu_acquire_saved(ctx); | |
806 | ret = lscsa->event_mask.slot[0]; | |
807 | spu_release(ctx); | |
808 | return ret; | |
809 | } | |
810 | DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, | |
811 | spufs_event_mask_set, "%llx\n") | |
812 | ||
813 | static void spufs_srr0_set(void *data, u64 val) | |
814 | { | |
815 | struct spu_context *ctx = data; | |
816 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
817 | spu_acquire_saved(ctx); | |
818 | lscsa->srr0.slot[0] = (u32) val; | |
819 | spu_release(ctx); | |
820 | } | |
821 | ||
822 | static u64 spufs_srr0_get(void *data) | |
823 | { | |
824 | struct spu_context *ctx = data; | |
825 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | |
826 | u64 ret; | |
827 | spu_acquire_saved(ctx); | |
828 | ret = lscsa->srr0.slot[0]; | |
829 | spu_release(ctx); | |
830 | return ret; | |
831 | } | |
832 | DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, | |
833 | "%llx\n") | |
834 | ||
67207b96 AB |
835 | struct tree_descr spufs_dir_contents[] = { |
836 | { "mem", &spufs_mem_fops, 0666, }, | |
8b3d6663 | 837 | { "regs", &spufs_regs_fops, 0666, }, |
67207b96 AB |
838 | { "mbox", &spufs_mbox_fops, 0444, }, |
839 | { "ibox", &spufs_ibox_fops, 0444, }, | |
840 | { "wbox", &spufs_wbox_fops, 0222, }, | |
841 | { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, | |
842 | { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, | |
843 | { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, | |
844 | { "signal1", &spufs_signal1_fops, 0666, }, | |
845 | { "signal2", &spufs_signal2_fops, 0666, }, | |
846 | { "signal1_type", &spufs_signal1_type, 0666, }, | |
847 | { "signal2_type", &spufs_signal2_type, 0666, }, | |
848 | { "npc", &spufs_npc_ops, 0666, }, | |
8b3d6663 AB |
849 | { "fpcr", &spufs_fpcr_fops, 0666, }, |
850 | { "decr", &spufs_decr_ops, 0666, }, | |
851 | { "decr_status", &spufs_decr_status_ops, 0666, }, | |
852 | { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, | |
853 | { "event_mask", &spufs_event_mask_ops, 0666, }, | |
854 | { "srr0", &spufs_srr0_ops, 0666, }, | |
67207b96 AB |
855 | {}, |
856 | }; |