Commit 27d5bf2a authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[POWERPC] spufs: cell spu problem state mapping updates

This patch adds a new "psmap" file to spufs that allows mmap of all of
the problem state mapping of SPEs. It is compatible with 64k pages. In
addition, it removes mmap ability of individual files when using 64k
pages, with the exception of signal1 and signal2 which will both map the
entire 64k page holding both registers. It also removes
CONFIG_SPUFS_MMAP as there is no point in not building mmap support in
spufs.

It goes along a separate patch to libspe implementing usage of that new
file to access problem state registers.

Another patch will follow up to fix races opened up by accessing
the 'runcntl' register directly, which is made possible with this
patch.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 3bdc9d0b
...@@ -16,11 +16,6 @@ config SPU_BASE ...@@ -16,11 +16,6 @@ config SPU_BASE
bool bool
default n default n
config SPUFS_MMAP
bool
depends on SPU_FS && SPARSEMEM
default y
config CBE_RAS config CBE_RAS
bool "RAS features for bare metal Cell BE" bool "RAS features for bare metal Cell BE"
default y default y
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#include "spufs.h" #include "spufs.h"
#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
static int static int
spufs_mem_open(struct inode *inode, struct file *file) spufs_mem_open(struct inode *inode, struct file *file)
...@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const char __user *buffer, ...@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const char __user *buffer,
return ret; return ret;
} }
#ifdef CONFIG_SPUFS_MMAP
static struct page * static struct page *
spufs_mem_mmap_nopage(struct vm_area_struct *vma, spufs_mem_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
...@@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mem_mmap_vmops; vma->vm_ops = &spufs_mem_mmap_vmops;
return 0; return 0;
} }
#endif
static struct file_operations spufs_mem_fops = { static struct file_operations spufs_mem_fops = {
.open = spufs_mem_open, .open = spufs_mem_open,
.read = spufs_mem_read, .read = spufs_mem_read,
.write = spufs_mem_write, .write = spufs_mem_write,
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mem_mmap, .mmap = spufs_mem_mmap,
#endif
}; };
#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_ps_nopage(struct vm_area_struct *vma, static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
unsigned long address, unsigned long address,
int *type, unsigned long ps_offs) int *type, unsigned long ps_offs,
unsigned long ps_size)
{ {
struct page *page = NOPAGE_SIGBUS; struct page *page = NOPAGE_SIGBUS;
int fault_type = VM_FAULT_SIGBUS; int fault_type = VM_FAULT_SIGBUS;
...@@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, ...@@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
int ret; int ret;
offset += vma->vm_pgoff << PAGE_SHIFT; offset += vma->vm_pgoff << PAGE_SHIFT;
if (offset >= 0x4000) if (offset >= ps_size)
goto out; goto out;
ret = spu_acquire_runnable(ctx); ret = spu_acquire_runnable(ctx);
...@@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma, ...@@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
return page; return page;
} }
#if SPUFS_MMAP_4K
static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return spufs_ps_nopage(vma, address, type, 0x4000); return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
} }
static struct vm_operations_struct spufs_cntl_mmap_vmops = { static struct vm_operations_struct spufs_cntl_mmap_vmops = {
...@@ -191,17 +190,12 @@ static struct vm_operations_struct spufs_cntl_mmap_vmops = { ...@@ -191,17 +190,12 @@ static struct vm_operations_struct spufs_cntl_mmap_vmops = {
/* /*
* mmap support for problem state control area [0x4000 - 0x4fff]. * mmap support for problem state control area [0x4000 - 0x4fff].
* Mapping this area requires that the application have CAP_SYS_RAWIO,
* as these registers require special care when read/writing.
*/ */
static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
{ {
if (!(vma->vm_flags & VM_SHARED)) if (!(vma->vm_flags & VM_SHARED))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED); | _PAGE_NO_CACHE | _PAGE_GUARDED);
...@@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_cntl_mmap_vmops; vma->vm_ops = &spufs_cntl_mmap_vmops;
return 0; return 0;
} }
#endif #else /* SPUFS_MMAP_4K */
#define spufs_cntl_mmap NULL
#endif /* !SPUFS_MMAP_4K */
static int spufs_cntl_open(struct inode *inode, struct file *file) static int spufs_cntl_open(struct inode *inode, struct file *file)
{ {
...@@ -242,9 +238,7 @@ static struct file_operations spufs_cntl_fops = { ...@@ -242,9 +238,7 @@ static struct file_operations spufs_cntl_fops = {
.open = spufs_cntl_open, .open = spufs_cntl_open,
.read = spufs_cntl_read, .read = spufs_cntl_read,
.write = spufs_cntl_write, .write = spufs_cntl_write,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_cntl_mmap, .mmap = spufs_cntl_mmap,
#endif
}; };
static int static int
...@@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, ...@@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
return 4; return 4;
} }
#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return spufs_ps_nopage(vma, address, type, 0x14000); #if PAGE_SIZE == 0x1000
return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
#elif PAGE_SIZE == 0x10000
/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
* signal 1 and 2 area
*/
return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
#else
#error unsupported page size
#endif
} }
static struct vm_operations_struct spufs_signal1_mmap_vmops = { 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,15 +682,12 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_signal1_mmap_vmops; vma->vm_ops = &spufs_signal1_mmap_vmops;
return 0; return 0;
} }
#endif
static struct file_operations spufs_signal1_fops = { static struct file_operations spufs_signal1_fops = {
.open = spufs_signal1_open, .open = spufs_signal1_open,
.read = spufs_signal1_read, .read = spufs_signal1_read,
.write = spufs_signal1_write, .write = spufs_signal1_write,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal1_mmap, .mmap = spufs_signal1_mmap,
#endif
}; };
static int spufs_signal2_open(struct inode *inode, struct file *file) 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,11 +742,20 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
return 4; return 4;
} }
#ifdef CONFIG_SPUFS_MMAP #if SPUFS_MMAP_4K
static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return spufs_ps_nopage(vma, address, type, 0x1c000); #if PAGE_SIZE == 0x1000
return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
#elif PAGE_SIZE == 0x10000
/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
* signal 1 and 2 area
*/
return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
#else
#error unsupported page size
#endif
} }
static struct vm_operations_struct spufs_signal2_mmap_vmops = { 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,15 +775,15 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_signal2_mmap_vmops; vma->vm_ops = &spufs_signal2_mmap_vmops;
return 0; return 0;
} }
#endif #else /* SPUFS_MMAP_4K */
#define spufs_signal2_mmap NULL
#endif /* !SPUFS_MMAP_4K */
static struct file_operations spufs_signal2_fops = { static struct file_operations spufs_signal2_fops = {
.open = spufs_signal2_open, .open = spufs_signal2_open,
.read = spufs_signal2_read, .read = spufs_signal2_read,
.write = spufs_signal2_write, .write = spufs_signal2_write,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal2_mmap, .mmap = spufs_signal2_mmap,
#endif
}; };
static void spufs_signal1_type_set(void *data, u64 val) static void spufs_signal1_type_set(void *data, u64 val)
...@@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *data) ...@@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *data)
DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
spufs_signal2_type_set, "%llu"); spufs_signal2_type_set, "%llu");
#ifdef CONFIG_SPUFS_MMAP #if SPUFS_MMAP_4K
static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return spufs_ps_nopage(vma, address, type, 0x0000); return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
} }
static struct vm_operations_struct spufs_mss_mmap_vmops = { static struct vm_operations_struct spufs_mss_mmap_vmops = {
...@@ -837,17 +845,12 @@ static struct vm_operations_struct spufs_mss_mmap_vmops = { ...@@ -837,17 +845,12 @@ static struct vm_operations_struct spufs_mss_mmap_vmops = {
/* /*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
* Mapping this area requires that the application have CAP_SYS_RAWIO,
* as these registers require special care when read/writing.
*/ */
static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
{ {
if (!(vma->vm_flags & VM_SHARED)) if (!(vma->vm_flags & VM_SHARED))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED); | _PAGE_NO_CACHE | _PAGE_GUARDED);
...@@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mss_mmap_vmops; vma->vm_ops = &spufs_mss_mmap_vmops;
return 0; return 0;
} }
#endif #else /* SPUFS_MMAP_4K */
#define spufs_mss_mmap NULL
#endif /* !SPUFS_MMAP_4K */
static int spufs_mss_open(struct inode *inode, struct file *file) static int spufs_mss_open(struct inode *inode, struct file *file)
{ {
...@@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *inode, struct file *file) ...@@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *inode, struct file *file)
static struct file_operations spufs_mss_fops = { static struct file_operations spufs_mss_fops = {
.open = spufs_mss_open, .open = spufs_mss_open,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mss_mmap, .mmap = spufs_mss_mmap,
#endif };
static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
}
static struct vm_operations_struct spufs_psmap_mmap_vmops = {
.nopage = spufs_psmap_mmap_nopage,
};
/*
* mmap support for full problem state area [0x00000 - 0x1ffff].
*/
static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
vma->vm_ops = &spufs_psmap_mmap_vmops;
return 0;
}
static int spufs_psmap_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
file->private_data = i->i_ctx;
return nonseekable_open(inode, file);
}
static struct file_operations spufs_psmap_fops = {
.open = spufs_psmap_open,
.mmap = spufs_psmap_mmap,
}; };
#ifdef CONFIG_SPUFS_MMAP #if SPUFS_MMAP_4K
static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return spufs_ps_nopage(vma, address, type, 0x3000); return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
} }
static struct vm_operations_struct spufs_mfc_mmap_vmops = { static struct vm_operations_struct spufs_mfc_mmap_vmops = {
...@@ -886,17 +928,12 @@ static struct vm_operations_struct spufs_mfc_mmap_vmops = { ...@@ -886,17 +928,12 @@ static struct vm_operations_struct spufs_mfc_mmap_vmops = {
/* /*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
* Mapping this area requires that the application have CAP_SYS_RAWIO,
* as these registers require special care when read/writing.
*/ */
static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
{ {
if (!(vma->vm_flags & VM_SHARED)) if (!(vma->vm_flags & VM_SHARED))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED); | _PAGE_NO_CACHE | _PAGE_GUARDED);
...@@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mfc_mmap_vmops; vma->vm_ops = &spufs_mfc_mmap_vmops;
return 0; return 0;
} }
#endif #else /* SPUFS_MMAP_4K */
#define spufs_mfc_mmap NULL
#endif /* !SPUFS_MMAP_4K */
static int spufs_mfc_open(struct inode *inode, struct file *file) static int spufs_mfc_open(struct inode *inode, struct file *file)
{ {
...@@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_fops = { ...@@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_fops = {
.flush = spufs_mfc_flush, .flush = spufs_mfc_flush,
.fsync = spufs_mfc_fsync, .fsync = spufs_mfc_fsync,
.fasync = spufs_mfc_fasync, .fasync = spufs_mfc_fasync,
#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mfc_mmap, .mmap = spufs_mfc_mmap,
#endif
}; };
static void spufs_npc_set(void *data, u64 val) static void spufs_npc_set(void *data, u64 val)
...@@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] = { ...@@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] = {
{ "event_mask", &spufs_event_mask_ops, 0666, }, { "event_mask", &spufs_event_mask_ops, 0666, },
{ "srr0", &spufs_srr0_ops, 0666, }, { "srr0", &spufs_srr0_ops, 0666, },
{ "phys-id", &spufs_id_ops, 0666, }, { "phys-id", &spufs_id_ops, 0666, },
{ "psmap", &spufs_psmap_fops, 0666, },
{}, {},
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment