18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Support for hardware-assisted userspace interrupt masking. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2010 Paul Mundt 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 78c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 88c2ecf20Sopenharmony_ci * for more details. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "intc: " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/stat.h> 178c2ecf20Sopenharmony_ci#include <linux/sizes.h> 188c2ecf20Sopenharmony_ci#include "internals.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void __iomem *uimask; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic ssize_t 238c2ecf20Sopenharmony_cishow_intc_userimask(struct device *dev, 248c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic ssize_t 308c2ecf20Sopenharmony_cistore_intc_userimask(struct device *dev, 318c2ecf20Sopenharmony_ci struct device_attribute *attr, 328c2ecf20Sopenharmony_ci const char *buf, size_t count) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci unsigned long level; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci level = simple_strtoul(buf, NULL, 10); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* 398c2ecf20Sopenharmony_ci * Minimal acceptable IRQ levels are in the 2 - 16 range, but 408c2ecf20Sopenharmony_ci * these are chomped so as to not interfere with normal IRQs. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Level 1 is a special case on some CPUs in that it's not 438c2ecf20Sopenharmony_ci * directly settable, but given that USERIMASK cuts off below a 448c2ecf20Sopenharmony_ci * certain level, we don't care about this limitation here. 458c2ecf20Sopenharmony_ci * Level 0 on the other hand equates to user masking disabled. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * We use the default priority level as a cut off so that only 488c2ecf20Sopenharmony_ci * special case opt-in IRQs can be mangled. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci if (level >= intc_get_dfl_prio_level()) 518c2ecf20Sopenharmony_ci return -EINVAL; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci __raw_writel(0xa5 << 24 | level << 4, uimask); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return count; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic DEVICE_ATTR(userimask, S_IRUSR | S_IWUSR, 598c2ecf20Sopenharmony_ci show_intc_userimask, store_intc_userimask); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int __init userimask_sysdev_init(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (unlikely(!uimask)) 658c2ecf20Sopenharmony_ci return -ENXIO; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return device_create_file(intc_subsys.dev_root, &dev_attr_userimask); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_cilate_initcall(userimask_sysdev_init); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciint register_intc_userimask(unsigned long addr) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (unlikely(uimask)) 748c2ecf20Sopenharmony_ci return -EBUSY; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci uimask = ioremap(addr, SZ_4K); 778c2ecf20Sopenharmony_ci if (unlikely(!uimask)) 788c2ecf20Sopenharmony_ci return -ENOMEM; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci pr_info("userimask support registered for levels 0 -> %d\n", 818c2ecf20Sopenharmony_ci intc_get_dfl_prio_level() - 1); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 85