]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - arch/powerpc/platforms/cell/spufs/file.c
[PATCH] spufs: The SPU file system, base
[mirror_ubuntu-zesty-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
23#include <linux/fs.h>
24#include <linux/ioctl.h>
25#include <linux/module.h>
26#include <linux/poll.h>
27
28#include <asm/io.h>
29#include <asm/semaphore.h>
30#include <asm/spu.h>
31#include <asm/uaccess.h>
32
33#include "spufs.h"
34
35static int
36spufs_mem_open(struct inode *inode, struct file *file)
37{
38 struct spufs_inode_info *i = SPUFS_I(inode);
39 file->private_data = i->i_ctx;
40 return 0;
41}
42
43static ssize_t
44spufs_mem_read(struct file *file, char __user *buffer,
45 size_t size, loff_t *pos)
46{
47 struct spu *spu;
48 struct spu_context *ctx;
49 int ret;
50
51 ctx = file->private_data;
52 spu = ctx->spu;
53
54 down_read(&ctx->backing_sema);
55 if (spu->number & 0/*1*/) {
56 ret = generic_file_read(file, buffer, size, pos);
57 goto out;
58 }
59
60 ret = simple_read_from_buffer(buffer, size, pos,
61 spu->local_store, LS_SIZE);
62out:
63 up_read(&ctx->backing_sema);
64 return ret;
65}
66
67static ssize_t
68spufs_mem_write(struct file *file, const char __user *buffer,
69 size_t size, loff_t *pos)
70{
71 struct spu_context *ctx = file->private_data;
72 struct spu *spu = ctx->spu;
73
74 if (spu->number & 0) //1)
75 return generic_file_write(file, buffer, size, pos);
76
77 size = min_t(ssize_t, LS_SIZE - *pos, size);
78 if (size <= 0)
79 return -EFBIG;
80 *pos += size;
81 return copy_from_user(spu->local_store + *pos - size,
82 buffer, size) ? -EFAULT : size;
83}
84
85static int
86spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
87{
88 struct spu_context *ctx = file->private_data;
89 struct spu *spu = ctx->spu;
90 unsigned long pfn;
91
92 if (spu->number & 0) //1)
93 return generic_file_mmap(file, vma);
94
95 vma->vm_flags |= VM_RESERVED;
96 vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot)
97 | _PAGE_NO_CACHE);
98 pfn = spu->local_store_phys >> PAGE_SHIFT;
99 /*
100 * This will work for actual SPUs, but not for vmalloc memory:
101 */
102 if (remap_pfn_range(vma, vma->vm_start, pfn,
103 vma->vm_end-vma->vm_start, vma->vm_page_prot))
104 return -EAGAIN;
105 return 0;
106}
107
108static struct file_operations spufs_mem_fops = {
109 .open = spufs_mem_open,
110 .read = spufs_mem_read,
111 .write = spufs_mem_write,
112 .mmap = spufs_mem_mmap,
113 .llseek = generic_file_llseek,
114};
115
116/* generic open function for all pipe-like files */
117static int spufs_pipe_open(struct inode *inode, struct file *file)
118{
119 struct spufs_inode_info *i = SPUFS_I(inode);
120 file->private_data = i->i_ctx;
121
122 return nonseekable_open(inode, file);
123}
124
125static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
126 size_t len, loff_t *pos)
127{
128 struct spu_context *ctx;
129 struct spu_problem __iomem *prob;
130 u32 mbox_stat;
131 u32 mbox_data;
132
133 if (len < 4)
134 return -EINVAL;
135
136 ctx = file->private_data;
137 prob = ctx->spu->problem;
138 mbox_stat = in_be32(&prob->mb_stat_R);
139 if (!(mbox_stat & 0x0000ff))
140 return -EAGAIN;
141
142 mbox_data = in_be32(&prob->pu_mb_R);
143
144 if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
145 return -EFAULT;
146
147 return 4;
148}
149
150static struct file_operations spufs_mbox_fops = {
151 .open = spufs_pipe_open,
152 .read = spufs_mbox_read,
153};
154
155static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
156 size_t len, loff_t *pos)
157{
158 struct spu_context *ctx;
159 u32 mbox_stat;
160
161 if (len < 4)
162 return -EINVAL;
163
164 ctx = file->private_data;
165 mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff;
166
167 if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat))
168 return -EFAULT;
169
170 return 4;
171}
172
173static struct file_operations spufs_mbox_stat_fops = {
174 .open = spufs_pipe_open,
175 .read = spufs_mbox_stat_read,
176};
177
178/* low-level ibox access function */
179size_t spu_ibox_read(struct spu *spu, u32 *data)
180{
181 int ret;
182
183 spin_lock_irq(&spu->register_lock);
184
185 if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) {
186 /* read the first available word */
187 *data = in_be64(&spu->priv2->puint_mb_R);
188 ret = 4;
189 } else {
190 /* make sure we get woken up by the interrupt */
191 out_be64(&spu->priv1->int_mask_class2_RW,
192 in_be64(&spu->priv1->int_mask_class2_RW) | 0x1);
193 ret = 0;
194 }
195
196 spin_unlock_irq(&spu->register_lock);
197 return ret;
198}
199EXPORT_SYMBOL(spu_ibox_read);
200
201static int spufs_ibox_fasync(int fd, struct file *file, int on)
202{
203 struct spu_context *ctx;
204 ctx = file->private_data;
205 return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync);
206}
207
208static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
209 size_t len, loff_t *pos)
210{
211 struct spu_context *ctx;
212 u32 ibox_data;
213 ssize_t ret;
214
215 if (len < 4)
216 return -EINVAL;
217
218 ctx = file->private_data;
219
220 ret = 0;
221 if (file->f_flags & O_NONBLOCK) {
222 if (!spu_ibox_read(ctx->spu, &ibox_data))
223 ret = -EAGAIN;
224 } else {
225 ret = wait_event_interruptible(ctx->spu->ibox_wq,
226 spu_ibox_read(ctx->spu, &ibox_data));
227 }
228
229 if (ret)
230 return ret;
231
232 ret = 4;
233 if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
234 ret = -EFAULT;
235
236 return ret;
237}
238
239static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
240{
241 struct spu_context *ctx;
242 struct spu_problem __iomem *prob;
243 u32 mbox_stat;
244 unsigned int mask;
245
246 ctx = file->private_data;
247 prob = ctx->spu->problem;
248 mbox_stat = in_be32(&prob->mb_stat_R);
249
250 poll_wait(file, &ctx->spu->ibox_wq, wait);
251
252 mask = 0;
253 if (mbox_stat & 0xff0000)
254 mask |= POLLIN | POLLRDNORM;
255
256 return mask;
257}
258
259static struct file_operations spufs_ibox_fops = {
260 .open = spufs_pipe_open,
261 .read = spufs_ibox_read,
262 .poll = spufs_ibox_poll,
263 .fasync = spufs_ibox_fasync,
264};
265
266static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
267 size_t len, loff_t *pos)
268{
269 struct spu_context *ctx;
270 u32 ibox_stat;
271
272 if (len < 4)
273 return -EINVAL;
274
275 ctx = file->private_data;
276 ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff;
277
278 if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat))
279 return -EFAULT;
280
281 return 4;
282}
283
284static struct file_operations spufs_ibox_stat_fops = {
285 .open = spufs_pipe_open,
286 .read = spufs_ibox_stat_read,
287};
288
289/* low-level mailbox write */
290size_t spu_wbox_write(struct spu *spu, u32 data)
291{
292 int ret;
293
294 spin_lock_irq(&spu->register_lock);
295
296 if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) {
297 /* we have space to write wbox_data to */
298 out_be32(&spu->problem->spu_mb_W, data);
299 ret = 4;
300 } else {
301 /* make sure we get woken up by the interrupt when space
302 becomes available */
303 out_be64(&spu->priv1->int_mask_class2_RW,
304 in_be64(&spu->priv1->int_mask_class2_RW) | 0x10);
305 ret = 0;
306 }
307
308 spin_unlock_irq(&spu->register_lock);
309 return ret;
310}
311EXPORT_SYMBOL(spu_wbox_write);
312
313static int spufs_wbox_fasync(int fd, struct file *file, int on)
314{
315 struct spu_context *ctx;
316 ctx = file->private_data;
317 return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync);
318}
319
320static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
321 size_t len, loff_t *pos)
322{
323 struct spu_context *ctx;
324 u32 wbox_data;
325 int ret;
326
327 if (len < 4)
328 return -EINVAL;
329
330 ctx = file->private_data;
331
332 if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
333 return -EFAULT;
334
335 ret = 0;
336 if (file->f_flags & O_NONBLOCK) {
337 if (!spu_wbox_write(ctx->spu, wbox_data))
338 ret = -EAGAIN;
339 } else {
340 ret = wait_event_interruptible(ctx->spu->wbox_wq,
341 spu_wbox_write(ctx->spu, wbox_data));
342 }
343
344 return ret ? ret : sizeof wbox_data;
345}
346
347static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
348{
349 struct spu_context *ctx;
350 struct spu_problem __iomem *prob;
351 u32 mbox_stat;
352 unsigned int mask;
353
354 ctx = file->private_data;
355 prob = ctx->spu->problem;
356 mbox_stat = in_be32(&prob->mb_stat_R);
357
358 poll_wait(file, &ctx->spu->wbox_wq, wait);
359
360 mask = 0;
361 if (mbox_stat & 0x00ff00)
362 mask = POLLOUT | POLLWRNORM;
363
364 return mask;
365}
366
367static struct file_operations spufs_wbox_fops = {
368 .open = spufs_pipe_open,
369 .write = spufs_wbox_write,
370 .poll = spufs_wbox_poll,
371 .fasync = spufs_wbox_fasync,
372};
373
374static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
375 size_t len, loff_t *pos)
376{
377 struct spu_context *ctx;
378 u32 wbox_stat;
379
380 if (len < 4)
381 return -EINVAL;
382
383 ctx = file->private_data;
384 wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff;
385
386 if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat))
387 return -EFAULT;
388
389 return 4;
390}
391
392static struct file_operations spufs_wbox_stat_fops = {
393 .open = spufs_pipe_open,
394 .read = spufs_wbox_stat_read,
395};
396
397long spufs_run_spu(struct file *file, struct spu_context *ctx,
398 u32 *npc, u32 *status)
399{
400 struct spu_problem __iomem *prob;
401 int ret;
402
403 if (file->f_flags & O_NONBLOCK) {
404 ret = -EAGAIN;
405 if (!down_write_trylock(&ctx->backing_sema))
406 goto out;
407 } else {
408 down_write(&ctx->backing_sema);
409 }
410
411 prob = ctx->spu->problem;
412 out_be32(&prob->spu_npc_RW, *npc);
413
414 ret = spu_run(ctx->spu);
415
416 *status = in_be32(&prob->spu_status_R);
417 *npc = in_be32(&prob->spu_npc_RW);
418
419 up_write(&ctx->backing_sema);
420
421out:
422 return ret;
423}
424
425static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
426 size_t len, loff_t *pos)
427{
428 struct spu_context *ctx;
429 struct spu_problem *prob;
430 u32 data;
431
432 ctx = file->private_data;
433 prob = ctx->spu->problem;
434
435 if (len < 4)
436 return -EINVAL;
437
438 data = in_be32(&prob->signal_notify1);
439 if (copy_to_user(buf, &data, 4))
440 return -EFAULT;
441
442 return 4;
443}
444
445static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
446 size_t len, loff_t *pos)
447{
448 struct spu_context *ctx;
449 struct spu_problem *prob;
450 u32 data;
451
452 ctx = file->private_data;
453 prob = ctx->spu->problem;
454
455 if (len < 4)
456 return -EINVAL;
457
458 if (copy_from_user(&data, buf, 4))
459 return -EFAULT;
460
461 out_be32(&prob->signal_notify1, data);
462
463 return 4;
464}
465
466static struct file_operations spufs_signal1_fops = {
467 .open = spufs_pipe_open,
468 .read = spufs_signal1_read,
469 .write = spufs_signal1_write,
470};
471
472static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
473 size_t len, loff_t *pos)
474{
475 struct spu_context *ctx;
476 struct spu_problem *prob;
477 u32 data;
478
479 ctx = file->private_data;
480 prob = ctx->spu->problem;
481
482 if (len < 4)
483 return -EINVAL;
484
485 data = in_be32(&prob->signal_notify2);
486 if (copy_to_user(buf, &data, 4))
487 return -EFAULT;
488
489 return 4;
490}
491
492static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
493 size_t len, loff_t *pos)
494{
495 struct spu_context *ctx;
496 struct spu_problem *prob;
497 u32 data;
498
499 ctx = file->private_data;
500 prob = ctx->spu->problem;
501
502 if (len < 4)
503 return -EINVAL;
504
505 if (copy_from_user(&data, buf, 4))
506 return -EFAULT;
507
508 out_be32(&prob->signal_notify2, data);
509
510 return 4;
511}
512
513static struct file_operations spufs_signal2_fops = {
514 .open = spufs_pipe_open,
515 .read = spufs_signal2_read,
516 .write = spufs_signal2_write,
517};
518
519static void spufs_signal1_type_set(void *data, u64 val)
520{
521 struct spu_context *ctx = data;
522 struct spu_priv2 *priv2 = ctx->spu->priv2;
523 u64 tmp;
524
525 spin_lock_irq(&ctx->spu->register_lock);
526 tmp = in_be64(&priv2->spu_cfg_RW);
527 if (val)
528 tmp |= 1;
529 else
530 tmp &= ~1;
531 out_be64(&priv2->spu_cfg_RW, tmp);
532 spin_unlock_irq(&ctx->spu->register_lock);
533}
534
535static u64 spufs_signal1_type_get(void *data)
536{
537 struct spu_context *ctx = data;
538 return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0;
539}
540DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get,
541 spufs_signal1_type_set, "%llu");
542
543static void spufs_signal2_type_set(void *data, u64 val)
544{
545 struct spu_context *ctx = data;
546 struct spu_priv2 *priv2 = ctx->spu->priv2;
547 u64 tmp;
548
549 spin_lock_irq(&ctx->spu->register_lock);
550 tmp = in_be64(&priv2->spu_cfg_RW);
551 if (val)
552 tmp |= 2;
553 else
554 tmp &= ~2;
555 out_be64(&priv2->spu_cfg_RW, tmp);
556 spin_unlock_irq(&ctx->spu->register_lock);
557}
558
559static u64 spufs_signal2_type_get(void *data)
560{
561 struct spu_context *ctx = data;
562 return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0;
563}
564DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
565 spufs_signal2_type_set, "%llu");
566
567static void spufs_npc_set(void *data, u64 val)
568{
569 struct spu_context *ctx = data;
570 out_be32(&ctx->spu->problem->spu_npc_RW, val);
571}
572
573static u64 spufs_npc_get(void *data)
574{
575 struct spu_context *ctx = data;
576 u64 ret;
577 ret = in_be32(&ctx->spu->problem->spu_npc_RW);
578 return ret;
579}
580DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n")
581
582struct tree_descr spufs_dir_contents[] = {
583 { "mem", &spufs_mem_fops, 0666, },
584 { "mbox", &spufs_mbox_fops, 0444, },
585 { "ibox", &spufs_ibox_fops, 0444, },
586 { "wbox", &spufs_wbox_fops, 0222, },
587 { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
588 { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
589 { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
590 { "signal1", &spufs_signal1_fops, 0666, },
591 { "signal2", &spufs_signal2_fops, 0666, },
592 { "signal1_type", &spufs_signal1_type, 0666, },
593 { "signal2_type", &spufs_signal2_type, 0666, },
594 { "npc", &spufs_npc_ops, 0666, },
595 {},
596};