diff options
Diffstat (limited to 'drivers/sh/intc')
| -rw-r--r-- | drivers/sh/intc/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/sh/intc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/sh/intc/chip.c | 6 | ||||
| -rw-r--r-- | drivers/sh/intc/core.c | 98 | ||||
| -rw-r--r-- | drivers/sh/intc/internals.h | 13 | ||||
| -rw-r--r-- | drivers/sh/intc/irqdomain.c | 5 | ||||
| -rw-r--r-- | drivers/sh/intc/userimask.c | 19 | ||||
| -rw-r--r-- | drivers/sh/intc/virq-debugfs.c | 15 | ||||
| -rw-r--r-- | drivers/sh/intc/virq.c | 38 |
9 files changed, 98 insertions, 106 deletions
diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig index a305731742a9..5c701709fef5 100644 --- a/drivers/sh/intc/Kconfig +++ b/drivers/sh/intc/Kconfig @@ -1,12 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only config SH_INTC - def_bool y + bool select IRQ_DOMAIN +if SH_INTC + comment "Interrupt controller options" config INTC_USERIMASK bool "Userspace interrupt masking support" - depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A) + depends on (SUPERH && CPU_SH4A) || COMPILE_TEST help This enables support for hardware-assisted userspace hardirq masking. @@ -37,3 +40,5 @@ config INTC_MAPPING_DEBUG between system IRQs and the per-controller id tables. If in doubt, say N. + +endif diff --git a/drivers/sh/intc/Makefile b/drivers/sh/intc/Makefile index 54ec2a0643df..bdd855327e41 100644 --- a/drivers/sh/intc/Makefile +++ b/drivers/sh/intc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-y := access.o chip.o core.o handle.o irqdomain.o virq.o obj-$(CONFIG_INTC_BALANCING) += balancing.o diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index 46427b48e2f1..828d81e02b37 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -22,7 +22,7 @@ void _intc_enable(struct irq_data *data, unsigned long handle) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); @@ -50,7 +50,7 @@ static void intc_disable(struct irq_data *data) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); @@ -72,7 +72,7 @@ static int intc_set_affinity(struct irq_data *data, if (!cpumask_intersects(cpumask, cpu_online_mask)) return -1; - cpumask_copy(data->affinity, cpumask); + irq_data_update_affinity(data, cpumask); return IRQ_SET_MASK_OK_NOCOPY; } diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 8f32a1323a79..3dde703b7766 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -65,9 +65,9 @@ void intc_set_prio_level(unsigned int irq, unsigned int level) raw_spin_unlock_irqrestore(&intc_big_lock, flags); } -static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) +static void intc_redirect_irq(struct irq_desc *desc) { - generic_handle_irq((unsigned int)irq_get_handler_data(irq)); + generic_handle_irq((unsigned int)irq_desc_get_handler_data(desc)); } static void __init intc_register_irq(struct intc_desc *desc, @@ -80,12 +80,6 @@ static void __init intc_register_irq(struct intc_desc *desc, unsigned int data[2], primary; unsigned long flags; - /* - * Register the IRQ position with the global IRQ map, then insert - * it in to the radix tree. - */ - irq_reserve_irq(irq); - raw_spin_lock_irqsave(&intc_big_lock, flags); radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); raw_spin_unlock_irqrestore(&intc_big_lock, flags); @@ -106,8 +100,8 @@ static void __init intc_register_irq(struct intc_desc *desc, primary = 1; if (!data[0] && !data[1]) - pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n", - irq, irq2evt(irq)); + pr_warn("missing unique irq mask for irq %d (vect 0x%04x)\n", + irq, irq2evt(irq)); data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1); data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1); @@ -185,6 +179,21 @@ static unsigned int __init save_reg(struct intc_desc_int *d, return 0; } +static bool __init intc_map(struct irq_domain *domain, int irq) +{ + if (!irq_to_desc(irq) && irq_alloc_desc_at(irq, NUMA_NO_NODE) != irq) { + pr_err("uname to allocate IRQ %d\n", irq); + return false; + } + + if (irq_domain_associate(domain, irq, irq)) { + pr_err("domain association failure\n"); + return false; + } + + return true; +} + int __init register_intc_controller(struct intc_desc *desc) { unsigned int i, k, smp; @@ -200,7 +209,6 @@ int __init register_intc_controller(struct intc_desc *desc) goto err0; INIT_LIST_HEAD(&d->list); - list_add_tail(&d->list, &intc_list); raw_spin_lock_init(&d->lock); INIT_RADIX_TREE(&d->tree, GFP_ATOMIC); @@ -209,7 +217,7 @@ int __init register_intc_controller(struct intc_desc *desc) if (desc->num_resources) { d->nr_windows = desc->num_resources; - d->window = kzalloc(d->nr_windows * sizeof(*d->window), + d->window = kcalloc(d->nr_windows, sizeof(*d->window), GFP_NOWAIT); if (!d->window) goto err1; @@ -219,8 +227,8 @@ int __init register_intc_controller(struct intc_desc *desc) WARN_ON(resource_type(res) != IORESOURCE_MEM); d->window[k].phys = res->start; d->window[k].size = resource_size(res); - d->window[k].virt = ioremap_nocache(res->start, - resource_size(res)); + d->window[k].virt = ioremap(res->start, + resource_size(res)); if (!d->window[k].virt) goto err2; } @@ -236,12 +244,12 @@ int __init register_intc_controller(struct intc_desc *desc) d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0; - d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); + d->reg = kcalloc(d->nr_reg, sizeof(*d->reg), GFP_NOWAIT); if (!d->reg) goto err2; #ifdef CONFIG_SMP - d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); + d->smp = kcalloc(d->nr_reg, sizeof(*d->smp), GFP_NOWAIT); if (!d->smp) goto err3; #endif @@ -259,7 +267,7 @@ int __init register_intc_controller(struct intc_desc *desc) } if (hw->prio_regs) { - d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), + d->prio = kcalloc(hw->nr_vectors, sizeof(*d->prio), GFP_NOWAIT); if (!d->prio) goto err4; @@ -275,7 +283,7 @@ int __init register_intc_controller(struct intc_desc *desc) } if (hw->sense_regs) { - d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), + d->sense = kcalloc(hw->nr_vectors, sizeof(*d->sense), GFP_NOWAIT); if (!d->sense) goto err5; @@ -317,24 +325,12 @@ int __init register_intc_controller(struct intc_desc *desc) for (i = 0; i < hw->nr_vectors; i++) { struct intc_vect *vect = hw->vectors + i; unsigned int irq = evt2irq(vect->vect); - int res; if (!vect->enum_id) continue; - res = irq_create_identity_mapping(d->domain, irq); - if (unlikely(res)) { - if (res == -EEXIST) { - res = irq_domain_associate(d->domain, irq, irq); - if (unlikely(res)) { - pr_err("domain association failure\n"); - continue; - } - } else { - pr_err("can't identity map IRQ %d\n", irq); - continue; - } - } + if (!intc_map(d->domain, irq)) + continue; intc_irq_xlate_set(irq, vect->enum_id, d); intc_register_irq(desc, d, vect->enum_id, irq); @@ -351,29 +347,16 @@ int __init register_intc_controller(struct intc_desc *desc) * IRQ support, each vector still needs to have * its own backing irq_desc. */ - res = irq_create_identity_mapping(d->domain, irq2); - if (unlikely(res)) { - if (res == -EEXIST) { - res = irq_domain_associate(d->domain, - irq2, irq2); - if (unlikely(res)) { - pr_err("domain association " - "failure\n"); - continue; - } - } else { - pr_err("can't identity map IRQ %d\n", - irq); - continue; - } - } + if (!intc_map(d->domain, irq2)) + continue; vect2->enum_id = 0; /* redirect this interrupts to the first one */ irq_set_chip(irq2, &dummy_irq_chip); - irq_set_chained_handler(irq2, intc_redirect_irq); - irq_set_handler_data(irq2, (void *)irq); + irq_set_chained_handler_and_data(irq2, + intc_redirect_irq, + (void *)irq); } } @@ -385,6 +368,7 @@ int __init register_intc_controller(struct intc_desc *desc) d->skip_suspend = desc->skip_syscore_suspend; + list_add_tail(&d->list, &intc_list); nr_intc_controllers++; return 0; @@ -410,7 +394,7 @@ err0: return -ENOMEM; } -static int intc_suspend(void) +static int intc_suspend(void *data) { struct intc_desc_int *d; @@ -436,7 +420,7 @@ static int intc_suspend(void) return 0; } -static void intc_resume(void) +static void intc_resume(void *data) { struct intc_desc_int *d; @@ -466,12 +450,16 @@ static void intc_resume(void) } } -struct syscore_ops intc_syscore_ops = { +static const struct syscore_ops intc_syscore_ops = { .suspend = intc_suspend, .resume = intc_resume, }; -struct bus_type intc_subsys = { +static struct syscore intc_syscore = { + .ops = &intc_syscore_ops, +}; + +const struct bus_type intc_subsys = { .name = "intc", .dev_name = "intc", }; @@ -493,7 +481,7 @@ static int __init register_intc_devs(void) struct intc_desc_int *d; int error; - register_syscore_ops(&intc_syscore_ops); + register_syscore(&intc_syscore); error = subsys_system_register(&intc_subsys, NULL); if (!error) { diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h index 7dff08e2a071..9b6cd1bebb4e 100644 --- a/drivers/sh/intc/internals.h +++ b/drivers/sh/intc/internals.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include <linux/sh_intc.h> #include <linux/irq.h> #include <linux/irqdomain.h> @@ -99,15 +100,7 @@ static inline struct intc_desc_int *get_intc_desc(unsigned int irq) */ static inline void activate_irq(int irq) { -#ifdef CONFIG_ARM - /* ARM requires an extra step to clear IRQ_NOREQUEST, which it - * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. - */ - set_irq_flags(irq, IRQF_VALID); -#else - /* same effect on other architectures */ - irq_set_noprobe(irq); -#endif + irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE); } static inline int intc_handle_int_cmp(const void *a, const void *b) @@ -167,7 +160,7 @@ void _intc_enable(struct irq_data *data, unsigned long handle); /* core.c */ extern struct list_head intc_list; extern raw_spinlock_t intc_big_lock; -extern struct bus_type intc_subsys; +extern const struct bus_type intc_subsys; unsigned int intc_get_dfl_prio_level(void); unsigned int intc_get_prio_level(unsigned int irq); diff --git a/drivers/sh/intc/irqdomain.c b/drivers/sh/intc/irqdomain.c index 3968f1c3c5c3..ed7a570ffdf2 100644 --- a/drivers/sh/intc/irqdomain.c +++ b/drivers/sh/intc/irqdomain.c @@ -59,10 +59,9 @@ void __init intc_irq_domain_init(struct intc_desc_int *d, * tree penalty for linear cases with non-zero hwirq bases. */ if (irq_base == 0 && irq_end == (irq_base + hw->nr_vectors - 1)) - d->domain = irq_domain_add_linear(NULL, hw->nr_vectors, - &intc_evt_ops, NULL); + d->domain = irq_domain_create_linear(NULL, hw->nr_vectors, &intc_evt_ops, NULL); else - d->domain = irq_domain_add_tree(NULL, &intc_evt_ops, NULL); + d->domain = irq_domain_create_tree(NULL, &intc_evt_ops, NULL); BUG_ON(!d->domain); } diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c index e649ceaaa410..a363f77881d1 100644 --- a/drivers/sh/intc/userimask.c +++ b/drivers/sh/intc/userimask.c @@ -14,7 +14,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/stat.h> -#include <asm/sizes.h> +#include <linux/sizes.h> #include "internals.h" static void __iomem *uimask; @@ -32,8 +32,11 @@ store_intc_userimask(struct device *dev, const char *buf, size_t count) { unsigned long level; + int ret; - level = simple_strtoul(buf, NULL, 10); + ret = kstrtoul(buf, 10, &level); + if (ret != 0) + return ret; /* * Minimal acceptable IRQ levels are in the 2 - 16 range, but @@ -61,10 +64,18 @@ static DEVICE_ATTR(userimask, S_IRUSR | S_IWUSR, static int __init userimask_sysdev_init(void) { + struct device *dev_root; + int ret = 0; + if (unlikely(!uimask)) return -ENXIO; - return device_create_file(intc_subsys.dev_root, &dev_attr_userimask); + dev_root = bus_get_dev_root(&intc_subsys); + if (dev_root) { + ret = device_create_file(dev_root, &dev_attr_userimask); + put_device(dev_root); + } + return ret; } late_initcall(userimask_sysdev_init); @@ -73,7 +84,7 @@ int register_intc_userimask(unsigned long addr) if (unlikely(uimask)) return -EBUSY; - uimask = ioremap_nocache(addr, SZ_4K); + uimask = ioremap(addr, SZ_4K); if (unlikely(!uimask)) return -ENOMEM; diff --git a/drivers/sh/intc/virq-debugfs.c b/drivers/sh/intc/virq-debugfs.c index 9e62ba9311f0..5dd8febe6da5 100644 --- a/drivers/sh/intc/virq-debugfs.c +++ b/drivers/sh/intc/virq-debugfs.c @@ -16,8 +16,9 @@ #include <linux/debugfs.h> #include "internals.h" -static int intc_irq_xlate_debug(struct seq_file *m, void *priv) +static int intc_irq_xlate_show(struct seq_file *m, void *priv) { + const unsigned int nr_irqs = irq_get_nr_irqs(); int i; seq_printf(m, "%-5s %-7s %-15s\n", "irq", "enum", "chip name"); @@ -37,17 +38,7 @@ static int intc_irq_xlate_debug(struct seq_file *m, void *priv) return 0; } -static int intc_irq_xlate_open(struct inode *inode, struct file *file) -{ - return single_open(file, intc_irq_xlate_debug, inode->i_private); -} - -static const struct file_operations intc_irq_xlate_fops = { - .open = intc_irq_xlate_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(intc_irq_xlate); static int __init intc_irq_xlate_init(void) { diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index f30ac9354ff2..a638c3048207 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -83,33 +83,34 @@ EXPORT_SYMBOL_GPL(intc_irq_lookup); static int add_virq_to_pirq(unsigned int irq, unsigned int virq) { - struct intc_virq_list **last, *entry; - struct irq_data *data = irq_get_irq_data(irq); + struct intc_virq_list *entry; + struct intc_virq_list **last = NULL; /* scan for duplicates */ - last = (struct intc_virq_list **)&data->handler_data; - for_each_virq(entry, data->handler_data) { + for_each_virq(entry, irq_get_handler_data(irq)) { if (entry->irq == virq) return 0; last = &entry->next; } entry = kzalloc(sizeof(struct intc_virq_list), GFP_ATOMIC); - if (!entry) { - pr_err("can't allocate VIRQ mapping for %d\n", virq); + if (!entry) return -ENOMEM; - } entry->irq = virq; - *last = entry; + if (last) + *last = entry; + else + irq_set_handler_data(irq, entry); return 0; } -static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) +static void intc_virq_handler(struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + unsigned int irq = irq_desc_get_irq(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); struct intc_desc_int *d = get_intc_desc(irq); @@ -118,12 +119,14 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) for_each_virq(entry, vlist) { unsigned long addr, handle; + struct irq_desc *vdesc = irq_to_desc(entry->irq); - handle = (unsigned long)irq_get_handler_data(entry->irq); - addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); - - if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) - generic_handle_irq(entry->irq); + if (vdesc) { + handle = (unsigned long)irq_desc_get_handler_data(vdesc); + addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); + if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) + generic_handle_irq_desc(vdesc); + } } chip->irq_unmask(data); @@ -243,12 +246,13 @@ restart: */ irq_set_nothread(irq); - irq_set_chained_handler(entry->pirq, intc_virq_handler); + /* Set handler data before installing the handler */ add_virq_to_pirq(entry->pirq, irq); + irq_set_chained_handler(entry->pirq, intc_virq_handler); radix_tree_tag_clear(&d->tree, entry->enum_id, INTC_TAG_VIRQ_NEEDS_ALLOC); - radix_tree_replace_slot((void **)entries[i], + radix_tree_replace_slot(&d->tree, (void **)entries[i], &intc_irq_xlate[irq]); } |
