2010-10-05 17:10:30 +04:00
/*
* Support for hardware - assisted userspace interrupt masking .
*
* Copyright ( C ) 2010 Paul Mundt
*
* 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 .
*/
# define pr_fmt(fmt) "intc: " fmt
# include <linux/errno.h>
2011-12-22 03:09:52 +04:00
# include <linux/device.h>
2010-10-05 17:10:30 +04:00
# include <linux/init.h>
# include <linux/io.h>
2011-10-04 05:17:21 +04:00
# include <linux/stat.h>
2019-05-15 01:46:51 +03:00
# include <linux/sizes.h>
2010-10-05 17:10:30 +04:00
# include "internals.h"
static void __iomem * uimask ;
static ssize_t
2011-12-22 03:09:52 +04:00
show_intc_userimask ( struct device * dev ,
struct device_attribute * attr , char * buf )
2010-10-05 17:10:30 +04:00
{
return sprintf ( buf , " %d \n " , ( __raw_readl ( uimask ) > > 4 ) & 0xf ) ;
}
static ssize_t
2011-12-22 03:09:52 +04:00
store_intc_userimask ( struct device * dev ,
struct device_attribute * attr ,
2010-10-05 17:10:30 +04:00
const char * buf , size_t count )
{
unsigned long level ;
level = simple_strtoul ( buf , NULL , 10 ) ;
/*
* Minimal acceptable IRQ levels are in the 2 - 16 range , but
* these are chomped so as to not interfere with normal IRQs .
*
* Level 1 is a special case on some CPUs in that it ' s not
* directly settable , but given that USERIMASK cuts off below a
* certain level , we don ' t care about this limitation here .
* Level 0 on the other hand equates to user masking disabled .
*
* We use the default priority level as a cut off so that only
* special case opt - in IRQs can be mangled .
*/
if ( level > = intc_get_dfl_prio_level ( ) )
return - EINVAL ;
__raw_writel ( 0xa5 < < 24 | level < < 4 , uimask ) ;
return count ;
}
2011-12-22 03:09:52 +04:00
static DEVICE_ATTR ( userimask , S_IRUSR | S_IWUSR ,
show_intc_userimask , store_intc_userimask ) ;
2010-10-05 17:10:30 +04:00
static int __init userimask_sysdev_init ( void )
{
if ( unlikely ( ! uimask ) )
return - ENXIO ;
2011-12-22 03:09:52 +04:00
return device_create_file ( intc_subsys . dev_root , & dev_attr_userimask ) ;
2010-10-05 17:10:30 +04:00
}
late_initcall ( userimask_sysdev_init ) ;
int register_intc_userimask ( unsigned long addr )
{
if ( unlikely ( uimask ) )
return - EBUSY ;
2020-01-06 11:43:50 +03:00
uimask = ioremap ( addr , SZ_4K ) ;
2010-10-05 17:10:30 +04:00
if ( unlikely ( ! uimask ) )
return - ENOMEM ;
pr_info ( " userimask support registered for levels 0 -> %d \n " ,
intc_get_dfl_prio_level ( ) - 1 ) ;
return 0 ;
}