* updated kollision (21.12.1 -> 21.12.2), untested
[t2-trunk.git] / architecture / powerpc64 / package / linux / 0220-spuisofs.patch
blob2cf05ddc117617e157ff0c2a19f4f420f5c4a107
1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # This copyright note is auto-generated by scripts/Create-CopyPatch.
3 #
4 # T2 SDE: architecture/powerpc64/package/.../0220-spuisofs.patch
5 # Copyright (C) 2020 The T2 SDE Project
6 #
7 # More information can be found in the files COPYING and README.
8 #
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
14 # version.
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
19 @@ -202,6 +202,13 @@
20 This support is required to access the PS3 ENCDEC device.
21 In general, all users will say Y or M.
23 +config SPUISO_FS
24 + tristate "PS3 isolated SPU file system"
25 + default m
26 + depends on PPC_PS3
27 + help
28 + The isolated SPU file system is used to execute isolated SPU modules.
30 config PS3GELIC_UDBG
31 bool "PS3 udbg output via UDP broadcasts on Ethernet"
32 depends on PPC_PS3
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
35 @@ -6,3 +6,5 @@
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
43 @@ -0,0 +1,1070 @@
44 +/*
45 + * PS3 spuisofs
46 + *
47 + * Copyright (C) 2012-2013 glevand <geoffrey.levand@mail.ru>
48 + * Copyright (C) 2021 René Rebe <rene@exactcode.de>
49 + * All rights reserved.
50 + *
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.
54 + *
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.
59 + *
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.
63 + */
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>
80 +#include <asm/ps3.h>
81 +#include <asm/spu.h>
82 +#include <asm/spu_priv1.h>
83 +#include <asm/lv1call.h>
85 +#define SPUISOFS_MAGIC 0x73707569
87 +struct spe_shadow {
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;
110 + void *virt_addr;
113 +struct spuisofs_tree_descr {
114 + const char *name;
115 + const struct file_operations *ops;
116 + umode_t mode;
117 + size_t size;
118 + unsigned long io_addr;
119 + void *virt_addr;
122 +#define SPUISOFS_I(inode) container_of(inode, struct spuisofs_inode_info, vfs_inode)
124 +struct spuisofs_run_args {
125 + u64 laid;
126 + u64 arg1_size;
127 + u64 arg2_size;
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
174 + */
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)
182 + return (0);
184 + return simple_read_from_buffer(buffer, size, pos,
185 + si->virt_addr, inode->i_size);
189 + * spuisofs_spe_regs_write
190 + */
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)
198 + return (-EFBIG);
200 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
201 + pos, buffer, size);
205 + * spuisofs_spe_regs_mmap
206 + */
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;
218 +#else
219 + vma->vm_flags |= VM_RESERVED | VM_IO;
220 +#endif
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
234 + */
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)
242 + return (0);
244 + return simple_read_from_buffer(buffer, size, pos,
245 + si->virt_addr, inode->i_size);
249 + * spuisofs_spe_mem_write
250 + */
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)
258 + return (-EFBIG);
260 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
261 + pos, buffer, size);
265 + * spuisofs_spe_mem_mmap
266 + */
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;
278 +#else
279 + vma->vm_flags |= VM_RESERVED | VM_IO;
280 +#endif
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
294 + */
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)
302 + return (0);
304 + return simple_read_from_buffer(buffer, size, pos,
305 + si->virt_addr, inode->i_size);
309 + * spuisofs_mem_write
310 + */
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)
318 + return (-EFBIG);
320 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
321 + pos, buffer, size);
325 + * spuisofs_mem_mmap
326 + */
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
343 + */
344 +static ssize_t spuisofs_info_read(struct file *file, char __user *buffer,
345 + size_t size, loff_t *pos)
347 + char buf[256];
348 + size_t len;
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,
358 + spe_buf_addr);
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
369 + */
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;
375 + int err;
377 + if (*pos || (size != inode->i_size))
378 + return (-EINVAL);
380 + if (copy_from_user(&args, buffer, sizeof(struct spuisofs_run_args)))
381 + return -EFAULT;
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)
390 + return (-EINVAL);
392 + if (args.arg2_size > spuisofs_spe_arg2_size)
393 + return (-EINVAL);
395 + err = lv1_undocumented_function_201(spuisofs_spe_id);
396 + if (err)
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);
402 + if (err) {
403 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_209 failed with %d\n", err);
404 + return (-ENXIO);
407 + return (size);
410 +static const struct file_operations spuisofs_run_fops = {
411 + .write = spuisofs_run_write,
415 + * spuisofs_cont_write
416 + */
417 +static ssize_t spuisofs_cont_write(struct file *file, const char __user *buffer,
418 + size_t size, loff_t *pos)
420 + u64 puint_mb_R;
421 + int err;
423 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
424 + if (err) {
425 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
426 + return (-ENXIO);
429 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
431 + err = lv1_undocumented_function_200(spuisofs_spe_id);
432 + if (err) {
433 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_200 failed with %d\n", err);
434 + return (-ENXIO);
437 + return (size);
440 +static const struct file_operations spuisofs_cont_fops = {
441 + .write = spuisofs_cont_write,
445 + * spuisofs_alloc_inode
446 + */
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);
452 + if (!si)
453 + return (NULL);
455 + return (&si->vfs_inode);
459 + * spuisofs_i_callback
460 + */
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
470 + */
471 +static void spuisofs_destroy_inode(struct inode *inode)
473 + call_rcu(&inode->i_rcu, spuisofs_i_callback);
477 + * spuisofs_init_once
478 + */
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
488 + */
489 +static struct inode *spuisofs_new_inode(struct super_block *sb, umode_t mode)
491 + struct inode *inode;
493 + inode = new_inode(sb);
494 + if (!inode)
495 + return (NULL);
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);
503 + return (inode);
507 + * spuisofs_setattr
508 + */
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);
517 + return (0);
520 +static const struct inode_operations spuisofs_inode_ops = {
521 + .setattr = spuisofs_setattr,
525 + * spuisofs_new_file
526 + */
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);
535 + if (!inode)
536 + return (-ENOMEM);
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);
549 + return (0);
553 + * spuisofs_fill_dir
554 + */
555 +static int spuisofs_fill_dir(struct dentry *dir,
556 + const struct spuisofs_tree_descr *files)
558 + struct dentry *dentry, *tmp;
559 + int err;
561 + while (files->name && files->name[0]) {
562 + dentry = d_alloc_name(dir, files->name);
563 + if (!dentry) {
564 + err = -ENOMEM;
565 + goto fail;
568 + err = spuisofs_new_file(dir->d_sb, dentry, files->ops,
569 + files->mode, files->size, files->io_addr, files->virt_addr);
570 + if (err)
571 + goto fail;
573 + files++;
576 + return (0);
578 +fail:
580 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child)
581 + dput(dentry);
583 + shrink_dcache_parent(dir);
585 + return (err);
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
596 + */
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, },
611 + { },
612 + };
613 + struct inode *root_inode;
614 + int err;
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);
624 + if (!root_inode)
625 + return (-ENOMEM);
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);
634 + if (!sb->s_root)
635 + return (-ENOMEM);
637 + err = spuisofs_fill_dir(sb->s_root, root_dir_contents);
638 + if (err)
639 + return (err);
641 + return (0);
645 + * spuisofs_spe_ea_to_kernel_ea
646 + */
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
666 + */
667 +static irqreturn_t spuisofs_spe_interrupt(int irq, void *data)
669 + u64 status;
670 + u64 ea, kernel_ea, dsisr, esid, vsid;
671 + u64 puint_mb_R;
672 + u32 spu_status_R;
673 + u64 spe_execution_status;
674 + int err;
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);
680 + if (err) {
681 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
682 + goto out;
685 + printk(KERN_INFO"spuisofs: status %llx\n", status);
687 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 0, status, 0);
688 + if (err) {
689 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
690 + goto out;
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);
696 + if (err) {
697 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
698 + goto out;
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);
713 + if (err) {
714 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_62 failed with %d\n", err);
715 + goto out;
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);
732 + if (err) {
733 + printk(KERN_INFO"spuisofs: hash_page failed with %d\n", err);
734 + goto out;
739 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 1, status, 0);
740 + if (err) {
741 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
742 + goto out;
745 + /* restart DMA */
747 + err = lv1_undocumented_function_168(spuisofs_spe_id, 0x3000, 1ull << 32);
748 + if (err) {
749 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_168 failed with %d\n", err);
750 + goto out;
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);
756 + if (err) {
757 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
758 + goto out;
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);
765 + if (err) {
766 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
767 + goto out;
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);
780 + if (err) {
781 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
782 + goto out;
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);
789 + } else {
790 + printk(KERN_INFO"spuisofs: got unknown irq %d\n", irq);
793 +out:
795 + return (IRQ_HANDLED);
799 + * spuisofs_create_spe
800 + */
801 +static int spuisofs_create_spe(void)
803 + u64 vas_id, junk;
804 + int err;
806 + err = lv1_get_virtual_address_space_id_of_ppe(&vas_id);
807 + if (err)
808 + return (-ENXIO);
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);
816 + if (err)
817 + return (-ENXIO);
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) {
823 + err = -ENOMEM;
824 + goto fail_destruct_spe;
827 + spuisofs_spe_problem = ioremap(spuisofs_spe_problem_addr, sizeof(struct spu_problem));
828 + if (!spuisofs_spe_problem) {
829 + err = -ENOMEM;
830 + goto fail_unmap_priv2;
833 + spuisofs_spe_ls = ioremap(spuisofs_spe_ls_addr, LS_SIZE);
834 + if (!spuisofs_spe_ls) {
835 + err = -ENOMEM;
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) {
842 + err = -ENOMEM;
843 + goto fail_unmap_ls;
846 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 0, &spuisofs_spe_virq[0]);
847 + if (err) {
848 + err = -ENXIO;
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]);
854 + if (err)
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]);
858 + if (err) {
859 + err = -ENXIO;
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]);
865 + if (err)
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]);
869 + if (err) {
870 + err = -ENXIO;
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]);
876 + if (err)
877 + goto fail_destroy_spe_irq_2;
879 + err = ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY, &spuisofs_spe_virq[3]);
880 + if (err) {
881 + err = -ENXIO;
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]));
887 + if (err) {
888 + printk(KERN_INFO"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err);
889 + err = -ENXIO;
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]);
895 + if (err)
896 + goto fail_destroy_event_recv_port;
898 + return (0);
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]);
928 +fail_unmap_shadow:
930 + iounmap(spuisofs_spe_shadow);
932 +fail_unmap_ls:
934 + iounmap(spuisofs_spe_ls);
936 +fail_unmap_problem:
938 + iounmap(spuisofs_spe_problem);
940 +fail_unmap_priv2:
942 + iounmap(spuisofs_spe_priv2);
944 +fail_destruct_spe:
946 + lv1_destruct_logical_spe(spuisofs_spe_id);
948 + return (err);
952 + * spuisofs_destruct_spe
953 + */
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);
977 + * spuisofs_mount
978 + */
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;
983 + int err;
985 + err = spuisofs_create_spe();
986 + if (err)
987 + return ERR_PTR(err);
989 + spuisofs_spe_app = vmalloc_user(spuisofs_spe_app_size);
990 + if (!spuisofs_spe_app) {
991 + err = -ENOMEM;
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) {
999 + err = -ENOMEM;
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) {
1007 + err = -ENOMEM;
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) {
1015 + err = -ENOMEM;
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;
1027 + return (root);
1029 +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);
1041 +fail_free_spe_app:
1043 + vfree(spuisofs_spe_app);
1045 +fail_destruct_spe:
1047 + spuisofs_destruct_spe();
1049 + return ERR_PTR(err);
1053 + * spuisofs_kill_sb
1054 + */
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,
1074 + * spuisofs_init
1075 + */
1076 +static int __init spuisofs_init(void)
1078 + int err;
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)
1084 + return (-ENOMEM);
1086 + err = register_filesystem(&spuisofs_type);
1087 + if (err)
1088 + goto fail_destroy_inode_cache;
1090 + return (0);
1092 +fail_destroy_inode_cache:
1094 + kmem_cache_destroy(spuisofs_inode_cache);
1096 + return (err);
1100 + * spuisofs_exit
1101 + */
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");