diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spufs/file.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 130 |
1 files changed, 84 insertions, 46 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 51fd197ab5d..64f8b0a9b9e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -36,6 +36,8 @@ | |||
36 | 36 | ||
37 | #include "spufs.h" | 37 | #include "spufs.h" |
38 | 38 | ||
39 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) | ||
40 | |||
39 | 41 | ||
40 | static int | 42 | static int |
41 | spufs_mem_open(struct inode *inode, struct file *file) | 43 | spufs_mem_open(struct inode *inode, struct file *file) |
@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const char __user *buffer, | |||
88 | return ret; | 90 | return ret; |
89 | } | 91 | } |
90 | 92 | ||
91 | #ifdef CONFIG_SPUFS_MMAP | ||
92 | static struct page * | 93 | static struct page * |
93 | spufs_mem_mmap_nopage(struct vm_area_struct *vma, | 94 | spufs_mem_mmap_nopage(struct vm_area_struct *vma, |
94 | unsigned long address, int *type) | 95 | unsigned long address, int *type) |
@@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) | |||
133 | vma->vm_ops = &spufs_mem_mmap_vmops; | 134 | vma->vm_ops = &spufs_mem_mmap_vmops; |
134 | return 0; | 135 | return 0; |
135 | } | 136 | } |
136 | #endif | ||
137 | 137 | ||
138 | static struct file_operations spufs_mem_fops = { | 138 | static struct file_operations spufs_mem_fops = { |
139 | .open = spufs_mem_open, | 139 | .open = spufs_mem_open, |
140 | .read = spufs_mem_read, | 140 | .read = spufs_mem_read, |
141 | .write = spufs_mem_write, | 141 | .write = spufs_mem_write, |
142 | .llseek = generic_file_llseek, | 142 | .llseek = generic_file_llseek, |
143 | #ifdef CONFIG_SPUFS_MMAP | ||
144 | .mmap = spufs_mem_mmap, | 143 | .mmap = spufs_mem_mmap, |
145 | #endif | ||
146 | }; | 144 | }; |
147 | 145 | ||
148 | #ifdef CONFIG_SPUFS_MMAP | ||
149 | static struct page *spufs_ps_nopage(struct vm_area_struct *vma, | 146 | static struct page *spufs_ps_nopage(struct vm_area_struct *vma, |
150 | unsigned long address, | 147 | unsigned long address, |
151 | int *type, unsigned long ps_offs) | 148 | int *type, unsigned long ps_offs, |
149 | unsigned long ps_size) | ||
152 | { | 150 | { |
153 | struct page *page = NOPAGE_SIGBUS; | 151 | struct page *page = NOPAGE_SIGBUS; |
154 | int fault_type = VM_FAULT_SIGBUS; | 152 | int fault_type = VM_FAULT_SIGBUS; |
@@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, | |||
158 | int ret; | 156 | int ret; |
159 | 157 | ||
160 | offset += vma->vm_pgoff << PAGE_SHIFT; | 158 | offset += vma->vm_pgoff << PAGE_SHIFT; |
161 | if (offset >= 0x4000) | 159 | if (offset >= ps_size) |
162 | goto out; | 160 | goto out; |
163 | 161 | ||
164 | ret = spu_acquire_runnable(ctx); | 162 | ret = spu_acquire_runnable(ctx); |
@@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, | |||
179 | return page; | 177 | return page; |
180 | } | 178 | } |
181 | 179 | ||
180 | #if SPUFS_MMAP_4K | ||
182 | static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, | 181 | static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, |
183 | unsigned long address, int *type) | 182 | unsigned long address, int *type) |
184 | { | 183 | { |
185 | return spufs_ps_nopage(vma, address, type, 0x4000); | 184 | return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); |
186 | } | 185 | } |
187 | 186 | ||
188 | static struct vm_operations_struct spufs_cntl_mmap_vmops = { | 187 | static struct vm_operations_struct spufs_cntl_mmap_vmops = { |
@@ -191,17 +190,12 @@ static struct vm_operations_struct spufs_cntl_mmap_vmops = { | |||
191 | 190 | ||
192 | /* | 191 | /* |
193 | * mmap support for problem state control area [0x4000 - 0x4fff]. | 192 | * mmap support for problem state control area [0x4000 - 0x4fff]. |
194 | * Mapping this area requires that the application have CAP_SYS_RAWIO, | ||
195 | * as these registers require special care when read/writing. | ||
196 | */ | 193 | */ |
197 | static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) | 194 | static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) |
198 | { | 195 | { |
199 | if (!(vma->vm_flags & VM_SHARED)) | 196 | if (!(vma->vm_flags & VM_SHARED)) |
200 | return -EINVAL; | 197 | return -EINVAL; |
201 | 198 | ||
202 | if (!capable(CAP_SYS_RAWIO)) | ||
203 | return -EPERM; | ||
204 | |||
205 | vma->vm_flags |= VM_RESERVED; | 199 | vma->vm_flags |= VM_RESERVED; |
206 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 200 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
207 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 201 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
@@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) | |||
209 | vma->vm_ops = &spufs_cntl_mmap_vmops; | 203 | vma->vm_ops = &spufs_cntl_mmap_vmops; |
210 | return 0; | 204 | return 0; |
211 | } | 205 | } |
212 | #endif | 206 | #else /* SPUFS_MMAP_4K */ |
207 | #define spufs_cntl_mmap NULL | ||
208 | #endif /* !SPUFS_MMAP_4K */ | ||
213 | 209 | ||
214 | static int spufs_cntl_open(struct inode *inode, struct file *file) | 210 | static int spufs_cntl_open(struct inode *inode, struct file *file) |
215 | { | 211 | { |
@@ -242,9 +238,7 @@ static struct file_operations spufs_cntl_fops = { | |||
242 | .open = spufs_cntl_open, | 238 | .open = spufs_cntl_open, |
243 | .read = spufs_cntl_read, | 239 | .read = spufs_cntl_read, |
244 | .write = spufs_cntl_write, | 240 | .write = spufs_cntl_write, |
245 | #ifdef CONFIG_SPUFS_MMAP | ||
246 | .mmap = spufs_cntl_mmap, | 241 | .mmap = spufs_cntl_mmap, |
247 | #endif | ||
248 | }; | 242 | }; |
249 | 243 | ||
250 | static int | 244 | static int |
@@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | |||
657 | return 4; | 651 | return 4; |
658 | } | 652 | } |
659 | 653 | ||
660 | #ifdef CONFIG_SPUFS_MMAP | ||
661 | static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, | 654 | static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, |
662 | unsigned long address, int *type) | 655 | unsigned long address, int *type) |
663 | { | 656 | { |
664 | return spufs_ps_nopage(vma, address, type, 0x14000); | 657 | #if PAGE_SIZE == 0x1000 |
658 | return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); | ||
659 | #elif PAGE_SIZE == 0x10000 | ||
660 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole | ||
661 | * signal 1 and 2 area | ||
662 | */ | ||
663 | return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); | ||
664 | #else | ||
665 | #error unsupported page size | ||
666 | #endif | ||
665 | } | 667 | } |
666 | 668 | ||
667 | static struct vm_operations_struct spufs_signal1_mmap_vmops = { | 669 | static struct vm_operations_struct spufs_signal1_mmap_vmops = { |
@@ -680,15 +682,12 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) | |||
680 | vma->vm_ops = &spufs_signal1_mmap_vmops; | 682 | vma->vm_ops = &spufs_signal1_mmap_vmops; |
681 | return 0; | 683 | return 0; |
682 | } | 684 | } |
683 | #endif | ||
684 | 685 | ||
685 | static struct file_operations spufs_signal1_fops = { | 686 | static struct file_operations spufs_signal1_fops = { |
686 | .open = spufs_signal1_open, | 687 | .open = spufs_signal1_open, |
687 | .read = spufs_signal1_read, | 688 | .read = spufs_signal1_read, |
688 | .write = spufs_signal1_write, | 689 | .write = spufs_signal1_write, |
689 | #ifdef CONFIG_SPUFS_MMAP | ||
690 | .mmap = spufs_signal1_mmap, | 690 | .mmap = spufs_signal1_mmap, |
691 | #endif | ||
692 | }; | 691 | }; |
693 | 692 | ||
694 | static int spufs_signal2_open(struct inode *inode, struct file *file) | 693 | static int spufs_signal2_open(struct inode *inode, struct file *file) |
@@ -743,11 +742,20 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | |||
743 | return 4; | 742 | return 4; |
744 | } | 743 | } |
745 | 744 | ||
746 | #ifdef CONFIG_SPUFS_MMAP | 745 | #if SPUFS_MMAP_4K |
747 | static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, | 746 | static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, |
748 | unsigned long address, int *type) | 747 | unsigned long address, int *type) |
749 | { | 748 | { |
750 | return spufs_ps_nopage(vma, address, type, 0x1c000); | 749 | #if PAGE_SIZE == 0x1000 |
750 | return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); | ||
751 | #elif PAGE_SIZE == 0x10000 | ||
752 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole | ||
753 | * signal 1 and 2 area | ||
754 | */ | ||
755 | return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); | ||
756 | #else | ||
757 | #error unsupported page size | ||
758 | #endif | ||
751 | } | 759 | } |
752 | 760 | ||
753 | static struct vm_operations_struct spufs_signal2_mmap_vmops = { | 761 | static struct vm_operations_struct spufs_signal2_mmap_vmops = { |
@@ -767,15 +775,15 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) | |||
767 | vma->vm_ops = &spufs_signal2_mmap_vmops; | 775 | vma->vm_ops = &spufs_signal2_mmap_vmops; |
768 | return 0; | 776 | return 0; |
769 | } | 777 | } |
770 | #endif | 778 | #else /* SPUFS_MMAP_4K */ |
779 | #define spufs_signal2_mmap NULL | ||
780 | #endif /* !SPUFS_MMAP_4K */ | ||
771 | 781 | ||
772 | static struct file_operations spufs_signal2_fops = { | 782 | static struct file_operations spufs_signal2_fops = { |
773 | .open = spufs_signal2_open, | 783 | .open = spufs_signal2_open, |
774 | .read = spufs_signal2_read, | 784 | .read = spufs_signal2_read, |
775 | .write = spufs_signal2_write, | 785 | .write = spufs_signal2_write, |
776 | #ifdef CONFIG_SPUFS_MMAP | ||
777 | .mmap = spufs_signal2_mmap, | 786 | .mmap = spufs_signal2_mmap, |
778 | #endif | ||
779 | }; | 787 | }; |
780 | 788 | ||
781 | static void spufs_signal1_type_set(void *data, u64 val) | 789 | static void spufs_signal1_type_set(void *data, u64 val) |
@@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *data) | |||
824 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, | 832 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, |
825 | spufs_signal2_type_set, "%llu"); | 833 | spufs_signal2_type_set, "%llu"); |
826 | 834 | ||
827 | #ifdef CONFIG_SPUFS_MMAP | 835 | #if SPUFS_MMAP_4K |
828 | static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, | 836 | static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, |
829 | unsigned long address, int *type) | 837 | unsigned long address, int *type) |
830 | { | 838 | { |
831 | return spufs_ps_nopage(vma, address, type, 0x0000); | 839 | return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); |
832 | } | 840 | } |
833 | 841 | ||
834 | static struct vm_operations_struct spufs_mss_mmap_vmops = { | 842 | static struct vm_operations_struct spufs_mss_mmap_vmops = { |
@@ -837,17 +845,12 @@ static struct vm_operations_struct spufs_mss_mmap_vmops = { | |||
837 | 845 | ||
838 | /* | 846 | /* |
839 | * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. | 847 | * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. |
840 | * Mapping this area requires that the application have CAP_SYS_RAWIO, | ||
841 | * as these registers require special care when read/writing. | ||
842 | */ | 848 | */ |
843 | static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) | 849 | static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) |
844 | { | 850 | { |
845 | if (!(vma->vm_flags & VM_SHARED)) | 851 | if (!(vma->vm_flags & VM_SHARED)) |
846 | return -EINVAL; | 852 | return -EINVAL; |
847 | 853 | ||
848 | if (!capable(CAP_SYS_RAWIO)) | ||
849 | return -EPERM; | ||
850 | |||
851 | vma->vm_flags |= VM_RESERVED; | 854 | vma->vm_flags |= VM_RESERVED; |
852 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 855 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
853 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 856 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
@@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) | |||
855 | vma->vm_ops = &spufs_mss_mmap_vmops; | 858 | vma->vm_ops = &spufs_mss_mmap_vmops; |
856 | return 0; | 859 | return 0; |
857 | } | 860 | } |
858 | #endif | 861 | #else /* SPUFS_MMAP_4K */ |
862 | #define spufs_mss_mmap NULL | ||
863 | #endif /* !SPUFS_MMAP_4K */ | ||
859 | 864 | ||
860 | static int spufs_mss_open(struct inode *inode, struct file *file) | 865 | static int spufs_mss_open(struct inode *inode, struct file *file) |
861 | { | 866 | { |
@@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *inode, struct file *file) | |||
867 | 872 | ||
868 | static struct file_operations spufs_mss_fops = { | 873 | static struct file_operations spufs_mss_fops = { |
869 | .open = spufs_mss_open, | 874 | .open = spufs_mss_open, |
870 | #ifdef CONFIG_SPUFS_MMAP | ||
871 | .mmap = spufs_mss_mmap, | 875 | .mmap = spufs_mss_mmap, |
872 | #endif | 876 | }; |
877 | |||
878 | static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, | ||
879 | unsigned long address, int *type) | ||
880 | { | ||
881 | return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); | ||
882 | } | ||
883 | |||
884 | static struct vm_operations_struct spufs_psmap_mmap_vmops = { | ||
885 | .nopage = spufs_psmap_mmap_nopage, | ||
886 | }; | ||
887 | |||
888 | /* | ||
889 | * mmap support for full problem state area [0x00000 - 0x1ffff]. | ||
890 | */ | ||
891 | static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) | ||
892 | { | ||
893 | if (!(vma->vm_flags & VM_SHARED)) | ||
894 | return -EINVAL; | ||
895 | |||
896 | vma->vm_flags |= VM_RESERVED; | ||
897 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | ||
898 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | ||
899 | |||
900 | vma->vm_ops = &spufs_psmap_mmap_vmops; | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static int spufs_psmap_open(struct inode *inode, struct file *file) | ||
905 | { | ||
906 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
907 | |||
908 | file->private_data = i->i_ctx; | ||
909 | return nonseekable_open(inode, file); | ||
910 | } | ||
911 | |||
912 | static struct file_operations spufs_psmap_fops = { | ||
913 | .open = spufs_psmap_open, | ||
914 | .mmap = spufs_psmap_mmap, | ||
873 | }; | 915 | }; |
874 | 916 | ||
875 | 917 | ||
876 | #ifdef CONFIG_SPUFS_MMAP | 918 | #if SPUFS_MMAP_4K |
877 | static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, | 919 | static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, |
878 | unsigned long address, int *type) | 920 | unsigned long address, int *type) |
879 | { | 921 | { |
880 | return spufs_ps_nopage(vma, address, type, 0x3000); | 922 | return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); |
881 | } | 923 | } |
882 | 924 | ||
883 | static struct vm_operations_struct spufs_mfc_mmap_vmops = { | 925 | static struct vm_operations_struct spufs_mfc_mmap_vmops = { |
@@ -886,17 +928,12 @@ static struct vm_operations_struct spufs_mfc_mmap_vmops = { | |||
886 | 928 | ||
887 | /* | 929 | /* |
888 | * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. | 930 | * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. |
889 | * Mapping this area requires that the application have CAP_SYS_RAWIO, | ||
890 | * as these registers require special care when read/writing. | ||
891 | */ | 931 | */ |
892 | static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) | 932 | static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) |
893 | { | 933 | { |
894 | if (!(vma->vm_flags & VM_SHARED)) | 934 | if (!(vma->vm_flags & VM_SHARED)) |
895 | return -EINVAL; | 935 | return -EINVAL; |
896 | 936 | ||
897 | if (!capable(CAP_SYS_RAWIO)) | ||
898 | return -EPERM; | ||
899 | |||
900 | vma->vm_flags |= VM_RESERVED; | 937 | vma->vm_flags |= VM_RESERVED; |
901 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 938 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
902 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 939 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
@@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) | |||
904 | vma->vm_ops = &spufs_mfc_mmap_vmops; | 941 | vma->vm_ops = &spufs_mfc_mmap_vmops; |
905 | return 0; | 942 | return 0; |
906 | } | 943 | } |
907 | #endif | 944 | #else /* SPUFS_MMAP_4K */ |
945 | #define spufs_mfc_mmap NULL | ||
946 | #endif /* !SPUFS_MMAP_4K */ | ||
908 | 947 | ||
909 | static int spufs_mfc_open(struct inode *inode, struct file *file) | 948 | static int spufs_mfc_open(struct inode *inode, struct file *file) |
910 | { | 949 | { |
@@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_fops = { | |||
1194 | .flush = spufs_mfc_flush, | 1233 | .flush = spufs_mfc_flush, |
1195 | .fsync = spufs_mfc_fsync, | 1234 | .fsync = spufs_mfc_fsync, |
1196 | .fasync = spufs_mfc_fasync, | 1235 | .fasync = spufs_mfc_fasync, |
1197 | #ifdef CONFIG_SPUFS_MMAP | ||
1198 | .mmap = spufs_mfc_mmap, | 1236 | .mmap = spufs_mfc_mmap, |
1199 | #endif | ||
1200 | }; | 1237 | }; |
1201 | 1238 | ||
1202 | static void spufs_npc_set(void *data, u64 val) | 1239 | static void spufs_npc_set(void *data, u64 val) |
@@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] = { | |||
1368 | { "event_mask", &spufs_event_mask_ops, 0666, }, | 1405 | { "event_mask", &spufs_event_mask_ops, 0666, }, |
1369 | { "srr0", &spufs_srr0_ops, 0666, }, | 1406 | { "srr0", &spufs_srr0_ops, 0666, }, |
1370 | { "phys-id", &spufs_id_ops, 0666, }, | 1407 | { "phys-id", &spufs_id_ops, 0666, }, |
1408 | { "psmap", &spufs_psmap_fops, 0666, }, | ||
1371 | {}, | 1409 | {}, |
1372 | }; | 1410 | }; |