aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/intc/userimask.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-05 09:10:30 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-05 09:10:30 -0400
commit2be6bb0c79c7fbda3425b65ee51c558bbaf4cf91 (patch)
treedb0dafd7e7f83945edc2c50c358a3d81fca960c3 /drivers/sh/intc/userimask.c
parentd74310d3b18aabbb7d0549ea9e3fd3259c1dce00 (diff)
sh: intc: Split up the INTC code.
This splits up the sh intc core in to something more vaguely resembling a subsystem. Most of the functionality was alread fairly well compartmentalized, and there were only a handful of interdependencies that needed to be resolved in the process. This also serves as future-proofing for the genirq and sparseirq rework, which will make some of the split out functionality wholly generic, allowing things to be killed off in place with minimal migration pain. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh/intc/userimask.c')
-rw-r--r--drivers/sh/intc/userimask.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c
new file mode 100644
index 000000000000..e32304b66cf1
--- /dev/null
+++ b/drivers/sh/intc/userimask.c
@@ -0,0 +1,83 @@
1/*
2 * Support for hardware-assisted userspace interrupt masking.
3 *
4 * Copyright (C) 2010 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#define pr_fmt(fmt) "intc: " fmt
11
12#include <linux/errno.h>
13#include <linux/sysdev.h>
14#include <linux/init.h>
15#include <linux/io.h>
16#include <asm/sizes.h>
17#include "internals.h"
18
19static void __iomem *uimask;
20
21static ssize_t
22show_intc_userimask(struct sysdev_class *cls,
23 struct sysdev_class_attribute *attr, char *buf)
24{
25 return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
26}
27
28static ssize_t
29store_intc_userimask(struct sysdev_class *cls,
30 struct sysdev_class_attribute *attr,
31 const char *buf, size_t count)
32{
33 unsigned long level;
34
35 level = simple_strtoul(buf, NULL, 10);
36
37 /*
38 * Minimal acceptable IRQ levels are in the 2 - 16 range, but
39 * these are chomped so as to not interfere with normal IRQs.
40 *
41 * Level 1 is a special case on some CPUs in that it's not
42 * directly settable, but given that USERIMASK cuts off below a
43 * certain level, we don't care about this limitation here.
44 * Level 0 on the other hand equates to user masking disabled.
45 *
46 * We use the default priority level as a cut off so that only
47 * special case opt-in IRQs can be mangled.
48 */
49 if (level >= intc_get_dfl_prio_level())
50 return -EINVAL;
51
52 __raw_writel(0xa5 << 24 | level << 4, uimask);
53
54 return count;
55}
56
57static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
58 show_intc_userimask, store_intc_userimask);
59
60
61static int __init userimask_sysdev_init(void)
62{
63 if (unlikely(!uimask))
64 return -ENXIO;
65
66 return sysdev_class_create_file(&intc_sysdev_class, &attr_userimask);
67}
68late_initcall(userimask_sysdev_init);
69
70int register_intc_userimask(unsigned long addr)
71{
72 if (unlikely(uimask))
73 return -EBUSY;
74
75 uimask = ioremap_nocache(addr, SZ_4K);
76 if (unlikely(!uimask))
77 return -ENOMEM;
78
79 pr_info("userimask support registered for levels 0 -> %d\n",
80 intc_get_dfl_prio_level() - 1);
81
82 return 0;
83}