initial import
[ps3linux_kernel_patches_41.git] / 0220-spuisofs.patch
blob2c9fec29c3a233ff7cfd02f184c21873e994e957
1 --- a/arch/powerpc/platforms/ps3/Kconfig 2012-08-08 21:45:40.869511244 +0200
2 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-08-08 21:43:09.502835770 +0200
3 @@ -202,6 +202,13 @@
4 This support is required to access the PS3 ENCDEC device.
5 In general, all users will say Y or M.
7 +config SPUISO_FS
8 + tristate "PS3 isolated SPU file system"
9 + default m
10 + depends on PPC_PS3
11 + help
12 + The isolated SPU file system is used to execute isolated SPU modules.
14 config PS3GELIC_UDBG
15 bool "PS3 udbg output via UDP broadcasts on Ethernet"
16 depends on PPC_PS3
17 --- a/arch/powerpc/platforms/ps3/Makefile 2012-08-08 21:45:25.436177008 +0200
18 +++ b/arch/powerpc/platforms/ps3/Makefile 2012-08-08 21:43:40.846170928 +0200
19 @@ -6,3 +6,5 @@
20 obj-$(CONFIG_SMP) += smp.o
21 obj-$(CONFIG_SPU_BASE) += spu.o
22 obj-y += device-init.o
24 +obj-$(CONFIG_SPUISO_FS) += spuisofs.o
25 --- /dev/null 2015-03-29 14:05:25.158040360 +0200
26 +++ b/arch/powerpc/platforms/ps3/spuisofs.c 2015-03-29 14:22:32.084766770 +0200
27 @@ -0,0 +1,1073 @@
29 +/*
30 + * PS3 spuisofs
31 + *
32 + * Copyright (C) 2012-2013 glevand <geoffrey.levand@mail.ru>
33 + * All rights reserved.
34 + *
35 + * This program is free software; you can redistribute it and/or modify it
36 + * under the terms of the GNU General Public License as published
37 + * by the Free Software Foundation; version 2 of the License.
38 + *
39 + * This program is distributed in the hope that it will be useful, but
40 + * WITHOUT ANY WARRANTY; without even the implied warranty of
41 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 + * General Public License for more details.
43 + *
44 + * You should have received a copy of the GNU General Public License along
45 + * with this program; if not, write to the Free Software Foundation, Inc.,
46 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
47 + */
49 +#include <linux/module.h>
50 +#include <linux/kernel.h>
51 +#include <linux/version.h>
52 +#include <linux/init.h>
53 +#include <linux/fs.h>
54 +#include <linux/fsnotify.h>
55 +#include <linux/file.h>
56 +#include <linux/slab.h>
57 +#include <linux/vmalloc.h>
58 +#include <linux/pagemap.h>
59 +#include <linux/io.h>
60 +#include <linux/interrupt.h>
62 +#include <asm/uaccess.h>
63 +#include <asm/ps3.h>
64 +#include <asm/spu.h>
65 +#include <asm/spu_priv1.h>
66 +#include <asm/lv1call.h>
68 +#define SPUISOFS_MAGIC 0x73707569
70 +struct spe_shadow {
71 + u8 padding_0140[0x0140];
72 + u64 int_status_class0_RW; /* 0x0140 */
73 + u64 int_status_class1_RW; /* 0x0148 */
74 + u64 int_status_class2_RW; /* 0x0150 */
75 + u8 padding_0158[0x0610-0x0158];
76 + u64 mfc_dsisr_RW; /* 0x0610 */
77 + u8 padding_0618[0x0620-0x0618];
78 + u64 mfc_dar_RW; /* 0x0620 */
79 + u8 padding_0628[0x0800-0x0628];
80 + u64 mfc_dsipr_R; /* 0x0800 */
81 + u8 padding_0808[0x0810-0x0808];
82 + u64 mfc_lscrr_R; /* 0x0810 */
83 + u8 padding_0818[0x0c00-0x0818];
84 + u64 mfc_cer_R; /* 0x0c00 */
85 + u8 padding_0c08[0x0f00-0x0c08];
86 + u64 spe_execution_status; /* 0x0f00 */
87 + u8 padding_0f08[0x1000-0x0f08];
88 +};
90 +struct spuisofs_inode_info {
91 + struct inode vfs_inode;
92 + unsigned long io_addr;
93 + void *virt_addr;
94 +};
96 +struct spuisofs_tree_descr {
97 + const char *name;
98 + const struct file_operations *ops;
99 + umode_t mode;
100 + size_t size;
101 + unsigned long io_addr;
102 + void *virt_addr;
105 +#define SPUISOFS_I(inode) container_of(inode, struct spuisofs_inode_info, vfs_inode)
107 +struct spuisofs_run_args {
108 + u64 laid;
109 + u64 arg1_size;
110 + u64 arg2_size;
113 +static struct kmem_cache *spuisofs_inode_cache;
115 +static u64 spuisofs_spe_priv2_addr;
116 +static u64 spuisofs_spe_problem_addr;
117 +static u64 spuisofs_spe_ls_addr;
118 +static u64 spuisofs_spe_shadow_addr;
120 +static void *spuisofs_spe_priv2;
121 +static struct spu_problem *spuisofs_spe_problem;
122 +static void *spuisofs_spe_ls;
123 +static struct spe_shadow *spuisofs_spe_shadow;
124 +static u64 spuisofs_spe_id;
125 +static unsigned int spuisofs_spe_virq[4];
127 +static void *spuisofs_spe_app;
128 +static void *spuisofs_spe_arg1;
129 +static void *spuisofs_spe_arg2;
130 +static void *spuisofs_spe_buf;
132 +static unsigned int spuisofs_spe_slb_index;
134 +static unsigned long spuisofs_spe_app_size = 1024 * 1024;
135 +module_param(spuisofs_spe_app_size, ulong, 0);
137 +static unsigned long spuisofs_spe_arg1_size = 1024 * 1024;
138 +module_param(spuisofs_spe_arg1_size, ulong, 0);
140 +static unsigned long spuisofs_spe_arg2_size = 1024 * 1024;
141 +module_param(spuisofs_spe_arg2_size, ulong, 0);
143 +static unsigned long spuisofs_spe_buf_size = 1024 * 1024;
144 +module_param(spuisofs_spe_buf_size, ulong, 0);
146 +static unsigned long spuisofs_spe_trans_notify_mask = 0xf;
147 +module_param(spuisofs_spe_trans_notify_mask, ulong, 0);
149 +static unsigned long spuisofs_spe_resource_id = 6;
150 +module_param(spuisofs_spe_resource_id, ulong, 0);
152 +static int spuisofs_spe_buf_addr_32bit = 0;
153 +module_param(spuisofs_spe_buf_addr_32bit, int, 0);
156 + * spuisofs_spe_regs_read
157 + */
158 +static ssize_t spuisofs_spe_regs_read(struct file *file, char __user *buffer,
159 + size_t size, loff_t *pos)
161 + struct inode *inode = file->f_path.dentry->d_inode;
162 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
164 + if (*pos >= inode->i_size)
165 + return (0);
167 + return simple_read_from_buffer(buffer, size, pos,
168 + si->virt_addr, inode->i_size);
172 + * spuisofs_spe_regs_write
173 + */
174 +static ssize_t spuisofs_spe_regs_write(struct file *file, const char __user *buffer,
175 + size_t size, loff_t *pos)
177 + struct inode *inode = file->f_path.dentry->d_inode;
178 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
180 + if (*pos >= inode->i_size)
181 + return (-EFBIG);
183 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
184 + pos, buffer, size);
188 + * spuisofs_spe_regs_mmap
189 + */
190 +static int spuisofs_spe_regs_mmap(struct file *file, struct vm_area_struct *vma)
192 + struct inode *inode = file->f_path.dentry->d_inode;
193 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
194 + unsigned long size, pfn;
196 + size = vma->vm_end - vma->vm_start;
197 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
199 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
200 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
201 +#else
202 + vma->vm_flags |= VM_RESERVED | VM_IO;
203 +#endif
204 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
206 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
209 +static const struct file_operations spuisofs_spe_regs_fops = {
210 + .read = spuisofs_spe_regs_read,
211 + .write = spuisofs_spe_regs_write,
212 + .mmap = spuisofs_spe_regs_mmap,
216 + * spuisofs_spe_mem_read
217 + */
218 +static ssize_t spuisofs_spe_mem_read(struct file *file, char __user *buffer,
219 + size_t size, loff_t *pos)
221 + struct inode *inode = file->f_path.dentry->d_inode;
222 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
224 + if (*pos >= inode->i_size)
225 + return (0);
227 + return simple_read_from_buffer(buffer, size, pos,
228 + si->virt_addr, inode->i_size);
232 + * spuisofs_spe_mem_write
233 + */
234 +static ssize_t spuisofs_spe_mem_write(struct file *file, const char __user *buffer,
235 + size_t size, loff_t *pos)
237 + struct inode *inode = file->f_path.dentry->d_inode;
238 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
240 + if (*pos >= inode->i_size)
241 + return (-EFBIG);
243 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
244 + pos, buffer, size);
248 + * spuisofs_spe_mem_mmap
249 + */
250 +static int spuisofs_spe_mem_mmap(struct file *file, struct vm_area_struct *vma)
252 + struct inode *inode = file->f_path.dentry->d_inode;
253 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
254 + unsigned long size, pfn;
256 + size = vma->vm_end - vma->vm_start;
257 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
259 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
260 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
261 +#else
262 + vma->vm_flags |= VM_RESERVED | VM_IO;
263 +#endif
264 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
266 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
269 +static const struct file_operations spuisofs_spe_mem_fops = {
270 + .read = spuisofs_spe_mem_read,
271 + .write = spuisofs_spe_mem_write,
272 + .mmap = spuisofs_spe_mem_mmap,
276 + * spuisofs_mem_read
277 + */
278 +static ssize_t spuisofs_mem_read(struct file *file, char __user *buffer,
279 + size_t size, loff_t *pos)
281 + struct inode *inode = file->f_path.dentry->d_inode;
282 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
284 + if (*pos >= inode->i_size)
285 + return (0);
287 + return simple_read_from_buffer(buffer, size, pos,
288 + si->virt_addr, inode->i_size);
292 + * spuisofs_mem_write
293 + */
294 +static ssize_t spuisofs_mem_write(struct file *file, const char __user *buffer,
295 + size_t size, loff_t *pos)
297 + struct inode *inode = file->f_path.dentry->d_inode;
298 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
300 + if (*pos >= inode->i_size)
301 + return (-EFBIG);
303 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
304 + pos, buffer, size);
308 + * spuisofs_mem_mmap
309 + */
310 +static int spuisofs_mem_mmap(struct file *file, struct vm_area_struct *vma)
312 + struct inode *inode = file->f_path.dentry->d_inode;
313 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
315 + return remap_vmalloc_range(vma, si->virt_addr, 0);
318 +static const struct file_operations spuisofs_mem_fops = {
319 + .read = spuisofs_mem_read,
320 + .write = spuisofs_mem_write,
321 + .mmap = spuisofs_mem_mmap,
325 + * spuisofs_info_read
326 + */
327 +static ssize_t spuisofs_info_read(struct file *file, char __user *buffer,
328 + size_t size, loff_t *pos)
330 + char buf[256];
331 + size_t len;
332 + unsigned long spe_buf_addr;
334 + spe_buf_addr = (unsigned long) spuisofs_spe_buf;
336 + if (spuisofs_spe_buf_addr_32bit)
337 + spe_buf_addr &= 0xfffffffful;
339 + len = sprintf(buf, "arg1 %lx\narg2 %lx\nbuf %lx\n",
340 + (unsigned long) spuisofs_spe_arg1, (unsigned long) spuisofs_spe_arg2,
341 + spe_buf_addr);
343 + return simple_read_from_buffer(buffer, size, pos, buf, len);
346 +static const struct file_operations spuisofs_info_fops = {
347 + .read = spuisofs_info_read,
351 + * spuisofs_run_write
352 + */
353 +static ssize_t spuisofs_run_write(struct file *file, const char __user *buffer,
354 + size_t size, loff_t *pos)
356 + struct inode *inode = file->f_path.dentry->d_inode;
357 + struct spuisofs_run_args args;
358 + int err;
360 + if (*pos || (size != inode->i_size))
361 + return (-EINVAL);
363 + if (copy_from_user(&args, buffer, sizeof(struct spuisofs_run_args)))
364 + return -EFAULT;
366 + if (args.arg1_size == 0)
367 + args.arg1_size = spuisofs_spe_arg1_size;
369 + if (args.arg2_size == 0)
370 + args.arg2_size = spuisofs_spe_arg2_size;
372 + if (args.arg1_size > spuisofs_spe_arg1_size)
373 + return (-EINVAL);
375 + if (args.arg2_size > spuisofs_spe_arg2_size)
376 + return (-EINVAL);
378 + err = lv1_undocumented_function_201(spuisofs_spe_id);
379 + if (err)
380 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_201 failed with %d\n", err);
382 + err = lv1_undocumented_function_209(spuisofs_spe_id, args.laid, (u64) spuisofs_spe_app,
383 + (u64) spuisofs_spe_arg1, args.arg1_size,
384 + (u64) spuisofs_spe_arg2, args.arg2_size, spuisofs_spe_resource_id);
385 + if (err) {
386 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_209 failed with %d\n", err);
387 + return (-ENXIO);
390 + return (size);
393 +static const struct file_operations spuisofs_run_fops = {
394 + .write = spuisofs_run_write,
398 + * spuisofs_cont_write
399 + */
400 +static ssize_t spuisofs_cont_write(struct file *file, const char __user *buffer,
401 + size_t size, loff_t *pos)
403 + u64 puint_mb_R;
404 + int err;
406 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
407 + if (err) {
408 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
409 + return (-ENXIO);
412 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
414 + err = lv1_undocumented_function_200(spuisofs_spe_id);
415 + if (err) {
416 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_200 failed with %d\n", err);
417 + return (-ENXIO);
420 + return (size);
423 +static const struct file_operations spuisofs_cont_fops = {
424 + .write = spuisofs_cont_write,
428 + * spuisofs_alloc_inode
429 + */
430 +static struct inode *spuisofs_alloc_inode(struct super_block *sb)
432 + struct spuisofs_inode_info *si;
434 + si = kmem_cache_alloc(spuisofs_inode_cache, GFP_KERNEL);
435 + if (!si)
436 + return (NULL);
438 + return (&si->vfs_inode);
442 + * spuisofs_i_callback
443 + */
444 +static void spuisofs_i_callback(struct rcu_head *head)
446 + struct inode *inode = container_of(head, struct inode, i_rcu);
448 + kmem_cache_free(spuisofs_inode_cache, SPUISOFS_I(inode));
452 + * spuisofs_destroy_inode
453 + */
454 +static void spuisofs_destroy_inode(struct inode *inode)
456 + call_rcu(&inode->i_rcu, spuisofs_i_callback);
460 + * spuisofs_init_once
461 + */
462 +static void spuisofs_init_once(void *p)
464 + struct spuisofs_inode_info *si = p;
466 + inode_init_once(&si->vfs_inode);
470 + * spuisofs_new_inode
471 + */
472 +static struct inode *spuisofs_new_inode(struct super_block *sb, umode_t mode)
474 + struct inode *inode;
476 + inode = new_inode(sb);
477 + if (!inode)
478 + return (NULL);
480 + inode->i_ino = get_next_ino();
481 + inode->i_mode = mode;
482 + inode->i_uid = current_fsuid();
483 + inode->i_gid = current_fsgid();
484 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
486 + return (inode);
490 + * spuisofs_setattr
491 + */
492 +static int spuisofs_setattr(struct dentry *dentry, struct iattr *attr)
494 + struct inode *inode = dentry->d_inode;
496 + setattr_copy(inode, attr);
497 + mark_inode_dirty(inode);
499 + return (0);
502 +static const struct inode_operations spuisofs_inode_ops = {
503 + .setattr = spuisofs_setattr,
507 + * spuisofs_new_file
508 + */
509 +static int spuisofs_new_file(struct super_block *sb, struct dentry *dentry,
510 + const struct file_operations *fops, umode_t mode, size_t size,
511 + unsigned long io_addr, void *virt_addr)
513 + struct inode *inode;
514 + struct spuisofs_inode_info *si;
516 + inode = spuisofs_new_inode(sb, S_IFREG | mode);
517 + if (!inode)
518 + return (-ENOMEM);
520 + inode->i_op = &spuisofs_inode_ops;
521 + inode->i_fop = fops;
522 + inode->i_size = size;
523 + inode->i_private = NULL;
525 + si = SPUISOFS_I(inode);
526 + si->io_addr = io_addr;
527 + si->virt_addr = virt_addr;
529 + d_add(dentry, inode);
531 + return (0);
535 + * spuisofs_fill_dir
536 + */
537 +static int spuisofs_fill_dir(struct dentry *dir,
538 + const struct spuisofs_tree_descr *files)
540 + struct dentry *dentry, *tmp;
541 + int err;
543 + while (files->name && files->name[0]) {
544 + dentry = d_alloc_name(dir, files->name);
545 + if (!dentry) {
546 + err = -ENOMEM;
547 + goto fail;
550 + err = spuisofs_new_file(dir->d_sb, dentry, files->ops,
551 + files->mode, files->size, files->io_addr, files->virt_addr);
552 + if (err)
553 + goto fail;
555 + files++;
558 + return (0);
560 +fail:
562 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,1)
563 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child)
564 + dput(dentry);
565 +#else
566 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child)
567 + dput(dentry);
568 +#endif
570 + shrink_dcache_parent(dir);
572 + return (err);
575 +static const struct super_operations spuisofs_super_ops = {
576 + .alloc_inode = spuisofs_alloc_inode,
577 + .destroy_inode = spuisofs_destroy_inode,
578 + .statfs = simple_statfs,
582 + * spuisofs_fill_super
583 + */
584 +static int spuisofs_fill_super(struct super_block *sb, void *data, int silent)
586 + const struct spuisofs_tree_descr root_dir_contents[] = {
587 + { "priv2", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_priv2), spuisofs_spe_priv2_addr, spuisofs_spe_priv2, },
588 + { "problem", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_problem), spuisofs_spe_problem_addr, spuisofs_spe_problem, },
589 + { "ls", &spuisofs_spe_mem_fops, 0666, LS_SIZE, spuisofs_spe_ls_addr, spuisofs_spe_ls, },
590 + { "shadow", &spuisofs_spe_mem_fops, 0444, sizeof(struct spe_shadow), spuisofs_spe_shadow_addr, spuisofs_spe_shadow, },
591 + { "app", &spuisofs_mem_fops, 0666, spuisofs_spe_app_size, 0, spuisofs_spe_app, },
592 + { "arg1", &spuisofs_mem_fops, 0666, spuisofs_spe_arg1_size, 0, spuisofs_spe_arg1, },
593 + { "arg2", &spuisofs_mem_fops, 0666, spuisofs_spe_arg2_size, 0, spuisofs_spe_arg2, },
594 + { "buf", &spuisofs_mem_fops, 0666, spuisofs_spe_buf_size, 0, spuisofs_spe_buf, },
595 + { "info", &spuisofs_info_fops, 0444, 0, 0, NULL, },
596 + { "run", &spuisofs_run_fops, 0222, sizeof(struct spuisofs_run_args), 0, NULL, },
597 + { "cont", &spuisofs_cont_fops, 0222, 0, 0, NULL, },
598 + { },
599 + };
600 + struct inode *root_inode;
601 + int err;
603 + sb->s_maxbytes = MAX_LFS_FILESIZE;
604 + sb->s_blocksize = PAGE_CACHE_SIZE;
605 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
606 + sb->s_magic = SPUISOFS_MAGIC;
607 + sb->s_op = &spuisofs_super_ops;
608 + sb->s_time_gran = 1;
610 + root_inode = spuisofs_new_inode(sb, S_IFDIR | 0755);
611 + if (!root_inode)
612 + return (-ENOMEM);
614 + root_inode->i_op = &simple_dir_inode_operations;
615 + root_inode->i_fop = &simple_dir_operations;
617 + /* directory inodes start off with i_nlink == 2 (for "." entry) */
618 + inc_nlink(root_inode);
620 + sb->s_root = d_make_root(root_inode);
621 + if (!sb->s_root)
622 + return (-ENOMEM);
624 + err = spuisofs_fill_dir(sb->s_root, root_dir_contents);
625 + if (err)
626 + return (err);
628 + return (0);
632 + * spuisofs_spe_ea_to_kernel_ea
633 + */
634 +static unsigned long spuisofs_spe_ea_to_kernel_ea(unsigned long spe_ea)
636 + unsigned long kernel_ea, spe_buf_addr;
638 + kernel_ea = spe_ea;
640 + if (!spuisofs_spe_buf_addr_32bit)
641 + return (kernel_ea);
643 + spe_buf_addr = (unsigned long) spuisofs_spe_buf & 0xfffffffful;
645 + if ((spe_ea >= spe_buf_addr) && (spe_ea < (spe_buf_addr + spuisofs_spe_buf_size)))
646 + kernel_ea = (unsigned long) spuisofs_spe_buf + (spe_buf_addr - spe_ea);
648 + return (kernel_ea);
652 + * spuisofs_spe_interrupt
653 + */
654 +static irqreturn_t spuisofs_spe_interrupt(int irq, void *data)
656 + u64 status;
657 + u64 ea, kernel_ea, dsisr, esid, vsid;
658 + u64 puint_mb_R;
659 + u32 spu_status_R;
660 + u64 spe_execution_status;
661 + int err;
663 + if (irq == spuisofs_spe_virq[0]) {
664 + printk(KERN_INFO"spuisofs: got class 0 irq\n");
666 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 0, &status);
667 + if (err) {
668 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
669 + goto out;
672 + printk(KERN_INFO"spuisofs: status %llx\n", status);
674 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 0, status, 0);
675 + if (err) {
676 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
677 + goto out;
679 + } else if (irq == spuisofs_spe_virq[1]) {
680 + printk(KERN_INFO"spuisofs: got class 1 irq\n");
682 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 1, &status);
683 + if (err) {
684 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
685 + goto out;
688 + printk(KERN_INFO"spuisofs: status %llx\n", status);
690 + if (status & CLASS1_SEGMENT_FAULT_INTR) {
691 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
692 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
694 + esid = (ea & ESID_MASK) | SLB_ESID_V;
695 + vsid = (get_kernel_vsid(kernel_ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K;
697 + printk(KERN_INFO"spuisofs: data segment fault at %llx (%llx)\n", ea, kernel_ea);
699 + err = lv1_undocumented_function_62(spuisofs_spe_id, 0, spuisofs_spe_slb_index, esid, vsid);
700 + if (err) {
701 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_62 failed with %d\n", err);
702 + goto out;
705 + spuisofs_spe_slb_index++;
706 + if (spuisofs_spe_slb_index > SLB_INDEX_MASK)
707 + spuisofs_spe_slb_index = 0;
710 + if (status & CLASS1_STORAGE_FAULT_INTR) {
711 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
712 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
713 + dsisr = in_be64(&spuisofs_spe_shadow->mfc_dsisr_RW);
715 + printk(KERN_INFO"spuisofs: data storage fault at %llx (%llx)\n", ea, kernel_ea);
717 + if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
718 + err = hash_page(kernel_ea, _PAGE_PRESENT, 0x300, dsisr);
719 + if (err) {
720 + printk(KERN_INFO"spuisofs: hash_page failed with %d\n", err);
721 + goto out;
726 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 1, status, 0);
727 + if (err) {
728 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
729 + goto out;
732 + /* restart DMA */
734 + err = lv1_undocumented_function_168(spuisofs_spe_id, 0x3000, 1ull << 32);
735 + if (err) {
736 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_168 failed with %d\n", err);
737 + goto out;
739 + } else if (irq == spuisofs_spe_virq[2]) {
740 + printk(KERN_INFO"spuisofs: got class 2 irq\n");
742 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 2, &status);
743 + if (err) {
744 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
745 + goto out;
748 + printk(KERN_INFO"spuisofs: status %llx\n", status);
750 + if (status & CLASS2_MAILBOX_INTR) {
751 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
752 + if (err) {
753 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
754 + goto out;
757 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
760 + if (status & CLASS2_SPU_STOP_INTR) {
761 + spu_status_R = in_be32(&spuisofs_spe_problem->spu_status_R);
763 + printk(KERN_INFO"spuisofs: spu_status_R %x\n", spu_status_R);
766 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 2, status, 0);
767 + if (err) {
768 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
769 + goto out;
771 + } else if (irq == spuisofs_spe_virq[3]) {
772 + spe_execution_status = spuisofs_spe_shadow->spe_execution_status;
774 + printk(KERN_INFO"spuisofs: transition notification: shadow spe_execution_status %llx\n",
775 + spe_execution_status);
776 + } else {
777 + printk(KERN_INFO"spuisofs: got unknown irq %d\n", irq);
780 +out:
782 + return (IRQ_HANDLED);
786 + * spuisofs_create_spe
787 + */
788 +static int spuisofs_create_spe(void)
790 + u64 vas_id, junk;
791 + int err;
793 + err = lv1_get_virtual_address_space_id_of_ppe(&vas_id);
794 + if (err)
795 + return (-ENXIO);
797 + printk(KERN_INFO"spuisofs: vas id %llu\n", vas_id);
799 + err = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT,
800 + PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, vas_id, 2,
801 + &spuisofs_spe_priv2_addr, &spuisofs_spe_problem_addr, &spuisofs_spe_ls_addr,
802 + &junk, &spuisofs_spe_shadow_addr, &spuisofs_spe_id);
803 + if (err)
804 + return (-ENXIO);
806 + printk(KERN_INFO"spuisofs: spe id %llu\n", spuisofs_spe_id);
808 + spuisofs_spe_priv2 = ioremap(spuisofs_spe_priv2_addr, sizeof(struct spu_priv2));
809 + if (!spuisofs_spe_priv2) {
810 + err = -ENOMEM;
811 + goto fail_destruct_spe;
814 + spuisofs_spe_problem = ioremap(spuisofs_spe_problem_addr, sizeof(struct spu_problem));
815 + if (!spuisofs_spe_problem) {
816 + err = -ENOMEM;
817 + goto fail_unmap_priv2;
820 + spuisofs_spe_ls = ioremap_prot(spuisofs_spe_ls_addr, LS_SIZE, _PAGE_NO_CACHE);
821 + if (!spuisofs_spe_ls) {
822 + err = -ENOMEM;
823 + goto fail_unmap_problem;
826 + spuisofs_spe_shadow = __ioremap(spuisofs_spe_shadow_addr, sizeof(struct spe_shadow),
827 + _PAGE_NO_CACHE | 3);
828 + if (!spuisofs_spe_shadow) {
829 + err = -ENOMEM;
830 + goto fail_unmap_ls;
833 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 0, &spuisofs_spe_virq[0]);
834 + if (err) {
835 + err = -ENXIO;
836 + goto fail_unmap_shadow;
839 + err = request_irq(spuisofs_spe_virq[0], spuisofs_spe_interrupt, 0,
840 + "spuisofs_spe_irq0", &spuisofs_spe_virq[0]);
841 + if (err)
842 + goto fail_destroy_spe_irq_0;
844 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 1, &spuisofs_spe_virq[1]);
845 + if (err) {
846 + err = -ENXIO;
847 + goto fail_free_spe_irq_0;
850 + err = request_irq(spuisofs_spe_virq[1], spuisofs_spe_interrupt, 0,
851 + "spuisofs_spe_irq1", &spuisofs_spe_virq[1]);
852 + if (err)
853 + goto fail_destroy_spe_irq_1;
855 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 2, &spuisofs_spe_virq[2]);
856 + if (err) {
857 + err = -ENXIO;
858 + goto fail_free_spe_irq_1;
861 + err = request_irq(spuisofs_spe_virq[2], spuisofs_spe_interrupt, 0,
862 + "spuisofs_spe_irq2", &spuisofs_spe_virq[2]);
863 + if (err)
864 + goto fail_destroy_spe_irq_2;
866 + err = ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY, &spuisofs_spe_virq[3]);
867 + if (err) {
868 + err = -ENXIO;
869 + goto fail_free_spe_irq_2;
872 + err = lv1_set_spe_transition_notifier(spuisofs_spe_id, spuisofs_spe_trans_notify_mask,
873 + virq_to_hw(spuisofs_spe_virq[3]));
874 + if (err) {
875 + printk(KERN_INFO"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err);
876 + err = -ENXIO;
877 + goto fail_destroy_event_recv_port;
880 + err = request_irq(spuisofs_spe_virq[3], spuisofs_spe_interrupt, 0,
881 + "spuisofs_spe_irq3", &spuisofs_spe_virq[3]);
882 + if (err)
883 + goto fail_destroy_event_recv_port;
885 + return (0);
887 +fail_destroy_event_recv_port:
889 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
891 +fail_free_spe_irq_2:
893 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
895 +fail_destroy_spe_irq_2:
897 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
899 +fail_free_spe_irq_1:
901 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
903 +fail_destroy_spe_irq_1:
905 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
907 +fail_free_spe_irq_0:
909 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
911 +fail_destroy_spe_irq_0:
913 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
915 +fail_unmap_shadow:
917 + iounmap(spuisofs_spe_shadow);
919 +fail_unmap_ls:
921 + iounmap(spuisofs_spe_ls);
923 +fail_unmap_problem:
925 + iounmap(spuisofs_spe_problem);
927 +fail_unmap_priv2:
929 + iounmap(spuisofs_spe_priv2);
931 +fail_destruct_spe:
933 + lv1_destruct_logical_spe(spuisofs_spe_id);
935 + return (err);
939 + * spuisofs_destruct_spe
940 + */
941 +static void spuisofs_destruct_spe(void)
943 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
944 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
946 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
947 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
949 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
950 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
952 + free_irq(spuisofs_spe_virq[3], &spuisofs_spe_virq[3]);
953 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
955 + iounmap(spuisofs_spe_shadow);
956 + iounmap(spuisofs_spe_ls);
957 + iounmap(spuisofs_spe_problem);
958 + iounmap(spuisofs_spe_priv2);
960 + lv1_destruct_logical_spe(spuisofs_spe_id);
964 + * spuisofs_mount
965 + */
966 +static struct dentry *spuisofs_mount(struct file_system_type *fs_type,
967 + int flags, const char *dev_name, void *data)
969 + struct dentry *root;
970 + int err;
972 + err = spuisofs_create_spe();
973 + if (err)
974 + return ERR_PTR(err);
976 + spuisofs_spe_app = vmalloc_user(spuisofs_spe_app_size);
977 + if (!spuisofs_spe_app) {
978 + err = -ENOMEM;
979 + goto fail_destruct_spe;
982 + memset(spuisofs_spe_app, 0, spuisofs_spe_app_size);
984 + spuisofs_spe_arg1 = vmalloc_user(spuisofs_spe_arg1_size);
985 + if (!spuisofs_spe_arg1) {
986 + err = -ENOMEM;
987 + goto fail_free_spe_app;
990 + memset(spuisofs_spe_arg1, 0, spuisofs_spe_arg1_size);
992 + spuisofs_spe_arg2 = vmalloc_user(spuisofs_spe_arg2_size);
993 + if (!spuisofs_spe_arg2) {
994 + err = -ENOMEM;
995 + goto fail_free_spe_arg1;
998 + memset(spuisofs_spe_arg2, 0, spuisofs_spe_arg2_size);
1000 + spuisofs_spe_buf = vmalloc_user(spuisofs_spe_buf_size);
1001 + if (!spuisofs_spe_buf) {
1002 + err = -ENOMEM;
1003 + goto fail_free_spe_arg2;
1006 + memset(spuisofs_spe_buf, 0, spuisofs_spe_buf_size);
1008 + root = mount_single(fs_type, flags, data, spuisofs_fill_super);
1009 + if (IS_ERR(root)) {
1010 + err = PTR_ERR(root);
1011 + goto fail_free_buf;
1014 + return (root);
1016 +fail_free_buf:
1018 + vfree(spuisofs_spe_buf);
1020 +fail_free_spe_arg2:
1022 + vfree(spuisofs_spe_arg2);
1024 +fail_free_spe_arg1:
1026 + vfree(spuisofs_spe_arg1);
1028 +fail_free_spe_app:
1030 + vfree(spuisofs_spe_app);
1032 +fail_destruct_spe:
1034 + spuisofs_destruct_spe();
1036 + return ERR_PTR(err);
1040 + * spuisofs_kill_sb
1041 + */
1042 +static void spuisofs_kill_sb(struct super_block *sb)
1044 + kill_litter_super(sb);
1046 + vfree(spuisofs_spe_app);
1047 + vfree(spuisofs_spe_arg1);
1048 + vfree(spuisofs_spe_arg2);
1049 + vfree(spuisofs_spe_buf);
1050 + spuisofs_destruct_spe();
1053 +static struct file_system_type spuisofs_type = {
1054 + .owner = THIS_MODULE,
1055 + .name = "spuisofs",
1056 + .mount = spuisofs_mount,
1057 + .kill_sb = spuisofs_kill_sb,
1061 + * spuisofs_init
1062 + */
1063 +static int __init spuisofs_init(void)
1065 + int err;
1067 + spuisofs_inode_cache = kmem_cache_create("spuisofs_inode_cache",
1068 + sizeof(struct spuisofs_inode_info), 0, SLAB_HWCACHE_ALIGN,
1069 + spuisofs_init_once);
1070 + if (!spuisofs_inode_cache)
1071 + return (-ENOMEM);
1073 + err = register_filesystem(&spuisofs_type);
1074 + if (err)
1075 + goto fail_destroy_inode_cache;
1077 + return (0);
1079 +fail_destroy_inode_cache:
1081 + kmem_cache_destroy(spuisofs_inode_cache);
1083 + return (err);
1087 + * spuisofs_exit
1088 + */
1089 +static void __exit spuisofs_exit(void)
1091 + unregister_filesystem(&spuisofs_type);
1092 + kmem_cache_destroy(spuisofs_inode_cache);
1095 +module_init(spuisofs_init);
1096 +module_exit(spuisofs_exit);
1098 +MODULE_DESCRIPTION("PS3 spuisofs");
1099 +MODULE_AUTHOR("glevand");
1100 +MODULE_LICENSE("GPL");