12be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt/*
22be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt * Support for hardware-assisted userspace interrupt masking.
32be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt *
42be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt * Copyright (C) 2010  Paul Mundt
52be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt *
62be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt * This file is subject to the terms and conditions of the GNU General Public
72be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt * License.  See the file "COPYING" in the main directory of this archive
82be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt * for more details.
92be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt */
102be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#define pr_fmt(fmt) "intc: " fmt
112be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
122be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#include <linux/errno.h>
13f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sievers#include <linux/device.h>
142be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#include <linux/init.h>
152be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#include <linux/io.h>
16a102a0888799d389c033fe22db3f1e153390fcc5Nobuhiro Iwamatsu#include <linux/stat.h>
172be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#include <asm/sizes.h>
182be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt#include "internals.h"
192be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
202be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtstatic void __iomem *uimask;
212be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
222be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtstatic ssize_t
23f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sieversshow_intc_userimask(struct device *dev,
24f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sievers		    struct device_attribute *attr, char *buf)
252be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt{
262be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
272be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt}
282be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
292be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtstatic ssize_t
30f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sieversstore_intc_userimask(struct device *dev,
31f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sievers		     struct device_attribute *attr,
322be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		     const char *buf, size_t count)
332be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt{
342be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	unsigned long level;
352be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
362be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	level = simple_strtoul(buf, NULL, 10);
372be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
382be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	/*
392be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * Minimal acceptable IRQ levels are in the 2 - 16 range, but
402be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * these are chomped so as to not interfere with normal IRQs.
412be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 *
422be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * Level 1 is a special case on some CPUs in that it's not
432be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * directly settable, but given that USERIMASK cuts off below a
442be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * certain level, we don't care about this limitation here.
452be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * Level 0 on the other hand equates to user masking disabled.
462be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 *
472be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * We use the default priority level as a cut off so that only
482be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 * special case opt-in IRQs can be mangled.
492be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	 */
502be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	if (level >= intc_get_dfl_prio_level())
512be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		return -EINVAL;
522be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
532be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	__raw_writel(0xa5 << 24 | level << 4, uimask);
542be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
552be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	return count;
562be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt}
572be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
58f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sieversstatic DEVICE_ATTR(userimask, S_IRUSR | S_IWUSR,
59f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sievers		   show_intc_userimask, store_intc_userimask);
602be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
612be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
622be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtstatic int __init userimask_sysdev_init(void)
632be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt{
642be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	if (unlikely(!uimask))
652be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		return -ENXIO;
662be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
67f4e73bfcd9cca0b64cc8096175852936fb1d111fKay Sievers	return device_create_file(intc_subsys.dev_root, &dev_attr_userimask);
682be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt}
692be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtlate_initcall(userimask_sysdev_init);
702be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
712be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundtint register_intc_userimask(unsigned long addr)
722be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt{
732be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	if (unlikely(uimask))
742be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		return -EBUSY;
752be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
762be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	uimask = ioremap_nocache(addr, SZ_4K);
772be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	if (unlikely(!uimask))
782be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		return -ENOMEM;
792be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
802be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	pr_info("userimask support registered for levels 0 -> %d\n",
812be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt		intc_get_dfl_prio_level() - 1);
822be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt
832be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt	return 0;
842be6bb0c79c7fbda3425b65ee51c558bbaf4cf91Paul Mundt}
85