From eda2845ae5e0ae466c1aca715d642b4977311747 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:15 +0200 Subject: irqdomain: Remove unused of_device_id forward declaration There is no users of of_device_id in irqdomain.h. Drop it. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20201030165919.86234-2-andriy.shevchenko@linux.intel.com --- include/linux/irqdomain.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 71535e87109f..56642188ec21 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -38,7 +38,6 @@ struct device_node; struct irq_domain; -struct of_device_id; struct irq_chip; struct irq_data; struct cpumask; -- cgit From 08219fb1efae451c83281cb6ba4bb6c35ac88fab Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:16 +0200 Subject: irqdomain: Add forward declaration of fwnode_handle irqdomain.h is a user of struct fwnode_handle. Add forward declaration of it. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20201030165919.86234-3-andriy.shevchenko@linux.intel.com --- include/linux/irqdomain.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 56642188ec21..d21f75d294d7 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -37,6 +37,7 @@ #include struct device_node; +struct fwnode_handle; struct irq_domain; struct irq_chip; struct irq_data; -- cgit From c3a877fea962d9d0fb1e3747334699978f566930 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:17 +0200 Subject: irqdomain: Replace open coded of_node_to_fwnode() of_node_to_fwnode() should be used for conversion. Replace the open coded variant of it in of_phandle_args_to_fwspec(). Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20201030165919.86234-4-andriy.shevchenko@linux.intel.com --- kernel/irq/irqdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index cf8b374b892d..831526f2e728 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -737,7 +737,7 @@ static void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args, { int i; - fwspec->fwnode = np ? &np->fwnode : NULL; + fwspec->fwnode = of_node_to_fwnode(np); fwspec->param_count = count; for (i = 0; i < count; i++) -- cgit From b6e95788fde8c9bc9da729102085dd36a5a0cda6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:18 +0200 Subject: irqdomain: Introduce irq_domain_create_legacy() API Introduce irq_domain_create_legacy() API which is functional equivalent to the existing irq_domain_add_legacy(), but takes a pointer to the struct fwnode_handle as a parameter. This is useful for non OF systems. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20201030165919.86234-5-andriy.shevchenko@linux.intel.com --- Documentation/core-api/irq/irq-domain.rst | 6 ++++++ include/linux/irqdomain.h | 6 ++++++ kernel/irq/irqdomain.c | 17 ++++++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Documentation/core-api/irq/irq-domain.rst b/Documentation/core-api/irq/irq-domain.rst index 096db12f32d5..a77c24c27f7b 100644 --- a/Documentation/core-api/irq/irq-domain.rst +++ b/Documentation/core-api/irq/irq-domain.rst @@ -147,6 +147,7 @@ Legacy irq_domain_add_simple() irq_domain_add_legacy() irq_domain_add_legacy_isa() + irq_domain_create_legacy() The Legacy mapping is a special case for drivers that already have a range of irq_descs allocated for the hwirqs. It is used when the @@ -185,6 +186,11 @@ that the driver using the simple domain call irq_create_mapping() before any irq_find_mapping() since the latter will actually work for the static IRQ assignment case. +irq_domain_add_legacy() and irq_domain_create_legacy() are functionally +equivalent, except for the first argument is different - the former +accepts an Open Firmware specific 'struct device_node', while the latter +accepts a more general abstraction 'struct fwnode_handle'. + Hierarchy IRQ domain -------------------- diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index d21f75d294d7..77bf7d84c673 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -271,6 +271,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, irq_hw_number_t first_hwirq, const struct irq_domain_ops *ops, void *host_data); +struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode, + unsigned int size, + unsigned int first_irq, + irq_hw_number_t first_hwirq, + const struct irq_domain_ops *ops, + void *host_data); extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token); extern bool irq_domain_check_msi_remap(void); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 831526f2e728..9c9cb8829f7a 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -350,17 +350,28 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, irq_hw_number_t first_hwirq, const struct irq_domain_ops *ops, void *host_data) +{ + return irq_domain_create_legacy(of_node_to_fwnode(of_node), size, + first_irq, first_hwirq, ops, host_data); +} +EXPORT_SYMBOL_GPL(irq_domain_add_legacy); + +struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode, + unsigned int size, + unsigned int first_irq, + irq_hw_number_t first_hwirq, + const struct irq_domain_ops *ops, + void *host_data) { struct irq_domain *domain; - domain = __irq_domain_add(of_node_to_fwnode(of_node), first_hwirq + size, - first_hwirq + size, 0, ops, host_data); + domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data); if (domain) irq_domain_associate_many(domain, first_irq, first_hwirq, size); return domain; } -EXPORT_SYMBOL_GPL(irq_domain_add_legacy); +EXPORT_SYMBOL_GPL(irq_domain_create_legacy); /** * irq_find_matching_fwspec() - Locates a domain for a given fwspec -- cgit From d315c627a18249930750fe4eb2b21f3fe9b32ea4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:19 +0200 Subject: regmap: irq: Convert to use irq_domain_create_legacy() irq_domain_create_legacy() takes a fwnode as parameter contrary to irq_domain_add_legacy() which requires a OF node. Switch the regmap irq domain creation to use that new function so it is not longer limited to OF based usage. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Acked-by: Mark Brown Link: https://lore.kernel.org/r/20201030165919.86234-6-andriy.shevchenko@linux.intel.com --- drivers/base/regmap/regmap-irq.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index ad5c2de395d1..19db764ffa4a 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -803,13 +803,12 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, } if (irq_base) - d->domain = irq_domain_add_legacy(to_of_node(fwnode), - chip->num_irqs, irq_base, - 0, ®map_domain_ops, d); + d->domain = irq_domain_create_legacy(fwnode, chip->num_irqs, + irq_base, 0, + ®map_domain_ops, d); else - d->domain = irq_domain_add_linear(to_of_node(fwnode), - chip->num_irqs, - ®map_domain_ops, d); + d->domain = irq_domain_create_linear(fwnode, chip->num_irqs, + ®map_domain_ops, d); if (!d->domain) { dev_err(map->dev, "Failed to create IRQ domain\n"); ret = -ENOMEM; -- cgit From f296dcd629aa412a80a53215e46087f53af87f08 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 14 Nov 2020 22:01:45 +0100 Subject: genirq: Remove GENERIC_IRQ_LEGACY_ALLOC_HWIRQ Commit bb9d812643d8 ("arch: remove tile port") removed the last user of this cruft two years ago... Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/87eekvac06.fsf@nanos.tec.linutronix.de --- include/linux/irq.h | 15 --------------- kernel/irq/Kconfig | 5 ----- kernel/irq/irqdesc.c | 51 --------------------------------------------------- 3 files changed, 71 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index c54365309e97..79ce314a603b 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -954,21 +954,6 @@ static inline void irq_free_desc(unsigned int irq) irq_free_descs(irq, 1); } -#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ -unsigned int irq_alloc_hwirqs(int cnt, int node); -static inline unsigned int irq_alloc_hwirq(int node) -{ - return irq_alloc_hwirqs(1, node); -} -void irq_free_hwirqs(unsigned int from, int cnt); -static inline void irq_free_hwirq(unsigned int irq) -{ - return irq_free_hwirqs(irq, 1); -} -int arch_setup_hwirq(unsigned int irq, int node); -void arch_teardown_hwirq(unsigned int irq); -#endif - #ifdef CONFIG_GENERIC_IRQ_LEGACY void irq_init_desc(unsigned int irq); #endif diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 10a5aff4eecc..f2cda6b0057f 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -26,11 +26,6 @@ config GENERIC_IRQ_SHOW_LEVEL config GENERIC_IRQ_EFFECTIVE_AFF_MASK bool -# Facility to allocate a hardware interrupt. This is legacy support -# and should not be used in new code. Use irq domains instead. -config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ - bool - # Support for delayed migration from interrupt context config GENERIC_PENDING_IRQ bool diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 1a7723604399..e810eb9906ea 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -810,57 +810,6 @@ unlock: } EXPORT_SYMBOL_GPL(__irq_alloc_descs); -#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ -/** - * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware - * @cnt: number of interrupts to allocate - * @node: node on which to allocate - * - * Returns an interrupt number > 0 or 0, if the allocation fails. - */ -unsigned int irq_alloc_hwirqs(int cnt, int node) -{ - int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL); - - if (irq < 0) - return 0; - - for (i = irq; cnt > 0; i++, cnt--) { - if (arch_setup_hwirq(i, node)) - goto err; - irq_clear_status_flags(i, _IRQ_NOREQUEST); - } - return irq; - -err: - for (i--; i >= irq; i--) { - irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); - arch_teardown_hwirq(i); - } - irq_free_descs(irq, cnt); - return 0; -} -EXPORT_SYMBOL_GPL(irq_alloc_hwirqs); - -/** - * irq_free_hwirqs - Free irq descriptor and cleanup the hardware - * @from: Free from irq number - * @cnt: number of interrupts to free - * - */ -void irq_free_hwirqs(unsigned int from, int cnt) -{ - int i, j; - - for (i = from, j = cnt; j > 0; i++, j--) { - irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); - arch_teardown_hwirq(i); - } - irq_free_descs(from, cnt); -} -EXPORT_SYMBOL_GPL(irq_free_hwirqs); -#endif - /** * irq_get_next_irq - get next allocated irq number * @offset: where to start the search -- cgit From e906a546bd8653ed2e7a14cb300fd17952d7f862 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 14 Nov 2020 23:36:28 +0100 Subject: genirq/irqdomain: Make irq_domain_disassociate() static No users outside of the core code. Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/87a6vja7mb.fsf@nanos.tec.linutronix.de --- include/linux/irqdomain.h | 2 -- kernel/irq/irqdomain.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 77bf7d84c673..5701a8b01726 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -387,8 +387,6 @@ extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq, extern void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, irq_hw_number_t hwirq_base, int count); -extern void irq_domain_disassociate(struct irq_domain *domain, - unsigned int irq); extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 9c9cb8829f7a..3d7463fd6453 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -496,7 +496,7 @@ static void irq_domain_set_mapping(struct irq_domain *domain, } } -void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq) +static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq) { struct irq_data *irq_data = irq_get_irq_data(irq); irq_hw_number_t hwirq; -- cgit From 8c67d247dcad67fbdd07c8bab9818d0b8d9240bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Nov 2020 11:18:15 +0100 Subject: genirq: Fix kernel-doc markups Some identifiers have different names between their prototypes and the kernel-doc markup. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/13a44f4f0c3135e14b16ae8fcce4af1eab27cb5f.1605521731.git.mchehab+huawei@kernel.org --- kernel/irq/chip.c | 2 +- kernel/irq/generic-chip.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index b9b9618e1aca..df75c3573dcb 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -61,7 +61,7 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip) EXPORT_SYMBOL(irq_set_chip); /** - * irq_set_type - set the irq trigger type for an irq + * irq_set_irq_type - set the irq trigger type for an irq * @irq: irq number * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h */ diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index e2999a070a99..a23ac2bbf433 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -269,7 +269,7 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags) } /** - * __irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain + * __irq_alloc_domain_generic_chips - Allocate generic chips for an irq domain * @d: irq domain for which to allocate chips * @irqs_per_chip: Number of interrupts each chip handles (max 32) * @num_ct: Number of irq_chip_type instances associated with this -- cgit From 9f112156f8da016df2dcbe77108e5b070aa58992 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:08 +0100 Subject: parisc: Remove bogus __IRQ_STAT macro This is a leftover from a historical array based implementation and unused. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141732.680780121@linutronix.de --- arch/parisc/include/asm/hardirq.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/parisc/include/asm/hardirq.h b/arch/parisc/include/asm/hardirq.h index 7f7039516e53..fad29aa6f45f 100644 --- a/arch/parisc/include/asm/hardirq.h +++ b/arch/parisc/include/asm/hardirq.h @@ -32,7 +32,6 @@ typedef struct { DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); #define __ARCH_IRQ_STAT -#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) #define inc_irq_stat(member) this_cpu_inc(irq_stat.member) #define __inc_irq_stat(member) __this_cpu_inc(irq_stat.member) #define ack_bad_irq(irq) WARN(1, "unexpected IRQ trap at vector %02x\n", irq) -- cgit From fe3f1d5d7cd3062c0cb8fe70dd77470019dedd19 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:09 +0100 Subject: sh: Get rid of nmi_count() nmi_count() is a historical leftover and SH is the only user. Replace it with regular per cpu accessors. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141732.844232404@linutronix.de --- arch/sh/kernel/irq.c | 2 +- arch/sh/kernel/traps.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 5717c7cbdd97..5addcb2c2da0 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -44,7 +44,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%*s: ", prec, "NMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", nmi_count(j)); + seq_printf(p, "%10u ", per_cpu(irq_stat.__nmi_count, j); seq_printf(p, " Non-maskable interrupts\n"); seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 9c3d32b80038..f5beecdac693 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -186,7 +186,7 @@ BUILD_TRAP_HANDLER(nmi) arch_ftrace_nmi_enter(); nmi_enter(); - nmi_count(cpu)++; + this_cpu_inc(irq_stat.__nmi_count); switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { case NOTIFY_OK: -- cgit From 769dda58d1f647a45270db2f02efe2e2de856709 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:10 +0100 Subject: irqstat: Get rid of nmi_count() and __IRQ_STAT() Nothing uses this anymore. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.005212732@linutronix.de --- include/linux/irq_cpustat.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/linux/irq_cpustat.h b/include/linux/irq_cpustat.h index 6e8895cd4d92..78fb2de3ea4d 100644 --- a/include/linux/irq_cpustat.h +++ b/include/linux/irq_cpustat.h @@ -19,10 +19,6 @@ #ifndef __ARCH_IRQ_STAT DECLARE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); /* defined in asm/hardirq.h */ -#define __IRQ_STAT(cpu, member) (per_cpu(irq_stat.member, cpu)) #endif -/* arch dependent irq_stat fields */ -#define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386 */ - #endif /* __irq_cpustat_h */ -- cgit From e83694a7b249de63beb1d8b45474b796dce3cd45 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:11 +0100 Subject: um/irqstat: Get rid of the duplicated declarations irq_cpustat_t and ack_bad_irq() are exactly the same as the asm-generic ones. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.156361337@linutronix.de --- arch/um/include/asm/hardirq.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/arch/um/include/asm/hardirq.h b/arch/um/include/asm/hardirq.h index b426796d26fd..52e2c36267a9 100644 --- a/arch/um/include/asm/hardirq.h +++ b/arch/um/include/asm/hardirq.h @@ -2,22 +2,7 @@ #ifndef __ASM_UM_HARDIRQ_H #define __ASM_UM_HARDIRQ_H -#include -#include - -typedef struct { - unsigned int __softirq_pending; -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ -#include - -#ifndef ack_bad_irq -static inline void ack_bad_irq(unsigned int irq) -{ - printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq); -} -#endif +#include #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 -- cgit From 7fd70c65faacd39628ba5f670be6490010c8132f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:12 +0100 Subject: ARM: irqstat: Get rid of duplicated declaration irq_cpustat_t is exactly the same as the asm-generic one. Define ack_bad_irq so the generic header does not emit the generic version of it. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Reviewed-by: Valentin Schneider Link: https://lore.kernel.org/r/20201113141733.276505871@linutronix.de --- arch/arm/include/asm/hardirq.h | 11 +++-------- arch/arm/include/asm/irq.h | 2 ++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index b95848ed2bc7..706efafbf972 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -2,16 +2,11 @@ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H -#include -#include #include -typedef struct { - unsigned int __softirq_pending; -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ - #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 +#define ack_bad_irq ack_bad_irq + +#include #endif /* __ASM_HARDIRQ_H */ diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index 46d41140df27..1cbcc462b07e 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -31,6 +31,8 @@ void handle_IRQ(unsigned int, struct pt_regs *); void init_IRQ(void); #ifdef CONFIG_SMP +#include + extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self); #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace -- cgit From 2cb0837e56e1b04b773ed05df72297de4e010063 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:13 +0100 Subject: arm64: irqstat: Get rid of duplicated declaration irq_cpustat_t is exactly the same as the asm-generic one. Define ack_bad_irq so the generic header does not emit the generic version of it. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Acked-by: Will Deacon Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/20201113141733.392015387@linutronix.de --- arch/arm64/include/asm/hardirq.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index 5ffa4bacdad3..cbfa7b6f2e09 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h @@ -13,11 +13,8 @@ #include #include -typedef struct { - unsigned int __softirq_pending; -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ +#define ack_bad_irq ack_bad_irq +#include #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 -- cgit From 1adb99eabce9deefb55985c19181d375ba6ff4aa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:14 +0100 Subject: asm-generic/irqstat: Add optional __nmi_count member Add an optional __nmi_count member to irq_cpustat_t so more architectures can use the generic version. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.501611990@linutronix.de --- include/asm-generic/hardirq.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-generic/hardirq.h b/include/asm-generic/hardirq.h index d14214dfc10b..f5dd99781e3c 100644 --- a/include/asm-generic/hardirq.h +++ b/include/asm-generic/hardirq.h @@ -7,6 +7,9 @@ typedef struct { unsigned int __softirq_pending; +#ifdef ARCH_WANTS_NMI_IRQSTAT + unsigned int __nmi_count; +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ -- cgit From fd15c1941f0ae0b46d48431d0020edfc843abd33 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:15 +0100 Subject: sh: irqstat: Use the generic irq_cpustat_t SH can now use the generic irq_cpustat_t. Define ack_bad_irq so the generic header does not emit the generic version of it. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.625146223@linutronix.de --- arch/sh/include/asm/hardirq.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h index edaea3559a23..9fe4495a8e90 100644 --- a/arch/sh/include/asm/hardirq.h +++ b/arch/sh/include/asm/hardirq.h @@ -2,16 +2,10 @@ #ifndef __ASM_SH_HARDIRQ_H #define __ASM_SH_HARDIRQ_H -#include -#include - -typedef struct { - unsigned int __softirq_pending; - unsigned int __nmi_count; /* arch dependent */ -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ - extern void ack_bad_irq(unsigned int irq); +#define ack_bad_irq ack_bad_irq +#define ARCH_WANTS_NMI_IRQSTAT + +#include #endif /* __ASM_SH_HARDIRQ_H */ -- cgit From e091bc90cd2d65f48e4688faead2911558d177d7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:16 +0100 Subject: irqstat: Move declaration into asm-generic/hardirq.h Move the declaration of the irq_cpustat per cpu variable to asm-generic/hardirq.h and remove the now empty linux/irq_cpustat.h header. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.737377332@linutronix.de --- include/asm-generic/hardirq.h | 3 ++- include/linux/irq_cpustat.h | 24 ------------------------ 2 files changed, 2 insertions(+), 25 deletions(-) delete mode 100644 include/linux/irq_cpustat.h diff --git a/include/asm-generic/hardirq.h b/include/asm-generic/hardirq.h index f5dd99781e3c..7317e8258b48 100644 --- a/include/asm-generic/hardirq.h +++ b/include/asm-generic/hardirq.h @@ -12,7 +12,8 @@ typedef struct { #endif } ____cacheline_aligned irq_cpustat_t; -#include /* Standard mappings for irq_cpustat_t above */ +DECLARE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); + #include #ifndef ack_bad_irq diff --git a/include/linux/irq_cpustat.h b/include/linux/irq_cpustat.h deleted file mode 100644 index 78fb2de3ea4d..000000000000 --- a/include/linux/irq_cpustat.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __irq_cpustat_h -#define __irq_cpustat_h - -/* - * Contains default mappings for irq_cpustat_t, used by almost every - * architecture. Some arch (like s390) have per cpu hardware pages and - * they define their own mappings for irq_stat. - * - * Keith Owens July 2000. - */ - - -/* - * Simple wrappers reducing source bloat. Define all irq_stat fields - * here, even ones that are arch dependent. That way we get common - * definitions instead of differing sets for each arch. - */ - -#ifndef __ARCH_IRQ_STAT -DECLARE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); /* defined in asm/hardirq.h */ -#endif - -#endif /* __irq_cpustat_h */ -- cgit From 15115830c88751ba83068aa37da996602ddc6a61 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:17 +0100 Subject: preempt: Cleanup the macro maze a bit Make the macro maze consistent and prepare it for adding the RT variant for BH accounting. - Use nmi_count() for the NMI portion of preempt count - Introduce in_hardirq() to make the naming consistent and non-ambiguos - Use the macros to create combined checks (e.g. in_task()) so the softirq representation for RT just falls into place. - Update comments and move the deprecated macros aside Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.864469886@linutronix.de --- include/linux/preempt.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 7d9c1c0e149c..7547857516d5 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -77,31 +77,33 @@ /* preempt_count() and related functions, depends on PREEMPT_NEED_RESCHED */ #include +#define nmi_count() (preempt_count() & NMI_MASK) #define hardirq_count() (preempt_count() & HARDIRQ_MASK) #define softirq_count() (preempt_count() & SOFTIRQ_MASK) -#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \ - | NMI_MASK)) +#define irq_count() (nmi_count() | hardirq_count() | softirq_count()) /* - * Are we doing bottom half or hardware interrupt processing? + * Macros to retrieve the current execution context: * - * in_irq() - We're in (hard) IRQ context + * in_nmi() - We're in NMI context + * in_hardirq() - We're in hard IRQ context + * in_serving_softirq() - We're in softirq context + * in_task() - We're in task context + */ +#define in_nmi() (nmi_count()) +#define in_hardirq() (hardirq_count()) +#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET) +#define in_task() (!(in_nmi() | in_hardirq() | in_serving_softirq())) + +/* + * The following macros are deprecated and should not be used in new code: + * in_irq() - Obsolete version of in_hardirq() * in_softirq() - We have BH disabled, or are processing softirqs * in_interrupt() - We're in NMI,IRQ,SoftIRQ context or have BH disabled - * in_serving_softirq() - We're in softirq context - * in_nmi() - We're in NMI context - * in_task() - We're in task context - * - * Note: due to the BH disabled confusion: in_softirq(),in_interrupt() really - * should not be used in new code. */ #define in_irq() (hardirq_count()) #define in_softirq() (softirq_count()) #define in_interrupt() (irq_count()) -#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET) -#define in_nmi() (preempt_count() & NMI_MASK) -#define in_task() (!(preempt_count() & \ - (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET))) /* * The preempt_count offset after preempt_disable(); -- cgit From ae9ef58996a4447dd44aa638759f913c883ba816 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:02:18 +0100 Subject: softirq: Move related code into one section To prepare for adding a RT aware variant of softirq serialization and processing move related code into one section so the necessary #ifdeffery is reduced to one. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20201113141733.974214480@linutronix.de --- kernel/softirq.c | 107 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 09229ad82209..617009ccd82c 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -92,6 +92,13 @@ static bool ksoftirqd_running(unsigned long pending) !__kthread_should_park(tsk); } +#ifdef CONFIG_TRACE_IRQFLAGS +DEFINE_PER_CPU(int, hardirqs_enabled); +DEFINE_PER_CPU(int, hardirq_context); +EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled); +EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context); +#endif + /* * preempt_count and SOFTIRQ_OFFSET usage: * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving @@ -102,17 +109,11 @@ static bool ksoftirqd_running(unsigned long pending) * softirq and whether we just have bh disabled. */ +#ifdef CONFIG_TRACE_IRQFLAGS /* - * This one is for softirq.c-internal use, - * where hardirqs are disabled legitimately: + * This is for softirq.c-internal use, where hardirqs are disabled + * legitimately: */ -#ifdef CONFIG_TRACE_IRQFLAGS - -DEFINE_PER_CPU(int, hardirqs_enabled); -DEFINE_PER_CPU(int, hardirq_context); -EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled); -EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context); - void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) { unsigned long flags; @@ -203,6 +204,50 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) } EXPORT_SYMBOL(__local_bh_enable_ip); +static inline void invoke_softirq(void) +{ + if (ksoftirqd_running(local_softirq_pending())) + return; + + if (!force_irqthreads) { +#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK + /* + * We can safely execute softirq on the current stack if + * it is the irq stack, because it should be near empty + * at this stage. + */ + __do_softirq(); +#else + /* + * Otherwise, irq_exit() is called on the task stack that can + * be potentially deep already. So call softirq in its own stack + * to prevent from any overrun. + */ + do_softirq_own_stack(); +#endif + } else { + wakeup_softirqd(); + } +} + +asmlinkage __visible void do_softirq(void) +{ + __u32 pending; + unsigned long flags; + + if (in_interrupt()) + return; + + local_irq_save(flags); + + pending = local_softirq_pending(); + + if (pending && !ksoftirqd_running(pending)) + do_softirq_own_stack(); + + local_irq_restore(flags); +} + /* * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times, * but break the loop if need_resched() is set or after 2 ms. @@ -327,24 +372,6 @@ restart: current_restore_flags(old_flags, PF_MEMALLOC); } -asmlinkage __visible void do_softirq(void) -{ - __u32 pending; - unsigned long flags; - - if (in_interrupt()) - return; - - local_irq_save(flags); - - pending = local_softirq_pending(); - - if (pending && !ksoftirqd_running(pending)) - do_softirq_own_stack(); - - local_irq_restore(flags); -} - /** * irq_enter_rcu - Enter an interrupt context with RCU watching */ @@ -371,32 +398,6 @@ void irq_enter(void) irq_enter_rcu(); } -static inline void invoke_softirq(void) -{ - if (ksoftirqd_running(local_softirq_pending())) - return; - - if (!force_irqthreads) { -#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK - /* - * We can safely execute softirq on the current stack if - * it is the irq stack, because it should be near empty - * at this stage. - */ - __do_softirq(); -#else - /* - * Otherwise, irq_exit() is called on the task stack that can - * be potentially deep already. So call softirq in its own stack - * to prevent from any overrun. - */ - do_softirq_own_stack(); -#endif - } else { - wakeup_softirqd(); - } -} - static inline void tick_irq_exit(void) { #ifdef CONFIG_NO_HZ_COMMON -- cgit From 15b8d9372f27c47e17c91f6f16d359314cf11404 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 24 Nov 2020 14:06:56 +0100 Subject: sh/irq: Add missing closing parentheses in arch_show_interrupts() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/sh/kernel/irq.c: In function ‘arch_show_interrupts’: arch/sh/kernel/irq.c:47:58: error: expected ‘)’ before ‘;’ token 47 | seq_printf(p, "%10u ", per_cpu(irq_stat.__nmi_count, j); | ^ Fixes: fe3f1d5d7cd3062c ("sh: Get rid of nmi_count()") Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201124130656.2741743-1-geert+renesas@glider.be --- arch/sh/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 5addcb2c2da0..ab5f790b0cd2 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -44,7 +44,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%*s: ", prec, "NMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat.__nmi_count, j); + seq_printf(p, "%10u ", per_cpu(irq_stat.__nmi_count, j)); seq_printf(p, " Non-maskable interrupts\n"); seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); -- cgit From 4615fbc3788ddc8e7c6d697714ad35a53729aa2c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:55:51 +0000 Subject: genirq/irqdomain: Don't try to free an interrupt that has no mapping When an interrupt allocation fails for N interrupts, it is pretty common for the error handling code to free the same number of interrupts, no matter how many interrupts have actually been allocated. This may result in the domain freeing code to be unexpectedly called for interrupts that have no mapping in that domain. Things end pretty badly. Instead, add some checks to irq_domain_free_irqs_hierarchy() to make sure that thiss does not follow the hierarchy if no mapping exists for a given interrupt. Fixes: 6a6544e520abe ("genirq/irqdomain: Remove auto-recursive hierarchy support") Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201129135551.396777-1-maz@kernel.org --- kernel/irq/irqdomain.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 3d7463fd6453..30a78872a5cf 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1381,8 +1381,15 @@ static void irq_domain_free_irqs_hierarchy(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs) { - if (domain->ops->free) - domain->ops->free(domain, irq_base, nr_irqs); + unsigned int i; + + if (!domain->ops->free) + return; + + for (i = 0; i < nr_irqs; i++) { + if (irq_domain_get_irq_data(domain, irq_base + i)) + domain->ops->free(domain, irq_base + i, 1); + } } int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain, -- cgit From 7197688b2006357da75a014e0a76be89ca9c2d46 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2020 12:57:28 +0100 Subject: sched/cputime: Remove symbol exports from IRQ time accounting account_irq_enter_time() and account_irq_exit_time() are not called from modules. EXPORT_SYMBOL_GPL() can be safely removed from the IRQ cputime accounting functions called from there. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201202115732.27827-2-frederic@kernel.org --- arch/s390/kernel/vtime.c | 10 +++++----- kernel/sched/cputime.c | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 8df10d3c8f6c..f9f2a11958a5 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -226,7 +226,7 @@ void vtime_flush(struct task_struct *tsk) * Update process times based on virtual cpu times stored by entry.S * to the lowcore fields user_timer, system_timer & steal_clock. */ -void vtime_account_irq_enter(struct task_struct *tsk) +void vtime_account_kernel(struct task_struct *tsk) { u64 timer; @@ -245,12 +245,12 @@ void vtime_account_irq_enter(struct task_struct *tsk) virt_timer_forward(timer); } -EXPORT_SYMBOL_GPL(vtime_account_irq_enter); - -void vtime_account_kernel(struct task_struct *tsk) -__attribute__((alias("vtime_account_irq_enter"))); EXPORT_SYMBOL_GPL(vtime_account_kernel); +void vtime_account_irq_enter(struct task_struct *tsk) +__attribute__((alias("vtime_account_kernel"))); + + /* * Sorted add to a list. List is linear searched until first bigger * element is found. diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 5a55d2300452..61ce9f9bf0a3 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -71,7 +71,6 @@ void irqtime_account_irq(struct task_struct *curr) else if (in_serving_softirq() && curr != this_cpu_ksoftirqd()) irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ); } -EXPORT_SYMBOL_GPL(irqtime_account_irq); static u64 irqtime_tick_accounted(u64 maxtime) { @@ -434,7 +433,6 @@ void vtime_account_irq_enter(struct task_struct *tsk) else vtime_account_kernel(tsk); } -EXPORT_SYMBOL_GPL(vtime_account_irq_enter); #endif /* __ARCH_HAS_VTIME_ACCOUNT */ void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev, -- cgit From 2b91ec9f551b56751cde48792f1c0a1130358844 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2020 12:57:29 +0100 Subject: s390/vtime: Use the generic IRQ entry accounting s390 has its own version of IRQ entry accounting because it doesn't account the idle time the same way the other architectures do. Only the actual idle sleep time is accounted as idle time, the rest of the idle task execution is accounted as system time. Make the generic IRQ entry accounting aware of architectures that have their own way of accounting idle time and convert s390 to use it. This prepares s390 to get involved in further consolidations of IRQ time accounting. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201202115732.27827-3-frederic@kernel.org --- arch/Kconfig | 7 ++++++- arch/s390/Kconfig | 1 + arch/s390/include/asm/vtime.h | 1 - arch/s390/kernel/vtime.c | 4 ---- kernel/sched/cputime.c | 13 ++----------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 56b6ccc0e32d..0f151b49c7b7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -627,6 +627,12 @@ config HAVE_TIF_NOHZ config HAVE_VIRT_CPU_ACCOUNTING bool +config HAVE_VIRT_CPU_ACCOUNTING_IDLE + bool + help + Architecture has its own way to account idle CPU time and therefore + doesn't implement vtime_account_idle(). + config ARCH_HAS_SCALED_CPUTIME bool @@ -641,7 +647,6 @@ config HAVE_VIRT_CPU_ACCOUNTING_GEN some 32-bit arches may require multiple accesses, so proper locking is needed to protect against concurrent accesses. - config HAVE_IRQ_TIME_ACCOUNTING bool help diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4a2a12be04c9..6f1fdcd3b5db 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -181,6 +181,7 @@ config S390 select HAVE_RSEQ select HAVE_SYSCALL_TRACEPOINTS select HAVE_VIRT_CPU_ACCOUNTING + select HAVE_VIRT_CPU_ACCOUNTING_IDLE select IOMMU_HELPER if PCI select IOMMU_SUPPORT if PCI select MODULES_USE_ELF_RELA diff --git a/arch/s390/include/asm/vtime.h b/arch/s390/include/asm/vtime.h index 3622d4ebc73a..fac6a67988eb 100644 --- a/arch/s390/include/asm/vtime.h +++ b/arch/s390/include/asm/vtime.h @@ -2,7 +2,6 @@ #ifndef _S390_VTIME_H #define _S390_VTIME_H -#define __ARCH_HAS_VTIME_ACCOUNT #define __ARCH_HAS_VTIME_TASK_SWITCH #endif /* _S390_VTIME_H */ diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index f9f2a11958a5..ebd8e5655789 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -247,10 +247,6 @@ void vtime_account_kernel(struct task_struct *tsk) } EXPORT_SYMBOL_GPL(vtime_account_kernel); -void vtime_account_irq_enter(struct task_struct *tsk) -__attribute__((alias("vtime_account_kernel"))); - - /* * Sorted add to a list. List is linear searched until first bigger * element is found. diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 61ce9f9bf0a3..2783162542b1 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -417,23 +417,14 @@ void vtime_task_switch(struct task_struct *prev) } # endif -/* - * Archs that account the whole time spent in the idle task - * (outside irq) as idle time can rely on this and just implement - * vtime_account_kernel() and vtime_account_idle(). Archs that - * have other meaning of the idle time (s390 only includes the - * time spent by the CPU when it's in low power mode) must override - * vtime_account(). - */ -#ifndef __ARCH_HAS_VTIME_ACCOUNT void vtime_account_irq_enter(struct task_struct *tsk) { - if (!in_interrupt() && is_idle_task(tsk)) + if (!IS_ENABLED(CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE) && + !in_interrupt() && is_idle_task(tsk)) vtime_account_idle(tsk); else vtime_account_kernel(tsk); } -#endif /* __ARCH_HAS_VTIME_ACCOUNT */ void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev, u64 *ut, u64 *st) -- cgit From 8a6a5920d3286eb0eae9f36a4ec4fc9df511eccb Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2020 12:57:30 +0100 Subject: sched/vtime: Consolidate IRQ time accounting The 3 architectures implementing CONFIG_VIRT_CPU_ACCOUNTING_NATIVE all have their own version of irq time accounting that dispatch the cputime to the appropriate index: hardirq, softirq, system, idle, guest... from an all-in-one function. Instead of having these ad-hoc versions, move the cputime destination dispatch decision to the core code and leave only the actual per-index cputime accounting to the architecture. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201202115732.27827-4-frederic@kernel.org --- arch/ia64/kernel/time.c | 20 ++++++++++++----- arch/powerpc/kernel/time.c | 56 +++++++++++++++++++++++++++++++++------------- arch/s390/kernel/vtime.c | 45 ++++++++++++++++++++++++++----------- include/linux/vtime.h | 16 +++++-------- kernel/sched/cputime.c | 13 +++++++---- 5 files changed, 102 insertions(+), 48 deletions(-) diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 7abc5f37bfaf..733e0e3324b8 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -138,12 +138,8 @@ void vtime_account_kernel(struct task_struct *tsk) struct thread_info *ti = task_thread_info(tsk); __u64 stime = vtime_delta(tsk); - if ((tsk->flags & PF_VCPU) && !irq_count()) + if (tsk->flags & PF_VCPU) ti->gtime += stime; - else if (hardirq_count()) - ti->hardirq_time += stime; - else if (in_serving_softirq()) - ti->softirq_time += stime; else ti->stime += stime; } @@ -156,6 +152,20 @@ void vtime_account_idle(struct task_struct *tsk) ti->idle_time += vtime_delta(tsk); } +void vtime_account_softirq(struct task_struct *tsk) +{ + struct thread_info *ti = task_thread_info(tsk); + + ti->softirq_time += vtime_delta(tsk); +} + +void vtime_account_hardirq(struct task_struct *tsk) +{ + struct thread_info *ti = task_thread_info(tsk); + + ti->hardirq_time += vtime_delta(tsk); +} + #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ static irqreturn_t diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 74efe46f5532..cf3f8db7e0e3 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -311,12 +311,11 @@ static unsigned long vtime_delta_scaled(struct cpu_accounting_data *acct, return stime_scaled; } -static unsigned long vtime_delta(struct task_struct *tsk, +static unsigned long vtime_delta(struct cpu_accounting_data *acct, unsigned long *stime_scaled, unsigned long *steal_time) { unsigned long now, stime; - struct cpu_accounting_data *acct = get_accounting(tsk); WARN_ON_ONCE(!irqs_disabled()); @@ -331,29 +330,30 @@ static unsigned long vtime_delta(struct task_struct *tsk, return stime; } +static void vtime_delta_kernel(struct cpu_accounting_data *acct, + unsigned long *stime, unsigned long *stime_scaled) +{ + unsigned long steal_time; + + *stime = vtime_delta(acct, stime_scaled, &steal_time); + *stime -= min(*stime, steal_time); + acct->steal_time += steal_time; +} + void vtime_account_kernel(struct task_struct *tsk) { - unsigned long stime, stime_scaled, steal_time; struct cpu_accounting_data *acct = get_accounting(tsk); + unsigned long stime, stime_scaled; - stime = vtime_delta(tsk, &stime_scaled, &steal_time); - - stime -= min(stime, steal_time); - acct->steal_time += steal_time; + vtime_delta_kernel(acct, &stime, &stime_scaled); - if ((tsk->flags & PF_VCPU) && !irq_count()) { + if (tsk->flags & PF_VCPU) { acct->gtime += stime; #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME acct->utime_scaled += stime_scaled; #endif } else { - if (hardirq_count()) - acct->hardirq_time += stime; - else if (in_serving_softirq()) - acct->softirq_time += stime; - else - acct->stime += stime; - + acct->stime += stime; #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME acct->stime_scaled += stime_scaled; #endif @@ -366,10 +366,34 @@ void vtime_account_idle(struct task_struct *tsk) unsigned long stime, stime_scaled, steal_time; struct cpu_accounting_data *acct = get_accounting(tsk); - stime = vtime_delta(tsk, &stime_scaled, &steal_time); + stime = vtime_delta(acct, &stime_scaled, &steal_time); acct->idle_time += stime + steal_time; } +static void vtime_account_irq_field(struct cpu_accounting_data *acct, + unsigned long *field) +{ + unsigned long stime, stime_scaled; + + vtime_delta_kernel(acct, &stime, &stime_scaled); + *field += stime; +#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME + acct->stime_scaled += stime_scaled; +#endif +} + +void vtime_account_softirq(struct task_struct *tsk) +{ + struct cpu_accounting_data *acct = get_accounting(tsk); + vtime_account_irq_field(acct, &acct->softirq_time); +} + +void vtime_account_hardirq(struct task_struct *tsk) +{ + struct cpu_accounting_data *acct = get_accounting(tsk); + vtime_account_irq_field(acct, &acct->hardirq_time); +} + static void vtime_flush_scaled(struct task_struct *tsk, struct cpu_accounting_data *acct) { diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ebd8e5655789..5aaa2ca6a928 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -222,31 +222,50 @@ void vtime_flush(struct task_struct *tsk) S390_lowcore.avg_steal_timer = avg_steal; } +static u64 vtime_delta(void) +{ + u64 timer = S390_lowcore.last_update_timer; + + S390_lowcore.last_update_timer = get_vtimer(); + + return timer - S390_lowcore.last_update_timer; +} + /* * Update process times based on virtual cpu times stored by entry.S * to the lowcore fields user_timer, system_timer & steal_clock. */ void vtime_account_kernel(struct task_struct *tsk) { - u64 timer; - - timer = S390_lowcore.last_update_timer; - S390_lowcore.last_update_timer = get_vtimer(); - timer -= S390_lowcore.last_update_timer; + u64 delta = vtime_delta(); - if ((tsk->flags & PF_VCPU) && (irq_count() == 0)) - S390_lowcore.guest_timer += timer; - else if (hardirq_count()) - S390_lowcore.hardirq_timer += timer; - else if (in_serving_softirq()) - S390_lowcore.softirq_timer += timer; + if (tsk->flags & PF_VCPU) + S390_lowcore.guest_timer += delta; else - S390_lowcore.system_timer += timer; + S390_lowcore.system_timer += delta; - virt_timer_forward(timer); + virt_timer_forward(delta); } EXPORT_SYMBOL_GPL(vtime_account_kernel); +void vtime_account_softirq(struct task_struct *tsk) +{ + u64 delta = vtime_delta(); + + S390_lowcore.softirq_timer += delta; + + virt_timer_forward(delta); +} + +void vtime_account_hardirq(struct task_struct *tsk) +{ + u64 delta = vtime_delta(); + + S390_lowcore.hardirq_timer += delta; + + virt_timer_forward(delta); +} + /* * Sorted add to a list. List is linear searched until first bigger * element is found. diff --git a/include/linux/vtime.h b/include/linux/vtime.h index 2cdeca062db3..6c9867419615 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -83,16 +83,12 @@ static inline void vtime_init_idle(struct task_struct *tsk, int cpu) { } #endif #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -extern void vtime_account_irq_enter(struct task_struct *tsk); -static inline void vtime_account_irq_exit(struct task_struct *tsk) -{ - /* On hard|softirq exit we always account to hard|softirq cputime */ - vtime_account_kernel(tsk); -} +extern void vtime_account_irq(struct task_struct *tsk); +extern void vtime_account_softirq(struct task_struct *tsk); +extern void vtime_account_hardirq(struct task_struct *tsk); extern void vtime_flush(struct task_struct *tsk); #else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ -static inline void vtime_account_irq_enter(struct task_struct *tsk) { } -static inline void vtime_account_irq_exit(struct task_struct *tsk) { } +static inline void vtime_account_irq(struct task_struct *tsk) { } static inline void vtime_flush(struct task_struct *tsk) { } #endif @@ -105,13 +101,13 @@ static inline void irqtime_account_irq(struct task_struct *tsk) { } static inline void account_irq_enter_time(struct task_struct *tsk) { - vtime_account_irq_enter(tsk); + vtime_account_irq(tsk); irqtime_account_irq(tsk); } static inline void account_irq_exit_time(struct task_struct *tsk) { - vtime_account_irq_exit(tsk); + vtime_account_irq(tsk); irqtime_account_irq(tsk); } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 2783162542b1..02163d4260d7 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -417,13 +417,18 @@ void vtime_task_switch(struct task_struct *prev) } # endif -void vtime_account_irq_enter(struct task_struct *tsk) +void vtime_account_irq(struct task_struct *tsk) { - if (!IS_ENABLED(CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE) && - !in_interrupt() && is_idle_task(tsk)) + if (hardirq_count()) { + vtime_account_hardirq(tsk); + } else if (in_serving_softirq()) { + vtime_account_softirq(tsk); + } else if (!IS_ENABLED(CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE) && + is_idle_task(tsk)) { vtime_account_idle(tsk); - else + } else { vtime_account_kernel(tsk); + } } void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev, -- cgit From d3759e7184f8f6187e62f8c4e7dcb1f6c47c075a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2020 12:57:31 +0100 Subject: irqtime: Move irqtime entry accounting after irq offset incrementation IRQ time entry is currently accounted before HARDIRQ_OFFSET or SOFTIRQ_OFFSET are incremented. This is convenient to decide to which index the cputime to account is dispatched. Unfortunately it prevents tick_irq_enter() from being called under HARDIRQ_OFFSET because tick_irq_enter() has to be called before the IRQ entry accounting due to the necessary clock catch up. As a result we don't benefit from appropriate lockdep coverage on tick_irq_enter(). To prepare for fixing this, move the IRQ entry cputime accounting after the preempt offset is incremented. This requires the cputime dispatch code to handle the extra offset. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20201202115732.27827-5-frederic@kernel.org --- include/linux/hardirq.h | 4 ++-- include/linux/vtime.h | 34 ++++++++++++++++++++++++---------- kernel/sched/cputime.c | 18 +++++++++++------- kernel/softirq.c | 6 +++--- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 754f67ac4326..7c9d6a2d7e90 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -32,9 +32,9 @@ static __always_inline void rcu_irq_enter_check_tick(void) */ #define __irq_enter() \ do { \ - account_irq_enter_time(current); \ preempt_count_add(HARDIRQ_OFFSET); \ lockdep_hardirq_enter(); \ + account_hardirq_enter(current); \ } while (0) /* @@ -62,8 +62,8 @@ void irq_enter_rcu(void); */ #define __irq_exit() \ do { \ + account_hardirq_exit(current); \ lockdep_hardirq_exit(); \ - account_irq_exit_time(current); \ preempt_count_sub(HARDIRQ_OFFSET); \ } while (0) diff --git a/include/linux/vtime.h b/include/linux/vtime.h index 6c9867419615..041d6524d144 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -83,32 +83,46 @@ static inline void vtime_init_idle(struct task_struct *tsk, int cpu) { } #endif #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -extern void vtime_account_irq(struct task_struct *tsk); +extern void vtime_account_irq(struct task_struct *tsk, unsigned int offset); extern void vtime_account_softirq(struct task_struct *tsk); extern void vtime_account_hardirq(struct task_struct *tsk); extern void vtime_flush(struct task_struct *tsk); #else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ -static inline void vtime_account_irq(struct task_struct *tsk) { } +static inline void vtime_account_irq(struct task_struct *tsk, unsigned int offset) { } +static inline void vtime_account_softirq(struct task_struct *tsk) { } +static inline void vtime_account_hardirq(struct task_struct *tsk) { } static inline void vtime_flush(struct task_struct *tsk) { } #endif #ifdef CONFIG_IRQ_TIME_ACCOUNTING -extern void irqtime_account_irq(struct task_struct *tsk); +extern void irqtime_account_irq(struct task_struct *tsk, unsigned int offset); #else -static inline void irqtime_account_irq(struct task_struct *tsk) { } +static inline void irqtime_account_irq(struct task_struct *tsk, unsigned int offset) { } #endif -static inline void account_irq_enter_time(struct task_struct *tsk) +static inline void account_softirq_enter(struct task_struct *tsk) { - vtime_account_irq(tsk); - irqtime_account_irq(tsk); + vtime_account_irq(tsk, SOFTIRQ_OFFSET); + irqtime_account_irq(tsk, SOFTIRQ_OFFSET); } -static inline void account_irq_exit_time(struct task_struct *tsk) +static inline void account_softirq_exit(struct task_struct *tsk) { - vtime_account_irq(tsk); - irqtime_account_irq(tsk); + vtime_account_softirq(tsk); + irqtime_account_irq(tsk, 0); +} + +static inline void account_hardirq_enter(struct task_struct *tsk) +{ + vtime_account_irq(tsk, HARDIRQ_OFFSET); + irqtime_account_irq(tsk, HARDIRQ_OFFSET); +} + +static inline void account_hardirq_exit(struct task_struct *tsk) +{ + vtime_account_hardirq(tsk); + irqtime_account_irq(tsk, 0); } #endif /* _LINUX_KERNEL_VTIME_H */ diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 02163d4260d7..5f611658eeab 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -44,12 +44,13 @@ static void irqtime_account_delta(struct irqtime *irqtime, u64 delta, } /* - * Called before incrementing preempt_count on {soft,}irq_enter + * Called after incrementing preempt_count on {soft,}irq_enter * and before decrementing preempt_count on {soft,}irq_exit. */ -void irqtime_account_irq(struct task_struct *curr) +void irqtime_account_irq(struct task_struct *curr, unsigned int offset) { struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime); + unsigned int pc; s64 delta; int cpu; @@ -59,6 +60,7 @@ void irqtime_account_irq(struct task_struct *curr) cpu = smp_processor_id(); delta = sched_clock_cpu(cpu) - irqtime->irq_start_time; irqtime->irq_start_time += delta; + pc = preempt_count() - offset; /* * We do not account for softirq time from ksoftirqd here. @@ -66,9 +68,9 @@ void irqtime_account_irq(struct task_struct *curr) * in that case, so as not to confuse scheduler with a special task * that do not consume any time, but still wants to run. */ - if (hardirq_count()) + if (pc & HARDIRQ_MASK) irqtime_account_delta(irqtime, delta, CPUTIME_IRQ); - else if (in_serving_softirq() && curr != this_cpu_ksoftirqd()) + else if ((pc & SOFTIRQ_OFFSET) && curr != this_cpu_ksoftirqd()) irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ); } @@ -417,11 +419,13 @@ void vtime_task_switch(struct task_struct *prev) } # endif -void vtime_account_irq(struct task_struct *tsk) +void vtime_account_irq(struct task_struct *tsk, unsigned int offset) { - if (hardirq_count()) { + unsigned int pc = preempt_count() - offset; + + if (pc & HARDIRQ_OFFSET) { vtime_account_hardirq(tsk); - } else if (in_serving_softirq()) { + } else if (pc & SOFTIRQ_OFFSET) { vtime_account_softirq(tsk); } else if (!IS_ENABLED(CONFIG_HAVE_VIRT_CPU_ACCOUNTING_IDLE) && is_idle_task(tsk)) { diff --git a/kernel/softirq.c b/kernel/softirq.c index 617009ccd82c..b8f42b3ba8ca 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -315,10 +315,10 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) current->flags &= ~PF_MEMALLOC; pending = local_softirq_pending(); - account_irq_enter_time(current); __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); in_hardirq = lockdep_softirq_start(); + account_softirq_enter(current); restart: /* Reset the pending bitmask before enabling irqs */ @@ -365,8 +365,8 @@ restart: wakeup_softirqd(); } + account_softirq_exit(current); lockdep_softirq_end(in_hardirq); - account_irq_exit_time(current); __local_bh_enable(SOFTIRQ_OFFSET); WARN_ON_ONCE(in_interrupt()); current_restore_flags(old_flags, PF_MEMALLOC); @@ -418,7 +418,7 @@ static inline void __irq_exit_rcu(void) #else lockdep_assert_irqs_disabled(); #endif - account_irq_exit_time(current); + account_hardirq_exit(current); preempt_count_sub(HARDIRQ_OFFSET); if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); -- cgit From d14ce74f1fb376ccbbc0b05ded477ada51253729 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2020 12:57:32 +0100 Subject: irq: Call tick_irq_enter() inside HARDIRQ_OFFSET Now that account_hardirq_enter() is called after HARDIRQ_OFFSET has been incremented, there is nothing left that prevents us from also moving tick_irq_enter() after HARDIRQ_OFFSET is incremented. The desired outcome is to remove the nasty hack that prevents softirqs from being raised through ksoftirqd instead of the hardirq bottom half. Also tick_irq_enter() then becomes appropriately covered by lockdep. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201202115732.27827-6-frederic@kernel.org --- kernel/softirq.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index b8f42b3ba8ca..d5bfd5e661fc 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -377,16 +377,12 @@ restart: */ void irq_enter_rcu(void) { - if (is_idle_task(current) && !in_interrupt()) { - /* - * Prevent raise_softirq from needlessly waking up ksoftirqd - * here, as softirq will be serviced on return from interrupt. - */ - local_bh_disable(); + __irq_enter_raw(); + + if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET)) tick_irq_enter(); - _local_bh_enable(); - } - __irq_enter(); + + account_hardirq_enter(current); } /** -- cgit From 42a590b0fdf72498ebf47b01ddf006ee92cbfc70 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 9 Dec 2020 11:15:04 +0100 Subject: irqchip/gic: Spelling s/REturn/Return/ Fix a capitalization typo. Signed-off-by: Geert Uytterhoeven Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201209101504.2206941-1-geert+renesas@glider.be --- drivers/irqchip/irq-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 6053245a4754..a3c2f18131b2 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -973,7 +973,7 @@ void gic_migrate_target(unsigned int new_cpu_id) /* * gic_get_sgir_physaddr - get the physical address for the SGI register * - * REturn the physical address of the SGI register to be used + * Return the physical address of the SGI register to be used * by some early assembly code when the kernel is not yet available. */ static unsigned long gic_dist_physaddr; -- cgit From 3ee36352e26935c7e8145eb4e7ed38b536ca01fc Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 5 Dec 2020 17:15:44 +0800 Subject: irqchip/loongson-htpic: Fix build warnings Fix build warnings as below: drivers/irqchip/irq-loongson-htpic.c: In function 'htpic_reg_init': >> drivers/irqchip/irq-loongson-htpic.c:62:12: warning: variable 'val' set but not used [-Wunused-but-set-variable] 62 | uint32_t val; | ^~~ drivers/irqchip/irq-loongson-htpic.c: At top level: >> drivers/irqchip/irq-loongson-htpic.c:84:12: warning: no previous prototype for 'htpic_of_init' [-Wmissing-prototypes] 84 | int __init htpic_of_init(struct device_node *node, struct device_node *parent) | ^~~~~~~~~~~~~ Fixes: a93f1d903fa34fc2c5d9fa450bd ("irqchip: Add driver for Loongson-3 HyperTransport PIC controller") Reported-by: kernel test robot Signed-off-by: Huacai Chen Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/1607159744-995-1-git-send-email-chenhuacai@kernel.org --- drivers/irqchip/irq-loongson-htpic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c index 63f72803c8c4..1b801c4fb026 100644 --- a/drivers/irqchip/irq-loongson-htpic.c +++ b/drivers/irqchip/irq-loongson-htpic.c @@ -59,11 +59,10 @@ static void htpic_reg_init(void) int i; for (i = 0; i < HTINT_NUM_VECTORS; i++) { - uint32_t val; - /* Disable all HT Vectors */ writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4); - val = readl(htpic->base + i * 0x4); + /* Read back to force write */ + (void) readl(htpic->base + i * 0x4); /* Ack all possible pending IRQs */ writel(GENMASK(31, 0), htpic->base + i * 0x4); } @@ -81,7 +80,7 @@ struct syscore_ops htpic_syscore_ops = { .resume = htpic_resume, }; -int __init htpic_of_init(struct device_node *node, struct device_node *parent) +static int __init htpic_of_init(struct device_node *node, struct device_node *parent) { unsigned int parent_irq[4]; int i, err; -- cgit From b16a1caf4686895427c810219d4b2f796e676160 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Mon, 30 Nov 2020 18:15:05 +0800 Subject: irqchip/ls-extirq: Add LS1043A, LS1088A external interrupt support Add an new IRQ chip declaration for LS1043A and LS1088A, and cleanup the use of the "bit_reverse" property, now gated on the Soc type. Signed-off-by: Hou Zhiqiang Signed-off-by: Biwen Li Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201130101515.27431-1-biwen.li@oss.nxp.com --- drivers/irqchip/irq-ls-extirq.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c index 4d1179fed77c..f94f974a8764 100644 --- a/drivers/irqchip/irq-ls-extirq.c +++ b/drivers/irqchip/irq-ls-extirq.c @@ -18,7 +18,7 @@ struct ls_extirq_data { struct regmap *syscon; u32 intpcr; - bool bit_reverse; + bool is_ls1021a_or_ls1043a; u32 nirq; struct irq_fwspec map[MAXIRQ]; }; @@ -30,7 +30,7 @@ ls_extirq_set_type(struct irq_data *data, unsigned int type) irq_hw_number_t hwirq = data->hwirq; u32 value, mask; - if (priv->bit_reverse) + if (priv->is_ls1021a_or_ls1043a) mask = 1U << (31 - hwirq); else mask = 1U << hwirq; @@ -174,14 +174,8 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent) if (ret) goto out; - if (of_device_is_compatible(node, "fsl,ls1021a-extirq")) { - u32 revcr; - - ret = regmap_read(priv->syscon, LS1021A_SCFGREVCR, &revcr); - if (ret) - goto out; - priv->bit_reverse = (revcr != 0); - } + priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") || + of_device_is_compatible(node, "fsl,ls1043a-extirq"); domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node, &extirq_domain_ops, priv); @@ -195,3 +189,5 @@ out: } IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init); +IRQCHIP_DECLARE(ls1043a_extirq, "fsl,ls1043a-extirq", ls_extirq_of_init); +IRQCHIP_DECLARE(ls1088a_extirq, "fsl,ls1088a-extirq", ls_extirq_of_init); -- cgit From 9898a59358d7cb925f63bb77bd40224d1bc4857e Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Mon, 30 Nov 2020 18:15:15 +0800 Subject: dt-bindings: interrupt-controller: update bindings for supporting more SoCs Update bindings for Layerscape external irqs, support more SoCs(LS1043A, LS1046A, LS1088A, LS208xA, LX216xA) Signed-off-by: Biwen Li Signed-off-by: Marc Zyngier Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201130101515.27431-11-biwen.li@oss.nxp.com --- .../devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt index f0ad7801e8cf..4d47df1a5c91 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-extirq.txt @@ -1,6 +1,7 @@ * Freescale Layerscape external IRQs -Some Layerscape SOCs (LS1021A, LS1043A, LS1046A) support inverting +Some Layerscape SOCs (LS1021A, LS1043A, LS1046A +LS1088A, LS208xA, LX216xA) support inverting the polarity of certain external interrupt lines. The device node must be a child of the node representing the @@ -8,12 +9,15 @@ Supplemental Configuration Unit (SCFG). Required properties: - compatible: should be "fsl,-extirq", e.g. "fsl,ls1021a-extirq". + "fsl,ls1043a-extirq": for LS1043A, LS1046A. + "fsl,ls1088a-extirq": for LS1088A, LS208xA, LX216xA. - #interrupt-cells: Must be 2. The first element is the index of the external interrupt line. The second element is the trigger type. - #address-cells: Must be 0. - interrupt-controller: Identifies the node as an interrupt controller - reg: Specifies the Interrupt Polarity Control Register (INTPCR) in - the SCFG. + the SCFG or the External Interrupt Control Register (IRQCR) in + the ISC. - interrupt-map: Specifies the mapping from external interrupts to GIC interrupts. - interrupt-map-mask: Must be <0xffffffff 0>. -- cgit From 3841245e8498a789c65dedd7ffa8fb2fee2c0684 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:55:25 +0000 Subject: irqchip/alpine-msi: Fix freeing of interrupts on allocation error path The alpine-msi driver has an interesting allocation error handling, where it frees the same interrupts repeatedly. Hilarity follows. This code is probably never executed, but let's fix it nonetheless. Fixes: e6b78f2c3e14 ("irqchip: Add the Alpine MSIX interrupt controller") Signed-off-by: Marc Zyngier Reviewed-by: Antoine Tenart Cc: Tsahee Zidenberg Cc: Antoine Tenart Link: https://lore.kernel.org/r/20201129135525.396671-1-maz@kernel.org --- drivers/irqchip/irq-alpine-msi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index 23a3b877f7f1..ede02dc2bcd0 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -165,8 +165,7 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, return 0; err_sgi: - while (--i >= 0) - irq_domain_free_irqs_parent(domain, virq, i); + irq_domain_free_irqs_parent(domain, virq, i - 1); alpine_msix_free_sgi(priv, sgi, nr_irqs); return err; } -- cgit From 0b39498230ae53e6af981141be99f4c7d5144de6 Mon Sep 17 00:00:00 2001 From: Shenming Lu Date: Sat, 28 Nov 2020 22:18:56 +0800 Subject: irqchip/gic-v4.1: Reduce the delay when polling GICR_VPENDBASER.Dirty The 10us delay of the poll on the GICR_VPENDBASER.Dirty bit is too high, which might greatly affect the total scheduling latency of a vCPU in our measurement. So we reduce it to 1 to lessen the impact. Signed-off-by: Shenming Lu Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201128141857.983-2-lushenming@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 4069c215328b..d74ef418e386 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3808,7 +3808,7 @@ static void its_wait_vpt_parse_complete(void) WARN_ON_ONCE(readq_relaxed_poll_timeout_atomic(vlpi_base + GICR_VPENDBASER, val, !(val & GICR_VPENDBASER_Dirty), - 10, 500)); + 1, 500)); } static void its_vpe_schedule(struct its_vpe *vpe) -- cgit From 47d5e0b0e1c151c06885a78a108001ead96adc75 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:01 +0100 Subject: dt-bindings: interrupt-controller: convert icpu intr bindings to json-schema Convert device tree bindings for Microsemi Ocelot SoC ICPU Interrupt Controller to YAML format Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201125103206.136498-2-gregory.clement@bootlin.com --- .../interrupt-controller/mscc,ocelot-icpu-intr.txt | 21 -------- .../mscc,ocelot-icpu-intr.yaml | 60 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt deleted file mode 100644 index f5baeccb689f..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt +++ /dev/null @@ -1,21 +0,0 @@ -Microsemi Ocelot SoC ICPU Interrupt Controller - -Required properties: - -- compatible : should be "mscc,ocelot-icpu-intr" -- reg : Specifies base physical address and size of the registers. -- interrupt-controller : Identifies the node as an interrupt controller -- #interrupt-cells : Specifies the number of cells needed to encode an - interrupt source. The value shall be 1. -- interrupts : Specifies the CPU interrupt the controller is connected to. - -Example: - - intc: interrupt-controller@70000070 { - compatible = "mscc,ocelot-icpu-intr"; - reg = <0x70000070 0x70>; - #interrupt-cells = <1>; - interrupt-controller; - interrupt-parent = <&cpuintc>; - interrupts = <2>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml new file mode 100644 index 000000000000..be82920f6798 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/interrupt-controller/mscc,ocelot-icpu-intr.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Microsemi Ocelot SoC ICPU Interrupt Controller + +maintainers: + - Alexandre Belloni + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +description: | + the Microsemi Ocelot interrupt controller that is part of the + ICPU. It is connected directly to the MIPS core interrupt + controller. + +properties: + compatible: + items: + - enum: + - mscc,ocelot-icpu-intr + + '#interrupt-cells': + const: 1 + + '#address-cells': + const: 0 + + interrupt-controller: true + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - '#interrupt-cells' + - '#address-cells' + - interrupt-controller + - reg + +additionalProperties: false + +examples: + - | + intc: interrupt-controller@70000070 { + compatible = "mscc,ocelot-icpu-intr"; + reg = <0x70000070 0x70>; + #interrupt-cells = <1>; + #address-cells = <0>; + interrupt-controller; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + }; +... -- cgit From b307ee828f61bc65d918e820a93b5c547a73dda3 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:02 +0100 Subject: dt-bindings: interrupt-controller: Add binding for few Microsemi interrupt controllers Add the Device Tree binding documentation for the Microsemi Jaguar2, Luton and Serval interrupt controller that is part of the ICPU. It is connected directly to the MIPS core interrupt controller. Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201125103206.136498-3-gregory.clement@bootlin.com --- .../bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml index be82920f6798..27b798bfe29b 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.yaml @@ -21,7 +21,11 @@ properties: compatible: items: - enum: + - mscc,jaguar2-icpu-intr + - mscc,luton-icpu-intr - mscc,ocelot-icpu-intr + - mscc,serval-icpu-intr + '#interrupt-cells': const: 1 -- cgit From 5f0c75e7a1333f5ebb5303af55d8c863ea292c23 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:03 +0100 Subject: irqchip/ocelot: prepare to support more SoC This patch extends irqchip driver for oceleot to be used with other vcoreiii base platforms. Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-4-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 76 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 88143c0b700c..6d4029a2ded0 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -12,30 +12,51 @@ #include #include -#define ICPU_CFG_INTR_INTR_STICKY 0x10 -#define ICPU_CFG_INTR_INTR_ENA 0x18 -#define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c -#define ICPU_CFG_INTR_INTR_ENA_SET 0x20 -#define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x)) -#define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x)) - -#define OCELOT_NR_IRQ 24 +#define ICPU_CFG_INTR_DST_INTR_IDENT(_p, x) ((_p)->reg_off_ident + 0x4 * (x)) +#define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x)) + +#define FLAGS_HAS_TRIGGER BIT(0) + +struct chip_props { + u8 flags; + u8 reg_off_sticky; + u8 reg_off_ena; + u8 reg_off_ena_clr; + u8 reg_off_ena_set; + u8 reg_off_ident; + u8 reg_off_trigger; + u8 reg_off_ena_irq0; + u8 n_irq; +}; + +static struct chip_props ocelot_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0x10, + .reg_off_ena = 0x18, + .reg_off_ena_clr = 0x1c, + .reg_off_ena_set = 0x20, + .reg_off_ident = 0x38, + .reg_off_trigger = 0x5c, + .n_irq = 24, +}; static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); + struct irq_domain *d = data->domain; + struct chip_props *p = d->host_data; struct irq_chip_type *ct = irq_data_get_chip_type(data); unsigned int mask = data->mask; u32 val; irq_gc_lock(gc); - val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) | - irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1)); + val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 0)) | + irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 1)); if (!(val & mask)) - irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY); + irq_reg_writel(gc, mask, p->reg_off_sticky); *ct->mask_cache &= ~mask; - irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET); + irq_reg_writel(gc, mask, p->reg_off_ena_set); irq_gc_unlock(gc); } @@ -43,8 +64,9 @@ static void ocelot_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_domain *d = irq_desc_get_handler_data(desc); + struct chip_props *p = d->host_data; struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); - u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0)); + u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(p, 0)); chained_irq_enter(chip, desc); @@ -58,8 +80,9 @@ static void ocelot_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int __init ocelot_irq_init(struct device_node *node, - struct device_node *parent) +static int __init vcoreiii_irq_init(struct device_node *node, + struct device_node *parent, + struct chip_props *p) { struct irq_domain *domain; struct irq_chip_generic *gc; @@ -69,14 +92,14 @@ static int __init ocelot_irq_init(struct device_node *node, if (!parent_irq) return -EINVAL; - domain = irq_domain_add_linear(node, OCELOT_NR_IRQ, + domain = irq_domain_add_linear(node, p->n_irq, &irq_generic_chip_ops, NULL); if (!domain) { pr_err("%pOFn: unable to add irq domain\n", node); return -ENOMEM; } - ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1, + ret = irq_alloc_domain_generic_chips(domain, p->n_irq, 1, "icpu", handle_level_irq, 0, 0, 0); if (ret) { @@ -92,16 +115,18 @@ static int __init ocelot_irq_init(struct device_node *node, goto err_gc_free; } - gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY; - gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR; + gc->chip_types[0].regs.ack = p->reg_off_sticky; + gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; + if (p->flags & FLAGS_HAS_TRIGGER) + gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; /* Mask and ack all interrupts */ - irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA); - irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY); + irq_reg_writel(gc, 0, p->reg_off_ena); + irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky); + domain->host_data = p; irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler, domain); @@ -115,4 +140,11 @@ err_domain_remove: return ret; } + +static int __init ocelot_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &ocelot_props); +} + IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); -- cgit From ffce73d4415391b2d6da4878bf04d6610edf56db Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:04 +0100 Subject: irqchip/ocelot: Add support for Luton platforms This patch extends irqchip driver for oceleot to be used with an other vcoreiii base platform: Luton. For this platform there is a few differences: - the interrupt must be enabled for the parent controller - there is no trigger register needed to be managed Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-5-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 6d4029a2ded0..496f955b8fc4 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -16,6 +16,7 @@ #define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x)) #define FLAGS_HAS_TRIGGER BIT(0) +#define FLAGS_NEED_INIT_ENABLE BIT(1) struct chip_props { u8 flags; @@ -40,6 +41,17 @@ static struct chip_props ocelot_props = { .n_irq = 24, }; +static struct chip_props luton_props = { + .flags = FLAGS_NEED_INIT_ENABLE, + .reg_off_sticky = 0, + .reg_off_ena = 0x4, + .reg_off_ena_clr = 0x8, + .reg_off_ena_set = 0xc, + .reg_off_ident = 0x18, + .reg_off_ena_irq0 = 0x14, + .n_irq = 28, +}; + static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); @@ -115,17 +127,27 @@ static int __init vcoreiii_irq_init(struct device_node *node, goto err_gc_free; } - gc->chip_types[0].regs.ack = p->reg_off_sticky; - gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - if (p->flags & FLAGS_HAS_TRIGGER) + gc->chip_types[0].regs.ack = p->reg_off_sticky; + if (p->flags & FLAGS_HAS_TRIGGER) { + gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + } else { + gc->chip_types[0].regs.enable = p->reg_off_ena_set; + gc->chip_types[0].regs.disable = p->reg_off_ena_clr; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; + } /* Mask and ack all interrupts */ irq_reg_writel(gc, 0, p->reg_off_ena); irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky); + /* Overall init */ + if (p->flags & FLAGS_NEED_INIT_ENABLE) + irq_reg_writel(gc, BIT(0), p->reg_off_ena_irq0); + domain->host_data = p; irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler, domain); @@ -148,3 +170,11 @@ static int __init ocelot_irq_init(struct device_node *node, } IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); + +static int __init luton_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &luton_props); +} + +IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init); -- cgit From 7efdfbd15a21788de8c0743590e777f151a3031b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:05 +0100 Subject: irqchip/ocelot: Add support for Serval platforms This patch extends irqchip driver for ocelot to be used with an other vcoreiii base platform: Serval. Based on a larger patch from Lars Povlsen Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-6-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 496f955b8fc4..da5a0ad991a1 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -41,6 +41,17 @@ static struct chip_props ocelot_props = { .n_irq = 24, }; +static struct chip_props serval_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0xc, + .reg_off_ena = 0x14, + .reg_off_ena_clr = 0x18, + .reg_off_ena_set = 0x1c, + .reg_off_ident = 0x20, + .reg_off_trigger = 0x4, + .n_irq = 24, +}; + static struct chip_props luton_props = { .flags = FLAGS_NEED_INIT_ENABLE, .reg_off_sticky = 0, @@ -171,6 +182,14 @@ static int __init ocelot_irq_init(struct device_node *node, IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); +static int __init serval_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &serval_props); +} + +IRQCHIP_DECLARE(serval_icpu, "mscc,serval-icpu-intr", serval_irq_init); + static int __init luton_irq_init(struct device_node *node, struct device_node *parent) { -- cgit From 550c1424acf0123ba0c17e22dfcac92d152b2f0e Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:06 +0100 Subject: irqchip/ocelot: Add support for Jaguar2 platforms This patch extends irqchip driver for ocelot to be used with an other vcoreiii base platform: Jaguar2. Based on a larger patch from Lars Povlsen Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-7-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index da5a0ad991a1..8235d98650c1 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -63,6 +63,17 @@ static struct chip_props luton_props = { .n_irq = 28, }; +static struct chip_props jaguar2_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0x10, + .reg_off_ena = 0x18, + .reg_off_ena_clr = 0x1c, + .reg_off_ena_set = 0x20, + .reg_off_ident = 0x38, + .reg_off_trigger = 0x5c, + .n_irq = 29, +}; + static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); @@ -197,3 +208,11 @@ static int __init luton_irq_init(struct device_node *node, } IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init); + +static int __init jaguar2_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &jaguar2_props); +} + +IRQCHIP_DECLARE(jaguar2_icpu, "mscc,jaguar2-icpu-intr", jaguar2_irq_init); -- cgit From 6abbd6988971aaa607b026eaa0ffd2301352f2ea Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:17 +0000 Subject: irqchip/gic, gic-v3: Make SGIs use handle_percpu_devid_irq() handle_percpu_devid_fasteoi_ipi() states: * The biggest difference with the IRQ version is that the interrupt is * EOIed early, as the IPI could result in a context switch, and we need to * make sure the IPI can fire again All that can actually happen scheduler-wise within the handling of an IPI is the raising of TIF_NEED_RESCHED (and / or folding thereof into preempt_count); see scheduler_ipi() or sched_ttwu_pending() for instance. Said flag / preempt_count is evaluated some time later before returning to whatever context was interrupted, and this gates a call to preempt_schedule_irq() (arm64_preempt_schedule_irq() in arm64). Per the above, SGI's do not need a different handler than PPI's, so make them use the same (handle_percpu_devid_irq). Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-2-valentin.schneider@arm.com --- drivers/irqchip/irq-gic-v3.c | 6 ------ drivers/irqchip/irq-gic.c | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 16fecc0febe8..3fc65375cbe0 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1302,12 +1302,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, switch (__get_intid_range(hw)) { case SGI_RANGE: - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, chip, d->host_data, - handle_percpu_devid_fasteoi_ipi, - NULL, NULL); - break; - case PPI_RANGE: case EPPI_RANGE: irq_set_percpu_devid(irq); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a3c2f18131b2..b1d9c22caf2e 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1005,13 +1005,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq)); switch (hw) { - case 0 ... 15: - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, - handle_percpu_devid_fasteoi_ipi, - NULL, NULL); - break; - case 16 ... 31: + case 0 ... 31: irq_set_percpu_devid(irq); irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); -- cgit From e52e73b7e9f7d08b8c2ef6fb1657105093e22a03 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:18 +0000 Subject: irqchip/armada-370-xp: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-3-valentin.schneider@arm.com --- drivers/irqchip/irq-armada-370-xp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index d7eb2e93db8f..32938dfc0e46 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -382,7 +382,7 @@ static int armada_370_xp_ipi_alloc(struct irq_domain *d, irq_set_percpu_devid(virq + i); irq_domain_set_info(d, virq + i, i, &ipi_irqchip, d->host_data, - handle_percpu_devid_fasteoi_ipi, + handle_percpu_devid_irq, NULL, NULL); } -- cgit From ffdad793d579c9286c7b67a86d1a3c890fb32082 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:19 +0000 Subject: irqchip/bcm2836: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-4-valentin.schneider@arm.com --- drivers/irqchip/irq-bcm2836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index cbc7c740e4dc..5f5eb8877c41 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -209,7 +209,7 @@ static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d, irq_set_percpu_devid(virq + i); irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi, d->host_data, - handle_percpu_devid_fasteoi_ipi, + handle_percpu_devid_irq, NULL, NULL); } -- cgit From a2e042e13ff322ad523a2f131dd6e03e8bc05053 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:20 +0000 Subject: irqchip/hip04: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-5-valentin.schneider@arm.com --- drivers/irqchip/irq-hip04.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 9b73dcfaf48d..a6ed877d9dd3 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -296,11 +296,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - if (hw < 16) { - irq_set_percpu_devid(irq); - irq_set_chip_and_handler(irq, &hip04_irq_chip, - handle_percpu_devid_fasteoi_ipi); - } else if (hw < 32) { + if (hw < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &hip04_irq_chip, handle_percpu_devid_irq); -- cgit From b388fa50142510fb6477f130bb1b3f05a0a263a1 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:21 +0000 Subject: Revert "genirq: Add fasteoi IPI flow" handle_percpu_devid_fasteoi_ipi() has no more users, and handle_percpu_devid_irq() can do all that it was supposed to do. Get rid of it. This reverts commit c5e5ec033c4ab25c53f1fd217849e75deb0bf7bf. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-6-valentin.schneider@arm.com --- include/linux/irq.h | 1 - kernel/irq/chip.c | 27 --------------------------- 2 files changed, 28 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index c54365309e97..ca26bec51cec 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -647,7 +647,6 @@ static inline int irq_set_parent(int irq, int parent_irq) */ extern void handle_level_irq(struct irq_desc *desc); extern void handle_fasteoi_irq(struct irq_desc *desc); -extern void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc); extern void handle_edge_irq(struct irq_desc *desc); extern void handle_edge_eoi_irq(struct irq_desc *desc); extern void handle_simple_irq(struct irq_desc *desc); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index b9b9618e1aca..0ae308efa604 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -944,33 +944,6 @@ void handle_percpu_devid_irq(struct irq_desc *desc) chip->irq_eoi(&desc->irq_data); } -/** - * handle_percpu_devid_fasteoi_ipi - Per CPU local IPI handler with per cpu - * dev ids - * @desc: the interrupt description structure for this irq - * - * The biggest difference with the IRQ version is that the interrupt is - * EOIed early, as the IPI could result in a context switch, and we need to - * make sure the IPI can fire again. We also assume that the arch code has - * registered an action. If not, we are positively doomed. - */ -void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct irqaction *action = desc->action; - unsigned int irq = irq_desc_get_irq(desc); - irqreturn_t res; - - __kstat_incr_irqs_this_cpu(desc); - - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); - - trace_irq_handler_entry(irq, action); - res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id)); - trace_irq_handler_exit(irq, action, res); -} - /** * handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu * dev ids -- cgit From 04e7f423f4a96ad492fd51bf2234b8982400ab5f Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 5 Nov 2020 13:22:09 -0800 Subject: drivers/irqchip: Remove EZChip NPS interrupt controller NPS platform has been removed from ARC port and there are no in-tree users of it now. So RIP ! Signed-off-by: Vineet Gupta Signed-off-by: Marc Zyngier Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-kernel@vger.kernel.org Link: https://lore.kernel.org/r/20201105212210.1891598-3-vgupta@synopsys.com --- drivers/irqchip/Kconfig | 7 -- drivers/irqchip/Makefile | 1 - drivers/irqchip/irq-eznps.c | 165 -------------------------------------------- 3 files changed, 173 deletions(-) delete mode 100644 drivers/irqchip/irq-eznps.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 2aa79c32ee22..94920a51c628 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -387,13 +387,6 @@ config LS_SCFG_MSI config PARTITION_PERCPU bool -config EZNPS_GIC - bool "NPS400 Global Interrupt Manager (GIM)" - depends on ARC || (COMPILE_TEST && !64BIT) - select IRQ_DOMAIN - help - Support the EZchip NPS400 global interrupt controller - config STM32_EXTI bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 94c2885882ee..0ac93bfaec61 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -86,7 +86,6 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o -obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c deleted file mode 100644 index 2a7a38830a8d..000000000000 --- a/drivers/irqchip/irq-eznps.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2016, Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define NPS_NR_CPU_IRQS 8 /* number of interrupt lines of NPS400 CPU */ -#define NPS_TIMER0_IRQ 3 - -/* - * NPS400 core includes an Interrupt Controller (IC) support. - * All cores can deactivate level irqs at first level control - * at cores mesh layer called MTM. - * For devices out side chip e.g. uart, network there is another - * level called Global Interrupt Manager (GIM). - * This second level can control level and edge interrupt. - * - * NOTE: AUX_IENABLE and CTOP_AUX_IACK are auxiliary registers - * with private HW copy per CPU. - */ - -static void nps400_irq_mask(struct irq_data *irqd) -{ - unsigned int ienb; - unsigned int irq = irqd_to_hwirq(irqd); - - ienb = read_aux_reg(AUX_IENABLE); - ienb &= ~(1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - -static void nps400_irq_unmask(struct irq_data *irqd) -{ - unsigned int ienb; - unsigned int irq = irqd_to_hwirq(irqd); - - ienb = read_aux_reg(AUX_IENABLE); - ienb |= (1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - -static void nps400_irq_eoi_global(struct irq_data *irqd) -{ - unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); - - write_aux_reg(CTOP_AUX_IACK, 1 << irq); - - /* Don't ack GIC before all device access attempts are done */ - mb(); - - nps_ack_gic(); -} - -static void nps400_irq_ack(struct irq_data *irqd) -{ - unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); - - write_aux_reg(CTOP_AUX_IACK, 1 << irq); -} - -static struct irq_chip nps400_irq_chip_fasteoi = { - .name = "NPS400 IC Global", - .irq_mask = nps400_irq_mask, - .irq_unmask = nps400_irq_unmask, - .irq_eoi = nps400_irq_eoi_global, -}; - -static struct irq_chip nps400_irq_chip_percpu = { - .name = "NPS400 IC", - .irq_mask = nps400_irq_mask, - .irq_unmask = nps400_irq_unmask, - .irq_ack = nps400_irq_ack, -}; - -static int nps400_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - switch (hw) { - case NPS_TIMER0_IRQ: -#ifdef CONFIG_SMP - case NPS_IPI_IRQ: -#endif - irq_set_percpu_devid(virq); - irq_set_chip_and_handler(virq, &nps400_irq_chip_percpu, - handle_percpu_devid_irq); - break; - default: - irq_set_chip_and_handler(virq, &nps400_irq_chip_fasteoi, - handle_fasteoi_irq); - break; - } - - return 0; -} - -static const struct irq_domain_ops nps400_irq_ops = { - .xlate = irq_domain_xlate_onecell, - .map = nps400_irq_map, -}; - -static int __init nps400_of_init(struct device_node *node, - struct device_node *parent) -{ - struct irq_domain *nps400_root_domain; - - if (parent) { - pr_err("DeviceTree incore ic not a root irq controller\n"); - return -EINVAL; - } - - nps400_root_domain = irq_domain_add_linear(node, NPS_NR_CPU_IRQS, - &nps400_irq_ops, NULL); - - if (!nps400_root_domain) { - pr_err("nps400 root irq domain not avail\n"); - return -ENOMEM; - } - - /* - * Needed for primary domain lookup to succeed - * This is a primary irqchip, and can never have a parent - */ - irq_set_default_host(nps400_root_domain); - -#ifdef CONFIG_SMP - irq_create_mapping(nps400_root_domain, NPS_IPI_IRQ); -#endif - - return 0; -} -IRQCHIP_DECLARE(ezchip_nps400_ic, "ezchip,nps400-ic", nps400_of_init); -- cgit From b10d5fd489b0c67f59cbdd28d95f4bd9f76a62f2 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 2 Nov 2020 17:36:14 +0530 Subject: irqchip/ti-sci-inta: Fix printing of inta id on probe success On a successful probe, the driver tries to print a success message with INTA device id. It uses pdev->id for printing the id but id is stored in inta->ti_sci_id. Fix it by correcting the dev_info parameter. Fixes: 5c4b585d2910 ("irqchip/ti-sci-inta: Add support for INTA directly connecting to GIC") Signed-off-by: Lokesh Vutla Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201102120614.11109-1-lokeshvutla@ti.com --- drivers/irqchip/irq-ti-sci-inta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index b2ab8db439d9..532d0ae172d9 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -726,7 +726,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev) INIT_LIST_HEAD(&inta->vint_list); mutex_init(&inta->vint_mutex); - dev_info(dev, "Interrupt Aggregator domain %d created\n", pdev->id); + dev_info(dev, "Interrupt Aggregator domain %d created\n", inta->ti_sci_id); return 0; } -- cgit From fc6c7cd3878641fd43189f15697e7ad0871f5c1a Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 2 Nov 2020 17:36:31 +0530 Subject: irqchip/ti-sci-intr: Fix freeing of irqs ti_sci_intr_irq_domain_free() assumes that out_irq of intr is stored in data->chip_data and uses it for calling ti_sci irq_free() and then mark the out_irq as available resource. But ti_sci_intr_irq_domain_alloc() is storing p_hwirq(parent's hardware irq) which is translated from out_irq. This is causing resource leakage and eventually out_irq resources might be exhausted. Fix ti_sci_intr_irq_domain_alloc() by storing the out_irq in data->chip_data. Fixes: a5b659bd4bc7 ("irqchip/ti-sci-intr: Add support for INTR being a parent to INTR") Signed-off-by: Lokesh Vutla Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201102120631.11165-1-lokeshvutla@ti.com --- drivers/irqchip/irq-ti-sci-intr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c index ac9d6d658e65..fe8fad22bcf9 100644 --- a/drivers/irqchip/irq-ti-sci-intr.c +++ b/drivers/irqchip/irq-ti-sci-intr.c @@ -129,7 +129,7 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain, * @virq: Corresponding Linux virtual IRQ number * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain * - * Returns parent irq if all went well else appropriate error pointer. + * Returns intr output irq if all went well else appropriate error pointer. */ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, unsigned int virq, u32 hwirq) @@ -173,7 +173,7 @@ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, if (err) goto err_msg; - return p_hwirq; + return out_irq; err_msg: irq_domain_free_irqs_parent(domain, virq, 1); @@ -198,19 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain, struct irq_fwspec *fwspec = data; unsigned long hwirq; unsigned int flags; - int err, p_hwirq; + int err, out_irq; err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags); if (err) return err; - p_hwirq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq); - if (p_hwirq < 0) - return p_hwirq; + out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq); + if (out_irq < 0) + return out_irq; irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &ti_sci_intr_irq_chip, - (void *)(uintptr_t)p_hwirq); + (void *)(uintptr_t)out_irq); return 0; } -- cgit From 91f90daa4fb2b77db7aa25ef2e0206f2e3962665 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:06 +0000 Subject: platform-msi: Track shared domain allocation We have two flavours of platform-MSI: - MSIs generated by devices for themselves (the usual case) - MSIs generated on behalf of other devices, as the generating device is some form of bridge (either a wire-to-MSI bridge, or even a non-transparent PCI bridge that repaints the PCI requester ID). In the latter case, the underlying interrupt architecture may need to track this in order to keep the mapping alive even when no MSI are currently being generated. Add a set of flags to the generic msi_alloc_info_t structure, as well as the MSI_ALLOC_FLAGS_PROXY_DEVICE flag that will get advertized by the platform-MSI code when allocating an irqdomain for a device. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-2-maz@kernel.org --- drivers/base/platform-msi.c | 7 +++++++ include/asm-generic/msi.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index c4a17e5edf8b..2c1e2e0c1a59 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -59,9 +59,15 @@ static int platform_msi_init(struct irq_domain *domain, return irq_domain_set_hwirq_and_chip(domain, virq, hwirq, info->chip, info->chip_data); } + +static void platform_msi_set_proxy_dev(msi_alloc_info_t *arg) +{ + arg->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; +} #else #define platform_msi_set_desc NULL #define platform_msi_init NULL +#define platform_msi_set_proxy_dev(x) do {} while(0) #endif static void platform_msi_update_dom_ops(struct msi_domain_info *info) @@ -343,6 +349,7 @@ __platform_msi_create_device_domain(struct device *dev, if (!domain) goto free_priv; + platform_msi_set_proxy_dev(&data->arg); err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg); if (err) goto free_domain; diff --git a/include/asm-generic/msi.h b/include/asm-generic/msi.h index e6795f088bdd..1010e74cb8e0 100644 --- a/include/asm-generic/msi.h +++ b/include/asm-generic/msi.h @@ -22,12 +22,16 @@ struct msi_desc; typedef struct msi_alloc_info { struct msi_desc *desc; irq_hw_number_t hwirq; + unsigned long flags; union { unsigned long ul; void *ptr; } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS]; } msi_alloc_info_t; +/* Device generating MSIs is proxying for another device */ +#define MSI_ALLOC_FLAGS_PROXY_DEVICE (1UL << 0) + #define GENERIC_MSI_DOMAIN_OPS 1 #endif -- cgit From 5fe71d271df8c05e1060c0184764eba18b17a96f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:07 +0000 Subject: irqchip/gic-v3-its: Tag ITS device as shared if allocating for a proxy device The ITS already has some notion of "shared" devices. Let's map the MSI_ALLOC_FLAGS_PROXY_DEVICE flag onto this internal property. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-3-maz@kernel.org --- drivers/irqchip/irq-gic-v3-its.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index d74ef418e386..c951ad24d377 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3487,6 +3487,9 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev, goto out; } + if (info->flags & MSI_ALLOC_FLAGS_PROXY_DEVICE) + its_dev->shared = true; + pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); out: mutex_unlock(&its->dev_alloc_lock); -- cgit From 34dd263fce3114147f21698f8e55e05b9e8185bd Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:08 +0000 Subject: irqchip/gic-v3-its: Flag device allocation as proxied if behind a PCI bridge An aliasing PCI bridge is another case where we should flag the corresponding allocation as "proxied", as MSIs are coming with the bridge's RID, and not the originating device's. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-4-maz@kernel.org --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 87711e0f8014..ad2810c017ed 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -67,11 +67,16 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, /* * If pdev is downstream of any aliasing bridges, take an upper * bound of how many other vectors could map to the same DevID. + * Also tell the ITS that the signalling will come from a proxy + * device, and that special allocation rules apply. */ pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); - if (alias_dev != pdev && alias_dev->subordinate) - pci_walk_bus(alias_dev->subordinate, its_pci_msi_vec_count, - &alias_count); + if (alias_dev != pdev) { + if (alias_dev->subordinate) + pci_walk_bus(alias_dev->subordinate, + its_pci_msi_vec_count, &alias_count); + info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; + } /* ITS specific DeviceID, as the core ITS ignores dev. */ info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); -- cgit From 1d3aec89286254487df7641c30f1b14ad1d127a5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:53 +0800 Subject: genirq/affinity: Add irq_update_affinity_desc() Add a function to allow the affinity of an interrupt be switched to managed, such that interrupts allocated for platform devices may be managed. This new interface has certain limitations, and attempts to use it in the following circumstances will fail: - For when the kernel is configured for generic IRQ reservation mode (in config GENERIC_IRQ_RESERVATION_MODE). The reason being that it could conflict with managed vs. non-managed interrupt accounting. - The interrupt is already started, which should not be the case during init - The interrupt is already configured as managed, which means double init Suggested-by: Thomas Gleixner Signed-off-by: John Garry Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/1606905417-183214-2-git-send-email-john.garry@huawei.com --- include/linux/interrupt.h | 8 ++++++ kernel/irq/manage.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index ee8299eb1f52..870b3251e174 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -352,6 +352,8 @@ extern int irq_can_set_affinity(unsigned int irq); extern int irq_select_affinity(unsigned int irq); extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); +extern int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity); extern int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); @@ -387,6 +389,12 @@ static inline int irq_set_affinity_hint(unsigned int irq, return -EINVAL; } +static inline int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity) +{ + return -EINVAL; +} + static inline int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) { diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index c460e0496006..c826ba4141fe 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -371,6 +371,76 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, return ret; } +/** + * irq_update_affinity_desc - Update affinity management for an interrupt + * @irq: The interrupt number to update + * @affinity: Pointer to the affinity descriptor + * + * This interface can be used to configure the affinity management of + * interrupts which have been allocated already. + * + * There are certain limitations on when it may be used - attempts to use it + * for when the kernel is configured for generic IRQ reservation mode (in + * config GENERIC_IRQ_RESERVATION_MODE) will fail, as it may conflict with + * managed/non-managed interrupt accounting. In addition, attempts to use it on + * an interrupt which is already started or which has already been configured + * as managed will also fail, as these mean invalid init state or double init. + */ +int irq_update_affinity_desc(unsigned int irq, + struct irq_affinity_desc *affinity) +{ + struct irq_desc *desc; + unsigned long flags; + bool activated; + int ret = 0; + + /* + * Supporting this with the reservation scheme used by x86 needs + * some more thought. Fail it for now. + */ + if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE)) + return -EOPNOTSUPP; + + desc = irq_get_desc_buslock(irq, &flags, 0); + if (!desc) + return -EINVAL; + + /* Requires the interrupt to be shut down */ + if (irqd_is_started(&desc->irq_data)) { + ret = -EBUSY; + goto out_unlock; + } + + /* Interrupts which are already managed cannot be modified */ + if (irqd_affinity_is_managed(&desc->irq_data)) { + ret = -EBUSY; + goto out_unlock; + } + + /* + * Deactivate the interrupt. That's required to undo + * anything an earlier activation has established. + */ + activated = irqd_is_activated(&desc->irq_data); + if (activated) + irq_domain_deactivate_irq(&desc->irq_data); + + if (affinity->is_managed) { + irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED); + irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN); + } + + cpumask_copy(desc->irq_common_data.affinity, &affinity->mask); + + /* Restore the activation state */ + if (activated) + irq_domain_activate_irq(&desc->irq_data, false); + +out_unlock: + irq_put_desc_busunlock(desc, flags); + return ret; +} + int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) { struct irq_desc *desc = irq_to_desc(irq); -- cgit From 9806731db684a475ade1e95d166089b9edbd9da3 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:54 +0800 Subject: resource: Add irqresource_disabled() Add a common function to set the fields for a irq resource to disabled, which mimics what is done in acpi_dev_irqresource_disabled(), with a view to replace that function. Signed-off-by: John Garry Signed-off-by: Marc Zyngier Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/1606905417-183214-3-git-send-email-john.garry@huawei.com --- include/linux/ioport.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 5135d4b86cd6..f9bf374f9633 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -307,6 +307,13 @@ struct resource *devm_request_free_mem_region(struct device *dev, struct resource *request_free_mem_region(struct resource *base, unsigned long size, const char *name); +static inline void irqresource_disabled(struct resource *res, u32 irq) +{ + res->start = irq; + res->end = irq; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; +} + #ifdef CONFIG_IO_STRICT_DEVMEM void revoke_devmem(struct resource *res); #else -- cgit From 1c3f69b4543af0aad514c127298e5ea40392575d Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:55 +0800 Subject: ACPI: Drop acpi_dev_irqresource_disabled() The functionality of acpi_dev_irqresource_disabled() is same as in common irqresource_disabled(), so drop acpi_dev_irqresource_disabled() in favour of that function. Signed-off-by: John Garry Signed-off-by: Marc Zyngier Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/1606905417-183214-4-git-send-email-john.garry@huawei.com --- drivers/acpi/resource.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index ad04824ca3ba..58203193417e 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -380,13 +380,6 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity) } EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type); -static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) -{ - res->start = gsi; - res->end = gsi; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; -} - static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, u8 triggering, u8 polarity, u8 shareable, bool legacy) @@ -394,7 +387,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, int irq, p, t; if (!valid_IRQ(gsi)) { - acpi_dev_irqresource_disabled(res, gsi); + irqresource_disabled(res, gsi); return; } @@ -426,7 +419,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, res->start = irq; res->end = irq; } else { - acpi_dev_irqresource_disabled(res, gsi); + irqresource_disabled(res, gsi); } } @@ -463,7 +456,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, */ irq = &ares->data.irq; if (index >= irq->interrupt_count) { - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); return false; } acpi_dev_get_irqresource(res, irq->interrupts[index], @@ -473,7 +466,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: ext_irq = &ares->data.extended_irq; if (index >= ext_irq->interrupt_count) { - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); return false; } if (is_gsi(ext_irq)) @@ -481,7 +474,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, ext_irq->triggering, ext_irq->polarity, ext_irq->shareable, false); else - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); break; default: res->flags = 0; -- cgit From e15f2fa959f2cce8a05e8e3a596e75d068cd42c5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:56 +0800 Subject: driver core: platform: Add devm_platform_get_irqs_affinity() Drivers for multi-queue platform devices may also want managed interrupts for handling HW queue completion interrupts, so add support. The function accepts an affinity descriptor pointer, which covers all IRQs expected for the device. The function is devm class as the only current in-tree user will also use devm method for requesting the interrupts; as such, the function is made as devm as it can ensure ordering of freeing the irq and disposing of the mapping. Signed-off-by: John Garry Signed-off-by: Marc Zyngier Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/1606905417-183214-5-git-send-email-john.garry@huawei.com --- drivers/base/platform.c | 121 ++++++++++++++++++++++++++++++++++++++++ include/linux/platform_device.h | 6 ++ 2 files changed, 127 insertions(+) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 88aef93eb4dd..ea8add164b89 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -289,6 +291,125 @@ int platform_irq_count(struct platform_device *dev) } EXPORT_SYMBOL_GPL(platform_irq_count); +struct irq_affinity_devres { + unsigned int count; + unsigned int irq[]; +}; + +static void platform_disable_acpi_irq(struct platform_device *pdev, int index) +{ + struct resource *r; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, index); + if (r) + irqresource_disabled(r, 0); +} + +static void devm_platform_get_irqs_affinity_release(struct device *dev, + void *res) +{ + struct irq_affinity_devres *ptr = res; + int i; + + for (i = 0; i < ptr->count; i++) { + irq_dispose_mapping(ptr->irq[i]); + + if (has_acpi_companion(dev)) + platform_disable_acpi_irq(to_platform_device(dev), i); + } +} + +/** + * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a + * device using an interrupt affinity descriptor + * @dev: platform device pointer + * @affd: affinity descriptor + * @minvec: minimum count of interrupt vectors + * @maxvec: maximum count of interrupt vectors + * @irqs: pointer holder for IRQ numbers + * + * Gets a set of IRQs for a platform device, and updates IRQ afffinty according + * to the passed affinity descriptor + * + * Return: Number of vectors on success, negative error number on failure. + */ +int devm_platform_get_irqs_affinity(struct platform_device *dev, + struct irq_affinity *affd, + unsigned int minvec, + unsigned int maxvec, + int **irqs) +{ + struct irq_affinity_devres *ptr; + struct irq_affinity_desc *desc; + size_t size; + int i, ret, nvec; + + if (!affd) + return -EPERM; + + if (maxvec < minvec) + return -ERANGE; + + nvec = platform_irq_count(dev); + + if (nvec < minvec) + return -ENOSPC; + + nvec = irq_calc_affinity_vectors(minvec, nvec, affd); + if (nvec < minvec) + return -ENOSPC; + + if (nvec > maxvec) + nvec = maxvec; + + size = sizeof(*ptr) + sizeof(unsigned int) * nvec; + ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ptr->count = nvec; + + for (i = 0; i < nvec; i++) { + int irq = platform_get_irq(dev, i); + if (irq < 0) { + ret = irq; + goto err_free_devres; + } + ptr->irq[i] = irq; + } + + desc = irq_create_affinity_masks(nvec, affd); + if (!desc) { + ret = -ENOMEM; + goto err_free_devres; + } + + for (i = 0; i < nvec; i++) { + ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]); + if (ret) { + dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n", + ptr->irq[i], ret); + goto err_free_desc; + } + } + + devres_add(&dev->dev, ptr); + + kfree(desc); + + *irqs = ptr->irq; + + return nvec; + +err_free_desc: + kfree(desc); +err_free_devres: + devres_free(ptr); + return ret; +} +EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity); + /** * platform_get_resource_byname - get a resource for a device by name * @dev: platform device diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 77a2aada106d..4d75633e6735 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -15,6 +15,7 @@ #define PLATFORM_DEVID_NONE (-1) #define PLATFORM_DEVID_AUTO (-2) +struct irq_affinity; struct mfd_cell; struct property_entry; struct platform_device_id; @@ -70,6 +71,11 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev, extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); +extern int devm_platform_get_irqs_affinity(struct platform_device *dev, + struct irq_affinity *affd, + unsigned int minvec, + unsigned int maxvec, + int **irqs); extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *); -- cgit From 2f5fbc4305d07725bfebaedb09e57271315691ef Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 11 Dec 2020 14:15:35 -0800 Subject: irqchip/qcom-pdc: Fix phantom irq when changing between rising/falling We have a problem if we use gpio-keys and configure wakeups such that we only want one edge to wake us up. AKA: wakeup-event-action = ; wakeup-source; Specifically we end up with a phantom interrupt that blocks suspend if the line was already high and we want wakeups on rising edges (AKA we want the GPIO to go low and then high again before we wake up). The opposite is also problematic. Specifically, here's what's happening today: 1. Normally, gpio-keys configures to look for both edges. Due to the current workaround introduced in commit c3c0c2e18d94 ("pinctrl: qcom: Handle broken/missing PDC dual edge IRQs on sc7180"), if the line was high we'd configure for falling edges. 2. At suspend time, we change to look for rising edges. 3. After qcom_pdc_gic_set_type() runs, we get a phantom interrupt. We can solve this by just clearing the phantom interrupt. NOTE: it is possible that this could cause problems for a client with very specific needs, but there's not much we can do with this hardware. As an example, let's say the interrupt signal is currently high and the client is looking for falling edges. The client now changes to look for rising edges. The client could possibly expect that if the line has a short pulse low (and back high) that it would always be detected. Specifically no matter when the pulse happened, it should either have tripped the (old) falling edge trigger or the (new) rising edge trigger. We will simply not trip it. We could narrow down the race a bit by polling our parent before changing types, but no matter what we do there will still be a period of time where we can't tell the difference between a real transition (or more than one transition) and the phantom. Fixes: f55c73aef890 ("irqchip/pdc: Add PDC interrupt controller for QCOM SoCs") Signed-off-by: Douglas Anderson Signed-off-by: Marc Zyngier Tested-by: Maulik Shah Reviewed-by: Maulik Shah Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20201211141514.v4.1.I2702919afc253e2a451bebc3b701b462b2d22344@changeid --- drivers/irqchip/qcom-pdc.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index bd39e9de6ecf..5dc63c20b67e 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -159,6 +159,8 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) { int pin_out = d->hwirq; enum pdc_irq_config_bits pdc_type; + enum pdc_irq_config_bits old_pdc_type; + int ret; if (pin_out == GPIO_NO_WAKE_IRQ) return 0; @@ -187,9 +189,26 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out); pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); - return irq_chip_set_type_parent(d, type); + ret = irq_chip_set_type_parent(d, type); + if (ret) + return ret; + + /* + * When we change types the PDC can give a phantom interrupt. + * Clear it. Specifically the phantom shows up when reconfiguring + * polarity of interrupt without changing the state of the signal + * but let's be consistent and clear it always. + * + * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the + * interrupt will be cleared before the rest of the system sees it. + */ + if (old_pdc_type != pdc_type) + irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false); + + return 0; } static struct irq_chip qcom_pdc_gic_chip = { -- cgit