5 * Copyright (C) 2012-2013 glevand <geoffrey.levand@mail.ru>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/version.h>
25 #include <linux/init.h>
27 #include <linux/fsnotify.h>
28 #include <linux/file.h>
29 #include <linux/slab.h>
30 #include <linux/vmalloc.h>
31 #include <linux/pagemap.h>
33 #include <linux/interrupt.h>
35 #include <asm/uaccess.h>
38 #include <asm/spu_priv1.h>
39 #include <asm/lv1call.h>
41 #define SPUISOFS_MAGIC 0x73707569
44 u8 padding_0140
[0x0140];
45 u64 int_status_class0_RW
; /* 0x0140 */
46 u64 int_status_class1_RW
; /* 0x0148 */
47 u64 int_status_class2_RW
; /* 0x0150 */
48 u8 padding_0158
[0x0610-0x0158];
49 u64 mfc_dsisr_RW
; /* 0x0610 */
50 u8 padding_0618
[0x0620-0x0618];
51 u64 mfc_dar_RW
; /* 0x0620 */
52 u8 padding_0628
[0x0800-0x0628];
53 u64 mfc_dsipr_R
; /* 0x0800 */
54 u8 padding_0808
[0x0810-0x0808];
55 u64 mfc_lscrr_R
; /* 0x0810 */
56 u8 padding_0818
[0x0c00-0x0818];
57 u64 mfc_cer_R
; /* 0x0c00 */
58 u8 padding_0c08
[0x0f00-0x0c08];
59 u64 spe_execution_status
; /* 0x0f00 */
60 u8 padding_0f08
[0x1000-0x0f08];
63 struct spuisofs_inode_info
{
64 struct inode vfs_inode
;
65 unsigned long io_addr
;
69 struct spuisofs_tree_descr
{
71 const struct file_operations
*ops
;
74 unsigned long io_addr
;
78 #define SPUISOFS_I(inode) container_of(inode, struct spuisofs_inode_info, vfs_inode)
80 struct spuisofs_run_args
{
86 static struct kmem_cache
*spuisofs_inode_cache
;
88 static u64 spuisofs_spe_priv2_addr
;
89 static u64 spuisofs_spe_problem_addr
;
90 static u64 spuisofs_spe_ls_addr
;
91 static u64 spuisofs_spe_shadow_addr
;
93 static void *spuisofs_spe_priv2
;
94 static struct spu_problem
*spuisofs_spe_problem
;
95 static void *spuisofs_spe_ls
;
96 static struct spe_shadow
*spuisofs_spe_shadow
;
97 static u64 spuisofs_spe_id
;
98 static unsigned int spuisofs_spe_virq
[4];
100 static void *spuisofs_spe_app
;
101 static void *spuisofs_spe_arg1
;
102 static void *spuisofs_spe_arg2
;
103 static void *spuisofs_spe_buf
;
105 static unsigned int spuisofs_spe_slb_index
;
107 static unsigned long spuisofs_spe_app_size
= 1024 * 1024;
108 module_param(spuisofs_spe_app_size
, ulong
, 0);
110 static unsigned long spuisofs_spe_arg1_size
= 1024 * 1024;
111 module_param(spuisofs_spe_arg1_size
, ulong
, 0);
113 static unsigned long spuisofs_spe_arg2_size
= 1024 * 1024;
114 module_param(spuisofs_spe_arg2_size
, ulong
, 0);
116 static unsigned long spuisofs_spe_buf_size
= 1024 * 1024;
117 module_param(spuisofs_spe_buf_size
, ulong
, 0);
119 static unsigned long spuisofs_spe_trans_notify_mask
= 0xf;
120 module_param(spuisofs_spe_trans_notify_mask
, ulong
, 0);
122 static unsigned long spuisofs_spe_resource_id
= 6;
123 module_param(spuisofs_spe_resource_id
, ulong
, 0);
125 static int spuisofs_spe_buf_addr_32bit
= 0;
126 module_param(spuisofs_spe_buf_addr_32bit
, int, 0);
129 * spuisofs_spe_regs_read
131 static ssize_t
spuisofs_spe_regs_read(struct file
*file
, char __user
*buffer
,
132 size_t size
, loff_t
*pos
)
134 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
135 struct inode
*inode
= file
->f_dentry
->d_inode
;
137 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
139 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
141 if (*pos
>= inode
->i_size
)
144 return simple_read_from_buffer(buffer
, size
, pos
,
145 si
->virt_addr
, inode
->i_size
);
149 * spuisofs_spe_regs_write
151 static ssize_t
spuisofs_spe_regs_write(struct file
*file
, const char __user
*buffer
,
152 size_t size
, loff_t
*pos
)
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
155 struct inode
*inode
= file
->f_dentry
->d_inode
;
157 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
159 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
161 if (*pos
>= inode
->i_size
)
164 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
169 * spuisofs_spe_regs_mmap
171 static int spuisofs_spe_regs_mmap(struct file
*file
, struct vm_area_struct
*vma
)
173 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
174 struct inode
*inode
= file
->f_dentry
->d_inode
;
176 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
178 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
179 unsigned long size
, pfn
;
181 size
= vma
->vm_end
- vma
->vm_start
;
182 pfn
= (si
->io_addr
>> PAGE_SHIFT
) + vma
->vm_pgoff
;
184 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
185 vma
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
| VM_IO
;
187 vma
->vm_flags
|= VM_RESERVED
| VM_IO
;
189 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
191 return io_remap_pfn_range(vma
, vma
->vm_start
, pfn
, size
, vma
->vm_page_prot
);
194 static const struct file_operations spuisofs_spe_regs_fops
= {
195 .read
= spuisofs_spe_regs_read
,
196 .write
= spuisofs_spe_regs_write
,
197 .mmap
= spuisofs_spe_regs_mmap
,
201 * spuisofs_spe_mem_read
203 static ssize_t
spuisofs_spe_mem_read(struct file
*file
, char __user
*buffer
,
204 size_t size
, loff_t
*pos
)
206 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
207 struct inode
*inode
= file
->f_dentry
->d_inode
;
209 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
211 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
213 if (*pos
>= inode
->i_size
)
216 return simple_read_from_buffer(buffer
, size
, pos
,
217 si
->virt_addr
, inode
->i_size
);
221 * spuisofs_spe_mem_write
223 static ssize_t
spuisofs_spe_mem_write(struct file
*file
, const char __user
*buffer
,
224 size_t size
, loff_t
*pos
)
226 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
227 struct inode
*inode
= file
->f_dentry
->d_inode
;
229 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
231 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
233 if (*pos
>= inode
->i_size
)
236 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
241 * spuisofs_spe_mem_mmap
243 static int spuisofs_spe_mem_mmap(struct file
*file
, struct vm_area_struct
*vma
)
245 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
246 struct inode
*inode
= file
->f_dentry
->d_inode
;
248 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
250 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
251 unsigned long size
, pfn
;
253 size
= vma
->vm_end
- vma
->vm_start
;
254 pfn
= (si
->io_addr
>> PAGE_SHIFT
) + vma
->vm_pgoff
;
256 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
257 vma
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
| VM_IO
;
259 vma
->vm_flags
|= VM_RESERVED
| VM_IO
;
261 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
263 return io_remap_pfn_range(vma
, vma
->vm_start
, pfn
, size
, vma
->vm_page_prot
);
266 static const struct file_operations spuisofs_spe_mem_fops
= {
267 .read
= spuisofs_spe_mem_read
,
268 .write
= spuisofs_spe_mem_write
,
269 .mmap
= spuisofs_spe_mem_mmap
,
275 static ssize_t
spuisofs_mem_read(struct file
*file
, char __user
*buffer
,
276 size_t size
, loff_t
*pos
)
278 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
279 struct inode
*inode
= file
->f_dentry
->d_inode
;
281 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
283 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
285 if (*pos
>= inode
->i_size
)
288 return simple_read_from_buffer(buffer
, size
, pos
,
289 si
->virt_addr
, inode
->i_size
);
295 static ssize_t
spuisofs_mem_write(struct file
*file
, const char __user
*buffer
,
296 size_t size
, loff_t
*pos
)
298 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
299 struct inode
*inode
= file
->f_dentry
->d_inode
;
301 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
303 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
305 if (*pos
>= inode
->i_size
)
308 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
315 static int spuisofs_mem_mmap(struct file
*file
, struct vm_area_struct
*vma
)
317 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
318 struct inode
*inode
= file
->f_dentry
->d_inode
;
320 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
322 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
324 return remap_vmalloc_range(vma
, si
->virt_addr
, 0);
327 static const struct file_operations spuisofs_mem_fops
= {
328 .read
= spuisofs_mem_read
,
329 .write
= spuisofs_mem_write
,
330 .mmap
= spuisofs_mem_mmap
,
336 static ssize_t
spuisofs_info_read(struct file
*file
, char __user
*buffer
,
337 size_t size
, loff_t
*pos
)
341 unsigned long spe_buf_addr
;
343 spe_buf_addr
= (unsigned long) spuisofs_spe_buf
;
345 if (spuisofs_spe_buf_addr_32bit
)
346 spe_buf_addr
&= 0xfffffffful
;
348 len
= sprintf(buf
, "arg1 %lx\narg2 %lx\nbuf %lx\n",
349 (unsigned long) spuisofs_spe_arg1
, (unsigned long) spuisofs_spe_arg2
,
352 return simple_read_from_buffer(buffer
, size
, pos
, buf
, len
);
355 static const struct file_operations spuisofs_info_fops
= {
356 .read
= spuisofs_info_read
,
362 static ssize_t
spuisofs_run_write(struct file
*file
, const char __user
*buffer
,
363 size_t size
, loff_t
*pos
)
365 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
366 struct inode
*inode
= file
->f_dentry
->d_inode
;
368 struct inode
*inode
= file
->f_path
.dentry
->d_inode
;
370 struct spuisofs_run_args args
;
373 if (*pos
|| (size
!= inode
->i_size
))
376 if (copy_from_user(&args
, buffer
, sizeof(struct spuisofs_run_args
)))
379 if (args
.arg1_size
== 0)
380 args
.arg1_size
= spuisofs_spe_arg1_size
;
382 if (args
.arg2_size
== 0)
383 args
.arg2_size
= spuisofs_spe_arg2_size
;
385 if (args
.arg1_size
> spuisofs_spe_arg1_size
)
388 if (args
.arg2_size
> spuisofs_spe_arg2_size
)
391 err
= lv1_undocumented_function_201(spuisofs_spe_id
);
393 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_201 failed with %d\n", err
);
395 err
= lv1_undocumented_function_209(spuisofs_spe_id
, args
.laid
, (u64
) spuisofs_spe_app
,
396 (u64
) spuisofs_spe_arg1
, args
.arg1_size
,
397 (u64
) spuisofs_spe_arg2
, args
.arg2_size
, spuisofs_spe_resource_id
);
399 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_209 failed with %d\n", err
);
406 static const struct file_operations spuisofs_run_fops
= {
407 .write
= spuisofs_run_write
,
411 * spuisofs_cont_write
413 static ssize_t
spuisofs_cont_write(struct file
*file
, const char __user
*buffer
,
414 size_t size
, loff_t
*pos
)
419 err
= lv1_undocumented_function_167(spuisofs_spe_id
, 0x4000, &puint_mb_R
);
421 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_167 failed with %d\n", err
);
425 printk(KERN_INFO
"spuisofs: puint_mb_R %llx\n", puint_mb_R
);
427 err
= lv1_undocumented_function_200(spuisofs_spe_id
);
429 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_200 failed with %d\n", err
);
436 static const struct file_operations spuisofs_cont_fops
= {
437 .write
= spuisofs_cont_write
,
441 * spuisofs_alloc_inode
443 static struct inode
*spuisofs_alloc_inode(struct super_block
*sb
)
445 struct spuisofs_inode_info
*si
;
447 si
= kmem_cache_alloc(spuisofs_inode_cache
, GFP_KERNEL
);
451 return (&si
->vfs_inode
);
455 * spuisofs_i_callback
457 static void spuisofs_i_callback(struct rcu_head
*head
)
459 struct inode
*inode
= container_of(head
, struct inode
, i_rcu
);
461 kmem_cache_free(spuisofs_inode_cache
, SPUISOFS_I(inode
));
465 * spuisofs_destroy_inode
467 static void spuisofs_destroy_inode(struct inode
*inode
)
469 call_rcu(&inode
->i_rcu
, spuisofs_i_callback
);
475 static void spuisofs_init_once(void *p
)
477 struct spuisofs_inode_info
*si
= p
;
479 inode_init_once(&si
->vfs_inode
);
485 static struct inode
*spuisofs_new_inode(struct super_block
*sb
, umode_t mode
)
489 inode
= new_inode(sb
);
493 inode
->i_ino
= get_next_ino();
494 inode
->i_mode
= mode
;
495 inode
->i_uid
= current_fsuid();
496 inode
->i_gid
= current_fsgid();
497 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
505 static int spuisofs_setattr(struct dentry
*dentry
, struct iattr
*attr
)
507 struct inode
*inode
= dentry
->d_inode
;
509 setattr_copy(inode
, attr
);
510 mark_inode_dirty(inode
);
515 static const struct inode_operations spuisofs_inode_ops
= {
516 .setattr
= spuisofs_setattr
,
522 static int spuisofs_new_file(struct super_block
*sb
, struct dentry
*dentry
,
523 const struct file_operations
*fops
, umode_t mode
, size_t size
,
524 unsigned long io_addr
, void *virt_addr
)
527 struct spuisofs_inode_info
*si
;
529 inode
= spuisofs_new_inode(sb
, S_IFREG
| mode
);
533 inode
->i_op
= &spuisofs_inode_ops
;
535 inode
->i_size
= size
;
536 inode
->i_private
= NULL
;
538 si
= SPUISOFS_I(inode
);
539 si
->io_addr
= io_addr
;
540 si
->virt_addr
= virt_addr
;
542 d_add(dentry
, inode
);
550 static int spuisofs_fill_dir(struct dentry
*dir
,
551 const struct spuisofs_tree_descr
*files
)
553 struct dentry
*dentry
, *tmp
;
556 while (files
->name
&& files
->name
[0]) {
557 dentry
= d_alloc_name(dir
, files
->name
);
563 err
= spuisofs_new_file(dir
->d_sb
, dentry
, files
->ops
,
564 files
->mode
, files
->size
, files
->io_addr
, files
->virt_addr
);
575 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,1)
576 list_for_each_entry_safe(dentry
, tmp
, &dir
->d_subdirs
, d_u
.d_child
)
579 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_CACHE_SIZE
;
618 sb
->s_blocksize_bits
= PAGE_CACHE_SHIFT
;
619 sb
->s_magic
= SPUISOFS_MAGIC
;
620 sb
->s_op
= &spuisofs_super_ops
;
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
;
653 if (!spuisofs_spe_buf_addr_32bit
)
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
);
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 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
732 err
= hash_page(kernel_ea
, _PAGE_PRESENT
, 0x300);
734 err
= hash_page(kernel_ea
, _PAGE_PRESENT
, 0x300, dsisr
);
737 printk(KERN_INFO
"spuisofs: hash_page failed with %d\n", err
);
743 err
= lv1_clear_spe_interrupt_status(spuisofs_spe_id
, 1, status
, 0);
745 printk(KERN_INFO
"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err
);
751 err
= lv1_undocumented_function_168(spuisofs_spe_id
, 0x3000, 1ull << 32);
753 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_168 failed with %d\n", err
);
756 } else if (irq
== spuisofs_spe_virq
[2]) {
757 printk(KERN_INFO
"spuisofs: got class 2 irq\n");
759 err
= lv1_get_spe_interrupt_status(spuisofs_spe_id
, 2, &status
);
761 printk(KERN_INFO
"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err
);
765 printk(KERN_INFO
"spuisofs: status %llx\n", status
);
767 if (status
& CLASS2_MAILBOX_INTR
) {
768 err
= lv1_undocumented_function_167(spuisofs_spe_id
, 0x4000, &puint_mb_R
);
770 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_167 failed with %d\n", err
);
774 printk(KERN_INFO
"spuisofs: puint_mb_R %llx\n", puint_mb_R
);
777 if (status
& CLASS2_SPU_STOP_INTR
) {
778 spu_status_R
= in_be32(&spuisofs_spe_problem
->spu_status_R
);
780 printk(KERN_INFO
"spuisofs: spu_status_R %x\n", spu_status_R
);
783 err
= lv1_clear_spe_interrupt_status(spuisofs_spe_id
, 2, status
, 0);
785 printk(KERN_INFO
"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err
);
788 } else if (irq
== spuisofs_spe_virq
[3]) {
789 spe_execution_status
= spuisofs_spe_shadow
->spe_execution_status
;
791 printk(KERN_INFO
"spuisofs: transition notification: shadow spe_execution_status %llx\n",
792 spe_execution_status
);
794 printk(KERN_INFO
"spuisofs: got unknown irq %d\n", irq
);
799 return (IRQ_HANDLED
);
803 * spuisofs_create_spe
805 static int spuisofs_create_spe(void)
810 err
= lv1_get_virtual_address_space_id_of_ppe(&vas_id
);
814 printk(KERN_INFO
"spuisofs: vas id %llu\n", vas_id
);
816 err
= lv1_construct_logical_spe(PAGE_SHIFT
, PAGE_SHIFT
,
817 PAGE_SHIFT
, PAGE_SHIFT
, PAGE_SHIFT
, vas_id
, 2,
818 &spuisofs_spe_priv2_addr
, &spuisofs_spe_problem_addr
, &spuisofs_spe_ls_addr
,
819 &junk
, &spuisofs_spe_shadow_addr
, &spuisofs_spe_id
);
823 printk(KERN_INFO
"spuisofs: spe id %llu\n", spuisofs_spe_id
);
825 spuisofs_spe_priv2
= ioremap(spuisofs_spe_priv2_addr
, sizeof(struct spu_priv2
));
826 if (!spuisofs_spe_priv2
) {
828 goto fail_destruct_spe
;
831 spuisofs_spe_problem
= ioremap(spuisofs_spe_problem_addr
, sizeof(struct spu_problem
));
832 if (!spuisofs_spe_problem
) {
834 goto fail_unmap_priv2
;
837 spuisofs_spe_ls
= ioremap_prot(spuisofs_spe_ls_addr
, LS_SIZE
, _PAGE_NO_CACHE
);
838 if (!spuisofs_spe_ls
) {
840 goto fail_unmap_problem
;
843 spuisofs_spe_shadow
= __ioremap(spuisofs_spe_shadow_addr
, sizeof(struct spe_shadow
),
845 if (!spuisofs_spe_shadow
) {
850 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 0, &spuisofs_spe_virq
[0]);
853 goto fail_unmap_shadow
;
856 err
= request_irq(spuisofs_spe_virq
[0], spuisofs_spe_interrupt
, 0,
857 "spuisofs_spe_irq0", &spuisofs_spe_virq
[0]);
859 goto fail_destroy_spe_irq_0
;
861 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 1, &spuisofs_spe_virq
[1]);
864 goto fail_free_spe_irq_0
;
867 err
= request_irq(spuisofs_spe_virq
[1], spuisofs_spe_interrupt
, 0,
868 "spuisofs_spe_irq1", &spuisofs_spe_virq
[1]);
870 goto fail_destroy_spe_irq_1
;
872 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 2, &spuisofs_spe_virq
[2]);
875 goto fail_free_spe_irq_1
;
878 err
= request_irq(spuisofs_spe_virq
[2], spuisofs_spe_interrupt
, 0,
879 "spuisofs_spe_irq2", &spuisofs_spe_virq
[2]);
881 goto fail_destroy_spe_irq_2
;
883 err
= ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY
, &spuisofs_spe_virq
[3]);
886 goto fail_free_spe_irq_2
;
889 err
= lv1_set_spe_transition_notifier(spuisofs_spe_id
, spuisofs_spe_trans_notify_mask
,
890 virq_to_hw(spuisofs_spe_virq
[3]));
892 printk(KERN_INFO
"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err
);
894 goto fail_destroy_event_recv_port
;
897 err
= request_irq(spuisofs_spe_virq
[3], spuisofs_spe_interrupt
, 0,
898 "spuisofs_spe_irq3", &spuisofs_spe_virq
[3]);
900 goto fail_destroy_event_recv_port
;
904 fail_destroy_event_recv_port
:
906 ps3_event_receive_port_destroy(spuisofs_spe_virq
[3]);
910 free_irq(spuisofs_spe_virq
[2], &spuisofs_spe_virq
[2]);
912 fail_destroy_spe_irq_2
:
914 ps3_spe_irq_destroy(spuisofs_spe_virq
[2]);
918 free_irq(spuisofs_spe_virq
[1], &spuisofs_spe_virq
[1]);
920 fail_destroy_spe_irq_1
:
922 ps3_spe_irq_destroy(spuisofs_spe_virq
[1]);
926 free_irq(spuisofs_spe_virq
[0], &spuisofs_spe_virq
[0]);
928 fail_destroy_spe_irq_0
:
930 ps3_spe_irq_destroy(spuisofs_spe_virq
[0]);
934 iounmap(spuisofs_spe_shadow
);
938 iounmap(spuisofs_spe_ls
);
942 iounmap(spuisofs_spe_problem
);
946 iounmap(spuisofs_spe_priv2
);
950 lv1_destruct_logical_spe(spuisofs_spe_id
);
956 * spuisofs_destruct_spe
958 static void spuisofs_destruct_spe(void)
960 free_irq(spuisofs_spe_virq
[0], &spuisofs_spe_virq
[0]);
961 ps3_spe_irq_destroy(spuisofs_spe_virq
[0]);
963 free_irq(spuisofs_spe_virq
[1], &spuisofs_spe_virq
[1]);
964 ps3_spe_irq_destroy(spuisofs_spe_virq
[1]);
966 free_irq(spuisofs_spe_virq
[2], &spuisofs_spe_virq
[2]);
967 ps3_spe_irq_destroy(spuisofs_spe_virq
[2]);
969 free_irq(spuisofs_spe_virq
[3], &spuisofs_spe_virq
[3]);
970 ps3_event_receive_port_destroy(spuisofs_spe_virq
[3]);
972 iounmap(spuisofs_spe_shadow
);
973 iounmap(spuisofs_spe_ls
);
974 iounmap(spuisofs_spe_problem
);
975 iounmap(spuisofs_spe_priv2
);
977 lv1_destruct_logical_spe(spuisofs_spe_id
);
983 static struct dentry
*spuisofs_mount(struct file_system_type
*fs_type
,
984 int flags
, const char *dev_name
, void *data
)
989 err
= spuisofs_create_spe();
993 spuisofs_spe_app
= vmalloc_user(spuisofs_spe_app_size
);
994 if (!spuisofs_spe_app
) {
996 goto fail_destruct_spe
;
999 memset(spuisofs_spe_app
, 0, spuisofs_spe_app_size
);
1001 spuisofs_spe_arg1
= vmalloc_user(spuisofs_spe_arg1_size
);
1002 if (!spuisofs_spe_arg1
) {
1004 goto fail_free_spe_app
;
1007 memset(spuisofs_spe_arg1
, 0, spuisofs_spe_arg1_size
);
1009 spuisofs_spe_arg2
= vmalloc_user(spuisofs_spe_arg2_size
);
1010 if (!spuisofs_spe_arg2
) {
1012 goto fail_free_spe_arg1
;
1015 memset(spuisofs_spe_arg2
, 0, spuisofs_spe_arg2_size
);
1017 spuisofs_spe_buf
= vmalloc_user(spuisofs_spe_buf_size
);
1018 if (!spuisofs_spe_buf
) {
1020 goto fail_free_spe_arg2
;
1023 memset(spuisofs_spe_buf
, 0, spuisofs_spe_buf_size
);
1025 root
= mount_single(fs_type
, flags
, data
, spuisofs_fill_super
);
1027 err
= PTR_ERR(root
);
1035 vfree(spuisofs_spe_buf
);
1039 vfree(spuisofs_spe_arg2
);
1043 vfree(spuisofs_spe_arg1
);
1047 vfree(spuisofs_spe_app
);
1051 spuisofs_destruct_spe();
1053 return ERR_PTR(err
);
1059 static void spuisofs_kill_sb(struct super_block
*sb
)
1061 kill_litter_super(sb
);
1063 vfree(spuisofs_spe_app
);
1064 vfree(spuisofs_spe_arg1
);
1065 vfree(spuisofs_spe_arg2
);
1066 vfree(spuisofs_spe_buf
);
1067 spuisofs_destruct_spe();
1070 static struct file_system_type spuisofs_type
= {
1071 .owner
= THIS_MODULE
,
1073 .mount
= spuisofs_mount
,
1074 .kill_sb
= spuisofs_kill_sb
,
1080 static int __init
spuisofs_init(void)
1084 spuisofs_inode_cache
= kmem_cache_create("spuisofs_inode_cache",
1085 sizeof(struct spuisofs_inode_info
), 0, SLAB_HWCACHE_ALIGN
,
1086 spuisofs_init_once
);
1087 if (!spuisofs_inode_cache
)
1090 err
= register_filesystem(&spuisofs_type
);
1092 goto fail_destroy_inode_cache
;
1096 fail_destroy_inode_cache
:
1098 kmem_cache_destroy(spuisofs_inode_cache
);
1106 static void __exit
spuisofs_exit(void)
1108 unregister_filesystem(&spuisofs_type
);
1109 kmem_cache_destroy(spuisofs_inode_cache
);
1112 module_init(spuisofs_init
);
1113 module_exit(spuisofs_exit
);
1115 MODULE_DESCRIPTION("PS3 spuisofs");
1116 MODULE_AUTHOR("glevand");
1117 MODULE_LICENSE("GPL");