1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # This copyright note is auto-generated by scripts/Create-CopyPatch.
4 # T2 SDE: architecture/powerpc64/package/.../0220-spuisofs.patch
5 # Copyright (C) 2020 The T2 SDE Project
7 # More information can be found in the files COPYING and README.
9 # This patch file is dual-licensed. It is available under the license the
10 # patched project is licensed under, as long as it is an OpenSource license
11 # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
12 # of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
15 # --- T2-COPYRIGHT-NOTE-END ---
17 --- a/arch/powerpc/platforms/ps3/Kconfig 2012-08-08 21:45:40.869511244 +0200
18 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-08-08 21:43:09.502835770 +0200
20 This support is required to access the PS3 ENCDEC device.
21 In general, all users will say Y or M.
24 + tristate "PS3 isolated SPU file system"
28 + The isolated SPU file system is used to execute isolated SPU modules.
31 bool "PS3 udbg output via UDP broadcasts on Ethernet"
33 --- a/arch/powerpc/platforms/ps3/Makefile 2012-08-08 21:45:25.436177008 +0200
34 +++ b/arch/powerpc/platforms/ps3/Makefile 2012-08-08 21:43:40.846170928 +0200
36 obj-$(CONFIG_SMP) += smp.o
37 obj-$(CONFIG_SPU_BASE) += spu.o
38 obj-y += device-init.o
40 +obj-$(CONFIG_SPUISO_FS) += spuisofs.o
41 --- /dev/null 2013-10-07 20:20:12.741358433 +0200
42 +++ b/arch/powerpc/platforms/ps3/spuisofs.c 2013-10-07 22:15:48.445095266 +0200
47 + * Copyright (C) 2012-2013 glevand <geoffrey.levand@mail.ru>
48 + * Copyright (C) 2021 René Rebe <rene@exactcode.de>
49 + * All rights reserved.
51 + * This program is free software; you can redistribute it and/or modify it
52 + * under the terms of the GNU General Public License as published
53 + * by the Free Software Foundation; version 2 of the License.
55 + * This program is distributed in the hope that it will be useful, but
56 + * WITHOUT ANY WARRANTY; without even the implied warranty of
57 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
58 + * General Public License for more details.
60 + * You should have received a copy of the GNU General Public License along
61 + * with this program; if not, write to the Free Software Foundation, Inc.,
62 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
65 +#include <linux/module.h>
66 +#include <linux/kernel.h>
67 +#include <linux/version.h>
68 +#include <linux/init.h>
69 +#include <linux/fs.h>
70 +#include <linux/fsnotify.h>
71 +#include <linux/file.h>
72 +#include <linux/slab.h>
73 +#include <linux/vmalloc.h>
74 +#include <linux/pagemap.h>
75 +#include <linux/io.h>
76 +#include <linux/interrupt.h>
77 +#include <linux/time.h>
79 +#include <asm/uaccess.h>
82 +#include <asm/spu_priv1.h>
83 +#include <asm/lv1call.h>
85 +#define SPUISOFS_MAGIC 0x73707569
88 + u8 padding_0140[0x0140];
89 + u64 int_status_class0_RW; /* 0x0140 */
90 + u64 int_status_class1_RW; /* 0x0148 */
91 + u64 int_status_class2_RW; /* 0x0150 */
92 + u8 padding_0158[0x0610-0x0158];
93 + u64 mfc_dsisr_RW; /* 0x0610 */
94 + u8 padding_0618[0x0620-0x0618];
95 + u64 mfc_dar_RW; /* 0x0620 */
96 + u8 padding_0628[0x0800-0x0628];
97 + u64 mfc_dsipr_R; /* 0x0800 */
98 + u8 padding_0808[0x0810-0x0808];
99 + u64 mfc_lscrr_R; /* 0x0810 */
100 + u8 padding_0818[0x0c00-0x0818];
101 + u64 mfc_cer_R; /* 0x0c00 */
102 + u8 padding_0c08[0x0f00-0x0c08];
103 + u64 spe_execution_status; /* 0x0f00 */
104 + u8 padding_0f08[0x1000-0x0f08];
107 +struct spuisofs_inode_info {
108 + struct inode vfs_inode;
109 + unsigned long io_addr;
113 +struct spuisofs_tree_descr {
115 + const struct file_operations *ops;
118 + unsigned long io_addr;
122 +#define SPUISOFS_I(inode) container_of(inode, struct spuisofs_inode_info, vfs_inode)
124 +struct spuisofs_run_args {
130 +static struct kmem_cache *spuisofs_inode_cache;
132 +static u64 spuisofs_spe_priv2_addr;
133 +static u64 spuisofs_spe_problem_addr;
134 +static u64 spuisofs_spe_ls_addr;
135 +static u64 spuisofs_spe_shadow_addr;
137 +static void *spuisofs_spe_priv2;
138 +static struct spu_problem *spuisofs_spe_problem;
139 +static void *spuisofs_spe_ls;
140 +static struct spe_shadow *spuisofs_spe_shadow;
141 +static u64 spuisofs_spe_id;
142 +static unsigned int spuisofs_spe_virq[4];
144 +static void *spuisofs_spe_app;
145 +static void *spuisofs_spe_arg1;
146 +static void *spuisofs_spe_arg2;
147 +static void *spuisofs_spe_buf;
149 +static unsigned int spuisofs_spe_slb_index;
151 +static unsigned long spuisofs_spe_app_size = 1024 * 1024;
152 +module_param(spuisofs_spe_app_size, ulong, 0);
154 +static unsigned long spuisofs_spe_arg1_size = 1024 * 1024;
155 +module_param(spuisofs_spe_arg1_size, ulong, 0);
157 +static unsigned long spuisofs_spe_arg2_size = 1024 * 1024;
158 +module_param(spuisofs_spe_arg2_size, ulong, 0);
160 +static unsigned long spuisofs_spe_buf_size = 1024 * 1024;
161 +module_param(spuisofs_spe_buf_size, ulong, 0);
163 +static unsigned long spuisofs_spe_trans_notify_mask = 0xf;
164 +module_param(spuisofs_spe_trans_notify_mask, ulong, 0);
166 +static unsigned long spuisofs_spe_resource_id = 6;
167 +module_param(spuisofs_spe_resource_id, ulong, 0);
169 +static int spuisofs_spe_buf_addr_32bit = 0;
170 +module_param(spuisofs_spe_buf_addr_32bit, int, 0);
173 + * spuisofs_spe_regs_read
175 +static ssize_t spuisofs_spe_regs_read(struct file *file, char __user *buffer,
176 + size_t size, loff_t *pos)
178 + struct inode *inode = file->f_path.dentry->d_inode;
179 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
181 + if (*pos >= inode->i_size)
184 + return simple_read_from_buffer(buffer, size, pos,
185 + si->virt_addr, inode->i_size);
189 + * spuisofs_spe_regs_write
191 +static ssize_t spuisofs_spe_regs_write(struct file *file, const char __user *buffer,
192 + size_t size, loff_t *pos)
194 + struct inode *inode = file->f_path.dentry->d_inode;
195 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
197 + if (*pos >= inode->i_size)
200 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
201 + pos, buffer, size);
205 + * spuisofs_spe_regs_mmap
207 +static int spuisofs_spe_regs_mmap(struct file *file, struct vm_area_struct *vma)
209 + struct inode *inode = file->f_path.dentry->d_inode;
210 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
211 + unsigned long size, pfn;
213 + size = vma->vm_end - vma->vm_start;
214 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
216 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
217 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
219 + vma->vm_flags |= VM_RESERVED | VM_IO;
221 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
223 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
226 +static const struct file_operations spuisofs_spe_regs_fops = {
227 + .read = spuisofs_spe_regs_read,
228 + .write = spuisofs_spe_regs_write,
229 + .mmap = spuisofs_spe_regs_mmap,
233 + * spuisofs_spe_mem_read
235 +static ssize_t spuisofs_spe_mem_read(struct file *file, char __user *buffer,
236 + size_t size, loff_t *pos)
238 + struct inode *inode = file->f_path.dentry->d_inode;
239 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
241 + if (*pos >= inode->i_size)
244 + return simple_read_from_buffer(buffer, size, pos,
245 + si->virt_addr, inode->i_size);
249 + * spuisofs_spe_mem_write
251 +static ssize_t spuisofs_spe_mem_write(struct file *file, const char __user *buffer,
252 + size_t size, loff_t *pos)
254 + struct inode *inode = file->f_path.dentry->d_inode;
255 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
257 + if (*pos >= inode->i_size)
260 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
261 + pos, buffer, size);
265 + * spuisofs_spe_mem_mmap
267 +static int spuisofs_spe_mem_mmap(struct file *file, struct vm_area_struct *vma)
269 + struct inode *inode = file->f_path.dentry->d_inode;
270 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
271 + unsigned long size, pfn;
273 + size = vma->vm_end - vma->vm_start;
274 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
276 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
277 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
279 + vma->vm_flags |= VM_RESERVED | VM_IO;
281 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
283 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
286 +static const struct file_operations spuisofs_spe_mem_fops = {
287 + .read = spuisofs_spe_mem_read,
288 + .write = spuisofs_spe_mem_write,
289 + .mmap = spuisofs_spe_mem_mmap,
293 + * spuisofs_mem_read
295 +static ssize_t spuisofs_mem_read(struct file *file, char __user *buffer,
296 + size_t size, loff_t *pos)
298 + struct inode *inode = file->f_path.dentry->d_inode;
299 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
301 + if (*pos >= inode->i_size)
304 + return simple_read_from_buffer(buffer, size, pos,
305 + si->virt_addr, inode->i_size);
309 + * spuisofs_mem_write
311 +static ssize_t spuisofs_mem_write(struct file *file, const char __user *buffer,
312 + size_t size, loff_t *pos)
314 + struct inode *inode = file->f_path.dentry->d_inode;
315 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
317 + if (*pos >= inode->i_size)
320 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
321 + pos, buffer, size);
325 + * spuisofs_mem_mmap
327 +static int spuisofs_mem_mmap(struct file *file, struct vm_area_struct *vma)
329 + struct inode *inode = file->f_path.dentry->d_inode;
330 + struct spuisofs_inode_info *si = SPUISOFS_I(inode);
332 + return remap_vmalloc_range(vma, si->virt_addr, 0);
335 +static const struct file_operations spuisofs_mem_fops = {
336 + .read = spuisofs_mem_read,
337 + .write = spuisofs_mem_write,
338 + .mmap = spuisofs_mem_mmap,
342 + * spuisofs_info_read
344 +static ssize_t spuisofs_info_read(struct file *file, char __user *buffer,
345 + size_t size, loff_t *pos)
349 + unsigned long spe_buf_addr;
351 + spe_buf_addr = (unsigned long) spuisofs_spe_buf;
353 + if (spuisofs_spe_buf_addr_32bit)
354 + spe_buf_addr &= 0xfffffffful;
356 + len = sprintf(buf, "arg1 %lx\narg2 %lx\nbuf %lx\n",
357 + (unsigned long) spuisofs_spe_arg1, (unsigned long) spuisofs_spe_arg2,
360 + return simple_read_from_buffer(buffer, size, pos, buf, len);
363 +static const struct file_operations spuisofs_info_fops = {
364 + .read = spuisofs_info_read,
368 + * spuisofs_run_write
370 +static ssize_t spuisofs_run_write(struct file *file, const char __user *buffer,
371 + size_t size, loff_t *pos)
373 + struct inode *inode = file->f_path.dentry->d_inode;
374 + struct spuisofs_run_args args;
377 + if (*pos || (size != inode->i_size))
380 + if (copy_from_user(&args, buffer, sizeof(struct spuisofs_run_args)))
383 + if (args.arg1_size == 0)
384 + args.arg1_size = spuisofs_spe_arg1_size;
386 + if (args.arg2_size == 0)
387 + args.arg2_size = spuisofs_spe_arg2_size;
389 + if (args.arg1_size > spuisofs_spe_arg1_size)
392 + if (args.arg2_size > spuisofs_spe_arg2_size)
395 + err = lv1_undocumented_function_201(spuisofs_spe_id);
397 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_201 failed with %d\n", err);
399 + err = lv1_undocumented_function_209(spuisofs_spe_id, args.laid, (u64) spuisofs_spe_app,
400 + (u64) spuisofs_spe_arg1, args.arg1_size,
401 + (u64) spuisofs_spe_arg2, args.arg2_size, spuisofs_spe_resource_id);
403 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_209 failed with %d\n", err);
410 +static const struct file_operations spuisofs_run_fops = {
411 + .write = spuisofs_run_write,
415 + * spuisofs_cont_write
417 +static ssize_t spuisofs_cont_write(struct file *file, const char __user *buffer,
418 + size_t size, loff_t *pos)
423 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
425 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
429 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
431 + err = lv1_undocumented_function_200(spuisofs_spe_id);
433 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_200 failed with %d\n", err);
440 +static const struct file_operations spuisofs_cont_fops = {
441 + .write = spuisofs_cont_write,
445 + * spuisofs_alloc_inode
447 +static struct inode *spuisofs_alloc_inode(struct super_block *sb)
449 + struct spuisofs_inode_info *si;
451 + si = kmem_cache_alloc(spuisofs_inode_cache, GFP_KERNEL);
455 + return (&si->vfs_inode);
459 + * spuisofs_i_callback
461 +static void spuisofs_i_callback(struct rcu_head *head)
463 + struct inode *inode = container_of(head, struct inode, i_rcu);
465 + kmem_cache_free(spuisofs_inode_cache, SPUISOFS_I(inode));
469 + * spuisofs_destroy_inode
471 +static void spuisofs_destroy_inode(struct inode *inode)
473 + call_rcu(&inode->i_rcu, spuisofs_i_callback);
477 + * spuisofs_init_once
479 +static void spuisofs_init_once(void *p)
481 + struct spuisofs_inode_info *si = p;
483 + inode_init_once(&si->vfs_inode);
487 + * spuisofs_new_inode
489 +static struct inode *spuisofs_new_inode(struct super_block *sb, umode_t mode)
491 + struct inode *inode;
493 + inode = new_inode(sb);
497 + inode->i_ino = get_next_ino();
498 + inode->i_mode = mode;
499 + inode->i_uid = current_fsuid();
500 + inode->i_gid = current_fsgid();
501 + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
509 +static int spuisofs_setattr(struct user_namespace *mnt_userns,
510 + struct dentry *dentry, struct iattr *attr)
512 + struct inode *inode = dentry->d_inode;
514 + setattr_copy(mnt_userns, inode, attr);
515 + mark_inode_dirty(inode);
520 +static const struct inode_operations spuisofs_inode_ops = {
521 + .setattr = spuisofs_setattr,
525 + * spuisofs_new_file
527 +static int spuisofs_new_file(struct super_block *sb, struct dentry *dentry,
528 + const struct file_operations *fops, umode_t mode, size_t size,
529 + unsigned long io_addr, void *virt_addr)
531 + struct inode *inode;
532 + struct spuisofs_inode_info *si;
534 + inode = spuisofs_new_inode(sb, S_IFREG | mode);
538 + inode->i_op = &spuisofs_inode_ops;
539 + inode->i_fop = fops;
540 + inode->i_size = size;
541 + inode->i_private = NULL;
543 + si = SPUISOFS_I(inode);
544 + si->io_addr = io_addr;
545 + si->virt_addr = virt_addr;
547 + d_add(dentry, inode);
553 + * spuisofs_fill_dir
555 +static int spuisofs_fill_dir(struct dentry *dir,
556 + const struct spuisofs_tree_descr *files)
558 + struct dentry *dentry, *tmp;
561 + while (files->name && files->name[0]) {
562 + dentry = d_alloc_name(dir, files->name);
568 + err = spuisofs_new_file(dir->d_sb, dentry, files->ops,
569 + files->mode, files->size, files->io_addr, files->virt_addr);
580 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child)
583 + shrink_dcache_parent(dir);
588 +static const struct super_operations spuisofs_super_ops = {
589 + .alloc_inode = spuisofs_alloc_inode,
590 + .destroy_inode = spuisofs_destroy_inode,
591 + .statfs = simple_statfs,
595 + * spuisofs_fill_super
597 +static int spuisofs_fill_super(struct super_block *sb, void *data, int silent)
599 + const struct spuisofs_tree_descr root_dir_contents[] = {
600 + { "priv2", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_priv2), spuisofs_spe_priv2_addr, spuisofs_spe_priv2, },
601 + { "problem", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_problem), spuisofs_spe_problem_addr, spuisofs_spe_problem, },
602 + { "ls", &spuisofs_spe_mem_fops, 0666, LS_SIZE, spuisofs_spe_ls_addr, spuisofs_spe_ls, },
603 + { "shadow", &spuisofs_spe_mem_fops, 0444, sizeof(struct spe_shadow), spuisofs_spe_shadow_addr, spuisofs_spe_shadow, },
604 + { "app", &spuisofs_mem_fops, 0666, spuisofs_spe_app_size, 0, spuisofs_spe_app, },
605 + { "arg1", &spuisofs_mem_fops, 0666, spuisofs_spe_arg1_size, 0, spuisofs_spe_arg1, },
606 + { "arg2", &spuisofs_mem_fops, 0666, spuisofs_spe_arg2_size, 0, spuisofs_spe_arg2, },
607 + { "buf", &spuisofs_mem_fops, 0666, spuisofs_spe_buf_size, 0, spuisofs_spe_buf, },
608 + { "info", &spuisofs_info_fops, 0444, 0, 0, NULL, },
609 + { "run", &spuisofs_run_fops, 0222, sizeof(struct spuisofs_run_args), 0, NULL, },
610 + { "cont", &spuisofs_cont_fops, 0222, 0, 0, NULL, },
613 + struct inode *root_inode;
616 + sb->s_maxbytes = MAX_LFS_FILESIZE;
617 + sb->s_blocksize = PAGE_SIZE;
618 + sb->s_blocksize_bits = PAGE_SHIFT;
619 + sb->s_magic = SPUISOFS_MAGIC;
620 + sb->s_op = &spuisofs_super_ops;
621 + sb->s_time_gran = 1;
623 + root_inode = spuisofs_new_inode(sb, S_IFDIR | 0755);
627 + root_inode->i_op = &simple_dir_inode_operations;
628 + root_inode->i_fop = &simple_dir_operations;
630 + /* directory inodes start off with i_nlink == 2 (for "." entry) */
631 + inc_nlink(root_inode);
633 + sb->s_root = d_make_root(root_inode);
637 + err = spuisofs_fill_dir(sb->s_root, root_dir_contents);
645 + * spuisofs_spe_ea_to_kernel_ea
647 +static unsigned long spuisofs_spe_ea_to_kernel_ea(unsigned long spe_ea)
649 + unsigned long kernel_ea, spe_buf_addr;
651 + kernel_ea = spe_ea;
653 + if (!spuisofs_spe_buf_addr_32bit)
654 + return (kernel_ea);
656 + spe_buf_addr = (unsigned long) spuisofs_spe_buf & 0xfffffffful;
658 + if ((spe_ea >= spe_buf_addr) && (spe_ea < (spe_buf_addr + spuisofs_spe_buf_size)))
659 + kernel_ea = (unsigned long) spuisofs_spe_buf + (spe_buf_addr - spe_ea);
661 + return (kernel_ea);
665 + * spuisofs_spe_interrupt
667 +static irqreturn_t spuisofs_spe_interrupt(int irq, void *data)
670 + u64 ea, kernel_ea, dsisr, esid, vsid;
673 + u64 spe_execution_status;
676 + if (irq == spuisofs_spe_virq[0]) {
677 + printk(KERN_INFO"spuisofs: got class 0 irq\n");
679 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 0, &status);
681 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
685 + printk(KERN_INFO"spuisofs: status %llx\n", status);
687 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 0, status, 0);
689 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
692 + } else if (irq == spuisofs_spe_virq[1]) {
693 + printk(KERN_INFO"spuisofs: got class 1 irq\n");
695 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 1, &status);
697 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
701 + printk(KERN_INFO"spuisofs: status %llx\n", status);
703 + if (status & CLASS1_SEGMENT_FAULT_INTR) {
704 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
705 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
707 + esid = (ea & ESID_MASK) | SLB_ESID_V;
708 + vsid = (get_kernel_vsid(kernel_ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K;
710 + printk(KERN_INFO"spuisofs: data segment fault at %llx (%llx)\n", ea, kernel_ea);
712 + err = lv1_undocumented_function_62(spuisofs_spe_id, 0, spuisofs_spe_slb_index, esid, vsid);
714 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_62 failed with %d\n", err);
718 + spuisofs_spe_slb_index++;
719 + if (spuisofs_spe_slb_index > SLB_INDEX_MASK)
720 + spuisofs_spe_slb_index = 0;
723 + if (status & CLASS1_STORAGE_FAULT_INTR) {
724 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
725 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
726 + dsisr = in_be64(&spuisofs_spe_shadow->mfc_dsisr_RW);
728 + printk(KERN_INFO"spuisofs: data storage fault at %llx (%llx)\n", ea, kernel_ea);
730 + if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
731 + err = hash_page(kernel_ea, _PAGE_PRESENT, 0x300, dsisr);
733 + printk(KERN_INFO"spuisofs: hash_page failed with %d\n", err);
739 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 1, status, 0);
741 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
747 + err = lv1_undocumented_function_168(spuisofs_spe_id, 0x3000, 1ull << 32);
749 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_168 failed with %d\n", err);
752 + } else if (irq == spuisofs_spe_virq[2]) {
753 + printk(KERN_INFO"spuisofs: got class 2 irq\n");
755 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 2, &status);
757 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
761 + printk(KERN_INFO"spuisofs: status %llx\n", status);
763 + if (status & CLASS2_MAILBOX_INTR) {
764 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
766 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
770 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
773 + if (status & CLASS2_SPU_STOP_INTR) {
774 + spu_status_R = in_be32(&spuisofs_spe_problem->spu_status_R);
776 + printk(KERN_INFO"spuisofs: spu_status_R %x\n", spu_status_R);
779 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 2, status, 0);
781 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
784 + } else if (irq == spuisofs_spe_virq[3]) {
785 + spe_execution_status = spuisofs_spe_shadow->spe_execution_status;
787 + printk(KERN_INFO"spuisofs: transition notification: shadow spe_execution_status %llx\n",
788 + spe_execution_status);
790 + printk(KERN_INFO"spuisofs: got unknown irq %d\n", irq);
795 + return (IRQ_HANDLED);
799 + * spuisofs_create_spe
801 +static int spuisofs_create_spe(void)
806 + err = lv1_get_virtual_address_space_id_of_ppe(&vas_id);
810 + printk(KERN_INFO"spuisofs: vas id %llu\n", vas_id);
812 + err = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT,
813 + PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, vas_id, 2,
814 + &spuisofs_spe_priv2_addr, &spuisofs_spe_problem_addr, &spuisofs_spe_ls_addr,
815 + &junk, &spuisofs_spe_shadow_addr, &spuisofs_spe_id);
819 + printk(KERN_INFO"spuisofs: spe id %llu\n", spuisofs_spe_id);
821 + spuisofs_spe_priv2 = ioremap(spuisofs_spe_priv2_addr, sizeof(struct spu_priv2));
822 + if (!spuisofs_spe_priv2) {
824 + goto fail_destruct_spe;
827 + spuisofs_spe_problem = ioremap(spuisofs_spe_problem_addr, sizeof(struct spu_problem));
828 + if (!spuisofs_spe_problem) {
830 + goto fail_unmap_priv2;
833 + spuisofs_spe_ls = ioremap(spuisofs_spe_ls_addr, LS_SIZE);
834 + if (!spuisofs_spe_ls) {
836 + goto fail_unmap_problem;
839 + spuisofs_spe_shadow = ioremap_prot(spuisofs_spe_shadow_addr, sizeof(struct spe_shadow),
840 + pgprot_val(pgprot_noncached_wc(PAGE_KERNEL_RO)));
841 + if (!spuisofs_spe_shadow) {
843 + goto fail_unmap_ls;
846 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 0, &spuisofs_spe_virq[0]);
849 + goto fail_unmap_shadow;
852 + err = request_irq(spuisofs_spe_virq[0], spuisofs_spe_interrupt, 0,
853 + "spuisofs_spe_irq0", &spuisofs_spe_virq[0]);
855 + goto fail_destroy_spe_irq_0;
857 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 1, &spuisofs_spe_virq[1]);
860 + goto fail_free_spe_irq_0;
863 + err = request_irq(spuisofs_spe_virq[1], spuisofs_spe_interrupt, 0,
864 + "spuisofs_spe_irq1", &spuisofs_spe_virq[1]);
866 + goto fail_destroy_spe_irq_1;
868 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 2, &spuisofs_spe_virq[2]);
871 + goto fail_free_spe_irq_1;
874 + err = request_irq(spuisofs_spe_virq[2], spuisofs_spe_interrupt, 0,
875 + "spuisofs_spe_irq2", &spuisofs_spe_virq[2]);
877 + goto fail_destroy_spe_irq_2;
879 + err = ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY, &spuisofs_spe_virq[3]);
882 + goto fail_free_spe_irq_2;
885 + err = lv1_set_spe_transition_notifier(spuisofs_spe_id, spuisofs_spe_trans_notify_mask,
886 + virq_to_hw(spuisofs_spe_virq[3]));
888 + printk(KERN_INFO"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err);
890 + goto fail_destroy_event_recv_port;
893 + err = request_irq(spuisofs_spe_virq[3], spuisofs_spe_interrupt, 0,
894 + "spuisofs_spe_irq3", &spuisofs_spe_virq[3]);
896 + goto fail_destroy_event_recv_port;
900 +fail_destroy_event_recv_port:
902 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
904 +fail_free_spe_irq_2:
906 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
908 +fail_destroy_spe_irq_2:
910 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
912 +fail_free_spe_irq_1:
914 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
916 +fail_destroy_spe_irq_1:
918 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
920 +fail_free_spe_irq_0:
922 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
924 +fail_destroy_spe_irq_0:
926 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
930 + iounmap(spuisofs_spe_shadow);
934 + iounmap(spuisofs_spe_ls);
938 + iounmap(spuisofs_spe_problem);
942 + iounmap(spuisofs_spe_priv2);
946 + lv1_destruct_logical_spe(spuisofs_spe_id);
952 + * spuisofs_destruct_spe
954 +static void spuisofs_destruct_spe(void)
956 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
957 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
959 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
960 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
962 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
963 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
965 + free_irq(spuisofs_spe_virq[3], &spuisofs_spe_virq[3]);
966 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
968 + iounmap(spuisofs_spe_shadow);
969 + iounmap(spuisofs_spe_ls);
970 + iounmap(spuisofs_spe_problem);
971 + iounmap(spuisofs_spe_priv2);
973 + lv1_destruct_logical_spe(spuisofs_spe_id);
979 +static struct dentry *spuisofs_mount(struct file_system_type *fs_type,
980 + int flags, const char *dev_name, void *data)
982 + struct dentry *root;
985 + err = spuisofs_create_spe();
987 + return ERR_PTR(err);
989 + spuisofs_spe_app = vmalloc_user(spuisofs_spe_app_size);
990 + if (!spuisofs_spe_app) {
992 + goto fail_destruct_spe;
995 + memset(spuisofs_spe_app, 0, spuisofs_spe_app_size);
997 + spuisofs_spe_arg1 = vmalloc_user(spuisofs_spe_arg1_size);
998 + if (!spuisofs_spe_arg1) {
1000 + goto fail_free_spe_app;
1003 + memset(spuisofs_spe_arg1, 0, spuisofs_spe_arg1_size);
1005 + spuisofs_spe_arg2 = vmalloc_user(spuisofs_spe_arg2_size);
1006 + if (!spuisofs_spe_arg2) {
1008 + goto fail_free_spe_arg1;
1011 + memset(spuisofs_spe_arg2, 0, spuisofs_spe_arg2_size);
1013 + spuisofs_spe_buf = vmalloc_user(spuisofs_spe_buf_size);
1014 + if (!spuisofs_spe_buf) {
1016 + goto fail_free_spe_arg2;
1019 + memset(spuisofs_spe_buf, 0, spuisofs_spe_buf_size);
1021 + root = mount_single(fs_type, flags, data, spuisofs_fill_super);
1022 + if (IS_ERR(root)) {
1023 + err = PTR_ERR(root);
1024 + goto fail_free_buf;
1031 + vfree(spuisofs_spe_buf);
1033 +fail_free_spe_arg2:
1035 + vfree(spuisofs_spe_arg2);
1037 +fail_free_spe_arg1:
1039 + vfree(spuisofs_spe_arg1);
1043 + vfree(spuisofs_spe_app);
1047 + spuisofs_destruct_spe();
1049 + return ERR_PTR(err);
1053 + * spuisofs_kill_sb
1055 +static void spuisofs_kill_sb(struct super_block *sb)
1057 + kill_litter_super(sb);
1059 + vfree(spuisofs_spe_app);
1060 + vfree(spuisofs_spe_arg1);
1061 + vfree(spuisofs_spe_arg2);
1062 + vfree(spuisofs_spe_buf);
1063 + spuisofs_destruct_spe();
1066 +static struct file_system_type spuisofs_type = {
1067 + .owner = THIS_MODULE,
1068 + .name = "spuisofs",
1069 + .mount = spuisofs_mount,
1070 + .kill_sb = spuisofs_kill_sb,
1076 +static int __init spuisofs_init(void)
1080 + spuisofs_inode_cache = kmem_cache_create("spuisofs_inode_cache",
1081 + sizeof(struct spuisofs_inode_info), 0, SLAB_HWCACHE_ALIGN,
1082 + spuisofs_init_once);
1083 + if (!spuisofs_inode_cache)
1086 + err = register_filesystem(&spuisofs_type);
1088 + goto fail_destroy_inode_cache;
1092 +fail_destroy_inode_cache:
1094 + kmem_cache_destroy(spuisofs_inode_cache);
1102 +static void __exit spuisofs_exit(void)
1104 + unregister_filesystem(&spuisofs_type);
1105 + kmem_cache_destroy(spuisofs_inode_cache);
1108 +module_init(spuisofs_init);
1109 +module_exit(spuisofs_exit);
1111 +MODULE_DESCRIPTION("PS3 spuisofs");
1112 +MODULE_AUTHOR("glevand");
1113 +MODULE_LICENSE("GPL");