2014-01-01 19:29:03 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2005 MIPS Technologies , Inc . All rights reserved .
* Copyright ( C ) 2013 Imagination Technologies Ltd .
*/
# include <linux/device.h>
# include <linux/fs.h>
# include <linux/err.h>
# include <linux/wait.h>
# include <linux/sched.h>
# include <linux/smp.h>
# include <asm/mips_mt.h>
# include <asm/vpe.h>
# include <asm/rtlx.h>
static int major ;
static void rtlx_interrupt ( void )
{
int i ;
struct rtlx_info * info ;
struct rtlx_info * * p = vpe_get_shared ( aprp_cpu_index ( ) ) ;
if ( p = = NULL | | * p = = NULL )
return ;
info = * p ;
if ( info - > ap_int_pending = = 1 & & smp_processor_id ( ) = = 0 ) {
for ( i = 0 ; i < RTLX_CHANNELS ; i + + ) {
wake_up ( & channel_wqs [ i ] . lx_queue ) ;
wake_up ( & channel_wqs [ i ] . rt_queue ) ;
}
info - > ap_int_pending = 0 ;
}
}
void _interrupt_sp ( void )
{
smp_send_reschedule ( aprp_cpu_index ( ) ) ;
}
int __init rtlx_module_init ( void )
{
struct device * dev ;
int i , err ;
if ( ! cpu_has_mipsmt ) {
pr_warn ( " VPE loader: not a MIPS MT capable processor \n " ) ;
return - ENODEV ;
}
if ( num_possible_cpus ( ) - aprp_cpu_index ( ) < 1 ) {
pr_warn ( " No TCs reserved for AP/SP, not initializing RTLX. \n "
" Pass maxcpus=<n> argument as kernel argument \n " ) ;
return - ENODEV ;
}
major = register_chrdev ( 0 , RTLX_MODULE_NAME , & rtlx_fops ) ;
if ( major < 0 ) {
pr_err ( " rtlx_module_init: unable to register device \n " ) ;
return major ;
}
/* initialise the wait queues */
for ( i = 0 ; i < RTLX_CHANNELS ; i + + ) {
init_waitqueue_head ( & channel_wqs [ i ] . rt_queue ) ;
init_waitqueue_head ( & channel_wqs [ i ] . lx_queue ) ;
atomic_set ( & channel_wqs [ i ] . in_open , 0 ) ;
mutex_init ( & channel_wqs [ i ] . mutex ) ;
dev = device_create ( mt_class , NULL , MKDEV ( major , i ) , NULL ,
" %s%d " , RTLX_MODULE_NAME , i ) ;
if ( IS_ERR ( dev ) ) {
2014-06-20 00:30:23 +04:00
while ( i - - )
device_destroy ( mt_class , MKDEV ( major , i ) ) ;
2014-01-01 19:29:03 +04:00
err = PTR_ERR ( dev ) ;
goto out_chrdev ;
}
}
/* set up notifiers */
rtlx_notify . start = rtlx_starting ;
rtlx_notify . stop = rtlx_stopping ;
vpe_notify ( aprp_cpu_index ( ) , & rtlx_notify ) ;
if ( cpu_has_vint ) {
aprp_hook = rtlx_interrupt ;
} else {
pr_err ( " APRP RTLX init on non-vectored-interrupt processor \n " ) ;
err = - ENODEV ;
goto out_class ;
}
return 0 ;
out_class :
for ( i = 0 ; i < RTLX_CHANNELS ; i + + )
device_destroy ( mt_class , MKDEV ( major , i ) ) ;
out_chrdev :
unregister_chrdev ( major , RTLX_MODULE_NAME ) ;
return err ;
}
void __exit rtlx_module_exit ( void )
{
int i ;
for ( i = 0 ; i < RTLX_CHANNELS ; i + + )
device_destroy ( mt_class , MKDEV ( major , i ) ) ;
2014-02-28 22:23:02 +04:00
2014-01-01 19:29:03 +04:00
unregister_chrdev ( major , RTLX_MODULE_NAME ) ;
2014-02-28 22:23:02 +04:00
aprp_hook = NULL ;
2014-01-01 19:29:03 +04:00
}