]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/powerpc/platforms/cell/spufs/file.c
[PATCH] spufs: implement mfc access for PPE-side DMA
[mirror_ubuntu-bionic-kernel.git] / arch / powerpc / platforms / cell / spufs / file.c
CommitLineData
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
a33a7d73
AB
23#undef DEBUG
24
67207b96
AB
25#include <linux/fs.h>
26#include <linux/ioctl.h>
27#include <linux/module.h>
d88cfffa 28#include <linux/pagemap.h>
67207b96 29#include <linux/poll.h>
5110459f 30#include <linux/ptrace.h>
67207b96
AB
31
32#include <asm/io.h>
33#include <asm/semaphore.h>
34#include <asm/spu.h>
35#include <asm/uaccess.h>
36
37#include "spufs.h"
38
8b3d6663 39
67207b96
AB
40static int
41spufs_mem_open(struct inode *inode, struct file *file)
42{
43 struct spufs_inode_info *i = SPUFS_I(inode);
44 file->private_data = i->i_ctx;
8b3d6663 45 file->f_mapping = i->i_ctx->local_store;
67207b96
AB
46 return 0;
47}
48
49static ssize_t
50spufs_mem_read(struct file *file, char __user *buffer,
51 size_t size, loff_t *pos)
52{
8b3d6663
AB
53 struct spu_context *ctx = file->private_data;
54 char *local_store;
67207b96
AB
55 int ret;
56
8b3d6663 57 spu_acquire(ctx);
67207b96 58
8b3d6663
AB
59 local_store = ctx->ops->get_ls(ctx);
60 ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE);
67207b96 61
8b3d6663 62 spu_release(ctx);
67207b96
AB
63 return ret;
64}
65
66static ssize_t
67spufs_mem_write(struct file *file, const char __user *buffer,
68 size_t size, loff_t *pos)
69{
70 struct spu_context *ctx = file->private_data;
8b3d6663
AB
71 char *local_store;
72 int ret;
67207b96
AB
73
74 size = min_t(ssize_t, LS_SIZE - *pos, size);
75 if (size <= 0)
76 return -EFBIG;
77 *pos += size;
8b3d6663
AB
78
79 spu_acquire(ctx);
80
81 local_store = ctx->ops->get_ls(ctx);
82 ret = copy_from_user(local_store + *pos - size,
83 buffer, size) ? -EFAULT : size;
84
85 spu_release(ctx);
86 return ret;
67207b96
AB
87}
88
8b3d6663
AB
89#ifdef CONFIG_SPARSEMEM
90static struct page *
91spufs_mem_mmap_nopage(struct vm_area_struct *vma,
92 unsigned long address, int *type)
93{
94 struct page *page = NOPAGE_SIGBUS;
95
96 struct spu_context *ctx = vma->vm_file->private_data;
97 unsigned long offset = address - vma->vm_start;
98 offset += vma->vm_pgoff << PAGE_SHIFT;
99
100 spu_acquire(ctx);
101
102 if (ctx->state == SPU_STATE_SAVED)
103 page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
104 else
105 page = pfn_to_page((ctx->spu->local_store_phys + offset)
106 >> PAGE_SHIFT);
107
108 spu_release(ctx);
109
110 if (type)
111 *type = VM_FAULT_MINOR;
112
d88cfffa 113 page_cache_get(page);
8b3d6663
AB
114 return page;
115}
116
117static struct vm_operations_struct spufs_mem_mmap_vmops = {
118 .nopage = spufs_mem_mmap_nopage,
119};
120
67207b96
AB
121static int
122spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
123{
8b3d6663
AB
124 if (!(vma->vm_flags & VM_SHARED))
125 return -EINVAL;
67207b96 126
8b3d6663 127 /* FIXME: */
8b3d6663
AB
128 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
129 | _PAGE_NO_CACHE);
130
131 vma->vm_ops = &spufs_mem_mmap_vmops;
67207b96
AB
132 return 0;
133}
8b3d6663 134#endif
67207b96
AB
135
136static struct file_operations spufs_mem_fops = {
137 .open = spufs_mem_open,
138 .read = spufs_mem_read,
139 .write = spufs_mem_write,
8b3d6663
AB
140 .llseek = generic_file_llseek,
141#ifdef CONFIG_SPARSEMEM
67207b96 142 .mmap = spufs_mem_mmap,
8b3d6663
AB
143#endif
144};
145
146static int
147spufs_regs_open(struct inode *inode, struct file *file)
148{
149 struct spufs_inode_info *i = SPUFS_I(inode);
150 file->private_data = i->i_ctx;
151 return 0;
152}
153
154static ssize_t
155spufs_regs_read(struct file *file, char __user *buffer,
156 size_t size, loff_t *pos)
157{
158 struct spu_context *ctx = file->private_data;
159 struct spu_lscsa *lscsa = ctx->csa.lscsa;
160 int ret;
161
162 spu_acquire_saved(ctx);
163
164 ret = simple_read_from_buffer(buffer, size, pos,
165 lscsa->gprs, sizeof lscsa->gprs);
166
167 spu_release(ctx);
168 return ret;
169}
170
171static ssize_t
172spufs_regs_write(struct file *file, const char __user *buffer,
173 size_t size, loff_t *pos)
174{
175 struct spu_context *ctx = file->private_data;
176 struct spu_lscsa *lscsa = ctx->csa.lscsa;
177 int ret;
178
179 size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size);
180 if (size <= 0)
181 return -EFBIG;
182 *pos += size;
183
184 spu_acquire_saved(ctx);
185
186 ret = copy_from_user(lscsa->gprs + *pos - size,
187 buffer, size) ? -EFAULT : size;
188
189 spu_release(ctx);
190 return ret;
191}
192
193static struct file_operations spufs_regs_fops = {
194 .open = spufs_regs_open,
195 .read = spufs_regs_read,
196 .write = spufs_regs_write,
67207b96
AB
197 .llseek = generic_file_llseek,
198};
199
8b3d6663
AB
200static ssize_t
201spufs_fpcr_read(struct file *file, char __user * buffer,
202 size_t size, loff_t * pos)
203{
204 struct spu_context *ctx = file->private_data;
205 struct spu_lscsa *lscsa = ctx->csa.lscsa;
206 int ret;
207
208 spu_acquire_saved(ctx);
209
210 ret = simple_read_from_buffer(buffer, size, pos,
211 &lscsa->fpcr, sizeof(lscsa->fpcr));
212
213 spu_release(ctx);
214 return ret;
215}
216
217static ssize_t
218spufs_fpcr_write(struct file *file, const char __user * buffer,
219 size_t size, loff_t * pos)
220{
221 struct spu_context *ctx = file->private_data;
222 struct spu_lscsa *lscsa = ctx->csa.lscsa;
223 int ret;
224
225 size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
226 if (size <= 0)
227 return -EFBIG;
228 *pos += size;
229
230 spu_acquire_saved(ctx);
231
232 ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
233 buffer, size) ? -EFAULT : size;
234
235 spu_release(ctx);
236 return ret;
237}
238
239static struct file_operations spufs_fpcr_fops = {
240 .open = spufs_regs_open,
241 .read = spufs_fpcr_read,
242 .write = spufs_fpcr_write,
243 .llseek = generic_file_llseek,
244};
245
67207b96
AB
246/* generic open function for all pipe-like files */
247static int spufs_pipe_open(struct inode *inode, struct file *file)
248{
249 struct spufs_inode_info *i = SPUFS_I(inode);
250 file->private_data = i->i_ctx;
251
252 return nonseekable_open(inode, file);
253}
254
255static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
256 size_t len, loff_t *pos)
257{
8b3d6663 258 struct spu_context *ctx = file->private_data;
67207b96 259 u32 mbox_data;
8b3d6663 260 int ret;
67207b96
AB
261
262 if (len < 4)
263 return -EINVAL;
264
8b3d6663
AB
265 spu_acquire(ctx);
266 ret = ctx->ops->mbox_read(ctx, &mbox_data);
267 spu_release(ctx);
67207b96 268
8b3d6663
AB
269 if (!ret)
270 return -EAGAIN;
67207b96
AB
271
272 if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
273 return -EFAULT;
274
275 return 4;
276}
277
278static struct file_operations spufs_mbox_fops = {
279 .open = spufs_pipe_open,
280 .read = spufs_mbox_read,
281};
282
283static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
284 size_t len, loff_t *pos)
285{
8b3d6663 286 struct spu_context *ctx = file->private_data;
67207b96
AB
287 u32 mbox_stat;
288
289 if (len < 4)
290 return -EINVAL;
291
8b3d6663
AB
292 spu_acquire(ctx);
293
294 mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff;
295
296 spu_release(ctx);
67207b96
AB
297
298 if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
299 return -EFAULT;
300
301 return 4;
302}
303
304static struct file_operations spufs_mbox_stat_fops = {
305 .open = spufs_pipe_open,
306 .read = spufs_mbox_stat_read,
307};
308
309/* low-level ibox access function */
8b3d6663 310size_t spu_ibox_read(struct spu_context *ctx, u32 *data)
67207b96 311{
8b3d6663
AB
312 return ctx->ops->ibox_read(ctx, data);
313}
67207b96 314
8b3d6663
AB
315static int spufs_ibox_fasync(int fd, struct file *file, int on)
316{
317 struct spu_context *ctx = file->private_data;
67207b96 318
8b3d6663 319 return fasync_helper(fd, file, on, &ctx->ibox_fasync);
67207b96 320}
67207b96 321
8b3d6663
AB
322/* interrupt-level ibox callback function. */
323void spufs_ibox_callback(struct spu *spu)
67207b96 324{
8b3d6663
AB
325 struct spu_context *ctx = spu->ctx;
326
327 wake_up_all(&ctx->ibox_wq);
328 kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
67207b96
AB
329}
330
331static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
332 size_t len, loff_t *pos)
333{
8b3d6663 334 struct spu_context *ctx = file->private_data;
67207b96
AB
335 u32 ibox_data;
336 ssize_t ret;
337
338 if (len < 4)
339 return -EINVAL;
340
8b3d6663 341 spu_acquire(ctx);
67207b96
AB
342
343 ret = 0;
344 if (file->f_flags & O_NONBLOCK) {
8b3d6663 345 if (!spu_ibox_read(ctx, &ibox_data))
67207b96
AB
346 ret = -EAGAIN;
347 } else {
8b3d6663 348 ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
67207b96
AB
349 }
350
8b3d6663
AB
351 spu_release(ctx);
352
67207b96
AB
353 if (ret)
354 return ret;
355
356 ret = 4;
357 if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
358 ret = -EFAULT;
359
360 return ret;
361}
362
363static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
364{
8b3d6663 365 struct spu_context *ctx = file->private_data;
67207b96
AB
366 unsigned int mask;
367
8b3d6663 368 poll_wait(file, &ctx->ibox_wq, wait);
67207b96 369
3a843d7c
AB
370 spu_acquire(ctx);
371 mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM);
372 spu_release(ctx);
67207b96
AB
373
374 return mask;
375}
376
377static struct file_operations spufs_ibox_fops = {
378 .open = spufs_pipe_open,
379 .read = spufs_ibox_read,
380 .poll = spufs_ibox_poll,
381 .fasync = spufs_ibox_fasync,
382};
383
384static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
385 size_t len, loff_t *pos)
386{
8b3d6663 387 struct spu_context *ctx = file->private_data;
67207b96
AB
388 u32 ibox_stat;
389
390 if (len < 4)
391 return -EINVAL;
392
8b3d6663
AB
393 spu_acquire(ctx);
394 ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff;
395 spu_release(ctx);
67207b96
AB
396
397 if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
398 return -EFAULT;
399
400 return 4;
401}
402
403static struct file_operations spufs_ibox_stat_fops = {
404 .open = spufs_pipe_open,
405 .read = spufs_ibox_stat_read,
406};
407
408/* low-level mailbox write */
8b3d6663 409size_t spu_wbox_write(struct spu_context *ctx, u32 data)
67207b96 410{
8b3d6663
AB
411 return ctx->ops->wbox_write(ctx, data);
412}
67207b96 413
8b3d6663
AB
414static int spufs_wbox_fasync(int fd, struct file *file, int on)
415{
416 struct spu_context *ctx = file->private_data;
417 int ret;
67207b96 418
8b3d6663 419 ret = fasync_helper(fd, file, on, &ctx->wbox_fasync);
67207b96 420
67207b96
AB
421 return ret;
422}
67207b96 423
8b3d6663
AB
424/* interrupt-level wbox callback function. */
425void spufs_wbox_callback(struct spu *spu)
67207b96 426{
8b3d6663
AB
427 struct spu_context *ctx = spu->ctx;
428
429 wake_up_all(&ctx->wbox_wq);
430 kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
67207b96
AB
431}
432
433static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
434 size_t len, loff_t *pos)
435{
8b3d6663 436 struct spu_context *ctx = file->private_data;
67207b96
AB
437 u32 wbox_data;
438 int ret;
439
440 if (len < 4)
441 return -EINVAL;
442
67207b96
AB
443 if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
444 return -EFAULT;
445
8b3d6663
AB
446 spu_acquire(ctx);
447
67207b96
AB
448 ret = 0;
449 if (file->f_flags & O_NONBLOCK) {
8b3d6663 450 if (!spu_wbox_write(ctx, wbox_data))
67207b96
AB
451 ret = -EAGAIN;
452 } else {
8b3d6663 453 ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
67207b96
AB
454 }
455
8b3d6663
AB
456 spu_release(ctx);
457
67207b96
AB
458 return ret ? ret : sizeof wbox_data;
459}
460
461static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
462{
8b3d6663 463 struct spu_context *ctx = file->private_data;
67207b96
AB
464 unsigned int mask;
465
8b3d6663 466 poll_wait(file, &ctx->wbox_wq, wait);
67207b96 467
3a843d7c
AB
468 spu_acquire(ctx);
469 mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM);
470 spu_release(ctx);
67207b96
AB
471
472 return mask;
473}
474
475static struct file_operations spufs_wbox_fops = {
476 .open = spufs_pipe_open,
477 .write = spufs_wbox_write,
478 .poll = spufs_wbox_poll,
479 .fasync = spufs_wbox_fasync,
480};
481
482static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
483 size_t len, loff_t *pos)
484{
8b3d6663 485 struct spu_context *ctx = file->private_data;
67207b96
AB
486 u32 wbox_stat;
487
488 if (len < 4)
489 return -EINVAL;
490
8b3d6663
AB
491 spu_acquire(ctx);
492 wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff;
493 spu_release(ctx);
67207b96
AB
494
495 if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
496 return -EFAULT;
497
498 return 4;
499}
500
501static struct file_operations spufs_wbox_stat_fops = {
502 .open = spufs_pipe_open,
503 .read = spufs_wbox_stat_read,
504};
505
67207b96
AB
506static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
507 size_t len, loff_t *pos)
508{
8b3d6663 509 struct spu_context *ctx = file->private_data;
67207b96
AB
510 u32 data;
511
67207b96
AB
512 if (len < 4)
513 return -EINVAL;
514
8b3d6663
AB
515 spu_acquire(ctx);
516 data = ctx->ops->signal1_read(ctx);
517 spu_release(ctx);
518
67207b96
AB
519 if (copy_to_user(buf, &data, 4))
520 return -EFAULT;
521
522 return 4;
523}
524
525static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
526 size_t len, loff_t *pos)
527{
528 struct spu_context *ctx;
67207b96
AB
529 u32 data;
530
531 ctx = file->private_data;
67207b96
AB
532
533 if (len < 4)
534 return -EINVAL;
535
536 if (copy_from_user(&data, buf, 4))
537 return -EFAULT;
538
8b3d6663
AB
539 spu_acquire(ctx);
540 ctx->ops->signal1_write(ctx, data);
541 spu_release(ctx);
67207b96
AB
542
543 return 4;
544}
545
546static struct file_operations spufs_signal1_fops = {
547 .open = spufs_pipe_open,
548 .read = spufs_signal1_read,
549 .write = spufs_signal1_write,
550};
551
552static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
553 size_t len, loff_t *pos)
554{
555 struct spu_context *ctx;
67207b96
AB
556 u32 data;
557
558 ctx = file->private_data;
67207b96
AB
559
560 if (len < 4)
561 return -EINVAL;
562
8b3d6663
AB
563 spu_acquire(ctx);
564 data = ctx->ops->signal2_read(ctx);
565 spu_release(ctx);
566
67207b96
AB
567 if (copy_to_user(buf, &data, 4))
568 return -EFAULT;
569
570 return 4;
571}
572
573static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
574 size_t len, loff_t *pos)
575{
576 struct spu_context *ctx;
67207b96
AB
577 u32 data;
578
579 ctx = file->private_data;
67207b96
AB
580
581 if (len < 4)
582 return -EINVAL;
583
584 if (copy_from_user(&data, buf, 4))
585 return -EFAULT;
586
8b3d6663
AB
587 spu_acquire(ctx);
588 ctx->ops->signal2_write(ctx, data);
589 spu_release(ctx);
67207b96
AB
590
591 return 4;
592}
593
594static struct file_operations spufs_signal2_fops = {
595 .open = spufs_pipe_open,
596 .read = spufs_signal2_read,
597 .write = spufs_signal2_write,
598};
599
600static void spufs_signal1_type_set(void *data, u64 val)
601{
602 struct spu_context *ctx = data;
67207b96 603
8b3d6663
AB
604 spu_acquire(ctx);
605 ctx->ops->signal1_type_set(ctx, val);
606 spu_release(ctx);
67207b96
AB
607}
608
609static u64 spufs_signal1_type_get(void *data)
610{
611 struct spu_context *ctx = data;
8b3d6663
AB
612 u64 ret;
613
614 spu_acquire(ctx);
615 ret = ctx->ops->signal1_type_get(ctx);
616 spu_release(ctx);
617
618 return ret;
67207b96
AB
619}
620DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
621 spufs_signal1_type_set, "%llu");
622
623static void spufs_signal2_type_set(void *data, u64 val)
624{
625 struct spu_context *ctx = data;
67207b96 626
8b3d6663
AB
627 spu_acquire(ctx);
628 ctx->ops->signal2_type_set(ctx, val);
629 spu_release(ctx);
67207b96
AB
630}
631
632static u64 spufs_signal2_type_get(void *data)
633{
634 struct spu_context *ctx = data;
8b3d6663
AB
635 u64 ret;
636
637 spu_acquire(ctx);
638 ret = ctx->ops->signal2_type_get(ctx);
639 spu_release(ctx);
640
641 return ret;
67207b96
AB
642}
643DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
644 spufs_signal2_type_set, "%llu");
645
a33a7d73
AB
646
647static int spufs_mfc_open(struct inode *inode, struct file *file)
648{
649 struct spufs_inode_info *i = SPUFS_I(inode);
650 struct spu_context *ctx = i->i_ctx;
651
652 /* we don't want to deal with DMA into other processes */
653 if (ctx->owner != current->mm)
654 return -EINVAL;
655
656 if (atomic_read(&inode->i_count) != 1)
657 return -EBUSY;
658
659 file->private_data = ctx;
660 return nonseekable_open(inode, file);
661}
662
663/* interrupt-level mfc callback function. */
664void spufs_mfc_callback(struct spu *spu)
665{
666 struct spu_context *ctx = spu->ctx;
667
668 wake_up_all(&ctx->mfc_wq);
669
670 pr_debug("%s %s\n", __FUNCTION__, spu->name);
671 if (ctx->mfc_fasync) {
672 u32 free_elements, tagstatus;
673 unsigned int mask;
674
675 /* no need for spu_acquire in interrupt context */
676 free_elements = ctx->ops->get_mfc_free_elements(ctx);
677 tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
678
679 mask = 0;
680 if (free_elements & 0xffff)
681 mask |= POLLOUT;
682 if (tagstatus & ctx->tagwait)
683 mask |= POLLIN;
684
685 kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
686 }
687}
688
689static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
690{
691 /* See if there is one tag group is complete */
692 /* FIXME we need locking around tagwait */
693 *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
694 ctx->tagwait &= ~*status;
695 if (*status)
696 return 1;
697
698 /* enable interrupt waiting for any tag group,
699 may silently fail if interrupts are already enabled */
700 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
701 return 0;
702}
703
704static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
705 size_t size, loff_t *pos)
706{
707 struct spu_context *ctx = file->private_data;
708 int ret = -EINVAL;
709 u32 status;
710
711 if (size != 4)
712 goto out;
713
714 spu_acquire(ctx);
715 if (file->f_flags & O_NONBLOCK) {
716 status = ctx->ops->read_mfc_tagstatus(ctx);
717 if (!(status & ctx->tagwait))
718 ret = -EAGAIN;
719 else
720 ctx->tagwait &= ~status;
721 } else {
722 ret = spufs_wait(ctx->mfc_wq,
723 spufs_read_mfc_tagstatus(ctx, &status));
724 }
725 spu_release(ctx);
726
727 if (ret)
728 goto out;
729
730 ret = 4;
731 if (copy_to_user(buffer, &status, 4))
732 ret = -EFAULT;
733
734out:
735 return ret;
736}
737
738static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
739{
740 pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
741 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
742
743 switch (cmd->cmd) {
744 case MFC_PUT_CMD:
745 case MFC_PUTF_CMD:
746 case MFC_PUTB_CMD:
747 case MFC_GET_CMD:
748 case MFC_GETF_CMD:
749 case MFC_GETB_CMD:
750 break;
751 default:
752 pr_debug("invalid DMA opcode %x\n", cmd->cmd);
753 return -EIO;
754 }
755
756 if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
757 pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
758 cmd->ea, cmd->lsa);
759 return -EIO;
760 }
761
762 switch (cmd->size & 0xf) {
763 case 1:
764 break;
765 case 2:
766 if (cmd->lsa & 1)
767 goto error;
768 break;
769 case 4:
770 if (cmd->lsa & 3)
771 goto error;
772 break;
773 case 8:
774 if (cmd->lsa & 7)
775 goto error;
776 break;
777 case 0:
778 if (cmd->lsa & 15)
779 goto error;
780 break;
781 error:
782 default:
783 pr_debug("invalid DMA alignment %x for size %x\n",
784 cmd->lsa & 0xf, cmd->size);
785 return -EIO;
786 }
787
788 if (cmd->size > 16 * 1024) {
789 pr_debug("invalid DMA size %x\n", cmd->size);
790 return -EIO;
791 }
792
793 if (cmd->tag & 0xfff0) {
794 /* we reserve the higher tag numbers for kernel use */
795 pr_debug("invalid DMA tag\n");
796 return -EIO;
797 }
798
799 if (cmd->class) {
800 /* not supported in this version */
801 pr_debug("invalid DMA class\n");
802 return -EIO;
803 }
804
805 return 0;
806}
807
808static int spu_send_mfc_command(struct spu_context *ctx,
809 struct mfc_dma_command cmd,
810 int *error)
811{
812 *error = ctx->ops->send_mfc_command(ctx, &cmd);
813 if (*error == -EAGAIN) {
814 /* wait for any tag group to complete
815 so we have space for the new command */
816 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
817 /* try again, because the queue might be
818 empty again */
819 *error = ctx->ops->send_mfc_command(ctx, &cmd);
820 if (*error == -EAGAIN)
821 return 0;
822 }
823 return 1;
824}
825
826static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
827 size_t size, loff_t *pos)
828{
829 struct spu_context *ctx = file->private_data;
830 struct mfc_dma_command cmd;
831 int ret = -EINVAL;
832
833 if (size != sizeof cmd)
834 goto out;
835
836 ret = -EFAULT;
837 if (copy_from_user(&cmd, buffer, sizeof cmd))
838 goto out;
839
840 ret = spufs_check_valid_dma(&cmd);
841 if (ret)
842 goto out;
843
844 spu_acquire_runnable(ctx);
845 if (file->f_flags & O_NONBLOCK) {
846 ret = ctx->ops->send_mfc_command(ctx, &cmd);
847 } else {
848 int status;
849 ret = spufs_wait(ctx->mfc_wq,
850 spu_send_mfc_command(ctx, cmd, &status));
851 if (status)
852 ret = status;
853 }
854 spu_release(ctx);
855
856 if (ret)
857 goto out;
858
859 ctx->tagwait |= 1 << cmd.tag;
860
861out:
862 return ret;
863}
864
865static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
866{
867 struct spu_context *ctx = file->private_data;
868 u32 free_elements, tagstatus;
869 unsigned int mask;
870
871 spu_acquire(ctx);
872 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
873 free_elements = ctx->ops->get_mfc_free_elements(ctx);
874 tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
875 spu_release(ctx);
876
877 poll_wait(file, &ctx->mfc_wq, wait);
878
879 mask = 0;
880 if (free_elements & 0xffff)
881 mask |= POLLOUT | POLLWRNORM;
882 if (tagstatus & ctx->tagwait)
883 mask |= POLLIN | POLLRDNORM;
884
885 pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
886 free_elements, tagstatus, ctx->tagwait);
887
888 return mask;
889}
890
891static int spufs_mfc_flush(struct file *file)
892{
893 struct spu_context *ctx = file->private_data;
894 int ret;
895
896 spu_acquire(ctx);
897#if 0
898/* this currently hangs */
899 ret = spufs_wait(ctx->mfc_wq,
900 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
901 if (ret)
902 goto out;
903 ret = spufs_wait(ctx->mfc_wq,
904 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
905out:
906#else
907 ret = 0;
908#endif
909 spu_release(ctx);
910
911 return ret;
912}
913
914static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
915 int datasync)
916{
917 return spufs_mfc_flush(file);
918}
919
920static int spufs_mfc_fasync(int fd, struct file *file, int on)
921{
922 struct spu_context *ctx = file->private_data;
923
924 return fasync_helper(fd, file, on, &ctx->mfc_fasync);
925}
926
927static struct file_operations spufs_mfc_fops = {
928 .open = spufs_mfc_open,
929 .read = spufs_mfc_read,
930 .write = spufs_mfc_write,
931 .poll = spufs_mfc_poll,
932 .flush = spufs_mfc_flush,
933 .fsync = spufs_mfc_fsync,
934 .fasync = spufs_mfc_fasync,
935};
936
67207b96
AB
937static void spufs_npc_set(void *data, u64 val)
938{
939 struct spu_context *ctx = data;
8b3d6663
AB
940 spu_acquire(ctx);
941 ctx->ops->npc_write(ctx, val);
942 spu_release(ctx);
67207b96
AB
943}
944
945static u64 spufs_npc_get(void *data)
946{
947 struct spu_context *ctx = data;
948 u64 ret;
8b3d6663
AB
949 spu_acquire(ctx);
950 ret = ctx->ops->npc_read(ctx);
951 spu_release(ctx);
67207b96
AB
952 return ret;
953}
954DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
955
8b3d6663
AB
956static void spufs_decr_set(void *data, u64 val)
957{
958 struct spu_context *ctx = data;
959 struct spu_lscsa *lscsa = ctx->csa.lscsa;
960 spu_acquire_saved(ctx);
961 lscsa->decr.slot[0] = (u32) val;
962 spu_release(ctx);
963}
964
965static u64 spufs_decr_get(void *data)
966{
967 struct spu_context *ctx = data;
968 struct spu_lscsa *lscsa = ctx->csa.lscsa;
969 u64 ret;
970 spu_acquire_saved(ctx);
971 ret = lscsa->decr.slot[0];
972 spu_release(ctx);
973 return ret;
974}
975DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
976 "%llx\n")
977
978static void spufs_decr_status_set(void *data, u64 val)
979{
980 struct spu_context *ctx = data;
981 struct spu_lscsa *lscsa = ctx->csa.lscsa;
982 spu_acquire_saved(ctx);
983 lscsa->decr_status.slot[0] = (u32) val;
984 spu_release(ctx);
985}
986
987static u64 spufs_decr_status_get(void *data)
988{
989 struct spu_context *ctx = data;
990 struct spu_lscsa *lscsa = ctx->csa.lscsa;
991 u64 ret;
992 spu_acquire_saved(ctx);
993 ret = lscsa->decr_status.slot[0];
994 spu_release(ctx);
995 return ret;
996}
997DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
998 spufs_decr_status_set, "%llx\n")
999
1000static void spufs_spu_tag_mask_set(void *data, u64 val)
1001{
1002 struct spu_context *ctx = data;
1003 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1004 spu_acquire_saved(ctx);
1005 lscsa->tag_mask.slot[0] = (u32) val;
1006 spu_release(ctx);
1007}
1008
1009static u64 spufs_spu_tag_mask_get(void *data)
1010{
1011 struct spu_context *ctx = data;
1012 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1013 u64 ret;
1014 spu_acquire_saved(ctx);
1015 ret = lscsa->tag_mask.slot[0];
1016 spu_release(ctx);
1017 return ret;
1018}
1019DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get,
1020 spufs_spu_tag_mask_set, "%llx\n")
1021
1022static void spufs_event_mask_set(void *data, u64 val)
1023{
1024 struct spu_context *ctx = data;
1025 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1026 spu_acquire_saved(ctx);
1027 lscsa->event_mask.slot[0] = (u32) val;
1028 spu_release(ctx);
1029}
1030
1031static u64 spufs_event_mask_get(void *data)
1032{
1033 struct spu_context *ctx = data;
1034 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1035 u64 ret;
1036 spu_acquire_saved(ctx);
1037 ret = lscsa->event_mask.slot[0];
1038 spu_release(ctx);
1039 return ret;
1040}
1041DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
1042 spufs_event_mask_set, "%llx\n")
1043
1044static void spufs_srr0_set(void *data, u64 val)
1045{
1046 struct spu_context *ctx = data;
1047 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1048 spu_acquire_saved(ctx);
1049 lscsa->srr0.slot[0] = (u32) val;
1050 spu_release(ctx);
1051}
1052
1053static u64 spufs_srr0_get(void *data)
1054{
1055 struct spu_context *ctx = data;
1056 struct spu_lscsa *lscsa = ctx->csa.lscsa;
1057 u64 ret;
1058 spu_acquire_saved(ctx);
1059 ret = lscsa->srr0.slot[0];
1060 spu_release(ctx);
1061 return ret;
1062}
1063DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
1064 "%llx\n")
1065
67207b96
AB
1066struct tree_descr spufs_dir_contents[] = {
1067 { "mem", &spufs_mem_fops, 0666, },
8b3d6663 1068 { "regs", &spufs_regs_fops, 0666, },
67207b96
AB
1069 { "mbox", &spufs_mbox_fops, 0444, },
1070 { "ibox", &spufs_ibox_fops, 0444, },
1071 { "wbox", &spufs_wbox_fops, 0222, },
1072 { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
1073 { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
1074 { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
1075 { "signal1", &spufs_signal1_fops, 0666, },
1076 { "signal2", &spufs_signal2_fops, 0666, },
1077 { "signal1_type", &spufs_signal1_type, 0666, },
1078 { "signal2_type", &spufs_signal2_type, 0666, },
a33a7d73 1079 { "mfc", &spufs_mfc_fops, 0666, },
67207b96 1080 { "npc", &spufs_npc_ops, 0666, },
8b3d6663
AB
1081 { "fpcr", &spufs_fpcr_fops, 0666, },
1082 { "decr", &spufs_decr_ops, 0666, },
1083 { "decr_status", &spufs_decr_status_ops, 0666, },
1084 { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
1085 { "event_mask", &spufs_event_mask_ops, 0666, },
1086 { "srr0", &spufs_srr0_ops, 0666, },
67207b96
AB
1087 {},
1088};