12be6bb0cSPaul Mundt /*
22be6bb0cSPaul Mundt * Support for hardware-assisted userspace interrupt masking.
32be6bb0cSPaul Mundt *
42be6bb0cSPaul Mundt * Copyright (C) 2010 Paul Mundt
52be6bb0cSPaul Mundt *
62be6bb0cSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public
72be6bb0cSPaul Mundt * License. See the file "COPYING" in the main directory of this archive
82be6bb0cSPaul Mundt * for more details.
92be6bb0cSPaul Mundt */
102be6bb0cSPaul Mundt #define pr_fmt(fmt) "intc: " fmt
112be6bb0cSPaul Mundt
122be6bb0cSPaul Mundt #include <linux/errno.h>
13f4e73bfcSKay Sievers #include <linux/device.h>
142be6bb0cSPaul Mundt #include <linux/init.h>
152be6bb0cSPaul Mundt #include <linux/io.h>
16a102a088SNobuhiro Iwamatsu #include <linux/stat.h>
1787dfb311SMasahiro Yamada #include <linux/sizes.h>
182be6bb0cSPaul Mundt #include "internals.h"
192be6bb0cSPaul Mundt
202be6bb0cSPaul Mundt static void __iomem *uimask;
212be6bb0cSPaul Mundt
222be6bb0cSPaul Mundt static ssize_t
show_intc_userimask(struct device * dev,struct device_attribute * attr,char * buf)23f4e73bfcSKay Sievers show_intc_userimask(struct device *dev,
24f4e73bfcSKay Sievers struct device_attribute *attr, char *buf)
252be6bb0cSPaul Mundt {
262be6bb0cSPaul Mundt return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
272be6bb0cSPaul Mundt }
282be6bb0cSPaul Mundt
292be6bb0cSPaul Mundt static ssize_t
store_intc_userimask(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)30f4e73bfcSKay Sievers store_intc_userimask(struct device *dev,
31f4e73bfcSKay Sievers struct device_attribute *attr,
322be6bb0cSPaul Mundt const char *buf, size_t count)
332be6bb0cSPaul Mundt {
342be6bb0cSPaul Mundt unsigned long level;
35*c3e878caSHongbo Li int ret;
362be6bb0cSPaul Mundt
37*c3e878caSHongbo Li ret = kstrtoul(buf, 10, &level);
38*c3e878caSHongbo Li if (ret != 0)
39*c3e878caSHongbo Li return ret;
402be6bb0cSPaul Mundt
412be6bb0cSPaul Mundt /*
422be6bb0cSPaul Mundt * Minimal acceptable IRQ levels are in the 2 - 16 range, but
432be6bb0cSPaul Mundt * these are chomped so as to not interfere with normal IRQs.
442be6bb0cSPaul Mundt *
452be6bb0cSPaul Mundt * Level 1 is a special case on some CPUs in that it's not
462be6bb0cSPaul Mundt * directly settable, but given that USERIMASK cuts off below a
472be6bb0cSPaul Mundt * certain level, we don't care about this limitation here.
482be6bb0cSPaul Mundt * Level 0 on the other hand equates to user masking disabled.
492be6bb0cSPaul Mundt *
502be6bb0cSPaul Mundt * We use the default priority level as a cut off so that only
512be6bb0cSPaul Mundt * special case opt-in IRQs can be mangled.
522be6bb0cSPaul Mundt */
532be6bb0cSPaul Mundt if (level >= intc_get_dfl_prio_level())
542be6bb0cSPaul Mundt return -EINVAL;
552be6bb0cSPaul Mundt
562be6bb0cSPaul Mundt __raw_writel(0xa5 << 24 | level << 4, uimask);
572be6bb0cSPaul Mundt
582be6bb0cSPaul Mundt return count;
592be6bb0cSPaul Mundt }
602be6bb0cSPaul Mundt
61f4e73bfcSKay Sievers static DEVICE_ATTR(userimask, S_IRUSR | S_IWUSR,
622be6bb0cSPaul Mundt show_intc_userimask, store_intc_userimask);
632be6bb0cSPaul Mundt
642be6bb0cSPaul Mundt
userimask_sysdev_init(void)652be6bb0cSPaul Mundt static int __init userimask_sysdev_init(void)
662be6bb0cSPaul Mundt {
6793c42c0bSGreg Kroah-Hartman struct device *dev_root;
6893c42c0bSGreg Kroah-Hartman int ret = 0;
6993c42c0bSGreg Kroah-Hartman
702be6bb0cSPaul Mundt if (unlikely(!uimask))
712be6bb0cSPaul Mundt return -ENXIO;
722be6bb0cSPaul Mundt
7393c42c0bSGreg Kroah-Hartman dev_root = bus_get_dev_root(&intc_subsys);
7493c42c0bSGreg Kroah-Hartman if (dev_root) {
7593c42c0bSGreg Kroah-Hartman ret = device_create_file(dev_root, &dev_attr_userimask);
7693c42c0bSGreg Kroah-Hartman put_device(dev_root);
7793c42c0bSGreg Kroah-Hartman }
7893c42c0bSGreg Kroah-Hartman return ret;
792be6bb0cSPaul Mundt }
802be6bb0cSPaul Mundt late_initcall(userimask_sysdev_init);
812be6bb0cSPaul Mundt
register_intc_userimask(unsigned long addr)822be6bb0cSPaul Mundt int register_intc_userimask(unsigned long addr)
832be6bb0cSPaul Mundt {
842be6bb0cSPaul Mundt if (unlikely(uimask))
852be6bb0cSPaul Mundt return -EBUSY;
862be6bb0cSPaul Mundt
874bdc0d67SChristoph Hellwig uimask = ioremap(addr, SZ_4K);
882be6bb0cSPaul Mundt if (unlikely(!uimask))
892be6bb0cSPaul Mundt return -ENOMEM;
902be6bb0cSPaul Mundt
912be6bb0cSPaul Mundt pr_info("userimask support registered for levels 0 -> %d\n",
922be6bb0cSPaul Mundt intc_get_dfl_prio_level() - 1);
932be6bb0cSPaul Mundt
942be6bb0cSPaul Mundt return 0;
952be6bb0cSPaul Mundt }
96