compare_ether_addr was removed in 3.14
[ps3linux_kernel_patches_314.git] / 0220-spuisofs.patch
blob1cabe9684df210758d1ca16c77f628afcc7b212f
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 2013-10-07 20:20:12.741358433 +0200
26 +++ b/arch/powerpc/platforms/ps3/spuisofs.c 2013-10-07 22:15:48.445095266 +0200
27 @@ -0,0 +1,1068 @@
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_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_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_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_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_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_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_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_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_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_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 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child)
563 + dput(dentry);
565 + shrink_dcache_parent(dir);
567 + return (err);
570 +static const struct super_operations spuisofs_super_ops = {
571 + .alloc_inode = spuisofs_alloc_inode,
572 + .destroy_inode = spuisofs_destroy_inode,
573 + .statfs = simple_statfs,
577 + * spuisofs_fill_super
578 + */
579 +static int spuisofs_fill_super(struct super_block *sb, void *data, int silent)
581 + const struct spuisofs_tree_descr root_dir_contents[] = {
582 + { "priv2", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_priv2), spuisofs_spe_priv2_addr, spuisofs_spe_priv2, },
583 + { "problem", &spuisofs_spe_regs_fops, 0666, sizeof(struct spu_problem), spuisofs_spe_problem_addr, spuisofs_spe_problem, },
584 + { "ls", &spuisofs_spe_mem_fops, 0666, LS_SIZE, spuisofs_spe_ls_addr, spuisofs_spe_ls, },
585 + { "shadow", &spuisofs_spe_mem_fops, 0444, sizeof(struct spe_shadow), spuisofs_spe_shadow_addr, spuisofs_spe_shadow, },
586 + { "app", &spuisofs_mem_fops, 0666, spuisofs_spe_app_size, 0, spuisofs_spe_app, },
587 + { "arg1", &spuisofs_mem_fops, 0666, spuisofs_spe_arg1_size, 0, spuisofs_spe_arg1, },
588 + { "arg2", &spuisofs_mem_fops, 0666, spuisofs_spe_arg2_size, 0, spuisofs_spe_arg2, },
589 + { "buf", &spuisofs_mem_fops, 0666, spuisofs_spe_buf_size, 0, spuisofs_spe_buf, },
590 + { "info", &spuisofs_info_fops, 0444, 0, 0, NULL, },
591 + { "run", &spuisofs_run_fops, 0222, sizeof(struct spuisofs_run_args), 0, NULL, },
592 + { "cont", &spuisofs_cont_fops, 0222, 0, 0, NULL, },
593 + { },
594 + };
595 + struct inode *root_inode;
596 + int err;
598 + sb->s_maxbytes = MAX_LFS_FILESIZE;
599 + sb->s_blocksize = PAGE_CACHE_SIZE;
600 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
601 + sb->s_magic = SPUISOFS_MAGIC;
602 + sb->s_op = &spuisofs_super_ops;
603 + sb->s_time_gran = 1;
605 + root_inode = spuisofs_new_inode(sb, S_IFDIR | 0755);
606 + if (!root_inode)
607 + return (-ENOMEM);
609 + root_inode->i_op = &simple_dir_inode_operations;
610 + root_inode->i_fop = &simple_dir_operations;
612 + /* directory inodes start off with i_nlink == 2 (for "." entry) */
613 + inc_nlink(root_inode);
615 + sb->s_root = d_make_root(root_inode);
616 + if (!sb->s_root)
617 + return (-ENOMEM);
619 + err = spuisofs_fill_dir(sb->s_root, root_dir_contents);
620 + if (err)
621 + return (err);
623 + return (0);
627 + * spuisofs_spe_ea_to_kernel_ea
628 + */
629 +static unsigned long spuisofs_spe_ea_to_kernel_ea(unsigned long spe_ea)
631 + unsigned long kernel_ea, spe_buf_addr;
633 + kernel_ea = spe_ea;
635 + if (!spuisofs_spe_buf_addr_32bit)
636 + return (kernel_ea);
638 + spe_buf_addr = (unsigned long) spuisofs_spe_buf & 0xfffffffful;
640 + if ((spe_ea >= spe_buf_addr) && (spe_ea < (spe_buf_addr + spuisofs_spe_buf_size)))
641 + kernel_ea = (unsigned long) spuisofs_spe_buf + (spe_buf_addr - spe_ea);
643 + return (kernel_ea);
647 + * spuisofs_spe_interrupt
648 + */
649 +static irqreturn_t spuisofs_spe_interrupt(int irq, void *data)
651 + u64 status;
652 + u64 ea, kernel_ea, dsisr, esid, vsid;
653 + u64 puint_mb_R;
654 + u32 spu_status_R;
655 + u64 spe_execution_status;
656 + int err;
658 + if (irq == spuisofs_spe_virq[0]) {
659 + printk(KERN_INFO"spuisofs: got class 0 irq\n");
661 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 0, &status);
662 + if (err) {
663 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
664 + goto out;
667 + printk(KERN_INFO"spuisofs: status %llx\n", status);
669 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 0, status, 0);
670 + if (err) {
671 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
672 + goto out;
674 + } else if (irq == spuisofs_spe_virq[1]) {
675 + printk(KERN_INFO"spuisofs: got class 1 irq\n");
677 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 1, &status);
678 + if (err) {
679 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
680 + goto out;
683 + printk(KERN_INFO"spuisofs: status %llx\n", status);
685 + if (status & CLASS1_SEGMENT_FAULT_INTR) {
686 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
687 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
689 + esid = (ea & ESID_MASK) | SLB_ESID_V;
690 + vsid = (get_kernel_vsid(kernel_ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K;
692 + printk(KERN_INFO"spuisofs: data segment fault at %llx (%llx)\n", ea, kernel_ea);
694 + err = lv1_undocumented_function_62(spuisofs_spe_id, 0, spuisofs_spe_slb_index, esid, vsid);
695 + if (err) {
696 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_62 failed with %d\n", err);
697 + goto out;
700 + spuisofs_spe_slb_index++;
701 + if (spuisofs_spe_slb_index > SLB_INDEX_MASK)
702 + spuisofs_spe_slb_index = 0;
705 + if (status & CLASS1_STORAGE_FAULT_INTR) {
706 + ea = in_be64(&spuisofs_spe_shadow->mfc_dar_RW);
707 + kernel_ea = spuisofs_spe_ea_to_kernel_ea(ea);
708 + dsisr = in_be64(&spuisofs_spe_shadow->mfc_dsisr_RW);
710 + printk(KERN_INFO"spuisofs: data storage fault at %llx (%llx)\n", ea, kernel_ea);
712 + if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
713 + err = hash_page(kernel_ea, _PAGE_PRESENT, 0x300);
714 + if (err) {
715 + printk(KERN_INFO"spuisofs: hash_page failed with %d\n", err);
716 + goto out;
721 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 1, status, 0);
722 + if (err) {
723 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
724 + goto out;
727 + /* restart DMA */
729 + err = lv1_undocumented_function_168(spuisofs_spe_id, 0x3000, 1ull << 32);
730 + if (err) {
731 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_168 failed with %d\n", err);
732 + goto out;
734 + } else if (irq == spuisofs_spe_virq[2]) {
735 + printk(KERN_INFO"spuisofs: got class 2 irq\n");
737 + err = lv1_get_spe_interrupt_status(spuisofs_spe_id, 2, &status);
738 + if (err) {
739 + printk(KERN_INFO"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err);
740 + goto out;
743 + printk(KERN_INFO"spuisofs: status %llx\n", status);
745 + if (status & CLASS2_MAILBOX_INTR) {
746 + err = lv1_undocumented_function_167(spuisofs_spe_id, 0x4000, &puint_mb_R);
747 + if (err) {
748 + printk(KERN_INFO"spuisofs: lv1_undocumented_function_167 failed with %d\n", err);
749 + goto out;
752 + printk(KERN_INFO"spuisofs: puint_mb_R %llx\n", puint_mb_R);
755 + if (status & CLASS2_SPU_STOP_INTR) {
756 + spu_status_R = in_be32(&spuisofs_spe_problem->spu_status_R);
758 + printk(KERN_INFO"spuisofs: spu_status_R %x\n", spu_status_R);
761 + err = lv1_clear_spe_interrupt_status(spuisofs_spe_id, 2, status, 0);
762 + if (err) {
763 + printk(KERN_INFO"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err);
764 + goto out;
766 + } else if (irq == spuisofs_spe_virq[3]) {
767 + spe_execution_status = spuisofs_spe_shadow->spe_execution_status;
769 + printk(KERN_INFO"spuisofs: transition notification: shadow spe_execution_status %llx\n",
770 + spe_execution_status);
771 + } else {
772 + printk(KERN_INFO"spuisofs: got unknown irq %d\n", irq);
775 +out:
777 + return (IRQ_HANDLED);
781 + * spuisofs_create_spe
782 + */
783 +static int spuisofs_create_spe(void)
785 + u64 vas_id, junk;
786 + int err;
788 + err = lv1_get_virtual_address_space_id_of_ppe(&vas_id);
789 + if (err)
790 + return (-ENXIO);
792 + printk(KERN_INFO"spuisofs: vas id %llu\n", vas_id);
794 + err = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT,
795 + PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, vas_id, 2,
796 + &spuisofs_spe_priv2_addr, &spuisofs_spe_problem_addr, &spuisofs_spe_ls_addr,
797 + &junk, &spuisofs_spe_shadow_addr, &spuisofs_spe_id);
798 + if (err)
799 + return (-ENXIO);
801 + printk(KERN_INFO"spuisofs: spe id %llu\n", spuisofs_spe_id);
803 + spuisofs_spe_priv2 = ioremap(spuisofs_spe_priv2_addr, sizeof(struct spu_priv2));
804 + if (!spuisofs_spe_priv2) {
805 + err = -ENOMEM;
806 + goto fail_destruct_spe;
809 + spuisofs_spe_problem = ioremap(spuisofs_spe_problem_addr, sizeof(struct spu_problem));
810 + if (!spuisofs_spe_problem) {
811 + err = -ENOMEM;
812 + goto fail_unmap_priv2;
815 + spuisofs_spe_ls = ioremap_prot(spuisofs_spe_ls_addr, LS_SIZE, _PAGE_NO_CACHE);
816 + if (!spuisofs_spe_ls) {
817 + err = -ENOMEM;
818 + goto fail_unmap_problem;
821 + spuisofs_spe_shadow = __ioremap(spuisofs_spe_shadow_addr, sizeof(struct spe_shadow),
822 + _PAGE_NO_CACHE | 3);
823 + if (!spuisofs_spe_shadow) {
824 + err = -ENOMEM;
825 + goto fail_unmap_ls;
828 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 0, &spuisofs_spe_virq[0]);
829 + if (err) {
830 + err = -ENXIO;
831 + goto fail_unmap_shadow;
834 + err = request_irq(spuisofs_spe_virq[0], spuisofs_spe_interrupt, 0,
835 + "spuisofs_spe_irq0", &spuisofs_spe_virq[0]);
836 + if (err)
837 + goto fail_destroy_spe_irq_0;
839 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 1, &spuisofs_spe_virq[1]);
840 + if (err) {
841 + err = -ENXIO;
842 + goto fail_free_spe_irq_0;
845 + err = request_irq(spuisofs_spe_virq[1], spuisofs_spe_interrupt, 0,
846 + "spuisofs_spe_irq1", &spuisofs_spe_virq[1]);
847 + if (err)
848 + goto fail_destroy_spe_irq_1;
850 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuisofs_spe_id, 2, &spuisofs_spe_virq[2]);
851 + if (err) {
852 + err = -ENXIO;
853 + goto fail_free_spe_irq_1;
856 + err = request_irq(spuisofs_spe_virq[2], spuisofs_spe_interrupt, 0,
857 + "spuisofs_spe_irq2", &spuisofs_spe_virq[2]);
858 + if (err)
859 + goto fail_destroy_spe_irq_2;
861 + err = ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY, &spuisofs_spe_virq[3]);
862 + if (err) {
863 + err = -ENXIO;
864 + goto fail_free_spe_irq_2;
867 + err = lv1_set_spe_transition_notifier(spuisofs_spe_id, spuisofs_spe_trans_notify_mask,
868 + virq_to_hw(spuisofs_spe_virq[3]));
869 + if (err) {
870 + printk(KERN_INFO"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err);
871 + err = -ENXIO;
872 + goto fail_destroy_event_recv_port;
875 + err = request_irq(spuisofs_spe_virq[3], spuisofs_spe_interrupt, 0,
876 + "spuisofs_spe_irq3", &spuisofs_spe_virq[3]);
877 + if (err)
878 + goto fail_destroy_event_recv_port;
880 + return (0);
882 +fail_destroy_event_recv_port:
884 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
886 +fail_free_spe_irq_2:
888 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
890 +fail_destroy_spe_irq_2:
892 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
894 +fail_free_spe_irq_1:
896 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
898 +fail_destroy_spe_irq_1:
900 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
902 +fail_free_spe_irq_0:
904 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
906 +fail_destroy_spe_irq_0:
908 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
910 +fail_unmap_shadow:
912 + iounmap(spuisofs_spe_shadow);
914 +fail_unmap_ls:
916 + iounmap(spuisofs_spe_ls);
918 +fail_unmap_problem:
920 + iounmap(spuisofs_spe_problem);
922 +fail_unmap_priv2:
924 + iounmap(spuisofs_spe_priv2);
926 +fail_destruct_spe:
928 + lv1_destruct_logical_spe(spuisofs_spe_id);
930 + return (err);
934 + * spuisofs_destruct_spe
935 + */
936 +static void spuisofs_destruct_spe(void)
938 + free_irq(spuisofs_spe_virq[0], &spuisofs_spe_virq[0]);
939 + ps3_spe_irq_destroy(spuisofs_spe_virq[0]);
941 + free_irq(spuisofs_spe_virq[1], &spuisofs_spe_virq[1]);
942 + ps3_spe_irq_destroy(spuisofs_spe_virq[1]);
944 + free_irq(spuisofs_spe_virq[2], &spuisofs_spe_virq[2]);
945 + ps3_spe_irq_destroy(spuisofs_spe_virq[2]);
947 + free_irq(spuisofs_spe_virq[3], &spuisofs_spe_virq[3]);
948 + ps3_event_receive_port_destroy(spuisofs_spe_virq[3]);
950 + iounmap(spuisofs_spe_shadow);
951 + iounmap(spuisofs_spe_ls);
952 + iounmap(spuisofs_spe_problem);
953 + iounmap(spuisofs_spe_priv2);
955 + lv1_destruct_logical_spe(spuisofs_spe_id);
959 + * spuisofs_mount
960 + */
961 +static struct dentry *spuisofs_mount(struct file_system_type *fs_type,
962 + int flags, const char *dev_name, void *data)
964 + struct dentry *root;
965 + int err;
967 + err = spuisofs_create_spe();
968 + if (err)
969 + return ERR_PTR(err);
971 + spuisofs_spe_app = vmalloc_user(spuisofs_spe_app_size);
972 + if (!spuisofs_spe_app) {
973 + err = -ENOMEM;
974 + goto fail_destruct_spe;
977 + memset(spuisofs_spe_app, 0, spuisofs_spe_app_size);
979 + spuisofs_spe_arg1 = vmalloc_user(spuisofs_spe_arg1_size);
980 + if (!spuisofs_spe_arg1) {
981 + err = -ENOMEM;
982 + goto fail_free_spe_app;
985 + memset(spuisofs_spe_arg1, 0, spuisofs_spe_arg1_size);
987 + spuisofs_spe_arg2 = vmalloc_user(spuisofs_spe_arg2_size);
988 + if (!spuisofs_spe_arg2) {
989 + err = -ENOMEM;
990 + goto fail_free_spe_arg1;
993 + memset(spuisofs_spe_arg2, 0, spuisofs_spe_arg2_size);
995 + spuisofs_spe_buf = vmalloc_user(spuisofs_spe_buf_size);
996 + if (!spuisofs_spe_buf) {
997 + err = -ENOMEM;
998 + goto fail_free_spe_arg2;
1001 + memset(spuisofs_spe_buf, 0, spuisofs_spe_buf_size);
1003 + root = mount_single(fs_type, flags, data, spuisofs_fill_super);
1004 + if (IS_ERR(root)) {
1005 + err = PTR_ERR(root);
1006 + goto fail_free_buf;
1009 + return (root);
1011 +fail_free_buf:
1013 + vfree(spuisofs_spe_buf);
1015 +fail_free_spe_arg2:
1017 + vfree(spuisofs_spe_arg2);
1019 +fail_free_spe_arg1:
1021 + vfree(spuisofs_spe_arg1);
1023 +fail_free_spe_app:
1025 + vfree(spuisofs_spe_app);
1027 +fail_destruct_spe:
1029 + spuisofs_destruct_spe();
1031 + return ERR_PTR(err);
1035 + * spuisofs_kill_sb
1036 + */
1037 +static void spuisofs_kill_sb(struct super_block *sb)
1039 + kill_litter_super(sb);
1041 + vfree(spuisofs_spe_app);
1042 + vfree(spuisofs_spe_arg1);
1043 + vfree(spuisofs_spe_arg2);
1044 + vfree(spuisofs_spe_buf);
1045 + spuisofs_destruct_spe();
1048 +static struct file_system_type spuisofs_type = {
1049 + .owner = THIS_MODULE,
1050 + .name = "spuisofs",
1051 + .mount = spuisofs_mount,
1052 + .kill_sb = spuisofs_kill_sb,
1056 + * spuisofs_init
1057 + */
1058 +static int __init spuisofs_init(void)
1060 + int err;
1062 + spuisofs_inode_cache = kmem_cache_create("spuisofs_inode_cache",
1063 + sizeof(struct spuisofs_inode_info), 0, SLAB_HWCACHE_ALIGN,
1064 + spuisofs_init_once);
1065 + if (!spuisofs_inode_cache)
1066 + return (-ENOMEM);
1068 + err = register_filesystem(&spuisofs_type);
1069 + if (err)
1070 + goto fail_destroy_inode_cache;
1072 + return (0);
1074 +fail_destroy_inode_cache:
1076 + kmem_cache_destroy(spuisofs_inode_cache);
1078 + return (err);
1082 + * spuisofs_exit
1083 + */
1084 +static void __exit spuisofs_exit(void)
1086 + unregister_filesystem(&spuisofs_type);
1087 + kmem_cache_destroy(spuisofs_inode_cache);
1090 +module_init(spuisofs_init);
1091 +module_exit(spuisofs_exit);
1093 +MODULE_DESCRIPTION("PS3 spuisofs");
1094 +MODULE_AUTHOR("glevand");
1095 +MODULE_LICENSE("GPL");