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_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_buf_size
= 1024 * 1024;
117 module_param(spuisofs_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_buf_addr_32bit
= 0;
126 module_param(spuisofs_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 struct inode
*inode
= file
->f_dentry
->d_inode
;
135 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
137 if (*pos
>= inode
->i_size
)
140 return simple_read_from_buffer(buffer
, size
, pos
,
141 si
->virt_addr
, inode
->i_size
);
145 * spuisofs_spe_regs_write
147 static ssize_t
spuisofs_spe_regs_write(struct file
*file
, const char __user
*buffer
,
148 size_t size
, loff_t
*pos
)
150 struct inode
*inode
= file
->f_dentry
->d_inode
;
151 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
153 if (*pos
>= inode
->i_size
)
156 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
161 * spuisofs_spe_regs_mmap
163 static int spuisofs_spe_regs_mmap(struct file
*file
, struct vm_area_struct
*vma
)
165 struct inode
*inode
= file
->f_dentry
->d_inode
;
166 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
167 unsigned long size
, pfn
;
169 size
= vma
->vm_end
- vma
->vm_start
;
170 pfn
= (si
->io_addr
>> PAGE_SHIFT
) + vma
->vm_pgoff
;
172 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
173 vma
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
| VM_IO
;
175 vma
->vm_flags
|= VM_RESERVED
| VM_IO
;
177 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
179 return io_remap_pfn_range(vma
, vma
->vm_start
, pfn
, size
, vma
->vm_page_prot
);
182 static const struct file_operations spuisofs_spe_regs_fops
= {
183 .read
= spuisofs_spe_regs_read
,
184 .write
= spuisofs_spe_regs_write
,
185 .mmap
= spuisofs_spe_regs_mmap
,
189 * spuisofs_spe_mem_read
191 static ssize_t
spuisofs_spe_mem_read(struct file
*file
, char __user
*buffer
,
192 size_t size
, loff_t
*pos
)
194 struct inode
*inode
= file
->f_dentry
->d_inode
;
195 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
197 if (*pos
>= inode
->i_size
)
200 return simple_read_from_buffer(buffer
, size
, pos
,
201 si
->virt_addr
, inode
->i_size
);
205 * spuisofs_spe_mem_write
207 static ssize_t
spuisofs_spe_mem_write(struct file
*file
, const char __user
*buffer
,
208 size_t size
, loff_t
*pos
)
210 struct inode
*inode
= file
->f_dentry
->d_inode
;
211 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
213 if (*pos
>= inode
->i_size
)
216 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
221 * spuisofs_spe_mem_mmap
223 static int spuisofs_spe_mem_mmap(struct file
*file
, struct vm_area_struct
*vma
)
225 struct inode
*inode
= file
->f_dentry
->d_inode
;
226 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
227 unsigned long size
, pfn
;
229 size
= vma
->vm_end
- vma
->vm_start
;
230 pfn
= (si
->io_addr
>> PAGE_SHIFT
) + vma
->vm_pgoff
;
232 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
233 vma
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
| VM_IO
;
235 vma
->vm_flags
|= VM_RESERVED
| VM_IO
;
237 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
239 return io_remap_pfn_range(vma
, vma
->vm_start
, pfn
, size
, vma
->vm_page_prot
);
242 static const struct file_operations spuisofs_spe_mem_fops
= {
243 .read
= spuisofs_spe_mem_read
,
244 .write
= spuisofs_spe_mem_write
,
245 .mmap
= spuisofs_spe_mem_mmap
,
251 static ssize_t
spuisofs_mem_read(struct file
*file
, char __user
*buffer
,
252 size_t size
, loff_t
*pos
)
254 struct inode
*inode
= file
->f_dentry
->d_inode
;
255 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
257 if (*pos
>= inode
->i_size
)
260 return simple_read_from_buffer(buffer
, size
, pos
,
261 si
->virt_addr
, inode
->i_size
);
267 static ssize_t
spuisofs_mem_write(struct file
*file
, const char __user
*buffer
,
268 size_t size
, loff_t
*pos
)
270 struct inode
*inode
= file
->f_dentry
->d_inode
;
271 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
273 if (*pos
>= inode
->i_size
)
276 return simple_write_to_buffer(si
->virt_addr
, inode
->i_size
,
283 static int spuisofs_mem_mmap(struct file
*file
, struct vm_area_struct
*vma
)
285 struct inode
*inode
= file
->f_dentry
->d_inode
;
286 struct spuisofs_inode_info
*si
= SPUISOFS_I(inode
);
288 return remap_vmalloc_range(vma
, si
->virt_addr
, 0);
291 static const struct file_operations spuisofs_mem_fops
= {
292 .read
= spuisofs_mem_read
,
293 .write
= spuisofs_mem_write
,
294 .mmap
= spuisofs_mem_mmap
,
300 static ssize_t
spuisofs_info_read(struct file
*file
, char __user
*buffer
,
301 size_t size
, loff_t
*pos
)
305 unsigned long buf_addr
;
307 buf_addr
= (unsigned long) spuisofs_buf
;
308 if (spuisofs_buf_addr_32bit
)
309 buf_addr
&= 0xfffffffful
;
311 len
= sprintf(buf
, "arg1 %lx\narg2 %lx\nbuf %lx\n",
312 (unsigned long) spuisofs_spe_arg1
, (unsigned long) spuisofs_spe_arg2
,
315 return simple_read_from_buffer(buffer
, size
, pos
, buf
, len
);
318 static const struct file_operations spuisofs_info_fops
= {
319 .read
= spuisofs_info_read
,
325 static ssize_t
spuisofs_run_write(struct file
*file
, const char __user
*buffer
,
326 size_t size
, loff_t
*pos
)
328 struct inode
*inode
= file
->f_dentry
->d_inode
;
329 struct spuisofs_run_args args
;
332 if (*pos
|| (size
!= inode
->i_size
))
335 if (copy_from_user(&args
, buffer
, sizeof(struct spuisofs_run_args
)))
338 if (args
.arg1_size
== 0)
339 args
.arg1_size
= spuisofs_spe_arg1_size
;
341 if (args
.arg2_size
== 0)
342 args
.arg2_size
= spuisofs_spe_arg2_size
;
344 if (args
.arg1_size
> spuisofs_spe_arg1_size
)
347 if (args
.arg2_size
> spuisofs_spe_arg2_size
)
350 err
= lv1_undocumented_function_201(spuisofs_spe_id
);
352 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_201 failed with %d\n", err
);
354 err
= lv1_undocumented_function_209(spuisofs_spe_id
, args
.laid
, (u64
) spuisofs_spe_app
,
355 (u64
) spuisofs_spe_arg1
, args
.arg1_size
,
356 (u64
) spuisofs_spe_arg2
, args
.arg2_size
, spuisofs_spe_resource_id
);
358 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_209 failed with %d\n", err
);
365 static const struct file_operations spuisofs_run_fops
= {
366 .write
= spuisofs_run_write
,
370 * spuisofs_cont_write
372 static ssize_t
spuisofs_cont_write(struct file
*file
, const char __user
*buffer
,
373 size_t size
, loff_t
*pos
)
378 err
= lv1_undocumented_function_167(spuisofs_spe_id
, 0x4000, &puint_mb_R
);
380 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_167 failed with %d\n", err
);
384 printk(KERN_INFO
"spuisofs: puint_mb_R %llx\n", puint_mb_R
);
386 err
= lv1_undocumented_function_200(spuisofs_spe_id
);
388 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_200 failed with %d\n", err
);
395 static const struct file_operations spuisofs_cont_fops
= {
396 .write
= spuisofs_cont_write
,
400 * spuisofs_alloc_inode
402 static struct inode
*spuisofs_alloc_inode(struct super_block
*sb
)
404 struct spuisofs_inode_info
*si
;
406 si
= kmem_cache_alloc(spuisofs_inode_cache
, GFP_KERNEL
);
410 return (&si
->vfs_inode
);
414 * spuisofs_i_callback
416 static void spuisofs_i_callback(struct rcu_head
*head
)
418 struct inode
*inode
= container_of(head
, struct inode
, i_rcu
);
420 kmem_cache_free(spuisofs_inode_cache
, SPUISOFS_I(inode
));
424 * spuisofs_destroy_inode
426 static void spuisofs_destroy_inode(struct inode
*inode
)
428 call_rcu(&inode
->i_rcu
, spuisofs_i_callback
);
434 static void spuisofs_init_once(void *p
)
436 struct spuisofs_inode_info
*si
= p
;
438 inode_init_once(&si
->vfs_inode
);
444 static struct inode
*spuisofs_new_inode(struct super_block
*sb
, umode_t mode
)
448 inode
= new_inode(sb
);
452 inode
->i_ino
= get_next_ino();
453 inode
->i_mode
= mode
;
454 inode
->i_uid
= current_fsuid();
455 inode
->i_gid
= current_fsgid();
456 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
464 static int spuisofs_setattr(struct dentry
*dentry
, struct iattr
*attr
)
466 struct inode
*inode
= dentry
->d_inode
;
468 setattr_copy(inode
, attr
);
469 mark_inode_dirty(inode
);
474 static const struct inode_operations spuisofs_inode_ops
= {
475 .setattr
= spuisofs_setattr
,
481 static int spuisofs_new_file(struct super_block
*sb
, struct dentry
*dentry
,
482 const struct file_operations
*fops
, umode_t mode
, size_t size
,
483 unsigned long io_addr
, void *virt_addr
)
486 struct spuisofs_inode_info
*si
;
488 inode
= spuisofs_new_inode(sb
, S_IFREG
| mode
);
492 inode
->i_op
= &spuisofs_inode_ops
;
494 inode
->i_size
= size
;
495 inode
->i_private
= NULL
;
497 si
= SPUISOFS_I(inode
);
498 si
->io_addr
= io_addr
;
499 si
->virt_addr
= virt_addr
;
501 d_add(dentry
, inode
);
509 static int spuisofs_fill_dir(struct dentry
*dir
,
510 const struct spuisofs_tree_descr
*files
)
512 struct dentry
*dentry
, *tmp
;
515 while (files
->name
&& files
->name
[0]) {
516 dentry
= d_alloc_name(dir
, files
->name
);
522 err
= spuisofs_new_file(dir
->d_sb
, dentry
, files
->ops
,
523 files
->mode
, files
->size
, files
->io_addr
, files
->virt_addr
);
534 list_for_each_entry_safe(dentry
, tmp
, &dir
->d_subdirs
, d_u
.d_child
)
537 shrink_dcache_parent(dir
);
542 static const struct super_operations spuisofs_super_ops
= {
543 .alloc_inode
= spuisofs_alloc_inode
,
544 .destroy_inode
= spuisofs_destroy_inode
,
545 .statfs
= simple_statfs
,
549 * spuisofs_fill_super
551 static int spuisofs_fill_super(struct super_block
*sb
, void *data
, int silent
)
553 const struct spuisofs_tree_descr root_dir_contents
[] = {
554 { "priv2", &spuisofs_spe_regs_fops
, 0666, sizeof(struct spu_priv2
), spuisofs_spe_priv2_addr
, spuisofs_spe_priv2
, },
555 { "problem", &spuisofs_spe_regs_fops
, 0666, sizeof(struct spu_problem
), spuisofs_spe_problem_addr
, spuisofs_spe_problem
, },
556 { "ls", &spuisofs_spe_mem_fops
, 0666, LS_SIZE
, spuisofs_spe_ls_addr
, spuisofs_spe_ls
, },
557 { "shadow", &spuisofs_spe_mem_fops
, 0444, sizeof(struct spe_shadow
), spuisofs_spe_shadow_addr
, spuisofs_spe_shadow
, },
558 { "app", &spuisofs_mem_fops
, 0666, spuisofs_spe_app_size
, 0, spuisofs_spe_app
, },
559 { "arg1", &spuisofs_mem_fops
, 0666, spuisofs_spe_arg1_size
, 0, spuisofs_spe_arg1
, },
560 { "arg2", &spuisofs_mem_fops
, 0666, spuisofs_spe_arg2_size
, 0, spuisofs_spe_arg2
, },
561 { "buf", &spuisofs_mem_fops
, 0666, spuisofs_buf_size
, 0, spuisofs_buf
, },
562 { "info", &spuisofs_info_fops
, 0444, 0, 0, NULL
, },
563 { "run", &spuisofs_run_fops
, 0222, sizeof(struct spuisofs_run_args
), 0, NULL
, },
564 { "cont", &spuisofs_cont_fops
, 0222, 0, 0, NULL
, },
567 struct inode
*root_inode
;
570 sb
->s_maxbytes
= MAX_LFS_FILESIZE
;
571 sb
->s_blocksize
= PAGE_CACHE_SIZE
;
572 sb
->s_blocksize_bits
= PAGE_CACHE_SHIFT
;
573 sb
->s_magic
= SPUISOFS_MAGIC
;
574 sb
->s_op
= &spuisofs_super_ops
;
577 root_inode
= spuisofs_new_inode(sb
, S_IFDIR
| 0755);
581 root_inode
->i_op
= &simple_dir_inode_operations
;
582 root_inode
->i_fop
= &simple_dir_operations
;
584 /* directory inodes start off with i_nlink == 2 (for "." entry) */
585 inc_nlink(root_inode
);
587 sb
->s_root
= d_make_root(root_inode
);
591 err
= spuisofs_fill_dir(sb
->s_root
, root_dir_contents
);
599 * spuisofs_spe_interrupt
601 static irqreturn_t
spuisofs_spe_interrupt(int irq
, void *data
)
604 u64 ea
, ea_full
, dsisr
, esid
, vsid
, buf_addr
;
607 u64 spe_execution_status
;
610 if (irq
== spuisofs_spe_virq
[0]) {
611 printk(KERN_INFO
"spuisofs: got class 0 irq\n");
613 err
= lv1_get_spe_interrupt_status(spuisofs_spe_id
, 0, &status
);
615 printk(KERN_INFO
"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err
);
619 printk(KERN_INFO
"spuisofs: status %llx\n", status
);
621 err
= lv1_clear_spe_interrupt_status(spuisofs_spe_id
, 0, status
, 0);
623 printk(KERN_INFO
"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err
);
626 } else if (irq
== spuisofs_spe_virq
[1]) {
627 printk(KERN_INFO
"spuisofs: got class 1 irq\n");
629 err
= lv1_get_spe_interrupt_status(spuisofs_spe_id
, 1, &status
);
631 printk(KERN_INFO
"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err
);
635 printk(KERN_INFO
"spuisofs: status %llx\n", status
);
637 if (status
& CLASS1_SEGMENT_FAULT_INTR
) {
638 ea
= in_be64(&spuisofs_spe_shadow
->mfc_dar_RW
);
641 buf_addr
= (u64
) spuisofs_buf
;
642 if (spuisofs_buf_addr_32bit
)
643 buf_addr
&= 0xfffffffful
;
645 if ((ea
>= buf_addr
) && (ea
< (buf_addr
+ spuisofs_buf_size
)))
646 ea_full
= (u64
) spuisofs_buf
+ (buf_addr
- ea
);
648 esid
= (ea
& ESID_MASK
) | SLB_ESID_V
;
649 vsid
= (get_kernel_vsid(ea_full
, MMU_SEGSIZE_256M
) << SLB_VSID_SHIFT
) | SLB_VSID_KERNEL
| MMU_PAGE_4K
;
651 printk(KERN_INFO
"spuisofs: data segment fault at %llx (%llx)\n", ea
, ea_full
);
653 err
= lv1_undocumented_function_62(spuisofs_spe_id
, 0, spuisofs_spe_slb_index
, esid
, vsid
);
655 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_62 failed with %d\n", err
);
659 spuisofs_spe_slb_index
++;
660 if (spuisofs_spe_slb_index
> SLB_INDEX_MASK
)
661 spuisofs_spe_slb_index
= 0;
664 if (status
& CLASS1_STORAGE_FAULT_INTR
) {
665 ea
= in_be64(&spuisofs_spe_shadow
->mfc_dar_RW
);
667 dsisr
= in_be64(&spuisofs_spe_shadow
->mfc_dsisr_RW
);
669 buf_addr
= (u64
) spuisofs_buf
;
670 if (spuisofs_buf_addr_32bit
)
671 buf_addr
&= 0xfffffffful
;
673 if ((ea
>= buf_addr
) && (ea
< (buf_addr
+ spuisofs_buf_size
)))
674 ea_full
= (u64
) spuisofs_buf
+ (buf_addr
- ea
);
676 printk(KERN_INFO
"spuisofs: data storage fault at %llx (%llx)\n", ea
, ea_full
);
678 if (dsisr
& MFC_DSISR_PTE_NOT_FOUND
) {
679 err
= hash_page(ea_full
, _PAGE_PRESENT
, 0x300);
681 printk(KERN_INFO
"spuisofs: hash_page failed with %d\n", err
);
687 err
= lv1_clear_spe_interrupt_status(spuisofs_spe_id
, 1, status
, 0);
689 printk(KERN_INFO
"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err
);
695 err
= lv1_undocumented_function_168(spuisofs_spe_id
, 0x3000, 1ull << 32);
697 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_168 failed with %d\n", err
);
700 } else if (irq
== spuisofs_spe_virq
[2]) {
701 printk(KERN_INFO
"spuisofs: got class 2 irq\n");
703 err
= lv1_get_spe_interrupt_status(spuisofs_spe_id
, 2, &status
);
705 printk(KERN_INFO
"spuisofs: lv1_get_spe_interrupt_status failed with %d\n", err
);
709 printk(KERN_INFO
"spuisofs: status %llx\n", status
);
711 if (status
& CLASS2_MAILBOX_INTR
) {
712 err
= lv1_undocumented_function_167(spuisofs_spe_id
, 0x4000, &puint_mb_R
);
714 printk(KERN_INFO
"spuisofs: lv1_undocumented_function_167 failed with %d\n", err
);
718 printk(KERN_INFO
"spuisofs: puint_mb_R %llx\n", puint_mb_R
);
721 if (status
& CLASS2_SPU_STOP_INTR
) {
722 spu_status_R
= in_be32(&spuisofs_spe_problem
->spu_status_R
);
724 printk(KERN_INFO
"spuisofs: spu_status_R %x\n", spu_status_R
);
727 err
= lv1_clear_spe_interrupt_status(spuisofs_spe_id
, 2, status
, 0);
729 printk(KERN_INFO
"spuisofs: lv1_clear_spe_interrupt_status failed with %d\n", err
);
732 } else if (irq
== spuisofs_spe_virq
[3]) {
733 spe_execution_status
= spuisofs_spe_shadow
->spe_execution_status
;
735 printk(KERN_INFO
"spuisofs: transition notification: shadow spe_execution_status %llx\n",
736 spe_execution_status
);
738 printk(KERN_INFO
"spuisofs: got unknown irq %d\n", irq
);
743 return (IRQ_HANDLED
);
747 * spuisofs_create_spe
749 static int spuisofs_create_spe(void)
754 err
= lv1_get_virtual_address_space_id_of_ppe(&vas_id
);
758 printk(KERN_INFO
"spuisofs: vas id %llu\n", vas_id
);
760 err
= lv1_construct_logical_spe(PAGE_SHIFT
, PAGE_SHIFT
,
761 PAGE_SHIFT
, PAGE_SHIFT
, PAGE_SHIFT
, vas_id
, 2,
762 &spuisofs_spe_priv2_addr
, &spuisofs_spe_problem_addr
, &spuisofs_spe_ls_addr
,
763 &junk
, &spuisofs_spe_shadow_addr
, &spuisofs_spe_id
);
767 printk(KERN_INFO
"spuisofs: spe id %llu\n", spuisofs_spe_id
);
769 spuisofs_spe_priv2
= ioremap(spuisofs_spe_priv2_addr
, sizeof(struct spu_priv2
));
770 if (!spuisofs_spe_priv2
) {
772 goto fail_destruct_spe
;
775 spuisofs_spe_problem
= ioremap(spuisofs_spe_problem_addr
, sizeof(struct spu_problem
));
776 if (!spuisofs_spe_problem
) {
778 goto fail_unmap_priv2
;
781 spuisofs_spe_ls
= ioremap_prot(spuisofs_spe_ls_addr
, LS_SIZE
, _PAGE_NO_CACHE
);
782 if (!spuisofs_spe_ls
) {
784 goto fail_unmap_problem
;
787 spuisofs_spe_shadow
= __ioremap(spuisofs_spe_shadow_addr
, sizeof(struct spe_shadow
),
789 if (!spuisofs_spe_shadow
) {
794 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 0, &spuisofs_spe_virq
[0]);
797 goto fail_unmap_shadow
;
800 err
= request_irq(spuisofs_spe_virq
[0], spuisofs_spe_interrupt
, 0,
801 "spuisofs_spe_irq0", &spuisofs_spe_virq
[0]);
803 goto fail_destroy_spe_irq_0
;
805 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 1, &spuisofs_spe_virq
[1]);
808 goto fail_free_spe_irq_0
;
811 err
= request_irq(spuisofs_spe_virq
[1], spuisofs_spe_interrupt
, 0,
812 "spuisofs_spe_irq1", &spuisofs_spe_virq
[1]);
814 goto fail_destroy_spe_irq_1
;
816 err
= ps3_spe_irq_setup(PS3_BINDING_CPU_ANY
, spuisofs_spe_id
, 2, &spuisofs_spe_virq
[2]);
819 goto fail_free_spe_irq_1
;
822 err
= request_irq(spuisofs_spe_virq
[2], spuisofs_spe_interrupt
, 0,
823 "spuisofs_spe_irq2", &spuisofs_spe_virq
[2]);
825 goto fail_destroy_spe_irq_2
;
827 err
= ps3_event_receive_port_setup(PS3_BINDING_CPU_ANY
, &spuisofs_spe_virq
[3]);
830 goto fail_free_spe_irq_2
;
833 err
= lv1_set_spe_transition_notifier(spuisofs_spe_id
, spuisofs_spe_trans_notify_mask
,
834 virq_to_hw(spuisofs_spe_virq
[3]));
836 printk(KERN_INFO
"spuisofs: lv1_set_spe_transition_notifier failed with %d\n", err
);
838 goto fail_destroy_event_recv_port
;
841 err
= request_irq(spuisofs_spe_virq
[3], spuisofs_spe_interrupt
, 0,
842 "spuisofs_spe_irq3", &spuisofs_spe_virq
[3]);
844 goto fail_destroy_event_recv_port
;
848 fail_destroy_event_recv_port
:
850 ps3_event_receive_port_destroy(spuisofs_spe_virq
[3]);
854 free_irq(spuisofs_spe_virq
[2], &spuisofs_spe_virq
[2]);
856 fail_destroy_spe_irq_2
:
858 ps3_spe_irq_destroy(spuisofs_spe_virq
[2]);
862 free_irq(spuisofs_spe_virq
[1], &spuisofs_spe_virq
[1]);
864 fail_destroy_spe_irq_1
:
866 ps3_spe_irq_destroy(spuisofs_spe_virq
[1]);
870 free_irq(spuisofs_spe_virq
[0], &spuisofs_spe_virq
[0]);
872 fail_destroy_spe_irq_0
:
874 ps3_spe_irq_destroy(spuisofs_spe_virq
[0]);
878 iounmap(spuisofs_spe_shadow
);
882 iounmap(spuisofs_spe_ls
);
886 iounmap(spuisofs_spe_problem
);
890 iounmap(spuisofs_spe_priv2
);
894 lv1_destruct_logical_spe(spuisofs_spe_id
);
900 * spuisofs_destruct_spe
902 static void spuisofs_destruct_spe(void)
904 free_irq(spuisofs_spe_virq
[0], &spuisofs_spe_virq
[0]);
905 ps3_spe_irq_destroy(spuisofs_spe_virq
[0]);
907 free_irq(spuisofs_spe_virq
[1], &spuisofs_spe_virq
[1]);
908 ps3_spe_irq_destroy(spuisofs_spe_virq
[1]);
910 free_irq(spuisofs_spe_virq
[2], &spuisofs_spe_virq
[2]);
911 ps3_spe_irq_destroy(spuisofs_spe_virq
[2]);
913 free_irq(spuisofs_spe_virq
[3], &spuisofs_spe_virq
[3]);
914 ps3_event_receive_port_destroy(spuisofs_spe_virq
[3]);
916 iounmap(spuisofs_spe_shadow
);
917 iounmap(spuisofs_spe_ls
);
918 iounmap(spuisofs_spe_problem
);
919 iounmap(spuisofs_spe_priv2
);
921 lv1_destruct_logical_spe(spuisofs_spe_id
);
927 static struct dentry
*spuisofs_mount(struct file_system_type
*fs_type
,
928 int flags
, const char *dev_name
, void *data
)
933 err
= spuisofs_create_spe();
937 spuisofs_spe_app
= vmalloc_user(spuisofs_spe_app_size
);
938 if (!spuisofs_spe_app
) {
940 goto fail_destruct_spe
;
943 memset(spuisofs_spe_app
, 0, spuisofs_spe_app_size
);
945 spuisofs_spe_arg1
= vmalloc_user(spuisofs_spe_arg1_size
);
946 if (!spuisofs_spe_arg1
) {
948 goto fail_free_spe_app
;
951 memset(spuisofs_spe_arg1
, 0, spuisofs_spe_arg1_size
);
953 spuisofs_spe_arg2
= vmalloc_user(spuisofs_spe_arg2_size
);
954 if (!spuisofs_spe_arg2
) {
956 goto fail_free_spe_arg1
;
959 memset(spuisofs_spe_arg2
, 0, spuisofs_spe_arg2_size
);
961 spuisofs_buf
= vmalloc_user(spuisofs_buf_size
);
964 goto fail_free_spe_arg2
;
967 memset(spuisofs_buf
, 0, spuisofs_buf_size
);
969 root
= mount_single(fs_type
, flags
, data
, spuisofs_fill_super
);
983 vfree(spuisofs_spe_arg2
);
987 vfree(spuisofs_spe_arg1
);
991 vfree(spuisofs_spe_app
);
995 spuisofs_destruct_spe();
1003 static void spuisofs_kill_sb(struct super_block
*sb
)
1005 kill_litter_super(sb
);
1007 vfree(spuisofs_spe_app
);
1008 vfree(spuisofs_spe_arg1
);
1009 vfree(spuisofs_spe_arg2
);
1010 vfree(spuisofs_buf
);
1011 spuisofs_destruct_spe();
1014 static struct file_system_type spuisofs_type
= {
1015 .owner
= THIS_MODULE
,
1017 .mount
= spuisofs_mount
,
1018 .kill_sb
= spuisofs_kill_sb
,
1024 static int __init
spuisofs_init(void)
1028 spuisofs_inode_cache
= kmem_cache_create("spuisofs_inode_cache",
1029 sizeof(struct spuisofs_inode_info
), 0, SLAB_HWCACHE_ALIGN
,
1030 spuisofs_init_once
);
1031 if (!spuisofs_inode_cache
)
1034 err
= register_filesystem(&spuisofs_type
);
1036 goto fail_destroy_inode_cache
;
1040 fail_destroy_inode_cache
:
1042 kmem_cache_destroy(spuisofs_inode_cache
);
1050 static void __exit
spuisofs_exit(void)
1052 unregister_filesystem(&spuisofs_type
);
1053 kmem_cache_destroy(spuisofs_inode_cache
);
1056 module_init(spuisofs_init
);
1057 module_exit(spuisofs_exit
);
1059 MODULE_DESCRIPTION("PS3 spuisofs");
1060 MODULE_AUTHOR("glevand");
1061 MODULE_LICENSE("GPL");