2005-11-15 15:53:48 -05:00
/*
* SPU file system - - file contents
*
* ( C ) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author : Arnd Bergmann < arndb @ de . ibm . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2006-03-23 00:00:11 +01:00
# undef DEBUG
2005-11-15 15:53:48 -05:00
# include <linux/fs.h>
# include <linux/ioctl.h>
# include <linux/module.h>
2005-12-05 22:52:22 -05:00
# include <linux/pagemap.h>
2005-11-15 15:53:48 -05:00
# include <linux/poll.h>
2005-12-05 22:52:25 -05:00
# include <linux/ptrace.h>
2005-11-15 15:53:48 -05:00
# include <asm/io.h>
# include <asm/semaphore.h>
# include <asm/spu.h>
2006-11-20 18:44:58 +01:00
# include <asm/spu_info.h>
2005-11-15 15:53:48 -05:00
# include <asm/uaccess.h>
# include "spufs.h"
2006-10-04 17:26:11 +02:00
# define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
2005-11-15 15:53:52 -05:00
2005-11-15 15:53:48 -05:00
static int
spufs_mem_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
2006-03-23 00:00:12 +01:00
struct spu_context * ctx = i - > i_ctx ;
file - > private_data = ctx ;
file - > f_mapping = inode - > i_mapping ;
ctx - > local_store = inode - > i_mapping ;
2005-11-15 15:53:48 -05:00
return 0 ;
}
static ssize_t
spufs_mem_read ( struct file * file , char __user * buffer ,
size_t size , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
char * local_store ;
2005-11-15 15:53:48 -05:00
int ret ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
local_store = ctx - > ops - > get_ls ( ctx ) ;
ret = simple_read_from_buffer ( buffer , size , pos , local_store , LS_SIZE ) ;
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return ret ;
}
static ssize_t
spufs_mem_write ( struct file * file , const char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:52 -05:00
char * local_store ;
int ret ;
2005-11-15 15:53:48 -05:00
size = min_t ( ssize_t , LS_SIZE - * pos , size ) ;
if ( size < = 0 )
return - EFBIG ;
* pos + = size ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
local_store = ctx - > ops - > get_ls ( ctx ) ;
ret = copy_from_user ( local_store + * pos - size ,
buffer , size ) ? - EFAULT : size ;
spu_release ( ctx ) ;
return ret ;
2005-11-15 15:53:48 -05:00
}
2005-11-15 15:53:52 -05:00
static struct page *
spufs_mem_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
struct page * page = NOPAGE_SIGBUS ;
struct spu_context * ctx = vma - > vm_file - > private_data ;
unsigned long offset = address - vma - > vm_start ;
offset + = vma - > vm_pgoff < < PAGE_SHIFT ;
spu_acquire ( ctx ) ;
2006-10-04 17:26:16 +02:00
if ( ctx - > state = = SPU_STATE_SAVED ) {
vma - > vm_page_prot = __pgprot ( pgprot_val ( vma - > vm_page_prot )
& ~ ( _PAGE_NO_CACHE | _PAGE_GUARDED ) ) ;
2005-11-15 15:53:52 -05:00
page = vmalloc_to_page ( ctx - > csa . lscsa - > ls + offset ) ;
2006-10-04 17:26:16 +02:00
} else {
vma - > vm_page_prot = __pgprot ( pgprot_val ( vma - > vm_page_prot )
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2005-11-15 15:53:52 -05:00
page = pfn_to_page ( ( ctx - > spu - > local_store_phys + offset )
> > PAGE_SHIFT ) ;
2006-10-04 17:26:16 +02:00
}
2005-11-15 15:53:52 -05:00
spu_release ( ctx ) ;
if ( type )
* type = VM_FAULT_MINOR ;
2005-12-05 22:52:22 -05:00
page_cache_get ( page ) ;
2005-11-15 15:53:52 -05:00
return page ;
}
static struct vm_operations_struct spufs_mem_mmap_vmops = {
. nopage = spufs_mem_mmap_nopage ,
} ;
2005-11-15 15:53:48 -05:00
static int
spufs_mem_mmap ( struct file * file , struct vm_area_struct * vma )
{
2005-11-15 15:53:52 -05:00
if ( ! ( vma - > vm_flags & VM_SHARED ) )
return - EINVAL ;
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
/* FIXME: */
vma - > vm_page_prot = __pgprot ( pgprot_val ( vma - > vm_page_prot )
| _PAGE_NO_CACHE ) ;
vma - > vm_ops = & spufs_mem_mmap_vmops ;
2005-11-15 15:53:48 -05:00
return 0 ;
}
static struct file_operations spufs_mem_fops = {
. open = spufs_mem_open ,
. read = spufs_mem_read ,
. write = spufs_mem_write ,
2005-11-15 15:53:52 -05:00
. llseek = generic_file_llseek ,
2005-11-15 15:53:48 -05:00
. mmap = spufs_mem_mmap ,
2005-11-15 15:53:52 -05:00
} ;
2006-03-23 00:00:12 +01:00
static struct page * spufs_ps_nopage ( struct vm_area_struct * vma ,
unsigned long address ,
2006-10-04 17:26:11 +02:00
int * type , unsigned long ps_offs ,
unsigned long ps_size )
2006-03-23 00:00:12 +01:00
{
struct page * page = NOPAGE_SIGBUS ;
int fault_type = VM_FAULT_SIGBUS ;
struct spu_context * ctx = vma - > vm_file - > private_data ;
unsigned long offset = address - vma - > vm_start ;
unsigned long area ;
int ret ;
offset + = vma - > vm_pgoff < < PAGE_SHIFT ;
2006-10-04 17:26:11 +02:00
if ( offset > = ps_size )
2006-03-23 00:00:12 +01:00
goto out ;
ret = spu_acquire_runnable ( ctx ) ;
if ( ret )
goto out ;
area = ctx - > spu - > problem_phys + ps_offs ;
page = pfn_to_page ( ( area + offset ) > > PAGE_SHIFT ) ;
fault_type = VM_FAULT_MINOR ;
page_cache_get ( page ) ;
spu_release ( ctx ) ;
out :
if ( type )
* type = fault_type ;
return page ;
}
2006-10-04 17:26:11 +02:00
# if SPUFS_MMAP_4K
2006-03-23 00:00:12 +01:00
static struct page * spufs_cntl_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
2006-10-04 17:26:11 +02:00
return spufs_ps_nopage ( vma , address , type , 0x4000 , 0x1000 ) ;
2006-03-23 00:00:12 +01:00
}
static struct vm_operations_struct spufs_cntl_mmap_vmops = {
. nopage = spufs_cntl_mmap_nopage ,
} ;
/*
* mmap support for problem state control area [ 0x4000 - 0x4fff ] .
*/
static int spufs_cntl_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 )
2006-06-23 20:57:47 +02:00
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2006-03-23 00:00:12 +01:00
vma - > vm_ops = & spufs_cntl_mmap_vmops ;
return 0 ;
}
2006-10-04 17:26:11 +02:00
# else /* SPUFS_MMAP_4K */
# define spufs_cntl_mmap NULL
# endif /* !SPUFS_MMAP_4K */
2006-03-23 00:00:12 +01:00
2006-10-04 17:26:19 +02:00
static u64 spufs_cntl_get ( void * data )
2006-03-23 00:00:12 +01:00
{
2006-10-04 17:26:19 +02:00
struct spu_context * ctx = data ;
u64 val ;
2006-03-23 00:00:12 +01:00
2006-10-04 17:26:19 +02:00
spu_acquire ( ctx ) ;
val = ctx - > ops - > status_read ( ctx ) ;
spu_release ( ctx ) ;
return val ;
2006-03-23 00:00:12 +01:00
}
2006-10-04 17:26:19 +02:00
static void spufs_cntl_set ( void * data , u64 val )
2006-03-23 00:00:12 +01:00
{
2006-10-04 17:26:19 +02:00
struct spu_context * ctx = data ;
spu_acquire ( ctx ) ;
ctx - > ops - > runcntl_write ( ctx , val ) ;
spu_release ( ctx ) ;
2006-03-23 00:00:12 +01:00
}
2006-10-04 17:26:19 +02:00
static int spufs_cntl_open ( struct inode * inode , struct file * file )
2006-03-23 00:00:12 +01:00
{
2006-10-04 17:26:19 +02:00
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
struct spu_context * ctx = i - > i_ctx ;
file - > private_data = ctx ;
file - > f_mapping = inode - > i_mapping ;
ctx - > cntl = inode - > i_mapping ;
return simple_attr_open ( inode , file , spufs_cntl_get ,
spufs_cntl_set , " 0x%08lx " ) ;
2006-03-23 00:00:12 +01:00
}
static struct file_operations spufs_cntl_fops = {
. open = spufs_cntl_open ,
2006-10-10 10:27:29 +02:00
. release = simple_attr_close ,
2006-10-04 17:26:19 +02:00
. read = simple_attr_read ,
. write = simple_attr_write ,
2006-03-23 00:00:12 +01:00
. mmap = spufs_cntl_mmap ,
} ;
2005-11-15 15:53:52 -05:00
static int
spufs_regs_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
file - > private_data = i - > i_ctx ;
return 0 ;
}
static ssize_t
spufs_regs_read ( struct file * file , char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
int ret ;
spu_acquire_saved ( ctx ) ;
ret = simple_read_from_buffer ( buffer , size , pos ,
lscsa - > gprs , sizeof lscsa - > gprs ) ;
spu_release ( ctx ) ;
return ret ;
}
static ssize_t
spufs_regs_write ( struct file * file , const char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
int ret ;
size = min_t ( ssize_t , sizeof lscsa - > gprs - * pos , size ) ;
if ( size < = 0 )
return - EFBIG ;
* pos + = size ;
spu_acquire_saved ( ctx ) ;
ret = copy_from_user ( lscsa - > gprs + * pos - size ,
buffer , size ) ? - EFAULT : size ;
spu_release ( ctx ) ;
return ret ;
}
static struct file_operations spufs_regs_fops = {
. open = spufs_regs_open ,
. read = spufs_regs_read ,
. write = spufs_regs_write ,
2005-11-15 15:53:48 -05:00
. llseek = generic_file_llseek ,
} ;
2005-11-15 15:53:52 -05:00
static ssize_t
spufs_fpcr_read ( struct file * file , char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
int ret ;
spu_acquire_saved ( ctx ) ;
ret = simple_read_from_buffer ( buffer , size , pos ,
& lscsa - > fpcr , sizeof ( lscsa - > fpcr ) ) ;
spu_release ( ctx ) ;
return ret ;
}
static ssize_t
spufs_fpcr_write ( struct file * file , const char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
int ret ;
size = min_t ( ssize_t , sizeof ( lscsa - > fpcr ) - * pos , size ) ;
if ( size < = 0 )
return - EFBIG ;
* pos + = size ;
spu_acquire_saved ( ctx ) ;
ret = copy_from_user ( ( char * ) & lscsa - > fpcr + * pos - size ,
buffer , size ) ? - EFAULT : size ;
spu_release ( ctx ) ;
return ret ;
}
static struct file_operations spufs_fpcr_fops = {
. open = spufs_regs_open ,
. read = spufs_fpcr_read ,
. write = spufs_fpcr_write ,
. llseek = generic_file_llseek ,
} ;
2005-11-15 15:53:48 -05:00
/* generic open function for all pipe-like files */
static int spufs_pipe_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 ) ;
}
2006-10-04 17:26:17 +02:00
/*
* Read as many bytes from the mailbox as possible , until
* one of the conditions becomes true :
*
* - no more data available in the mailbox
* - end of the user provided buffer
* - end of the mapped area
*/
2005-11-15 15:53:48 -05:00
static ssize_t spufs_mbox_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2006-10-04 17:26:17 +02:00
u32 mbox_data , __user * udata ;
ssize_t count ;
2005-11-15 15:53:48 -05:00
if ( len < 4 )
return - EINVAL ;
2006-10-04 17:26:17 +02:00
if ( ! access_ok ( VERIFY_WRITE , buf , len ) )
return - EFAULT ;
udata = ( void __user * ) buf ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
2006-10-24 18:01:42 +02:00
for ( count = 0 ; ( count + 4 ) < = len ; count + = 4 , udata + + ) {
2006-10-04 17:26:17 +02:00
int ret ;
ret = ctx - > ops - > mbox_read ( ctx , & mbox_data ) ;
if ( ret = = 0 )
break ;
/*
* at the end of the mapped area , we can fault
* but still need to return the data we have
* read successfully so far .
*/
ret = __put_user ( mbox_data , udata ) ;
if ( ret ) {
if ( ! count )
count = - EFAULT ;
break ;
}
}
2005-11-15 15:53:52 -05:00
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
if ( ! count )
count = - EAGAIN ;
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
return count ;
2005-11-15 15:53:48 -05:00
}
static struct file_operations spufs_mbox_fops = {
. open = spufs_pipe_open ,
. read = spufs_mbox_read ,
} ;
static ssize_t spufs_mbox_stat_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
u32 mbox_stat ;
if ( len < 4 )
return - EINVAL ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
mbox_stat = ctx - > ops - > mbox_stat_read ( ctx ) & 0xff ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
if ( copy_to_user ( buf , & mbox_stat , sizeof mbox_stat ) )
return - EFAULT ;
return 4 ;
}
static struct file_operations spufs_mbox_stat_fops = {
. open = spufs_pipe_open ,
. read = spufs_mbox_stat_read ,
} ;
/* low-level ibox access function */
2005-11-15 15:53:52 -05:00
size_t spu_ibox_read ( struct spu_context * ctx , u32 * data )
2005-11-15 15:53:48 -05:00
{
2005-11-15 15:53:52 -05:00
return ctx - > ops - > ibox_read ( ctx , data ) ;
}
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
static int spufs_ibox_fasync ( int fd , struct file * file , int on )
{
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
return fasync_helper ( fd , file , on , & ctx - > ibox_fasync ) ;
2005-11-15 15:53:48 -05:00
}
2005-11-15 15:53:52 -05:00
/* interrupt-level ibox callback function. */
void spufs_ibox_callback ( struct spu * spu )
2005-11-15 15:53:48 -05:00
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = spu - > ctx ;
wake_up_all ( & ctx - > ibox_wq ) ;
kill_fasync ( & ctx - > ibox_fasync , SIGIO , POLLIN ) ;
2005-11-15 15:53:48 -05:00
}
2006-10-04 17:26:17 +02:00
/*
* Read as many bytes from the interrupt mailbox as possible , until
* one of the conditions becomes true :
*
* - no more data available in the mailbox
* - end of the user provided buffer
* - end of the mapped area
*
* If the file is opened without O_NONBLOCK , we wait here until
* any data is available , but return when we have been able to
* read something .
*/
2005-11-15 15:53:48 -05:00
static ssize_t spufs_ibox_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2006-10-04 17:26:17 +02:00
u32 ibox_data , __user * udata ;
ssize_t count ;
2005-11-15 15:53:48 -05:00
if ( len < 4 )
return - EINVAL ;
2006-10-04 17:26:17 +02:00
if ( ! access_ok ( VERIFY_WRITE , buf , len ) )
return - EFAULT ;
udata = ( void __user * ) buf ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
/* wait only for the first element */
count = 0 ;
2005-11-15 15:53:48 -05:00
if ( file - > f_flags & O_NONBLOCK ) {
2005-11-15 15:53:52 -05:00
if ( ! spu_ibox_read ( ctx , & ibox_data ) )
2006-10-04 17:26:17 +02:00
count = - EAGAIN ;
2005-11-15 15:53:48 -05:00
} else {
2006-10-04 17:26:17 +02:00
count = spufs_wait ( ctx - > ibox_wq , spu_ibox_read ( ctx , & ibox_data ) ) ;
2005-11-15 15:53:48 -05:00
}
2006-10-04 17:26:17 +02:00
if ( count )
goto out ;
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
/* if we can't write at all, return -EFAULT */
count = __put_user ( ibox_data , udata ) ;
if ( count )
goto out ;
2005-11-15 15:53:52 -05:00
2006-10-04 17:26:17 +02:00
for ( count = 4 , udata + + ; ( count + 4 ) < = len ; count + = 4 , udata + + ) {
int ret ;
ret = ctx - > ops - > ibox_read ( ctx , & ibox_data ) ;
if ( ret = = 0 )
break ;
/*
* at the end of the mapped area , we can fault
* but still need to return the data we have
* read successfully so far .
*/
ret = __put_user ( ibox_data , udata ) ;
if ( ret )
break ;
}
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
out :
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
2006-10-04 17:26:17 +02:00
return count ;
2005-11-15 15:53:48 -05:00
}
static unsigned int spufs_ibox_poll ( struct file * file , poll_table * wait )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
unsigned int mask ;
2005-11-15 15:53:52 -05:00
poll_wait ( file , & ctx - > ibox_wq , wait ) ;
2005-11-15 15:53:48 -05:00
2005-12-05 22:52:27 -05:00
spu_acquire ( ctx ) ;
mask = ctx - > ops - > mbox_stat_poll ( ctx , POLLIN | POLLRDNORM ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return mask ;
}
static struct file_operations spufs_ibox_fops = {
. open = spufs_pipe_open ,
. read = spufs_ibox_read ,
. poll = spufs_ibox_poll ,
. fasync = spufs_ibox_fasync ,
} ;
static ssize_t spufs_ibox_stat_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
u32 ibox_stat ;
if ( len < 4 )
return - EINVAL ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ibox_stat = ( ctx - > ops - > mbox_stat_read ( ctx ) > > 16 ) & 0xff ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
if ( copy_to_user ( buf , & ibox_stat , sizeof ibox_stat ) )
return - EFAULT ;
return 4 ;
}
static struct file_operations spufs_ibox_stat_fops = {
. open = spufs_pipe_open ,
. read = spufs_ibox_stat_read ,
} ;
/* low-level mailbox write */
2005-11-15 15:53:52 -05:00
size_t spu_wbox_write ( struct spu_context * ctx , u32 data )
2005-11-15 15:53:48 -05:00
{
2005-11-15 15:53:52 -05:00
return ctx - > ops - > wbox_write ( ctx , data ) ;
}
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
static int spufs_wbox_fasync ( int fd , struct file * file , int on )
{
struct spu_context * ctx = file - > private_data ;
int ret ;
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
ret = fasync_helper ( fd , file , on , & ctx - > wbox_fasync ) ;
2005-11-15 15:53:48 -05:00
return ret ;
}
2005-11-15 15:53:52 -05:00
/* interrupt-level wbox callback function. */
void spufs_wbox_callback ( struct spu * spu )
2005-11-15 15:53:48 -05:00
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = spu - > ctx ;
wake_up_all ( & ctx - > wbox_wq ) ;
kill_fasync ( & ctx - > wbox_fasync , SIGIO , POLLOUT ) ;
2005-11-15 15:53:48 -05:00
}
2006-10-04 17:26:17 +02:00
/*
* Write as many bytes to the interrupt mailbox as possible , until
* one of the conditions becomes true :
*
* - the mailbox is full
* - end of the user provided buffer
* - end of the mapped area
*
* If the file is opened without O_NONBLOCK , we wait here until
* space is availabyl , but return when we have been able to
* write something .
*/
2005-11-15 15:53:48 -05:00
static ssize_t spufs_wbox_write ( struct file * file , const char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2006-10-04 17:26:17 +02:00
u32 wbox_data , __user * udata ;
ssize_t count ;
2005-11-15 15:53:48 -05:00
if ( len < 4 )
return - EINVAL ;
2006-10-04 17:26:17 +02:00
udata = ( void __user * ) buf ;
if ( ! access_ok ( VERIFY_READ , buf , len ) )
return - EFAULT ;
if ( __get_user ( wbox_data , udata ) )
2005-11-15 15:53:48 -05:00
return - EFAULT ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
2006-10-04 17:26:17 +02:00
/*
* make sure we can at least write one element , by waiting
* in case of ! O_NONBLOCK
*/
count = 0 ;
2005-11-15 15:53:48 -05:00
if ( file - > f_flags & O_NONBLOCK ) {
2005-11-15 15:53:52 -05:00
if ( ! spu_wbox_write ( ctx , wbox_data ) )
2006-10-04 17:26:17 +02:00
count = - EAGAIN ;
2005-11-15 15:53:48 -05:00
} else {
2006-10-04 17:26:17 +02:00
count = spufs_wait ( ctx - > wbox_wq , spu_wbox_write ( ctx , wbox_data ) ) ;
2005-11-15 15:53:48 -05:00
}
2006-10-04 17:26:17 +02:00
if ( count )
goto out ;
2005-11-15 15:53:52 -05:00
2006-10-04 17:26:17 +02:00
/* write aѕ much as possible */
for ( count = 4 , udata + + ; ( count + 4 ) < = len ; count + = 4 , udata + + ) {
int ret ;
ret = __get_user ( wbox_data , udata ) ;
if ( ret )
break ;
ret = spu_wbox_write ( ctx , wbox_data ) ;
if ( ret = = 0 )
break ;
}
out :
spu_release ( ctx ) ;
return count ;
2005-11-15 15:53:48 -05:00
}
static unsigned int spufs_wbox_poll ( struct file * file , poll_table * wait )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
unsigned int mask ;
2005-11-15 15:53:52 -05:00
poll_wait ( file , & ctx - > wbox_wq , wait ) ;
2005-11-15 15:53:48 -05:00
2005-12-05 22:52:27 -05:00
spu_acquire ( ctx ) ;
mask = ctx - > ops - > mbox_stat_poll ( ctx , POLLOUT | POLLWRNORM ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return mask ;
}
static struct file_operations spufs_wbox_fops = {
. open = spufs_pipe_open ,
. write = spufs_wbox_write ,
. poll = spufs_wbox_poll ,
. fasync = spufs_wbox_fasync ,
} ;
static ssize_t spufs_wbox_stat_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
u32 wbox_stat ;
if ( len < 4 )
return - EINVAL ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
wbox_stat = ( ctx - > ops - > mbox_stat_read ( ctx ) > > 8 ) & 0xff ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
if ( copy_to_user ( buf , & wbox_stat , sizeof wbox_stat ) )
return - EFAULT ;
return 4 ;
}
static struct file_operations spufs_wbox_stat_fops = {
. open = spufs_pipe_open ,
. read = spufs_wbox_stat_read ,
} ;
2006-03-23 00:00:12 +01:00
static int spufs_signal1_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
struct spu_context * ctx = i - > i_ctx ;
file - > private_data = ctx ;
file - > f_mapping = inode - > i_mapping ;
ctx - > signal1 = inode - > i_mapping ;
return nonseekable_open ( inode , file ) ;
}
2005-11-15 15:53:48 -05:00
static ssize_t spufs_signal1_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
2005-11-15 15:53:52 -05:00
struct spu_context * ctx = file - > private_data ;
2005-11-15 15:53:48 -05:00
u32 data ;
if ( len < 4 )
return - EINVAL ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
data = ctx - > ops - > signal1_read ( ctx ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
if ( copy_to_user ( buf , & data , 4 ) )
return - EFAULT ;
return 4 ;
}
static ssize_t spufs_signal1_write ( struct file * file , const char __user * buf ,
size_t len , loff_t * pos )
{
struct spu_context * ctx ;
u32 data ;
ctx = file - > private_data ;
if ( len < 4 )
return - EINVAL ;
if ( copy_from_user ( & data , buf , 4 ) )
return - EFAULT ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ctx - > ops - > signal1_write ( ctx , data ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return 4 ;
}
2006-03-23 00:00:12 +01:00
static struct page * spufs_signal1_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
2006-10-04 17:26:11 +02:00
# 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
2006-03-23 00:00:12 +01:00
}
static struct vm_operations_struct spufs_signal1_mmap_vmops = {
. nopage = spufs_signal1_mmap_nopage ,
} ;
static int spufs_signal1_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 )
2006-06-23 20:57:47 +02:00
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2006-03-23 00:00:12 +01:00
vma - > vm_ops = & spufs_signal1_mmap_vmops ;
return 0 ;
}
2005-11-15 15:53:48 -05:00
static struct file_operations spufs_signal1_fops = {
2006-03-23 00:00:12 +01:00
. open = spufs_signal1_open ,
2005-11-15 15:53:48 -05:00
. read = spufs_signal1_read ,
. write = spufs_signal1_write ,
2006-03-23 00:00:12 +01:00
. mmap = spufs_signal1_mmap ,
2005-11-15 15:53:48 -05:00
} ;
2006-03-23 00:00:12 +01:00
static int spufs_signal2_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
struct spu_context * ctx = i - > i_ctx ;
file - > private_data = ctx ;
file - > f_mapping = inode - > i_mapping ;
ctx - > signal2 = inode - > i_mapping ;
return nonseekable_open ( inode , file ) ;
}
2005-11-15 15:53:48 -05:00
static ssize_t spufs_signal2_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
struct spu_context * ctx ;
u32 data ;
ctx = file - > private_data ;
if ( len < 4 )
return - EINVAL ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
data = ctx - > ops - > signal2_read ( ctx ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
if ( copy_to_user ( buf , & data , 4 ) )
return - EFAULT ;
return 4 ;
}
static ssize_t spufs_signal2_write ( struct file * file , const char __user * buf ,
size_t len , loff_t * pos )
{
struct spu_context * ctx ;
u32 data ;
ctx = file - > private_data ;
if ( len < 4 )
return - EINVAL ;
if ( copy_from_user ( & data , buf , 4 ) )
return - EFAULT ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ctx - > ops - > signal2_write ( ctx , data ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return 4 ;
}
2006-10-04 17:26:11 +02:00
# if SPUFS_MMAP_4K
2006-03-23 00:00:12 +01:00
static struct page * spufs_signal2_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
2006-10-04 17:26:11 +02:00
# 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
2006-03-23 00:00:12 +01:00
}
static struct vm_operations_struct spufs_signal2_mmap_vmops = {
. nopage = spufs_signal2_mmap_nopage ,
} ;
static int spufs_signal2_mmap ( struct file * file , struct vm_area_struct * vma )
{
if ( ! ( vma - > vm_flags & VM_SHARED ) )
return - EINVAL ;
/* FIXME: */
vma - > vm_flags | = VM_RESERVED ;
vma - > vm_page_prot = __pgprot ( pgprot_val ( vma - > vm_page_prot )
2006-06-23 20:57:47 +02:00
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2006-03-23 00:00:12 +01:00
vma - > vm_ops = & spufs_signal2_mmap_vmops ;
return 0 ;
}
2006-10-04 17:26:11 +02:00
# else /* SPUFS_MMAP_4K */
# define spufs_signal2_mmap NULL
# endif /* !SPUFS_MMAP_4K */
2006-03-23 00:00:12 +01:00
2005-11-15 15:53:48 -05:00
static struct file_operations spufs_signal2_fops = {
2006-03-23 00:00:12 +01:00
. open = spufs_signal2_open ,
2005-11-15 15:53:48 -05:00
. read = spufs_signal2_read ,
. write = spufs_signal2_write ,
2006-03-23 00:00:12 +01:00
. mmap = spufs_signal2_mmap ,
2005-11-15 15:53:48 -05:00
} ;
static void spufs_signal1_type_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ctx - > ops - > signal1_type_set ( ctx , val ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
}
static u64 spufs_signal1_type_get ( void * data )
{
struct spu_context * ctx = data ;
2005-11-15 15:53:52 -05:00
u64 ret ;
spu_acquire ( ctx ) ;
ret = ctx - > ops - > signal1_type_get ( ctx ) ;
spu_release ( ctx ) ;
return ret ;
2005-11-15 15:53:48 -05:00
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_signal1_type , spufs_signal1_type_get ,
spufs_signal1_type_set , " %llu " ) ;
static void spufs_signal2_type_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ctx - > ops - > signal2_type_set ( ctx , val ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
}
static u64 spufs_signal2_type_get ( void * data )
{
struct spu_context * ctx = data ;
2005-11-15 15:53:52 -05:00
u64 ret ;
spu_acquire ( ctx ) ;
ret = ctx - > ops - > signal2_type_get ( ctx ) ;
spu_release ( ctx ) ;
return ret ;
2005-11-15 15:53:48 -05:00
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_signal2_type , spufs_signal2_type_get ,
spufs_signal2_type_set , " %llu " ) ;
2006-10-04 17:26:11 +02:00
# if SPUFS_MMAP_4K
2006-06-19 20:33:21 +02:00
static struct page * spufs_mss_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
2006-10-04 17:26:11 +02:00
return spufs_ps_nopage ( vma , address , type , 0x0000 , 0x1000 ) ;
2006-06-19 20:33:21 +02:00
}
static struct vm_operations_struct spufs_mss_mmap_vmops = {
. nopage = spufs_mss_mmap_nopage ,
} ;
/*
* mmap support for problem state MFC DMA area [ 0x0000 - 0x0fff ] .
*/
static int spufs_mss_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 )
2006-06-23 20:57:47 +02:00
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2006-06-19 20:33:21 +02:00
vma - > vm_ops = & spufs_mss_mmap_vmops ;
return 0 ;
}
2006-10-04 17:26:11 +02:00
# else /* SPUFS_MMAP_4K */
# define spufs_mss_mmap NULL
# endif /* !SPUFS_MMAP_4K */
2006-06-19 20:33:21 +02:00
static int spufs_mss_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_mss_fops = {
. open = spufs_mss_open ,
. mmap = spufs_mss_mmap ,
2006-10-04 17:26:11 +02:00
} ;
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 ,
2006-06-19 20:33:21 +02:00
} ;
2006-10-04 17:26:11 +02:00
# if SPUFS_MMAP_4K
2006-03-23 00:00:12 +01:00
static struct page * spufs_mfc_mmap_nopage ( struct vm_area_struct * vma ,
unsigned long address , int * type )
{
2006-10-04 17:26:11 +02:00
return spufs_ps_nopage ( vma , address , type , 0x3000 , 0x1000 ) ;
2006-03-23 00:00:12 +01:00
}
static struct vm_operations_struct spufs_mfc_mmap_vmops = {
. nopage = spufs_mfc_mmap_nopage ,
} ;
/*
* mmap support for problem state MFC DMA area [ 0x0000 - 0x0fff ] .
*/
static int spufs_mfc_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 )
2006-06-23 20:57:47 +02:00
| _PAGE_NO_CACHE | _PAGE_GUARDED ) ;
2006-03-23 00:00:12 +01:00
vma - > vm_ops = & spufs_mfc_mmap_vmops ;
return 0 ;
}
2006-10-04 17:26:11 +02:00
# else /* SPUFS_MMAP_4K */
# define spufs_mfc_mmap NULL
# endif /* !SPUFS_MMAP_4K */
2006-03-23 00:00:11 +01:00
static int spufs_mfc_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
struct spu_context * ctx = i - > i_ctx ;
/* we don't want to deal with DMA into other processes */
if ( ctx - > owner ! = current - > mm )
return - EINVAL ;
if ( atomic_read ( & inode - > i_count ) ! = 1 )
return - EBUSY ;
file - > private_data = ctx ;
return nonseekable_open ( inode , file ) ;
}
/* interrupt-level mfc callback function. */
void spufs_mfc_callback ( struct spu * spu )
{
struct spu_context * ctx = spu - > ctx ;
wake_up_all ( & ctx - > mfc_wq ) ;
pr_debug ( " %s %s \n " , __FUNCTION__ , spu - > name ) ;
if ( ctx - > mfc_fasync ) {
u32 free_elements , tagstatus ;
unsigned int mask ;
/* no need for spu_acquire in interrupt context */
free_elements = ctx - > ops - > get_mfc_free_elements ( ctx ) ;
tagstatus = ctx - > ops - > read_mfc_tagstatus ( ctx ) ;
mask = 0 ;
if ( free_elements & 0xffff )
mask | = POLLOUT ;
if ( tagstatus & ctx - > tagwait )
mask | = POLLIN ;
kill_fasync ( & ctx - > mfc_fasync , SIGIO , mask ) ;
}
}
static int spufs_read_mfc_tagstatus ( struct spu_context * ctx , u32 * status )
{
/* See if there is one tag group is complete */
/* FIXME we need locking around tagwait */
* status = ctx - > ops - > read_mfc_tagstatus ( ctx ) & ctx - > tagwait ;
ctx - > tagwait & = ~ * status ;
if ( * status )
return 1 ;
/* enable interrupt waiting for any tag group,
may silently fail if interrupts are already enabled */
ctx - > ops - > set_mfc_query ( ctx , ctx - > tagwait , 1 ) ;
return 0 ;
}
static ssize_t spufs_mfc_read ( struct file * file , char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
int ret = - EINVAL ;
u32 status ;
if ( size ! = 4 )
goto out ;
spu_acquire ( ctx ) ;
if ( file - > f_flags & O_NONBLOCK ) {
status = ctx - > ops - > read_mfc_tagstatus ( ctx ) ;
if ( ! ( status & ctx - > tagwait ) )
ret = - EAGAIN ;
else
ctx - > tagwait & = ~ status ;
} else {
ret = spufs_wait ( ctx - > mfc_wq ,
spufs_read_mfc_tagstatus ( ctx , & status ) ) ;
}
spu_release ( ctx ) ;
if ( ret )
goto out ;
ret = 4 ;
if ( copy_to_user ( buffer , & status , 4 ) )
ret = - EFAULT ;
out :
return ret ;
}
static int spufs_check_valid_dma ( struct mfc_dma_command * cmd )
{
pr_debug ( " queueing DMA %x %lx %x %x %x \n " , cmd - > lsa ,
cmd - > ea , cmd - > size , cmd - > tag , cmd - > cmd ) ;
switch ( cmd - > cmd ) {
case MFC_PUT_CMD :
case MFC_PUTF_CMD :
case MFC_PUTB_CMD :
case MFC_GET_CMD :
case MFC_GETF_CMD :
case MFC_GETB_CMD :
break ;
default :
pr_debug ( " invalid DMA opcode %x \n " , cmd - > cmd ) ;
return - EIO ;
}
if ( ( cmd - > lsa & 0xf ) ! = ( cmd - > ea & 0xf ) ) {
pr_debug ( " invalid DMA alignment, ea %lx lsa %x \n " ,
cmd - > ea , cmd - > lsa ) ;
return - EIO ;
}
switch ( cmd - > size & 0xf ) {
case 1 :
break ;
case 2 :
if ( cmd - > lsa & 1 )
goto error ;
break ;
case 4 :
if ( cmd - > lsa & 3 )
goto error ;
break ;
case 8 :
if ( cmd - > lsa & 7 )
goto error ;
break ;
case 0 :
if ( cmd - > lsa & 15 )
goto error ;
break ;
error :
default :
pr_debug ( " invalid DMA alignment %x for size %x \n " ,
cmd - > lsa & 0xf , cmd - > size ) ;
return - EIO ;
}
if ( cmd - > size > 16 * 1024 ) {
pr_debug ( " invalid DMA size %x \n " , cmd - > size ) ;
return - EIO ;
}
if ( cmd - > tag & 0xfff0 ) {
/* we reserve the higher tag numbers for kernel use */
pr_debug ( " invalid DMA tag \n " ) ;
return - EIO ;
}
if ( cmd - > class ) {
/* not supported in this version */
pr_debug ( " invalid DMA class \n " ) ;
return - EIO ;
}
return 0 ;
}
static int spu_send_mfc_command ( struct spu_context * ctx ,
struct mfc_dma_command cmd ,
int * error )
{
* error = ctx - > ops - > send_mfc_command ( ctx , & cmd ) ;
if ( * error = = - EAGAIN ) {
/* wait for any tag group to complete
so we have space for the new command */
ctx - > ops - > set_mfc_query ( ctx , ctx - > tagwait , 1 ) ;
/* try again, because the queue might be
empty again */
* error = ctx - > ops - > send_mfc_command ( ctx , & cmd ) ;
if ( * error = = - EAGAIN )
return 0 ;
}
return 1 ;
}
static ssize_t spufs_mfc_write ( struct file * file , const char __user * buffer ,
size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct mfc_dma_command cmd ;
int ret = - EINVAL ;
if ( size ! = sizeof cmd )
goto out ;
ret = - EFAULT ;
if ( copy_from_user ( & cmd , buffer , sizeof cmd ) )
goto out ;
ret = spufs_check_valid_dma ( & cmd ) ;
if ( ret )
goto out ;
spu_acquire_runnable ( ctx ) ;
if ( file - > f_flags & O_NONBLOCK ) {
ret = ctx - > ops - > send_mfc_command ( ctx , & cmd ) ;
} else {
int status ;
ret = spufs_wait ( ctx - > mfc_wq ,
spu_send_mfc_command ( ctx , cmd , & status ) ) ;
if ( status )
ret = status ;
}
spu_release ( ctx ) ;
if ( ret )
goto out ;
ctx - > tagwait | = 1 < < cmd . tag ;
out :
return ret ;
}
static unsigned int spufs_mfc_poll ( struct file * file , poll_table * wait )
{
struct spu_context * ctx = file - > private_data ;
u32 free_elements , tagstatus ;
unsigned int mask ;
spu_acquire ( ctx ) ;
ctx - > ops - > set_mfc_query ( ctx , ctx - > tagwait , 2 ) ;
free_elements = ctx - > ops - > get_mfc_free_elements ( ctx ) ;
tagstatus = ctx - > ops - > read_mfc_tagstatus ( ctx ) ;
spu_release ( ctx ) ;
poll_wait ( file , & ctx - > mfc_wq , wait ) ;
mask = 0 ;
if ( free_elements & 0xffff )
mask | = POLLOUT | POLLWRNORM ;
if ( tagstatus & ctx - > tagwait )
mask | = POLLIN | POLLRDNORM ;
pr_debug ( " %s: free %d tagstatus %d tagwait %d \n " , __FUNCTION__ ,
free_elements , tagstatus , ctx - > tagwait ) ;
return mask ;
}
2006-06-25 16:42:33 -07:00
static int spufs_mfc_flush ( struct file * file , fl_owner_t id )
2006-03-23 00:00:11 +01:00
{
struct spu_context * ctx = file - > private_data ;
int ret ;
spu_acquire ( ctx ) ;
#if 0
/* this currently hangs */
ret = spufs_wait ( ctx - > mfc_wq ,
ctx - > ops - > set_mfc_query ( ctx , ctx - > tagwait , 2 ) ) ;
if ( ret )
goto out ;
ret = spufs_wait ( ctx - > mfc_wq ,
ctx - > ops - > read_mfc_tagstatus ( ctx ) = = ctx - > tagwait ) ;
out :
# else
ret = 0 ;
# endif
spu_release ( ctx ) ;
return ret ;
}
static int spufs_mfc_fsync ( struct file * file , struct dentry * dentry ,
int datasync )
{
2006-06-25 16:42:33 -07:00
return spufs_mfc_flush ( file , NULL ) ;
2006-03-23 00:00:11 +01:00
}
static int spufs_mfc_fasync ( int fd , struct file * file , int on )
{
struct spu_context * ctx = file - > private_data ;
return fasync_helper ( fd , file , on , & ctx - > mfc_fasync ) ;
}
static struct file_operations spufs_mfc_fops = {
. open = spufs_mfc_open ,
. read = spufs_mfc_read ,
. write = spufs_mfc_write ,
. poll = spufs_mfc_poll ,
. flush = spufs_mfc_flush ,
. fsync = spufs_mfc_fsync ,
. fasync = spufs_mfc_fasync ,
2006-03-23 00:00:12 +01:00
. mmap = spufs_mfc_mmap ,
2006-03-23 00:00:11 +01:00
} ;
2006-10-24 18:31:19 +02:00
static int spufs_recycle_open ( struct inode * inode , struct file * file )
{
file - > private_data = SPUFS_I ( inode ) - > i_ctx ;
return nonseekable_open ( inode , file ) ;
}
static ssize_t spufs_recycle_write ( struct file * file ,
const char __user * buffer , size_t size , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
int ret ;
if ( ! ( ctx - > flags & SPU_CREATE_ISOLATE ) )
return - EINVAL ;
if ( size < 1 )
return - EINVAL ;
ret = spu_recycle_isolated ( ctx ) ;
if ( ret )
return ret ;
return size ;
}
static struct file_operations spufs_recycle_fops = {
. open = spufs_recycle_open ,
. write = spufs_recycle_write ,
} ;
2005-11-15 15:53:48 -05:00
static void spufs_npc_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ctx - > ops - > npc_write ( ctx , val ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
}
static u64 spufs_npc_get ( void * data )
{
struct spu_context * ctx = data ;
u64 ret ;
2005-11-15 15:53:52 -05:00
spu_acquire ( ctx ) ;
ret = ctx - > ops - > npc_read ( ctx ) ;
spu_release ( ctx ) ;
2005-11-15 15:53:48 -05:00
return ret ;
}
2006-11-20 18:44:57 +01:00
DEFINE_SIMPLE_ATTRIBUTE ( spufs_npc_ops , spufs_npc_get , spufs_npc_set ,
" 0x%llx \n " )
2005-11-15 15:53:48 -05:00
2005-11-15 15:53:52 -05:00
static void spufs_decr_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
spu_acquire_saved ( ctx ) ;
lscsa - > decr . slot [ 0 ] = ( u32 ) val ;
spu_release ( ctx ) ;
}
static u64 spufs_decr_get ( void * data )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
u64 ret ;
spu_acquire_saved ( ctx ) ;
ret = lscsa - > decr . slot [ 0 ] ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_decr_ops , spufs_decr_get , spufs_decr_set ,
2006-11-20 18:44:57 +01:00
" 0x%llx \n " )
2005-11-15 15:53:52 -05:00
static void spufs_decr_status_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
spu_acquire_saved ( ctx ) ;
lscsa - > decr_status . slot [ 0 ] = ( u32 ) val ;
spu_release ( ctx ) ;
}
static u64 spufs_decr_status_get ( void * data )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
u64 ret ;
spu_acquire_saved ( ctx ) ;
ret = lscsa - > decr_status . slot [ 0 ] ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_decr_status_ops , spufs_decr_status_get ,
2006-11-20 18:44:57 +01:00
spufs_decr_status_set , " 0x%llx \n " )
2005-11-15 15:53:52 -05:00
static void spufs_event_mask_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
spu_acquire_saved ( ctx ) ;
lscsa - > event_mask . slot [ 0 ] = ( u32 ) val ;
spu_release ( ctx ) ;
}
static u64 spufs_event_mask_get ( void * data )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
u64 ret ;
spu_acquire_saved ( ctx ) ;
ret = lscsa - > event_mask . slot [ 0 ] ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_event_mask_ops , spufs_event_mask_get ,
2006-11-20 18:44:57 +01:00
spufs_event_mask_set , " 0x%llx \n " )
2005-11-15 15:53:52 -05:00
2006-11-20 18:44:58 +01:00
static u64 spufs_event_status_get ( void * data )
{
struct spu_context * ctx = data ;
struct spu_state * state = & ctx - > csa ;
u64 ret = 0 ;
u64 stat ;
spu_acquire_saved ( ctx ) ;
stat = state - > spu_chnlcnt_RW [ 0 ] ;
if ( stat )
ret = state - > spu_chnldata_RW [ 0 ] ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_event_status_ops , spufs_event_status_get ,
NULL , " 0x%llx \n " )
2005-11-15 15:53:52 -05:00
static void spufs_srr0_set ( void * data , u64 val )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
spu_acquire_saved ( ctx ) ;
lscsa - > srr0 . slot [ 0 ] = ( u32 ) val ;
spu_release ( ctx ) ;
}
static u64 spufs_srr0_get ( void * data )
{
struct spu_context * ctx = data ;
struct spu_lscsa * lscsa = ctx - > csa . lscsa ;
u64 ret ;
spu_acquire_saved ( ctx ) ;
ret = lscsa - > srr0 . slot [ 0 ] ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_srr0_ops , spufs_srr0_get , spufs_srr0_set ,
2006-11-20 18:44:57 +01:00
" 0x%llx \n " )
2005-11-15 15:53:52 -05:00
2006-06-19 20:33:24 +02:00
static u64 spufs_id_get ( void * data )
{
struct spu_context * ctx = data ;
u64 num ;
spu_acquire ( ctx ) ;
if ( ctx - > state = = SPU_STATE_RUNNABLE )
num = ctx - > spu - > number ;
else
num = ( unsigned int ) - 1 ;
spu_release ( ctx ) ;
return num ;
}
2006-09-23 01:37:41 +01:00
DEFINE_SIMPLE_ATTRIBUTE ( spufs_id_ops , spufs_id_get , NULL , " 0x%llx \n " )
2006-06-19 20:33:24 +02:00
2006-10-04 17:26:21 +02:00
static u64 spufs_object_id_get ( void * data )
{
struct spu_context * ctx = data ;
return ctx - > object_id ;
}
static void spufs_object_id_set ( void * data , u64 id )
{
struct spu_context * ctx = data ;
ctx - > object_id = id ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_object_id_ops , spufs_object_id_get ,
spufs_object_id_set , " 0x%llx \n " ) ;
2006-11-20 18:44:58 +01:00
static u64 spufs_lslr_get ( void * data )
{
struct spu_context * ctx = data ;
u64 ret ;
spu_acquire_saved ( ctx ) ;
ret = ctx - > csa . priv2 . spu_lslr_RW ;
spu_release ( ctx ) ;
return ret ;
}
DEFINE_SIMPLE_ATTRIBUTE ( spufs_lslr_ops , spufs_lslr_get , NULL , " 0x%llx \n " )
static int spufs_info_open ( struct inode * inode , struct file * file )
{
struct spufs_inode_info * i = SPUFS_I ( inode ) ;
struct spu_context * ctx = i - > i_ctx ;
file - > private_data = ctx ;
return 0 ;
}
static ssize_t spufs_dma_info_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_dma_info info ;
struct mfc_cq_sr * qp , * spuqp ;
int i ;
if ( ! access_ok ( VERIFY_WRITE , buf , len ) )
return - EFAULT ;
spu_acquire_saved ( ctx ) ;
spin_lock ( & ctx - > csa . register_lock ) ;
info . dma_info_type = ctx - > csa . priv2 . spu_tag_status_query_RW ;
info . dma_info_mask = ctx - > csa . lscsa - > tag_mask . slot [ 0 ] ;
info . dma_info_status = ctx - > csa . spu_chnldata_RW [ 24 ] ;
info . dma_info_stall_and_notify = ctx - > csa . spu_chnldata_RW [ 25 ] ;
info . dma_info_atomic_command_status = ctx - > csa . spu_chnldata_RW [ 27 ] ;
for ( i = 0 ; i < 16 ; i + + ) {
qp = & info . dma_info_command_data [ i ] ;
spuqp = & ctx - > csa . priv2 . spuq [ i ] ;
qp - > mfc_cq_data0_RW = spuqp - > mfc_cq_data0_RW ;
qp - > mfc_cq_data1_RW = spuqp - > mfc_cq_data1_RW ;
qp - > mfc_cq_data2_RW = spuqp - > mfc_cq_data2_RW ;
qp - > mfc_cq_data3_RW = spuqp - > mfc_cq_data3_RW ;
}
spin_unlock ( & ctx - > csa . register_lock ) ;
spu_release ( ctx ) ;
return simple_read_from_buffer ( buf , len , pos , & info ,
sizeof info ) ;
}
static struct file_operations spufs_dma_info_fops = {
. open = spufs_info_open ,
. read = spufs_dma_info_read ,
} ;
static ssize_t spufs_proxydma_info_read ( struct file * file , char __user * buf ,
size_t len , loff_t * pos )
{
struct spu_context * ctx = file - > private_data ;
struct spu_proxydma_info info ;
int ret = sizeof info ;
struct mfc_cq_sr * qp , * puqp ;
int i ;
if ( len < ret )
return - EINVAL ;
if ( ! access_ok ( VERIFY_WRITE , buf , len ) )
return - EFAULT ;
spu_acquire_saved ( ctx ) ;
spin_lock ( & ctx - > csa . register_lock ) ;
info . proxydma_info_type = ctx - > csa . prob . dma_querytype_RW ;
info . proxydma_info_mask = ctx - > csa . prob . dma_querymask_RW ;
info . proxydma_info_status = ctx - > csa . prob . dma_tagstatus_R ;
for ( i = 0 ; i < 8 ; i + + ) {
qp = & info . proxydma_info_command_data [ i ] ;
puqp = & ctx - > csa . priv2 . puq [ i ] ;
qp - > mfc_cq_data0_RW = puqp - > mfc_cq_data0_RW ;
qp - > mfc_cq_data1_RW = puqp - > mfc_cq_data1_RW ;
qp - > mfc_cq_data2_RW = puqp - > mfc_cq_data2_RW ;
qp - > mfc_cq_data3_RW = puqp - > mfc_cq_data3_RW ;
}
spin_unlock ( & ctx - > csa . register_lock ) ;
spu_release ( ctx ) ;
if ( copy_to_user ( buf , & info , sizeof info ) )
ret = - EFAULT ;
return ret ;
}
static struct file_operations spufs_proxydma_info_fops = {
. open = spufs_info_open ,
. read = spufs_proxydma_info_read ,
} ;
2005-11-15 15:53:48 -05:00
struct tree_descr spufs_dir_contents [ ] = {
{ " mem " , & spufs_mem_fops , 0666 , } ,
2005-11-15 15:53:52 -05:00
{ " regs " , & spufs_regs_fops , 0666 , } ,
2005-11-15 15:53:48 -05:00
{ " mbox " , & spufs_mbox_fops , 0444 , } ,
{ " ibox " , & spufs_ibox_fops , 0444 , } ,
{ " wbox " , & spufs_wbox_fops , 0222 , } ,
{ " mbox_stat " , & spufs_mbox_stat_fops , 0444 , } ,
{ " ibox_stat " , & spufs_ibox_stat_fops , 0444 , } ,
{ " wbox_stat " , & spufs_wbox_stat_fops , 0444 , } ,
{ " signal1 " , & spufs_signal1_fops , 0666 , } ,
{ " signal2 " , & spufs_signal2_fops , 0666 , } ,
{ " signal1_type " , & spufs_signal1_type , 0666 , } ,
{ " signal2_type " , & spufs_signal2_type , 0666 , } ,
2006-03-23 00:00:12 +01:00
{ " cntl " , & spufs_cntl_fops , 0666 , } ,
2005-11-15 15:53:52 -05:00
{ " fpcr " , & spufs_fpcr_fops , 0666 , } ,
2006-11-20 18:44:58 +01:00
{ " lslr " , & spufs_lslr_ops , 0444 , } ,
{ " mfc " , & spufs_mfc_fops , 0666 , } ,
{ " mss " , & spufs_mss_fops , 0666 , } ,
{ " npc " , & spufs_npc_ops , 0666 , } ,
{ " srr0 " , & spufs_srr0_ops , 0666 , } ,
2005-11-15 15:53:52 -05:00
{ " decr " , & spufs_decr_ops , 0666 , } ,
{ " decr_status " , & spufs_decr_status_ops , 0666 , } ,
{ " event_mask " , & spufs_event_mask_ops , 0666 , } ,
2006-11-20 18:44:58 +01:00
{ " event_status " , & spufs_event_status_ops , 0444 , } ,
2006-10-04 17:26:11 +02:00
{ " psmap " , & spufs_psmap_fops , 0666 , } ,
2006-10-04 17:26:21 +02:00
{ " phys-id " , & spufs_id_ops , 0666 , } ,
{ " object-id " , & spufs_object_id_ops , 0666 , } ,
2006-11-20 18:44:58 +01:00
{ " dma_info " , & spufs_dma_info_fops , 0444 , } ,
{ " proxydma_info " , & spufs_proxydma_info_fops , 0444 , } ,
2005-11-15 15:53:48 -05:00
{ } ,
} ;
2006-10-24 18:31:16 +02:00
struct tree_descr spufs_dir_nosched_contents [ ] = {
{ " mem " , & spufs_mem_fops , 0666 , } ,
{ " mbox " , & spufs_mbox_fops , 0444 , } ,
{ " ibox " , & spufs_ibox_fops , 0444 , } ,
{ " wbox " , & spufs_wbox_fops , 0222 , } ,
{ " mbox_stat " , & spufs_mbox_stat_fops , 0444 , } ,
{ " ibox_stat " , & spufs_ibox_stat_fops , 0444 , } ,
{ " wbox_stat " , & spufs_wbox_stat_fops , 0444 , } ,
{ " signal1 " , & spufs_signal1_fops , 0666 , } ,
{ " signal2 " , & spufs_signal2_fops , 0666 , } ,
{ " signal1_type " , & spufs_signal1_type , 0666 , } ,
{ " signal2_type " , & spufs_signal2_type , 0666 , } ,
{ " mss " , & spufs_mss_fops , 0666 , } ,
{ " mfc " , & spufs_mfc_fops , 0666 , } ,
{ " cntl " , & spufs_cntl_fops , 0666 , } ,
{ " npc " , & spufs_npc_ops , 0666 , } ,
{ " psmap " , & spufs_psmap_fops , 0666 , } ,
{ " phys-id " , & spufs_id_ops , 0666 , } ,
{ " object-id " , & spufs_object_id_ops , 0666 , } ,
2006-10-24 18:31:19 +02:00
{ " recycle " , & spufs_recycle_fops , 0222 , } ,
2006-10-24 18:31:16 +02:00
{ } ,
} ;