1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # This copyright note is auto-generated by scripts/Create-CopyPatch.
4 # T2 SDE: architecture/powerpc64/package/.../0230-spuldrfs.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-16 21:28:29.947236099 +0200
18 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-08-16 21:30:29.967243082 +0200
21 The isolated SPU file system is used to execute isolated SPU modules.
24 + tristate "PS3 isolated SPU loader file system"
28 + The isolated SPU loader file system is used to execute isolated SPU loaders.
31 bool "PS3 udbg output via UDP broadcasts on Ethernet"
33 --- a/arch/powerpc/platforms/ps3/Makefile 2012-08-16 21:28:29.947236099 +0200
34 +++ b/arch/powerpc/platforms/ps3/Makefile 2012-08-16 21:30:54.793911193 +0200
36 obj-y += device-init.o
38 obj-$(CONFIG_SPUISO_FS) += spuisofs.o
39 +obj-$(CONFIG_SPULDR_FS) += spuldrfs.o
40 --- /dev/null 2013-10-07 20:20:12.741358433 +0200
41 +++ b/arch/powerpc/platforms/ps3/spuldrfs.c 2013-10-07 22:16:03.015096113 +0200
46 + * Copyright (C) 2012 glevand <geoffrey.levand@mail.ru>
47 + * Copyright (C) 2021 René Rebe <rene@exactcode.de>
48 + * All rights reserved.
50 + * This program is free software; you can redistribute it and/or modify it
51 + * under the terms of the GNU General Public License as published
52 + * by the Free Software Foundation; version 2 of the License.
54 + * This program is distributed in the hope that it will be useful, but
55 + * WITHOUT ANY WARRANTY; without even the implied warranty of
56 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57 + * General Public License for more details.
59 + * You should have received a copy of the GNU General Public License along
60 + * with this program; if not, write to the Free Software Foundation, Inc.,
61 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
64 +#include <linux/module.h>
65 +#include <linux/kernel.h>
66 +#include <linux/version.h>
67 +#include <linux/init.h>
68 +#include <linux/fs.h>
69 +#include <linux/fsnotify.h>
70 +#include <linux/file.h>
71 +#include <linux/slab.h>
72 +#include <linux/vmalloc.h>
73 +#include <linux/pagemap.h>
74 +#include <linux/io.h>
75 +#include <linux/interrupt.h>
76 +#include <linux/time.h>
78 +#include <asm/uaccess.h>
81 +#include <asm/spu_priv1.h>
82 +#include <asm/lv1call.h>
84 +#define SPULDRFS_MAGIC 0x7370756c
87 + u8 padding_0140[0x0140];
88 + u64 int_status_class0_RW; /* 0x0140 */
89 + u64 int_status_class1_RW; /* 0x0148 */
90 + u64 int_status_class2_RW; /* 0x0150 */
91 + u8 padding_0158[0x0610-0x0158];
92 + u64 mfc_dsisr_RW; /* 0x0610 */
93 + u8 padding_0618[0x0620-0x0618];
94 + u64 mfc_dar_RW; /* 0x0620 */
95 + u8 padding_0628[0x0800-0x0628];
96 + u64 mfc_dsipr_R; /* 0x0800 */
97 + u8 padding_0808[0x0810-0x0808];
98 + u64 mfc_lscrr_R; /* 0x0810 */
99 + u8 padding_0818[0x0c00-0x0818];
100 + u64 mfc_cer_R; /* 0x0c00 */
101 + u8 padding_0c08[0x0f00-0x0c08];
102 + u64 spe_execution_status; /* 0x0f00 */
103 + u8 padding_0f08[0x1000-0x0f08];
106 +struct spuldrfs_inode_info {
107 + struct inode vfs_inode;
108 + unsigned long io_addr;
112 +struct spuldrfs_tree_descr {
114 + const struct file_operations *ops;
117 + unsigned long io_addr;
121 +#define SPULDRFS_I(inode) container_of(inode, struct spuldrfs_inode_info, vfs_inode)
123 +static struct kmem_cache *spuldrfs_inode_cache;
125 +static u64 spuldrfs_spe_priv2_addr;
126 +static u64 spuldrfs_spe_problem_addr;
127 +static u64 spuldrfs_spe_ls_addr;
128 +static u64 spuldrfs_spe_shadow_addr;
130 +static struct spu_priv2 *spuldrfs_spe_priv2;
131 +static struct spu_problem *spuldrfs_spe_problem;
132 +static void *spuldrfs_spe_ls;
133 +static struct spe_shadow *spuldrfs_spe_shadow;
134 +static u64 spuldrfs_spe_id;
135 +static unsigned int spuldrfs_spe_virq[4];
137 +static void *spuldrfs_spe_metldr;
138 +static void *spuldrfs_spe_ldr;
139 +static void *spuldrfs_spe_buf1;
140 +static void *spuldrfs_spe_buf2;
141 +static void *spuldrfs_spe_buf3;
143 +static unsigned int spuldrfs_spe_slb_index;
145 +static unsigned long spuldrfs_spe_metldr_size = 1024 * 1024;
146 +module_param(spuldrfs_spe_metldr_size, ulong, 0);
148 +static unsigned long spuldrfs_spe_ldr_size = 1024 * 1024;
149 +module_param(spuldrfs_spe_ldr_size, ulong, 0);
151 +static unsigned long spuldrfs_spe_buf1_size = 1024 * 1024;
152 +module_param(spuldrfs_spe_buf1_size, ulong, 0);
154 +static unsigned long spuldrfs_spe_buf2_size = 1024 * 1024;
155 +module_param(spuldrfs_spe_buf2_size, ulong, 0);
157 +static unsigned long spuldrfs_spe_buf3_size = 1024 * 1024;
158 +module_param(spuldrfs_spe_buf3_size, ulong, 0);
160 +static unsigned long spuldrfs_spe_trans_notify_mask = 0x7;
161 +module_param(spuldrfs_spe_trans_notify_mask, ulong, 0);
163 +static unsigned long spuldrfs_spe_resource_id = 6;
164 +module_param(spuldrfs_spe_resource_id, ulong, 0);
166 +static int spuldrfs_spe_buf_addr_32bit = 0;
167 +module_param(spuldrfs_spe_buf_addr_32bit, int, 0);
170 + * spuldrfs_spe_regs_read
172 +static ssize_t spuldrfs_spe_regs_read(struct file *file, char __user *buffer,
173 + size_t size, loff_t *pos)
175 + struct inode *inode = file->f_path.dentry->d_inode;
176 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
178 + if (*pos >= inode->i_size)
181 + return simple_read_from_buffer(buffer, size, pos,
182 + si->virt_addr, inode->i_size);
186 + * spuldrfs_spe_regs_write
188 +static ssize_t spuldrfs_spe_regs_write(struct file *file, const char __user *buffer,
189 + size_t size, loff_t *pos)
191 + struct inode *inode = file->f_path.dentry->d_inode;
192 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
194 + if (*pos >= inode->i_size)
197 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
198 + pos, buffer, size);
202 + * spuldrfs_spe_regs_mmap
204 +static int spuldrfs_spe_regs_mmap(struct file *file, struct vm_area_struct *vma)
206 + struct inode *inode = file->f_path.dentry->d_inode;
207 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
208 + unsigned long size, pfn;
210 + size = vma->vm_end - vma->vm_start;
211 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
213 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
214 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
216 + vma->vm_flags |= VM_RESERVED | VM_IO;
218 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
220 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
223 +static const struct file_operations spuldrfs_spe_regs_fops = {
224 + .read = spuldrfs_spe_regs_read,
225 + .write = spuldrfs_spe_regs_write,
226 + .mmap = spuldrfs_spe_regs_mmap,
230 + * spuldrfs_spe_mem_read
232 +static ssize_t spuldrfs_spe_mem_read(struct file *file, char __user *buffer,
233 + size_t size, loff_t *pos)
235 + struct inode *inode = file->f_path.dentry->d_inode;
236 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
238 + if (*pos >= inode->i_size)
241 + return simple_read_from_buffer(buffer, size, pos,
242 + si->virt_addr, inode->i_size);
246 + * spuldrfs_spe_mem_write
248 +static ssize_t spuldrfs_spe_mem_write(struct file *file, const char __user *buffer,
249 + size_t size, loff_t *pos)
251 + struct inode *inode = file->f_path.dentry->d_inode;
252 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
254 + if (*pos >= inode->i_size)
257 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
258 + pos, buffer, size);
262 + * spuldrfs_spe_mem_mmap
264 +static int spuldrfs_spe_mem_mmap(struct file *file, struct vm_area_struct *vma)
266 + struct inode *inode = file->f_path.dentry->d_inode;
267 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
268 + unsigned long size, pfn;
270 + size = vma->vm_end - vma->vm_start;
271 + pfn = (si->io_addr >> PAGE_SHIFT) + vma->vm_pgoff;
273 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
274 + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
276 + vma->vm_flags |= VM_RESERVED | VM_IO;
278 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
280 + return io_remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
283 +static const struct file_operations spuldrfs_spe_mem_fops = {
284 + .read = spuldrfs_spe_mem_read,
285 + .write = spuldrfs_spe_mem_write,
286 + .mmap = spuldrfs_spe_mem_mmap,
290 + * spuldrfs_mem_read
292 +static ssize_t spuldrfs_mem_read(struct file *file, char __user *buffer,
293 + size_t size, loff_t *pos)
295 + struct inode *inode = file->f_path.dentry->d_inode;
296 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
298 + if (*pos >= inode->i_size)
301 + return simple_read_from_buffer(buffer, size, pos,
302 + si->virt_addr, inode->i_size);
306 + * spuldrfs_mem_write
308 +static ssize_t spuldrfs_mem_write(struct file *file, const char __user *buffer,
309 + size_t size, loff_t *pos)
311 + struct inode *inode = file->f_path.dentry->d_inode;
312 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
314 + if (*pos >= inode->i_size)
317 + return simple_write_to_buffer(si->virt_addr, inode->i_size,
318 + pos, buffer, size);
322 + * spuldrfs_mem_mmap
324 +static int spuldrfs_mem_mmap(struct file *file, struct vm_area_struct *vma)
326 + struct inode *inode = file->f_path.dentry->d_inode;
327 + struct spuldrfs_inode_info *si = SPULDRFS_I(inode);
329 + return remap_vmalloc_range(vma, si->virt_addr, 0);
332 +static const struct file_operations spuldrfs_mem_fops = {
333 + .read = spuldrfs_mem_read,
334 + .write = spuldrfs_mem_write,
335 + .mmap = spuldrfs_mem_mmap,
339 + * spuldrfs_info_read
341 +static ssize_t spuldrfs_info_read(struct file *file, char __user *buffer,
342 + size_t size, loff_t *pos)
346 + unsigned long spe_buf1_addr, spe_buf2_addr, spe_buf3_addr;
348 + spe_buf1_addr = (unsigned long) spuldrfs_spe_buf1;
349 + spe_buf2_addr = (unsigned long) spuldrfs_spe_buf2;
350 + spe_buf3_addr = (unsigned long) spuldrfs_spe_buf3;
352 + if (spuldrfs_spe_buf_addr_32bit) {
353 + spe_buf1_addr &= 0xfffffffful;
354 + spe_buf2_addr &= 0xfffffffful;
355 + spe_buf3_addr &= 0xfffffffful;
358 + len = sprintf(buf, "buf1 %lx\nbuf2 %lx\nbuf3 %lx",
359 + spe_buf1_addr, spe_buf2_addr, spe_buf3_addr);
361 + return simple_read_from_buffer(buffer, size, pos, buf, len);
364 +static const struct file_operations spuldrfs_info_fops = {
365 + .read = spuldrfs_info_read,
369 + * spuldrfs_run_write
371 +static ssize_t spuldrfs_run_write(struct file *file, const char __user *buffer,
372 + size_t size, loff_t *pos)
379 + err = lv1_disable_logical_spe(spuldrfs_spe_id, 0);
381 + printk(KERN_INFO"spuldrfs: lv1_disable_logical_spe failed with %d\n", err);
383 + err = lv1_enable_logical_spe(spuldrfs_spe_id, spuldrfs_spe_resource_id);
385 + printk(KERN_INFO"spuldrfs: lv1_enable_logical_spe failed with %d\n", err);
389 + out_be32(&spuldrfs_spe_problem->spu_runcntl_RW, SPU_RUNCNTL_ISOLATE | SPU_RUNCNTL_STOP);
391 + /* enable interrupts */
393 + err = lv1_set_spe_interrupt_mask(spuldrfs_spe_id, 0, 0x7);
395 + printk(KERN_INFO"spuldrfs: lv1_set_spe_interrupt_mask failed with %d\n", err);
399 + err = lv1_set_spe_interrupt_mask(spuldrfs_spe_id, 1, 0xf);
401 + printk(KERN_INFO"spuldrfs: lv1_set_spe_interrupt_mask failed with %d\n", err);
405 + err = lv1_set_spe_interrupt_mask(spuldrfs_spe_id, 2, 0xf);
407 + printk(KERN_INFO"spuldrfs: lv1_set_spe_interrupt_mask failed with %d\n", err);
411 + err = lv1_set_spe_privilege_state_area_1_register(spuldrfs_spe_id, offsetof(struct spu_priv1, mfc_sr1_RW),
412 + MFC_STATE1_RELOCATE_MASK);
414 + printk(KERN_INFO"spuldrfs: lv1_set_spe_privilege_state_area_1_register failed with %d\n", err);
418 + /* invalidate all SLB entries */
420 + out_be64(&spuldrfs_spe_priv2->slb_invalidate_all_W, 0);
422 + for (i = 0; i <= SLB_INDEX_MASK; i++) {
423 + out_be64(&spuldrfs_spe_priv2->slb_index_W, i);
424 + out_be64(&spuldrfs_spe_priv2->slb_vsid_RW, 0);
425 + out_be64(&spuldrfs_spe_priv2->slb_esid_RW, 0);
428 + out_be64(&spuldrfs_spe_priv2->spu_cfg_RW, 0);
430 + out_be32(&spuldrfs_spe_problem->spu_mb_W, (unsigned long) spuldrfs_spe_ldr >> 32);
431 + out_be32(&spuldrfs_spe_problem->spu_mb_W, (unsigned long) spuldrfs_spe_ldr);
433 + out_be32(&spuldrfs_spe_problem->signal_notify1, (unsigned long) spuldrfs_spe_metldr >> 32);
434 + out_be32(&spuldrfs_spe_problem->signal_notify2, (unsigned long) spuldrfs_spe_metldr);
436 + out_be64(&spuldrfs_spe_priv2->spu_privcntl_RW, SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK);
438 + out_be32(&spuldrfs_spe_problem->spu_runcntl_RW, SPU_RUNCNTL_ISOLATE | SPU_RUNCNTL_RUNNABLE);
443 +static const struct file_operations spuldrfs_run_fops = {
444 + .write = spuldrfs_run_write,
448 + * spuldrfs_alloc_inode
450 +static struct inode *spuldrfs_alloc_inode(struct super_block *sb)
452 + struct spuldrfs_inode_info *si;
454 + si = kmem_cache_alloc(spuldrfs_inode_cache, GFP_KERNEL);
458 + return (&si->vfs_inode);
462 + * spuldrfs_i_callback
464 +static void spuldrfs_i_callback(struct rcu_head *head)
466 + struct inode *inode = container_of(head, struct inode, i_rcu);
468 + kmem_cache_free(spuldrfs_inode_cache, SPULDRFS_I(inode));
472 + * spuldrfs_destroy_inode
474 +static void spuldrfs_destroy_inode(struct inode *inode)
476 + call_rcu(&inode->i_rcu, spuldrfs_i_callback);
480 + * spuldrfs_init_once
482 +static void spuldrfs_init_once(void *p)
484 + struct spuldrfs_inode_info *si = p;
486 + inode_init_once(&si->vfs_inode);
490 + * spuldrfs_new_inode
492 +static struct inode *spuldrfs_new_inode(struct super_block *sb, umode_t mode)
494 + struct inode *inode;
496 + inode = new_inode(sb);
500 + inode->i_ino = get_next_ino();
501 + inode->i_mode = mode;
502 + inode->i_uid = current_fsuid();
503 + inode->i_gid = current_fsgid();
504 + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
512 +static int spuldrfs_setattr(struct user_namespace *mnt_userns,
513 + struct dentry *dentry, struct iattr *attr)
515 + struct inode *inode = dentry->d_inode;
517 + setattr_copy(mnt_userns, inode, attr);
518 + mark_inode_dirty(inode);
523 +static const struct inode_operations spuldrfs_inode_ops = {
524 + .setattr = spuldrfs_setattr,
528 + * spuldrfs_new_file
530 +static int spuldrfs_new_file(struct super_block *sb, struct dentry *dentry,
531 + const struct file_operations *fops, umode_t mode, size_t size,
532 + unsigned long io_addr, void *virt_addr)
534 + struct inode *inode;
535 + struct spuldrfs_inode_info *si;
537 + inode = spuldrfs_new_inode(sb, S_IFREG | mode);
541 + inode->i_op = &spuldrfs_inode_ops;
542 + inode->i_fop = fops;
543 + inode->i_size = size;
544 + inode->i_private = NULL;
546 + si = SPULDRFS_I(inode);
547 + si->io_addr = io_addr;
548 + si->virt_addr = virt_addr;
550 + d_add(dentry, inode);
556 + * spuldrfs_fill_dir
558 +static int spuldrfs_fill_dir(struct dentry *dir,
559 + const struct spuldrfs_tree_descr *files)
561 + struct dentry *dentry, *tmp;
564 + while (files->name && files->name[0]) {
565 + dentry = d_alloc_name(dir, files->name);
571 + err = spuldrfs_new_file(dir->d_sb, dentry, files->ops,
572 + files->mode, files->size, files->io_addr, files->virt_addr);
583 + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child)
586 + shrink_dcache_parent(dir);
591 +static const struct super_operations spuldrfs_super_ops = {
592 + .alloc_inode = spuldrfs_alloc_inode,
593 + .destroy_inode = spuldrfs_destroy_inode,
594 + .statfs = simple_statfs,
598 + * spuldrfs_fill_super
600 +static int spuldrfs_fill_super(struct super_block *sb, void *data, int silent)
602 + const struct spuldrfs_tree_descr root_dir_contents[] = {
603 + { "priv2", &spuldrfs_spe_regs_fops, 0666, sizeof(struct spu_priv2), spuldrfs_spe_priv2_addr, spuldrfs_spe_priv2, },
604 + { "problem", &spuldrfs_spe_regs_fops, 0666, sizeof(struct spu_problem), spuldrfs_spe_problem_addr, spuldrfs_spe_problem, },
605 + { "ls", &spuldrfs_spe_mem_fops, 0666, LS_SIZE, spuldrfs_spe_ls_addr, spuldrfs_spe_ls, },
606 + { "shadow", &spuldrfs_spe_mem_fops, 0444, sizeof(struct spe_shadow), spuldrfs_spe_shadow_addr, spuldrfs_spe_shadow, },
607 + { "metldr", &spuldrfs_mem_fops, 0666, spuldrfs_spe_metldr_size, 0, spuldrfs_spe_metldr, },
608 + { "ldr", &spuldrfs_mem_fops, 0666, spuldrfs_spe_ldr_size, 0, spuldrfs_spe_ldr, },
609 + { "buf1", &spuldrfs_mem_fops, 0666, spuldrfs_spe_buf1_size, 0, spuldrfs_spe_buf1, },
610 + { "buf2", &spuldrfs_mem_fops, 0666, spuldrfs_spe_buf2_size, 0, spuldrfs_spe_buf2, },
611 + { "buf3", &spuldrfs_mem_fops, 0666, spuldrfs_spe_buf3_size, 0, spuldrfs_spe_buf3, },
612 + { "info", &spuldrfs_info_fops, 0444, 0, 0, NULL, },
613 + { "run", &spuldrfs_run_fops, 0222, 0, 0, NULL, },
616 + struct inode *root_inode;
619 + sb->s_maxbytes = MAX_LFS_FILESIZE;
620 + sb->s_blocksize = PAGE_SIZE;
621 + sb->s_blocksize_bits = PAGE_SHIFT;
622 + sb->s_magic = SPULDRFS_MAGIC;
623 + sb->s_op = &spuldrfs_super_ops;
624 + sb->s_time_gran = 1;
626 + root_inode = spuldrfs_new_inode(sb, S_IFDIR | 0755);
630 + root_inode->i_op = &simple_dir_inode_operations;
631 + root_inode->i_fop = &simple_dir_operations;
633 + /* directory inodes start off with i_nlink == 2 (for "." entry) */
634 + inc_nlink(root_inode);
636 + sb->s_root = d_make_root(root_inode);
640 + err = spuldrfs_fill_dir(sb->s_root, root_dir_contents);
648 + * spuldrfs_spe_ea_to_kernel_ea
650 +static unsigned long spuldrfs_spe_ea_to_kernel_ea(unsigned long spe_ea)
652 + unsigned long kernel_ea, spe_buf1_addr, spe_buf2_addr, spe_buf3_addr;
654 + kernel_ea = spe_ea;
656 + if (!spuldrfs_spe_buf_addr_32bit)
657 + return (kernel_ea);
659 + spe_buf1_addr = (unsigned long) spuldrfs_spe_buf1 & 0xfffffffful;
660 + spe_buf2_addr = (unsigned long) spuldrfs_spe_buf2 & 0xfffffffful;
661 + spe_buf3_addr = (unsigned long) spuldrfs_spe_buf3 & 0xfffffffful;
663 + if ((spe_ea >= spe_buf1_addr) && (spe_ea < (spe_buf1_addr + spuldrfs_spe_buf1_size)))
664 + kernel_ea = (unsigned long) spuldrfs_spe_buf1 + (spe_buf1_addr - spe_ea);
665 + else if ((spe_ea >= spe_buf2_addr) && (spe_ea < (spe_buf2_addr + spuldrfs_spe_buf2_size)))
666 + kernel_ea = (unsigned long) spuldrfs_spe_buf2 + (spe_buf2_addr - spe_ea);
667 + else if ((spe_ea >= spe_buf3_addr) && (spe_ea < (spe_buf3_addr + spuldrfs_spe_buf3_size)))
668 + kernel_ea = (unsigned long) spuldrfs_spe_buf3 + (spe_buf3_addr - spe_ea);
670 + return (kernel_ea);
674 + * spuldrfs_spe_interrupt
676 +static irqreturn_t spuldrfs_spe_interrupt(int irq, void *data)
679 + u64 ea, kernel_ea, dsisr, esid, vsid;
682 + u64 spe_execution_status;
685 + if (irq == spuldrfs_spe_virq[0]) {
686 + printk(KERN_INFO"spuldrfs: got class 0 irq\n");
688 + err = lv1_get_spe_interrupt_status(spuldrfs_spe_id, 0, &status);
690 + printk(KERN_INFO"spuldrfs: lv1_get_spe_interrupt_status failed with %d\n", err);
694 + printk(KERN_INFO"spuldrfs: status %llx\n", status);
696 + err = lv1_clear_spe_interrupt_status(spuldrfs_spe_id, 0, status, 0);
698 + printk(KERN_INFO"spuldrfs: lv1_clear_spe_interrupt_status failed with %d\n", err);
701 + } else if (irq == spuldrfs_spe_virq[1]) {
702 + printk(KERN_INFO"spuldrfs: got class 1 irq\n");
704 + err = lv1_get_spe_interrupt_status(spuldrfs_spe_id, 1, &status);
706 + printk(KERN_INFO"spuldrfs: lv1_get_spe_interrupt_status failed with %d\n", err);
710 + printk(KERN_INFO"spuldrfs: status %llx\n", status);
712 + if (status & CLASS1_SEGMENT_FAULT_INTR) {
713 + ea = in_be64(&spuldrfs_spe_shadow->mfc_dar_RW);
714 + kernel_ea = spuldrfs_spe_ea_to_kernel_ea(ea);
716 + esid = (ea & ESID_MASK) | SLB_ESID_V;
717 + vsid = (get_kernel_vsid(kernel_ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | MMU_PAGE_4K;
719 + printk(KERN_INFO"spuldrfs: data segment fault at %llx (%llx)\n", ea, kernel_ea);
721 + out_be64(&spuldrfs_spe_priv2->slb_index_W, spuldrfs_spe_slb_index);
722 + out_be64(&spuldrfs_spe_priv2->slb_vsid_RW, vsid);
723 + out_be64(&spuldrfs_spe_priv2->slb_esid_RW, esid);
725 + spuldrfs_spe_slb_index++;
726 + if (spuldrfs_spe_slb_index > SLB_INDEX_MASK)
727 + spuldrfs_spe_slb_index = 0;
730 + if (status & CLASS1_STORAGE_FAULT_INTR) {
731 + ea = in_be64(&spuldrfs_spe_shadow->mfc_dar_RW);
732 + kernel_ea = spuldrfs_spe_ea_to_kernel_ea(ea);
733 + dsisr = in_be64(&spuldrfs_spe_shadow->mfc_dsisr_RW);
735 + printk(KERN_INFO"spuldrfs: data storage fault at %llx (%llx)\n", ea, kernel_ea);
737 + if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
738 + err = hash_page(kernel_ea, _PAGE_PRESENT, 0x300, dsisr);
740 + printk(KERN_INFO"spuldrfs: hash_page failed with %d\n", err);
746 + err = lv1_clear_spe_interrupt_status(spuldrfs_spe_id, 1, status, 0);
748 + printk(KERN_INFO"spuldrfs: lv1_clear_spe_interrupt_status failed with %d\n", err);
754 + out_be64(&spuldrfs_spe_priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
755 + } else if (irq == spuldrfs_spe_virq[2]) {
756 + printk(KERN_INFO"spuldrfs: got class 2 irq\n");
758 + err = lv1_get_spe_interrupt_status(spuldrfs_spe_id, 2, &status);
760 + printk(KERN_INFO"spuldrfs: lv1_get_spe_interrupt_status failed with %d\n", err);
764 + printk(KERN_INFO"spuldrfs: status %llx\n", status);
766 + if (status & CLASS2_MAILBOX_INTR) {
767 + puint_mb_R = in_be64(&spuldrfs_spe_priv2->puint_mb_R);
769 + printk(KERN_INFO"spuldrfs: puint_mb_R %llx\n", puint_mb_R);
772 + if (status & CLASS2_SPU_STOP_INTR) {
773 + spu_status_R = in_be32(&spuldrfs_spe_problem->spu_status_R);
775 + printk(KERN_INFO"spuldrfs: spu_status_R %x\n", spu_status_R);
778 + err = lv1_clear_spe_interrupt_status(spuldrfs_spe_id, 2, status, 0);
780 + printk(KERN_INFO"spuldrfs: lv1_clear_spe_interrupt_status failed with %d\n", err);
783 + } else if (irq == spuldrfs_spe_virq[3]) {
784 + spe_execution_status = spuldrfs_spe_shadow->spe_execution_status;
786 + printk(KERN_INFO"spuldrfs: transition notification: shadow spe_execution_status %llx\n",
787 + spe_execution_status);
789 + printk(KERN_INFO"spuldrfs: got unknown irq %d\n", irq);
794 + return (IRQ_HANDLED);
798 + * spuldrfs_create_spe
800 +static int spuldrfs_create_spe(void)
805 + err = lv1_get_virtual_address_space_id_of_ppe(&vas_id);
809 + printk(KERN_INFO"spuldrfs: vas id %llu\n", vas_id);
811 + err = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT,
812 + PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, vas_id, 0,
813 + &spuldrfs_spe_priv2_addr, &spuldrfs_spe_problem_addr, &spuldrfs_spe_ls_addr,
814 + &junk, &spuldrfs_spe_shadow_addr, &spuldrfs_spe_id);
818 + printk(KERN_INFO"spuldrfs: spe id %llu\n", spuldrfs_spe_id);
820 + spuldrfs_spe_priv2 = ioremap(spuldrfs_spe_priv2_addr, sizeof(struct spu_priv2));
821 + if (!spuldrfs_spe_priv2) {
823 + goto fail_destruct_spe;
826 + spuldrfs_spe_problem = ioremap(spuldrfs_spe_problem_addr, sizeof(struct spu_problem));
827 + if (!spuldrfs_spe_problem) {
829 + goto fail_unmap_priv2;
832 + spuldrfs_spe_ls = ioremap(spuldrfs_spe_ls_addr, LS_SIZE);
833 + if (!spuldrfs_spe_ls) {
835 + goto fail_unmap_problem;
838 + spuldrfs_spe_shadow = ioremap_prot(spuldrfs_spe_shadow_addr, sizeof(struct spe_shadow),
839 + pgprot_val(pgprot_noncached_wc(PAGE_KERNEL_RO)));
840 + if (!spuldrfs_spe_shadow) {
842 + goto fail_unmap_ls;
845 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuldrfs_spe_id, 0, &spuldrfs_spe_virq[0]);
848 + goto fail_unmap_shadow;
851 + err = request_irq(spuldrfs_spe_virq[0], spuldrfs_spe_interrupt, 0,
852 + "spuldrfs_spe_irq0", &spuldrfs_spe_virq[0]);
854 + goto fail_destroy_spe_irq_0;
856 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuldrfs_spe_id, 1, &spuldrfs_spe_virq[1]);
859 + goto fail_free_spe_irq_0;
862 + err = request_irq(spuldrfs_spe_virq[1], spuldrfs_spe_interrupt, 0,
863 + "spuldrfs_spe_irq1", &spuldrfs_spe_virq[1]);
865 + goto fail_destroy_spe_irq_1;
867 + err = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spuldrfs_spe_id, 2, &spuldrfs_spe_virq[2]);
870 + goto fail_free_spe_irq_1;
873 + err = request_irq(spuldrfs_spe_virq[2], spuldrfs_spe_interrupt, 0,
874 + "spuldrfs_spe_irq2", &spuldrfs_spe_virq[2]);
876 + goto fail_destroy_spe_irq_2;
878 + err = ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY, &spuldrfs_spe_virq[3]);
881 + goto fail_free_spe_irq_2;
884 + err = lv1_set_spe_transition_notifier(spuldrfs_spe_id, spuldrfs_spe_trans_notify_mask,
885 + virq_to_hw(spuldrfs_spe_virq[3]));
887 + printk(KERN_INFO"spuldrfs: lv1_set_spe_transition_notifier failed with %d\n", err);
889 + goto fail_destroy_event_recv_port;
892 + err = request_irq(spuldrfs_spe_virq[3], spuldrfs_spe_interrupt, 0,
893 + "spuldrfs_spe_irq3", &spuldrfs_spe_virq[3]);
895 + goto fail_destroy_event_recv_port;
899 +fail_destroy_event_recv_port:
901 + ps3_event_receive_port_destroy(spuldrfs_spe_virq[3]);
903 +fail_free_spe_irq_2:
905 + free_irq(spuldrfs_spe_virq[2], &spuldrfs_spe_virq[2]);
907 +fail_destroy_spe_irq_2:
909 + ps3_spe_irq_destroy(spuldrfs_spe_virq[2]);
911 +fail_free_spe_irq_1:
913 + free_irq(spuldrfs_spe_virq[1], &spuldrfs_spe_virq[1]);
915 +fail_destroy_spe_irq_1:
917 + ps3_spe_irq_destroy(spuldrfs_spe_virq[1]);
919 +fail_free_spe_irq_0:
921 + free_irq(spuldrfs_spe_virq[0], &spuldrfs_spe_virq[0]);
923 +fail_destroy_spe_irq_0:
925 + ps3_spe_irq_destroy(spuldrfs_spe_virq[0]);
929 + iounmap(spuldrfs_spe_shadow);
933 + iounmap(spuldrfs_spe_ls);
937 + iounmap(spuldrfs_spe_problem);
941 + iounmap(spuldrfs_spe_priv2);
945 + lv1_destruct_logical_spe(spuldrfs_spe_id);
951 + * spuldrfs_destruct_spe
953 +static void spuldrfs_destruct_spe(void)
955 + lv1_disable_logical_spe(spuldrfs_spe_id, 0);
957 + free_irq(spuldrfs_spe_virq[0], &spuldrfs_spe_virq[0]);
958 + ps3_spe_irq_destroy(spuldrfs_spe_virq[0]);
960 + free_irq(spuldrfs_spe_virq[1], &spuldrfs_spe_virq[1]);
961 + ps3_spe_irq_destroy(spuldrfs_spe_virq[1]);
963 + free_irq(spuldrfs_spe_virq[2], &spuldrfs_spe_virq[2]);
964 + ps3_spe_irq_destroy(spuldrfs_spe_virq[2]);
966 + free_irq(spuldrfs_spe_virq[3], &spuldrfs_spe_virq[3]);
967 + ps3_event_receive_port_destroy(spuldrfs_spe_virq[3]);
969 + iounmap(spuldrfs_spe_shadow);
970 + iounmap(spuldrfs_spe_ls);
971 + iounmap(spuldrfs_spe_problem);
972 + iounmap(spuldrfs_spe_priv2);
974 + lv1_destruct_logical_spe(spuldrfs_spe_id);
980 +static struct dentry *spuldrfs_mount(struct file_system_type *fs_type,
981 + int flags, const char *dev_name, void *data)
983 + struct dentry *root;
986 + err = spuldrfs_create_spe();
988 + return ERR_PTR(err);
990 + spuldrfs_spe_metldr = vmalloc_user(spuldrfs_spe_metldr_size);
991 + if (!spuldrfs_spe_metldr) {
993 + goto fail_destruct_spe;
996 + memset(spuldrfs_spe_metldr, 0, spuldrfs_spe_metldr_size);
998 + spuldrfs_spe_ldr = vmalloc_user(spuldrfs_spe_ldr_size);
999 + if (!spuldrfs_spe_ldr) {
1001 + goto fail_free_spe_metldr;
1004 + memset(spuldrfs_spe_ldr, 0, spuldrfs_spe_ldr_size);
1006 + spuldrfs_spe_buf1 = vmalloc_user(spuldrfs_spe_buf1_size);
1007 + if (!spuldrfs_spe_buf1) {
1009 + goto fail_free_spe_ldr;
1012 + memset(spuldrfs_spe_buf1, 0, spuldrfs_spe_buf1_size);
1014 + spuldrfs_spe_buf2 = vmalloc_user(spuldrfs_spe_buf2_size);
1015 + if (!spuldrfs_spe_buf2) {
1017 + goto fail_free_spe_buf1;
1020 + memset(spuldrfs_spe_buf2, 0, spuldrfs_spe_buf2_size);
1022 + spuldrfs_spe_buf3 = vmalloc_user(spuldrfs_spe_buf3_size);
1023 + if (!spuldrfs_spe_buf3) {
1025 + goto fail_free_spe_buf2;
1028 + memset(spuldrfs_spe_buf3, 0, spuldrfs_spe_buf3_size);
1030 + root = mount_single(fs_type, flags, data, spuldrfs_fill_super);
1031 + if (IS_ERR(root)) {
1032 + err = PTR_ERR(root);
1033 + goto fail_free_spe_buf3;
1038 +fail_free_spe_buf3:
1040 + vfree(spuldrfs_spe_buf3);
1042 +fail_free_spe_buf2:
1044 + vfree(spuldrfs_spe_buf2);
1046 +fail_free_spe_buf1:
1048 + vfree(spuldrfs_spe_buf1);
1052 + vfree(spuldrfs_spe_ldr);
1054 +fail_free_spe_metldr:
1056 + vfree(spuldrfs_spe_metldr);
1060 + spuldrfs_destruct_spe();
1062 + return ERR_PTR(err);
1066 + * spuldrfs_kill_sb
1068 +static void spuldrfs_kill_sb(struct super_block *sb)
1070 + kill_litter_super(sb);
1072 + vfree(spuldrfs_spe_metldr);
1073 + vfree(spuldrfs_spe_ldr);
1074 + vfree(spuldrfs_spe_buf1);
1075 + vfree(spuldrfs_spe_buf2);
1076 + vfree(spuldrfs_spe_buf3);
1077 + spuldrfs_destruct_spe();
1080 +static struct file_system_type spuldrfs_type = {
1081 + .owner = THIS_MODULE,
1082 + .name = "spuldrfs",
1083 + .mount = spuldrfs_mount,
1084 + .kill_sb = spuldrfs_kill_sb,
1090 +static int __init spuldrfs_init(void)
1094 + spuldrfs_inode_cache = kmem_cache_create("spuldrfs_inode_cache",
1095 + sizeof(struct spuldrfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
1096 + spuldrfs_init_once);
1097 + if (!spuldrfs_inode_cache)
1100 + err = register_filesystem(&spuldrfs_type);
1102 + goto fail_destroy_inode_cache;
1106 +fail_destroy_inode_cache:
1108 + kmem_cache_destroy(spuldrfs_inode_cache);
1116 +static void __exit spuldrfs_exit(void)
1118 + unregister_filesystem(&spuldrfs_type);
1119 + kmem_cache_destroy(spuldrfs_inode_cache);
1122 +module_init(spuldrfs_init);
1123 +module_exit(spuldrfs_exit);
1125 +MODULE_DESCRIPTION("PS3 spuldrfs");
1126 +MODULE_AUTHOR("glevand");
1127 +MODULE_LICENSE("GPL");