[tip: irq/urgent] genirq/msi: Activate Multi-MSI early when MSI_FLAG_ACTIVATE_EARLY is set
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 4c457e8cb75eda91906a4f89fc39bde3f9a43922 Gitweb: https://git.kernel.org/tip/4c457e8cb75eda91906a4f89fc39bde3f9a43922 Author:Marc Zyngier AuthorDate:Sat, 23 Jan 2021 12:27:59 Committer: Thomas Gleixner CommitterDate: Sat, 30 Jan 2021 01:22:31 +01:00 genirq/msi: Activate Multi-MSI early when MSI_FLAG_ACTIVATE_EARLY is set When MSI_FLAG_ACTIVATE_EARLY is set (which is the case for PCI), __msi_domain_alloc_irqs() performs the activation of the interrupt (which in the case of PCI results in the endpoint being programmed) as soon as the interrupt is allocated. But it appears that this is only done for the first vector, introducing an inconsistent behaviour for PCI Multi-MSI. Fix it by iterating over the number of vectors allocated to each MSI descriptor. This is easily achieved by introducing a new "for_each_msi_vector" iterator, together with a tiny bit of refactoring. Fixes: f3b0946d629c ("genirq/msi: Make sure PCI MSIs are activated early") Reported-by: Shameer Kolothum Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Tested-by: Shameer Kolothum Cc: sta...@vger.kernel.org Link: https://lore.kernel.org/r/20210123122759.1781359-1-...@kernel.org --- include/linux/msi.h | 6 ++- kernel/irq/msi.c| 44 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/linux/msi.h b/include/linux/msi.h index 360a0a7..aef35fd 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -178,6 +178,12 @@ struct msi_desc { list_for_each_entry((desc), dev_to_msi_list((dev)), list) #define for_each_msi_entry_safe(desc, tmp, dev)\ list_for_each_entry_safe((desc), (tmp), dev_to_msi_list((dev)), list) +#define for_each_msi_vector(desc, __irq, dev) \ + for_each_msi_entry((desc), (dev)) \ + if ((desc)->irq)\ + for (__irq = (desc)->irq; \ +__irq < ((desc)->irq + (desc)->nvec_used); \ +__irq++) #ifdef CONFIG_IRQ_MSI_IOMMU static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index dc0e2d7..b338d62 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -436,22 +436,22 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, can_reserve = msi_check_reservation_mode(domain, info, dev); - for_each_msi_entry(desc, dev) { - virq = desc->irq; - if (desc->nvec_used == 1) - dev_dbg(dev, "irq %d for MSI\n", virq); - else + /* +* This flag is set by the PCI layer as we need to activate +* the MSI entries before the PCI layer enables MSI in the +* card. Otherwise the card latches a random msi message. +*/ + if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY)) + goto skip_activate; + + for_each_msi_vector(desc, i, dev) { + if (desc->irq == i) { + virq = desc->irq; dev_dbg(dev, "irq [%d-%d] for MSI\n", virq, virq + desc->nvec_used - 1); - /* -* This flag is set by the PCI layer as we need to activate -* the MSI entries before the PCI layer enables MSI in the -* card. Otherwise the card latches a random msi message. -*/ - if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY)) - continue; + } - irq_data = irq_domain_get_irq_data(domain, desc->irq); + irq_data = irq_domain_get_irq_data(domain, i); if (!can_reserve) { irqd_clr_can_reserve(irq_data); if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK) @@ -462,28 +462,24 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, goto cleanup; } +skip_activate: /* * If these interrupts use reservation mode, clear the activated bit * so request_irq() will assign the final vector. */ if (can_reserve) { - for_each_msi_entry(desc, dev) { - irq_data = irq_domain_get_irq_data(domain, desc->irq); + for_each_msi_vector(desc, i, dev) { + irq_data = irq_domain_get_irq_data(domain, i); irqd_clr_activated(irq_data); } } return 0; cleanup: - for_each_msi_entry(desc, dev) { - struct irq_data *irqd; - - if (desc->irq == virq) - break; - - irqd =
[tip: irq/core] genirq/irqdomain: Don't try to free an interrupt that has no mapping
The following commit has been merged into the irq/core branch of tip: Commit-ID: 4615fbc3788ddc8e7c6d697714ad35a53729aa2c Gitweb: https://git.kernel.org/tip/4615fbc3788ddc8e7c6d697714ad35a53729aa2c Author:Marc Zyngier AuthorDate:Sun, 29 Nov 2020 13:55:51 Committer: Thomas Gleixner CommitterDate: Mon, 30 Nov 2020 14:50:21 +01:00 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-...@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 3d7463f..30a7887 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,
[tip: irq/urgent] MAINTAINERS: Move Jason Cooper to CREDITS
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 509920aee72ae23235615a009c5148cdb38794c3 Gitweb: https://git.kernel.org/tip/509920aee72ae23235615a009c5148cdb38794c3 Author:Marc Zyngier AuthorDate:Sat, 28 Nov 2020 10:37:07 Committer: Thomas Gleixner CommitterDate: Mon, 30 Nov 2020 10:20:34 +01:00 MAINTAINERS: Move Jason Cooper to CREDITS Jason's email address has now been bouncing for weeks, and no reply was received when trying to reach out on other addresses. We really hope he is OK. But until we hear of his whereabouts, let's move him to the CREDITS file so that people stop Cc-ing him. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Acked-by: Gregory CLEMENT Acked-by: Andrew Lunn Link: https://lore.kernel.org/r/20201128103707.332874-1-...@kernel.org --- CREDITS | 5 + MAINTAINERS | 4 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CREDITS b/CREDITS index 7483019..e88d1a7 100644 --- a/CREDITS +++ b/CREDITS @@ -740,6 +740,11 @@ S: (ask for current address) S: Portland, Oregon S: USA +N: Jason Cooper +D: ARM/Marvell SOC co-maintainer +D: irqchip co-maintainer +D: MVEBU PCI DRIVER co-maintainer + N: Robin Cornelius E: robincornel...@users.sourceforge.net D: Ralink rt2x00 WLAN driver diff --git a/MAINTAINERS b/MAINTAINERS index 2daa6ee..4f27f43 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2014,7 +2014,6 @@ M:Philipp Zabel S: Maintained ARM/Marvell Dove/MV78xx0/Orion SOC support -M: Jason Cooper M: Andrew Lunn M: Sebastian Hesselbarth M: Gregory Clement @@ -2031,7 +2030,6 @@ F:arch/arm/plat-orion/ F: drivers/soc/dove/ ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support -M: Jason Cooper M: Andrew Lunn M: Gregory Clement M: Sebastian Hesselbarth @@ -9248,7 +9246,6 @@ F:kernel/irq/ IRQCHIP DRIVERS M: Thomas Gleixner -M: Jason Cooper M: Marc Zyngier L: linux-kernel@vger.kernel.org S: Maintained @@ -13394,7 +13391,6 @@ F: drivers/pci/controller/mobiveil/pcie-mobiveil* PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support) M: Thomas Petazzoni -M: Jason Cooper L: linux-...@vger.kernel.org L: linux-arm-ker...@lists.infradead.org (moderated for non-subscribers) S: Maintained
[tip: irq/urgent] irqchip/mips: Drop selection of IRQ_DOMAIN_HIERARCHY
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: d26dd4131d0d6ad7aa294a7f8d18782b47c27c93 Gitweb: https://git.kernel.org/tip/d26dd4131d0d6ad7aa294a7f8d18782b47c27c93 Author:Marc Zyngier AuthorDate:Fri, 16 Oct 2020 09:28:23 +01:00 Committer: Marc Zyngier CommitterDate: Fri, 16 Oct 2020 10:51:12 +01:00 irqchip/mips: Drop selection of IRQ_DOMAIN_HIERARCHY Now that GENERIC_IRQ_IPI selects IRQ_DOMAIN_HIERARCHY, there is no need to have this conditional select for IRQ_MIPS_CPU. Similarily, MIPS_GIC only needs selecting GENERIC_IRQ_IPI. Suggested-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/irqchip/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index cd734df..38785a0 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -180,7 +180,6 @@ config IRQ_MIPS_CPU select GENERIC_IRQ_CHIP select GENERIC_IRQ_IPI if SYS_SUPPORTS_MULTITHREADING select IRQ_DOMAIN - select IRQ_DOMAIN_HIERARCHY if GENERIC_IRQ_IPI select GENERIC_IRQ_EFFECTIVE_AFF_MASK config CLPS711X_IRQCHIP @@ -307,7 +306,6 @@ config KEYSTONE_IRQ config MIPS_GIC bool select GENERIC_IRQ_IPI - select IRQ_DOMAIN_HIERARCHY select MIPS_CM config INGENIC_IRQ
[tip: irq/urgent] irqchip/mst: Make mst_intc_of_init static
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 893a7cfb6b0bea650fafa43838d7f7f8f0f076bc Gitweb: https://git.kernel.org/tip/893a7cfb6b0bea650fafa43838d7f7f8f0f076bc Author:Marc Zyngier AuthorDate:Thu, 15 Oct 2020 22:26:26 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 15 Oct 2020 22:32:31 +01:00 irqchip/mst: Make mst_intc_of_init static mst_intc_of_init has no external caller, so let's make it static. Reported-by: kernel test robot Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-mst-intc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-mst-intc.c b/drivers/irqchip/irq-mst-intc.c index 4be0775..143657b 100644 --- a/drivers/irqchip/irq-mst-intc.c +++ b/drivers/irqchip/irq-mst-intc.c @@ -154,8 +154,8 @@ static const struct irq_domain_ops mst_intc_domain_ops = { .free = irq_domain_free_irqs_common, }; -int __init -mst_intc_of_init(struct device_node *dn, struct device_node *parent) +static int __init mst_intc_of_init(struct device_node *dn, + struct device_node *parent) { struct irq_domain *domain, *domain_parent; struct mst_intc_chip_data *cd;
[tip: irq/urgent] irqchip/bcm2836: Fix missing __init annotation
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 57733e009f0c7e0526e10a18be12f56996c5460e Gitweb: https://git.kernel.org/tip/57733e009f0c7e0526e10a18be12f56996c5460e Author:Marc Zyngier AuthorDate:Sun, 25 Oct 2020 11:10:29 Committer: Marc Zyngier CommitterDate: Sun, 25 Oct 2020 11:10:29 irqchip/bcm2836: Fix missing __init annotation bcm2836_arm_irqchip_smp_init() calls set_smp_ipi_range(), which has an __init annotation. Make sure the caller has the same annotation. Reported-by: kernel test robot Signed-off-by: Marc Zyngier --- 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 97838eb..cbc7c74 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -244,7 +244,7 @@ static int bcm2836_cpu_dying(unsigned int cpu) #define BITS_PER_MBOX 32 -static void bcm2836_arm_irqchip_smp_init(void) +static void __init bcm2836_arm_irqchip_smp_init(void) { struct irq_fwspec ipi_fwspec = { .fwnode = intc.domain->fwnode,
[tip: irq/urgent] genirq: Let GENERIC_IRQ_IPI select IRQ_DOMAIN_HIERARCHY
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 151a535171be6ff824a0a3875553ea38570f4c05 Gitweb: https://git.kernel.org/tip/151a535171be6ff824a0a3875553ea38570f4c05 Author:Marc Zyngier AuthorDate:Thu, 15 Oct 2020 21:41:44 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 15 Oct 2020 21:41:44 +01:00 genirq: Let GENERIC_IRQ_IPI select IRQ_DOMAIN_HIERARCHY kernel/irq/ipi.c otherwise fails to compile if nothing else selects it. Fixes: 379b656446a3 ("genirq: Add GENERIC_IRQ_IPI Kconfig symbol") Reported-by: Pavel Machek Tested-by: Pavel Machek Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201015101222.GA32747@amd --- kernel/irq/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 10a5aff..164a031 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -82,6 +82,7 @@ config IRQ_FASTEOI_HIERARCHY_HANDLERS # Generic IRQ IPI support config GENERIC_IRQ_IPI bool + select IRQ_DOMAIN_HIERARCHY # Generic MSI interrupt support config GENERIC_MSI_IRQ
[tip: irq/core] arm: Move ipi_teardown() to a CONFIG_HOTPLUG_CPU section
The following commit has been merged into the irq/core branch of tip: Commit-ID: ac15a54e03d13686d2fc016a88311801b0734046 Gitweb: https://git.kernel.org/tip/ac15a54e03d13686d2fc016a88311801b0734046 Author:Marc Zyngier AuthorDate:Fri, 18 Sep 2020 17:19:46 +01:00 Committer: Marc Zyngier CommitterDate: Fri, 18 Sep 2020 17:40:48 +01:00 arm: Move ipi_teardown() to a CONFIG_HOTPLUG_CPU section ipi_teardown() is only used when CONFIG_HOTPLUG_CPU is enabled. Move the function to a location guarded by this config option. Signed-off-by: Marc Zyngier --- arch/arm/kernel/smp.c | 23 +++ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 00327fa..8425da5 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -85,7 +85,6 @@ static int nr_ipi __read_mostly = NR_IPI; static struct irq_desc *ipi_desc[MAX_IPI] __read_mostly; static void ipi_setup(int cpu); -static void ipi_teardown(int cpu); static DECLARE_COMPLETION(cpu_running); @@ -236,6 +235,17 @@ int platform_can_hotplug_cpu(unsigned int cpu) return cpu != 0; } +static void ipi_teardown(int cpu) +{ + int i; + + if (WARN_ON_ONCE(!ipi_irq_base)) + return; + + for (i = 0; i < nr_ipi; i++) + disable_percpu_irq(ipi_irq_base + i); +} + /* * __cpu_disable runs on the processor to be shutdown. */ @@ -707,17 +717,6 @@ static void ipi_setup(int cpu) enable_percpu_irq(ipi_irq_base + i, 0); } -static void ipi_teardown(int cpu) -{ - int i; - - if (WARN_ON_ONCE(!ipi_irq_base)) - return; - - for (i = 0; i < nr_ipi; i++) - disable_percpu_irq(ipi_irq_base + i); -} - void __init set_smp_ipi_range(int ipi_base, int n) { int i;
[tip: irq/core] gpio: tegra186: Allow optional irq parent callbacks
The following commit has been merged into the irq/core branch of tip: Commit-ID: 986ec63d4482292570b579ac98b151acf8bdd1de Gitweb: https://git.kernel.org/tip/986ec63d4482292570b579ac98b151acf8bdd1de Author:Marc Zyngier AuthorDate:Mon, 05 Oct 2020 10:27:27 +01:00 Committer: Marc Zyngier CommitterDate: Sat, 10 Oct 2020 12:12:10 +01:00 gpio: tegra186: Allow optional irq parent callbacks Make the tegra186 GPIO driver resistent to variable depth interrupt hierarchy, which we are about to introduce. No functionnal change yet. Signed-off-by: Marc Zyngier --- drivers/gpio/gpio-tegra186.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 178e912..9500074 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -430,7 +430,18 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type) else irq_set_handler_locked(data, handle_edge_irq); - return irq_chip_set_type_parent(data, type); + if (data->parent_data) + return irq_chip_set_type_parent(data, type); + + return 0; +} + +static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on) +{ + if (data->parent_data) + return irq_chip_set_wake_parent(data, on); + + return 0; } static void tegra186_gpio_irq(struct irq_desc *desc) @@ -678,7 +689,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->intc.irq_mask = tegra186_irq_mask; gpio->intc.irq_unmask = tegra186_irq_unmask; gpio->intc.irq_set_type = tegra186_irq_set_type; - gpio->intc.irq_set_wake = irq_chip_set_wake_parent; + gpio->intc.irq_set_wake = tegra186_irq_set_wake; irq = >gpio.irq; irq->chip = >intc;
[tip: irq/core] genirq/irqdomain: Allow partial trimming of irq_data hierarchy
The following commit has been merged into the irq/core branch of tip: Commit-ID: 55567976629e58fde28fb70612ca73228271eef2 Gitweb: https://git.kernel.org/tip/55567976629e58fde28fb70612ca73228271eef2 Author:Marc Zyngier AuthorDate:Tue, 06 Oct 2020 10:10:20 +01:00 Committer: Marc Zyngier CommitterDate: Sat, 10 Oct 2020 12:12:10 +01:00 genirq/irqdomain: Allow partial trimming of irq_data hierarchy It appears that some HW is ugly enough that not all the interrupts connected to a particular interrupt controller end up with the same hierarchy depth (some of them are terminated early). This leaves the irqchip hacker with only two choices, both equally bad: - create discrete domain chains, one for each "hierarchy depth", which is very hard to maintain - create fake hierarchy levels for the shallow paths, leading to all kind of problems (what are the safe hwirq values for these fake levels?) Implement the ability to cut short a single interrupt hierarchy from a level marked as being disconnected by using the new irq_domain_disconnect_hierarchy() helper. The irqdomain allocation code will then perform the trimming Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 3 +- kernel/irq/irqdomain.c| 99 +++-- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index b37350c..a52b095 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -509,6 +509,9 @@ extern void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs); +extern int irq_domain_disconnect_hierarchy(struct irq_domain *domain, + unsigned int virq); + static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) { return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 76cd7eb..cf8b374 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1136,6 +1136,17 @@ static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain, return irq_data; } +static void __irq_domain_free_hierarchy(struct irq_data *irq_data) +{ + struct irq_data *tmp; + + while (irq_data) { + tmp = irq_data; + irq_data = irq_data->parent_data; + kfree(tmp); + } +} + static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs) { struct irq_data *irq_data, *tmp; @@ -1147,12 +1158,83 @@ static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs) irq_data->parent_data = NULL; irq_data->domain = NULL; - while (tmp) { - irq_data = tmp; - tmp = tmp->parent_data; - kfree(irq_data); + __irq_domain_free_hierarchy(tmp); + } +} + +/** + * irq_domain_disconnect_hierarchy - Mark the first unused level of a hierarchy + * @domain:IRQ domain from which the hierarchy is to be disconnected + * @virq: IRQ number where the hierarchy is to be trimmed + * + * Marks the @virq level belonging to @domain as disconnected. + * Returns -EINVAL if @virq doesn't have a valid irq_data pointing + * to @domain. + * + * Its only use is to be able to trim levels of hierarchy that do not + * have any real meaning for this interrupt, and that the driver marks + * as such from its .alloc() callback. + */ +int irq_domain_disconnect_hierarchy(struct irq_domain *domain, + unsigned int virq) +{ + struct irq_data *irqd; + + irqd = irq_domain_get_irq_data(domain, virq); + if (!irqd) + return -EINVAL; + + irqd->chip = ERR_PTR(-ENOTCONN); + return 0; +} + +static int irq_domain_trim_hierarchy(unsigned int virq) +{ + struct irq_data *tail, *irqd, *irq_data; + + irq_data = irq_get_irq_data(virq); + tail = NULL; + + /* The first entry must have a valid irqchip */ + if (!irq_data->chip || IS_ERR(irq_data->chip)) + return -EINVAL; + + /* +* Validate that the irq_data chain is sane in the presence of +* a hierarchy trimming marker. +*/ + for (irqd = irq_data->parent_data; irqd; irq_data = irqd, irqd = irqd->parent_data) { + /* Can't have a valid irqchip after a trim marker */ + if (irqd->chip && tail) + return -EINVAL; + + /* Can't have an empty irqchip before a trim marker */ + if (!irqd->chip && !tail) + return -EINVAL; + + if (IS_ERR(irqd->chip)) { + /* Only -ENOTCONN is a valid trim marker */ + if (PTR_ERR(irqd->chip) !=
[tip: irq/core] irqchip/bcm2836: Configure mailbox interrupts as standard interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 0809ae724904c3c5dbdddf4169d48aac9c6fcdc8 Gitweb: https://git.kernel.org/tip/0809ae724904c3c5dbdddf4169d48aac9c6fcdc8 Author:Marc Zyngier AuthorDate:Tue, 05 May 2020 12:59:04 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:27 +01:00 irqchip/bcm2836: Configure mailbox interrupts as standard interrupts In order to switch the bcm2836 driver to privide standard interrupts for IPIs, it first needs to stop lying about the way things work. The mailbox interrupt is actually a multiplexer, with enough bits to store 32 pending interrupts per CPU. So let's turn it into a chained irqchip. Once this is done, we can instanciate the corresponding IPIs, and pass them to the architecture code. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-bcm2836.c | 151 +++-- 1 file changed, 125 insertions(+), 26 deletions(-) diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 2038693..85df6dd 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -89,12 +90,24 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = { .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, }; +static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d) +{ +} + +static struct irq_chip bcm2836_arm_irqchip_dummy = { + .name = "bcm2836-dummy", + .irq_eoi= bcm2836_arm_irqchip_dummy_op, +}; + static int bcm2836_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { struct irq_chip *chip; switch (hw) { + case LOCAL_IRQ_MAILBOX0: + chip = _arm_irqchip_dummy; + break; case LOCAL_IRQ_CNTPSIRQ: case LOCAL_IRQ_CNTPNSIRQ: case LOCAL_IRQ_CNTHPIRQ: @@ -127,17 +140,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) u32 stat; stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); - if (stat & BIT(LOCAL_IRQ_MAILBOX0)) { -#ifdef CONFIG_SMP - void __iomem *mailbox0 = (intc.base + - LOCAL_MAILBOX0_CLR0 + 16 * cpu); - u32 mbox_val = readl(mailbox0); - u32 ipi = ffs(mbox_val) - 1; - - writel(1 << ipi, mailbox0); - handle_IPI(ipi, regs); -#endif - } else if (stat) { + if (stat) { u32 hwirq = ffs(stat) - 1; handle_domain_irq(intc.domain, hwirq, regs); @@ -145,8 +148,35 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) } #ifdef CONFIG_SMP -static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, -unsigned int ipi) +static struct irq_domain *ipi_domain; + +static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + int cpu = smp_processor_id(); + u32 mbox_val; + + chained_irq_enter(chip, desc); + + mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); + if (mbox_val) { + int hwirq = ffs(mbox_val) - 1; + generic_handle_irq(irq_find_mapping(ipi_domain, hwirq)); + } + + chained_irq_exit(chip, desc); +} + +static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d) +{ + int cpu = smp_processor_id(); + + writel_relaxed(BIT(d->hwirq), + intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); +} + +static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, + const struct cpumask *mask) { int cpu; void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; @@ -157,11 +187,45 @@ static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, */ smp_wmb(); - for_each_cpu(cpu, mask) { - writel(1 << ipi, mailbox0_base + 16 * cpu); + for_each_cpu(cpu, mask) + writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu); +} + +static struct irq_chip bcm2836_arm_irqchip_ipi = { + .name = "IPI", + .irq_eoi= bcm2836_arm_irqchip_ipi_eoi, + .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, +}; + +static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d, +unsigned int virq, +unsigned int nr_irqs, void *args) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_percpu_devid(virq + i); + irq_domain_set_info(d, virq + i, i, _arm_irqchip_ipi, + d->host_data, + handle_percpu_devid_fasteoi_ipi, +
[tip: irq/core] irqchip/gic-v3: Configure SGIs as standard interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 64b499d8df40dadb1818ad9f74c4546951b37a8f Gitweb: https://git.kernel.org/tip/64b499d8df40dadb1818ad9f74c4546951b37a8f Author:Marc Zyngier AuthorDate:Sat, 25 Apr 2020 15:24:01 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:26 +01:00 irqchip/gic-v3: Configure SGIs as standard interrupts Change the way we deal with GICv3 SGIs by turning them into proper IRQs, and calling into the arch code to register the interrupt range instead of a callback. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 94 ++- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index f7c99a3..84ceb63 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -36,6 +36,8 @@ #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996(1ULL << 0) #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) +#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) + struct redist_region { void __iomem*redist_base; phys_addr_t phys_base; @@ -383,7 +385,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, { u32 reg; - if (d->hwirq >= 8192) /* PPI/SPI only */ + if (d->hwirq >= 8192) /* SGI/PPI/SPI only */ return -EINVAL; switch (which) { @@ -550,12 +552,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type) u32 offset, index; int ret; - /* Interrupt configuration for SGIs can't be changed */ - if (irq < 16) - return -EINVAL; - range = get_intid_range(d); + /* Interrupt configuration for SGIs can't be changed */ + if (range == SGI_RANGE) + return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0; + /* SPIs have restrictions on the supported types */ if ((range == SPI_RANGE || range == ESPI_RANGE) && type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) @@ -583,6 +585,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) { + if (get_intid_range(d) == SGI_RANGE) + return -EINVAL; + if (vcpu) irqd_set_forwarded_to_vcpu(d); else @@ -657,38 +662,14 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs if ((irqnr >= 1020 && irqnr <= 1023)) return; - /* Treat anything but SGIs in a uniform way */ - if (likely(irqnr > 15)) { - int err; - - if (static_branch_likely(_deactivate_key)) - gic_write_eoir(irqnr); - else - isb(); - - err = handle_domain_irq(gic_data.domain, irqnr, regs); - if (err) { - WARN_ONCE(true, "Unexpected interrupt received!\n"); - gic_deactivate_unhandled(irqnr); - } - return; - } - if (irqnr < 16) { + if (static_branch_likely(_deactivate_key)) gic_write_eoir(irqnr); - if (static_branch_likely(_deactivate_key)) - gic_write_dir(irqnr); -#ifdef CONFIG_SMP - /* -* Unlike GICv2, we don't need an smp_rmb() here. -* The control dependency from gic_read_iar to -* the ISB in gic_write_eoir is enough to ensure -* that any shared data read by handle_IPI will -* be read after the ACK. -*/ - handle_IPI(irqnr, regs); -#else - WARN_ONCE(true, "Unexpected SGI received!\n"); -#endif + else + isb(); + + if (handle_domain_irq(gic_data.domain, irqnr, regs)) { + WARN_ONCE(true, "Unexpected interrupt received!\n"); + gic_deactivate_unhandled(irqnr); } } @@ -1136,11 +1117,11 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) gic_write_sgi1r(val); } -static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) +static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) { int cpu; - if (WARN_ON(irq >= 16)) + if (WARN_ON(d->hwirq >= 16)) return; /* @@ -1154,7 +1135,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) u16 tlist; tlist = gic_compute_target_list(, mask, cluster_id); - gic_send_sgi(cluster_id, tlist, irq); + gic_send_sgi(cluster_id, tlist, d->hwirq); } /* Force the above writes to ICC_SGI1R_EL1 to be executed */ @@ -1163,10 +1144,24 @@ static void
[tip: irq/core] irqchip/gic: Cleanup Franken-GIC handling
The following commit has been merged into the irq/core branch of tip: Commit-ID: 8594c3b85171b6f68e34e07b533ec2f1bf7fb065 Gitweb: https://git.kernel.org/tip/8594c3b85171b6f68e34e07b533ec2f1bf7fb065 Author:Marc Zyngier AuthorDate:Tue, 15 Sep 2020 14:03:51 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:29 +01:00 irqchip/gic: Cleanup Franken-GIC handling Introduce a static key identifying Samsung's unique creation, allowing to replace the indirect call to compute the base addresses with a simple test on the static key. Faster, cheaper, negative diffstat. Tested-by: Marek Szyprowski Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic.c | 41 +++--- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 66671e1..30edcca 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -83,9 +83,6 @@ struct gic_chip_data { #endif struct irq_domain *domain; unsigned int gic_irqs; -#ifdef CONFIG_GIC_NON_BANKED - void __iomem *(*get_base)(union gic_base *); -#endif }; #ifdef CONFIG_BL_SWITCHER @@ -127,35 +124,27 @@ static struct gic_kvm_info gic_v2_kvm_info; static DEFINE_PER_CPU(u32, sgi_intid); #ifdef CONFIG_GIC_NON_BANKED -static void __iomem *gic_get_percpu_base(union gic_base *base) -{ - return raw_cpu_read(*base->percpu_base); -} +static DEFINE_STATIC_KEY_FALSE(frankengic_key); -static void __iomem *gic_get_common_base(union gic_base *base) +static void enable_frankengic(void) { - return base->common_base; + static_branch_enable(_key); } -static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data) +static inline void __iomem *__get_base(union gic_base *base) { - return data->get_base(>dist_base); -} + if (static_branch_unlikely(_key)) + return raw_cpu_read(*base->percpu_base); -static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data) -{ - return data->get_base(>cpu_base); + return base->common_base; } -static inline void gic_set_base_accessor(struct gic_chip_data *data, -void __iomem *(*f)(union gic_base *)) -{ - data->get_base = f; -} +#define gic_data_dist_base(d) __get_base(&(d)->dist_base) +#define gic_data_cpu_base(d) __get_base(&(d)->cpu_base) #else #define gic_data_dist_base(d) ((d)->dist_base.common_base) #define gic_data_cpu_base(d) ((d)->cpu_base.common_base) -#define gic_set_base_accessor(d, f) +#define enable_frankengic()do { } while(0) #endif static inline void __iomem *gic_dist_base(struct irq_data *d) @@ -307,7 +296,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) - return type == IRQ_TYPE_EDGE_RISING ? 0 : -EINVAL; + return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0; /* SPIs have restrictions on the supported types */ if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && @@ -720,11 +709,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,void *v) int i; for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) { -#ifdef CONFIG_GIC_NON_BANKED - /* Skip over unused GICs */ - if (!gic_data[i].get_base) - continue; -#endif switch (cmd) { case CPU_PM_ENTER: gic_cpu_save(_data[i]); @@ -1165,7 +1149,7 @@ static int gic_init_bases(struct gic_chip_data *gic, gic->raw_cpu_base + offset; } - gic_set_base_accessor(gic, gic_get_percpu_base); + enable_frankengic(); } else { /* Normal, sane GIC... */ WARN(gic->percpu_offset, @@ -1173,7 +1157,6 @@ static int gic_init_bases(struct gic_chip_data *gic, gic->percpu_offset); gic->dist_base.common_base = gic->raw_dist_base; gic->cpu_base.common_base = gic->raw_cpu_base; - gic_set_base_accessor(gic, gic_get_common_base); } /*
[tip: irq/core] arm64: Kill __smp_cross_call and co
The following commit has been merged into the irq/core branch of tip: Commit-ID: 5cebfd2d47c214f69d918e3d34ad183c061eddb2 Gitweb: https://git.kernel.org/tip/5cebfd2d47c214f69d918e3d34ad183c061eddb2 Author:Marc Zyngier AuthorDate:Sat, 09 May 2020 14:00:23 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:28 +01:00 arm64: Kill __smp_cross_call and co The old IPI registration interface is now unused on arm64, so let's get rid of it. Reviewed-by: Valentin Schneider Acked-by: Catalin Marinas Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/irq_work.h | 4 +--- arch/arm64/include/asm/smp.h | 12 +- arch/arm64/kernel/smp.c | 38 +- 3 files changed, 8 insertions(+), 46 deletions(-) diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index 8a1ef19..a102028 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h @@ -2,11 +2,9 @@ #ifndef __ASM_IRQ_WORK_H #define __ASM_IRQ_WORK_H -#include - static inline bool arch_irq_work_has_interrupt(void) { - return !!__smp_cross_call; + return true; } #endif /* __ASM_IRQ_WORK_H */ diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 57c5db1..c298ad0 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -61,24 +61,12 @@ struct seq_file; extern void show_ipi_list(struct seq_file *p, int prec); /* - * Called from C code, this handles an IPI. - */ -extern void handle_IPI(int ipinr, struct pt_regs *regs); - -/* * Discover the set of possible CPUs and determine their * SMP operations. */ extern void smp_init_cpus(void); /* - * Provide a function to raise an IPI cross call on CPUs in callmap. - */ -extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int)); - -extern void (*__smp_cross_call)(const struct cpumask *, unsigned int); - -/* * Register IPI interrupts with the arch SMP code */ extern void set_smp_ipi_range(int ipi_base, int nr_ipi); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 00c9db1..58fb155 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -782,13 +782,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } } -void (*__smp_cross_call)(const struct cpumask *, unsigned int); - -void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) -{ - __smp_cross_call = fn; -} - static const char *ipi_types[NR_IPI] __tracepoint_string = { #define S(x,s) [x] = s S(IPI_RESCHEDULE, "Rescheduling interrupts"), @@ -800,11 +793,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { S(IPI_WAKEUP, "CPU wake-up interrupts"), }; -static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) -{ - trace_ipi_raise(target, ipi_types[ipinr]); - __smp_cross_call(target, ipinr); -} +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr); void show_ipi_list(struct seq_file *p, int prec) { @@ -851,8 +840,7 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask) #ifdef CONFIG_IRQ_WORK void arch_irq_work_raise(void) { - if (__smp_cross_call) - smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); + smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); } #endif @@ -959,34 +947,23 @@ static void do_handle_IPI(int ipinr) trace_ipi_exit_rcuidle(ipi_types[ipinr]); } -/* Legacy version, should go away once all irqchips have been converted */ -void handle_IPI(int ipinr, struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - do_handle_IPI(ipinr); - irq_exit(); - - set_irq_regs(old_regs); -} - static irqreturn_t ipi_handler(int irq, void *data) { do_handle_IPI(irq - ipi_irq_base); return IRQ_HANDLED; } -static void ipi_send(const struct cpumask *target, unsigned int ipi) +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) { - __ipi_send_mask(ipi_desc[ipi], target); + trace_ipi_raise(target, ipi_types[ipinr]); + __ipi_send_mask(ipi_desc[ipinr], target); } static void ipi_setup(int cpu) { int i; - if (!ipi_irq_base) + if (WARN_ON_ONCE(!ipi_irq_base)) return; for (i = 0; i < nr_ipi; i++) @@ -997,7 +974,7 @@ static void ipi_teardown(int cpu) { int i; - if (!ipi_irq_base) + if (WARN_ON_ONCE(!ipi_irq_base)) return; for (i = 0; i < nr_ipi; i++) @@ -1023,7 +1000,6 @@ void __init set_smp_ipi_range(int ipi_base, int n) } ipi_irq_base = ipi_base; - __smp_cross_call = ipi_send; /* Setup the boot CPU immediately */ ipi_setup(smp_processor_id());
[tip: irq/core] ARM: Kill __smp_cross_call and co
The following commit has been merged into the irq/core branch of tip: Commit-ID: 8aa837cb7a032884c787b15de81f7d9de8af0869 Gitweb: https://git.kernel.org/tip/8aa837cb7a032884c787b15de81f7d9de8af0869 Author:Marc Zyngier AuthorDate:Mon, 22 Jun 2020 22:15:54 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:28 +01:00 ARM: Kill __smp_cross_call and co The old IPI registration interface is now unused on arm, so let's get rid of it. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- arch/arm/include/asm/smp.h | 6 -- arch/arm/kernel/smp.c | 26 +++--- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 0e29730..0ca55a6 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -39,12 +39,6 @@ void handle_IPI(int ipinr, struct pt_regs *regs); */ extern void smp_init_cpus(void); - -/* - * Provide a function to raise an IPI cross call on CPUs in callmap. - */ -extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int)); - /* * Register IPI interrupts with the arch SMP code */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index f21f784..d51e649 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -511,14 +511,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } } -static void (*__smp_cross_call)(const struct cpumask *, unsigned int); - -void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) -{ - if (!__smp_cross_call) - __smp_cross_call = fn; -} - static const char *ipi_types[NR_IPI] __tracepoint_string = { #define S(x,s) [x] = s S(IPI_WAKEUP, "CPU wakeup interrupts"), @@ -530,11 +522,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { S(IPI_COMPLETION, "completion interrupts"), }; -static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) -{ - trace_ipi_raise_rcuidle(target, ipi_types[ipinr]); - __smp_cross_call(target, ipinr); -} +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr); void show_ipi_list(struct seq_file *p, int prec) { @@ -713,16 +701,17 @@ static irqreturn_t ipi_handler(int irq, void *data) return IRQ_HANDLED; } -static void ipi_send(const struct cpumask *target, unsigned int ipi) +static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) { - __ipi_send_mask(ipi_desc[ipi], target); + trace_ipi_raise_rcuidle(target, ipi_types[ipinr]); + __ipi_send_mask(ipi_desc[ipinr], target); } static void ipi_setup(int cpu) { int i; - if (!ipi_irq_base) + if (WARN_ON_ONCE(!ipi_irq_base)) return; for (i = 0; i < nr_ipi; i++) @@ -733,7 +722,7 @@ static void ipi_teardown(int cpu) { int i; - if (!ipi_irq_base) + if (WARN_ON_ONCE(!ipi_irq_base)) return; for (i = 0; i < nr_ipi; i++) @@ -759,7 +748,6 @@ void __init set_smp_ipi_range(int ipi_base, int n) } ipi_irq_base = ipi_base; - set_smp_cross_call(ipi_send); /* Setup the boot CPU immediately */ ipi_setup(smp_processor_id()); @@ -872,7 +860,7 @@ core_initcall(register_cpufreq_notifier); static void raise_nmi(cpumask_t *mask) { - __smp_cross_call(mask, IPI_CPU_BACKTRACE); + __ipi_send_mask(ipi_desc[IPI_CPU_BACKTRACE], mask); } void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
[tip: irq/core] ARM: Remove custom IRQ stat accounting
The following commit has been merged into the irq/core branch of tip: Commit-ID: 5ebf353af22c89d18964bb3b877a95200dfe07b9 Gitweb: https://git.kernel.org/tip/5ebf353af22c89d18964bb3b877a95200dfe07b9 Author:Marc Zyngier AuthorDate:Tue, 23 Jun 2020 21:15:00 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:28 +01:00 ARM: Remove custom IRQ stat accounting Let's switch the arm code to the core accounting, which already does everything we need. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- arch/arm/include/asm/hardirq.h | 17 - arch/arm/kernel/irq.c | 1 - arch/arm/kernel/smp.c | 21 + 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 7a88f16..b95848e 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -6,29 +6,12 @@ #include #include -/* number of IPIS _not_ including IPI_CPU_BACKTRACE */ -#define NR_IPI 7 - typedef struct { unsigned int __softirq_pending; -#ifdef CONFIG_SMP - unsigned int ipi_irqs[NR_IPI]; -#endif } cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ -#define __inc_irq_stat(cpu, member)__IRQ_STAT(cpu, member)++ -#define __get_irq_stat(cpu, member)__IRQ_STAT(cpu, member) - -#ifdef CONFIG_SMP -u64 smp_irq_stat_cpu(unsigned int cpu); -#else -#define smp_irq_stat_cpu(cpu) 0 -#endif - -#define arch_irq_stat_cpu smp_irq_stat_cpu - #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 #endif /* __ASM_HARDIRQ_H */ diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ee51403..698b6f6 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -18,7 +18,6 @@ * IRQ's are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. */ -#include #include #include #include diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index d51e649..00327fa 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,7 @@ enum ipi_msg_type { IPI_CPU_STOP, IPI_IRQ_WORK, IPI_COMPLETION, + NR_IPI, /* * CPU_BACKTRACE is special and not included in NR_IPI * or tracable with trace_ipi_* @@ -529,27 +531,16 @@ void show_ipi_list(struct seq_file *p, int prec) unsigned int cpu, i; for (i = 0; i < NR_IPI; i++) { + unsigned int irq = irq_desc_get_irq(ipi_desc[i]); seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); for_each_online_cpu(cpu) - seq_printf(p, "%10u ", - __get_irq_stat(cpu, ipi_irqs[i])); + seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu)); seq_printf(p, " %s\n", ipi_types[i]); } } -u64 smp_irq_stat_cpu(unsigned int cpu) -{ - u64 sum = 0; - int i; - - for (i = 0; i < NR_IPI; i++) - sum += __get_irq_stat(cpu, ipi_irqs[i]); - - return sum; -} - void arch_send_call_function_ipi_mask(const struct cpumask *mask) { smp_cross_call(mask, IPI_CALL_FUNC); @@ -630,10 +621,8 @@ static void do_handle_IPI(int ipinr) { unsigned int cpu = smp_processor_id(); - if ((unsigned)ipinr < NR_IPI) { + if ((unsigned)ipinr < NR_IPI) trace_ipi_entry_rcuidle(ipi_types[ipinr]); - __inc_irq_stat(cpu, ipi_irqs[ipinr]); - } switch (ipinr) { case IPI_WAKEUP:
[tip: irq/core] irqchip/bcm2836: Provide mask/unmask dummy methods for IPIs
The following commit has been merged into the irq/core branch of tip: Commit-ID: c3330399931be38ce459e82bf7dea140338ae43f Gitweb: https://git.kernel.org/tip/c3330399931be38ce459e82bf7dea140338ae43f Author:Marc Zyngier AuthorDate:Mon, 14 Sep 2020 17:21:16 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:28 +01:00 irqchip/bcm2836: Provide mask/unmask dummy methods for IPIs Although it doesn't seem possible to disable individual mailbox interrupts, we still need to provide some callbacks. Fixes: 09eb672ce4fb ("irqchip/bcm2836: Configure mailbox interrupts as standard interrupts") Reported-by: Marek Szyprowski Tested-by: Marek Szyprowski Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-bcm2836.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 85df6dd..97838eb 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -193,6 +193,8 @@ static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, static struct irq_chip bcm2836_arm_irqchip_ipi = { .name = "IPI", + .irq_mask = bcm2836_arm_irqchip_dummy_op, + .irq_unmask = bcm2836_arm_irqchip_dummy_op, .irq_eoi= bcm2836_arm_irqchip_ipi_eoi, .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, };
[tip: irq/core] ARM: Allow IPIs to be handled as normal interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 56afcd3dbd1995c526bfbd920cebde6158b22c4a Gitweb: https://git.kernel.org/tip/56afcd3dbd1995c526bfbd920cebde6158b22c4a Author:Marc Zyngier AuthorDate:Tue, 23 Jun 2020 20:38:41 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 13 Sep 2020 17:05:39 +01:00 ARM: Allow IPIs to be handled as normal interrupts In order to deal with IPIs as normal interrupts, let's add a new way to register them with the architecture code. set_smp_ipi_range() takes a range of interrupts, and allows the arch code to request them as if the were normal interrupts. A standard handler is then called by the core IRQ code to deal with the IPI. This means that we don't need to call irq_enter/irq_exit, and that we don't need to deal with set_irq_regs either. So let's move the dispatcher into its own function, and leave handle_IPI() as a compatibility function. On the sending side, let's make use of ipi_send_mask, which already exists for this purpose. One of the major difference is that we end up, in some cases (such as when performing IRQ time accounting on the scheduler IPI), end up with nested irq_enter()/irq_exit() pairs. Other than the (relatively small) overhead, there should be no consequences to it (these pairs are designed to nest correctly, and the accounting shouldn't be off). Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- arch/arm/Kconfig | 1 +- arch/arm/include/asm/smp.h | 5 ++- arch/arm/kernel/smp.c | 99 ++-- 3 files changed, 89 insertions(+), 16 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e00d94b..e67ef15 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -49,6 +49,7 @@ config ARM select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY select GENERIC_ATOMIC64 if CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI select GENERIC_CLOCKEVENTS_BROADCAST if SMP + select GENERIC_IRQ_IPI if SMP select GENERIC_CPU_AUTOPROBE select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index a91f21e..0e29730 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -46,6 +46,11 @@ extern void smp_init_cpus(void); extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int)); /* + * Register IPI interrupts with the arch SMP code + */ +extern void set_smp_ipi_range(int ipi_base, int nr_ipi); + +/* * Called from platform specific assembly code, this is the * secondary CPU entry point. */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 5d9da61..f21f784 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -69,14 +69,22 @@ enum ipi_msg_type { * CPU_BACKTRACE is special and not included in NR_IPI * or tracable with trace_ipi_* */ - IPI_CPU_BACKTRACE, + IPI_CPU_BACKTRACE = NR_IPI, /* * SGI8-15 can be reserved by secure firmware, and thus may * not be usable by the kernel. Please keep the above limited * to at most 8 entries. */ + MAX_IPI }; +static int ipi_irq_base __read_mostly; +static int nr_ipi __read_mostly = NR_IPI; +static struct irq_desc *ipi_desc[MAX_IPI] __read_mostly; + +static void ipi_setup(int cpu); +static void ipi_teardown(int cpu); + static DECLARE_COMPLETION(cpu_running); static struct smp_operations smp_ops __ro_after_init; @@ -247,6 +255,7 @@ int __cpu_disable(void) * and we must not schedule until we're ready to give up the cpu. */ set_cpu_online(cpu, false); + ipi_teardown(cpu); /* * OK - migrate IRQs away from this CPU @@ -422,6 +431,8 @@ asmlinkage void secondary_start_kernel(void) notify_cpu_starting(cpu); + ipi_setup(cpu); + calibrate_delay(); smp_store_cpu_info(cpu); @@ -627,10 +638,9 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) handle_IPI(ipinr, regs); } -void handle_IPI(int ipinr, struct pt_regs *regs) +static void do_handle_IPI(int ipinr) { unsigned int cpu = smp_processor_id(); - struct pt_regs *old_regs = set_irq_regs(regs); if ((unsigned)ipinr < NR_IPI) { trace_ipi_entry_rcuidle(ipi_types[ipinr]); @@ -643,9 +653,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs) #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST case IPI_TIMER: - irq_enter(); tick_receive_broadcast(); - irq_exit(); break; #endif @@ -654,36 +662,26 @@ void handle_IPI(int ipinr, struct pt_regs *regs) break; case IPI_CALL_FUNC: - irq_enter(); generic_smp_call_function_interrupt(); - irq_exit(); break; case IPI_CPU_STOP:
[tip: irq/core] irqchip/gic-v3: Describe the SGI range
The following commit has been merged into the irq/core branch of tip: Commit-ID: 70a29c32cf7909e96a469ae71d88b2c0fbcbd767 Gitweb: https://git.kernel.org/tip/70a29c32cf7909e96a469ae71d88b2c0fbcbd767 Author:Marc Zyngier AuthorDate:Sat, 25 Apr 2020 15:11:20 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 13 Sep 2020 17:05:39 +01:00 irqchip/gic-v3: Describe the SGI range As we are about to start making use of SGIs in a more conventional way, let's describe it is the GICv3 list of interrupt types. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 18 +++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 850842f..f7c99a3 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -112,6 +112,7 @@ static DEFINE_PER_CPU(bool, has_rss); #define DEFAULT_PMR_VALUE 0xf0 enum gic_intid_range { + SGI_RANGE, PPI_RANGE, SPI_RANGE, EPPI_RANGE, @@ -123,6 +124,8 @@ enum gic_intid_range { static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) { switch (hwirq) { + case 0 ... 15: + return SGI_RANGE; case 16 ... 31: return PPI_RANGE; case 32 ... 1019: @@ -148,15 +151,22 @@ static inline unsigned int gic_irq(struct irq_data *d) return d->hwirq; } -static inline int gic_irq_in_rdist(struct irq_data *d) +static inline bool gic_irq_in_rdist(struct irq_data *d) { - enum gic_intid_range range = get_intid_range(d); - return range == PPI_RANGE || range == EPPI_RANGE; + switch (get_intid_range(d)) { + case SGI_RANGE: + case PPI_RANGE: + case EPPI_RANGE: + return true; + default: + return false; + } } static inline void __iomem *gic_dist_base(struct irq_data *d) { switch (get_intid_range(d)) { + case SGI_RANGE: case PPI_RANGE: case EPPI_RANGE: /* SGI+PPI -> SGI_base for this CPU */ @@ -253,6 +263,7 @@ static void gic_enable_redist(bool enable) static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) { switch (get_intid_range(d)) { + case SGI_RANGE: case PPI_RANGE: case SPI_RANGE: *index = d->hwirq; @@ -1277,6 +1288,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, chip = _eoimode1_chip; switch (__get_intid_range(hw)) { + case SGI_RANGE: case PPI_RANGE: case EPPI_RANGE: irq_set_percpu_devid(irq);
[tip: irq/core] genirq: Add fasteoi IPI flow
The following commit has been merged into the irq/core branch of tip: Commit-ID: c5e5ec033c4ab25c53f1fd217849e75deb0bf7bf Gitweb: https://git.kernel.org/tip/c5e5ec033c4ab25c53f1fd217849e75deb0bf7bf Author:Marc Zyngier AuthorDate:Tue, 19 May 2020 10:41:00 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 13 Sep 2020 17:04:38 +01:00 genirq: Add fasteoi IPI flow For irqchips using the fasteoi flow, IPIs are a bit special. They need to be EOI'd early (before calling the handler), as funny things may happen in the handler (they do not necessarily behave like a normal interrupt). Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- include/linux/irq.h | 1 + kernel/irq/chip.c | 27 +++ 2 files changed, 28 insertions(+) diff --git a/include/linux/irq.h b/include/linux/irq.h index 1b7f4df..57205bb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -634,6 +634,7 @@ 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 857f5f4..bed517d 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -945,6 +945,33 @@ void handle_percpu_devid_irq(struct irq_desc *desc) } /** + * 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(>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 * @desc: the interrupt description structure for this irq
[tip: irq/core] genirq: Allow interrupts to be excluded from /proc/interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 83cfac95c01817819c2a51f0931d798d851f8a08 Gitweb: https://git.kernel.org/tip/83cfac95c01817819c2a51f0931d798d851f8a08 Author:Marc Zyngier AuthorDate:Tue, 19 May 2020 14:58:13 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 13 Sep 2020 17:04:38 +01:00 genirq: Allow interrupts to be excluded from /proc/interrupts A number of architectures implement IPI statistics directly, duplicating the core kstat_irqs accounting. As we move IPIs to being actual IRQs, we would end-up with a confusing display in /proc/interrupts (where the IPIs would appear twice). In order to solve this, allow interrupts to be flagged as "hidden", which excludes them from /proc/interrupts. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- include/linux/irq.h | 4 +++- kernel/irq/debugfs.c | 1 + kernel/irq/proc.c | 2 +- kernel/irq/settings.h | 7 +++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 57205bb..63b9d96 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -71,6 +71,7 @@ enum irqchip_irq_state; * it from the spurious interrupt detection * mechanism and from core side polling. * IRQ_DISABLE_UNLAZY - Disable lazy irq disable + * IRQ_HIDDEN - Don't show up in /proc/interrupts */ enum { IRQ_TYPE_NONE = 0x, @@ -97,13 +98,14 @@ enum { IRQ_PER_CPU_DEVID = (1 << 17), IRQ_IS_POLLED = (1 << 18), IRQ_DISABLE_UNLAZY = (1 << 19), + IRQ_HIDDEN = (1 << 20), }; #define IRQF_MODIFY_MASK \ (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \ -IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY) +IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY | IRQ_HIDDEN) #define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c index b95ff5d..acabc0c 100644 --- a/kernel/irq/debugfs.c +++ b/kernel/irq/debugfs.c @@ -136,6 +136,7 @@ static const struct irq_bit_descr irqdesc_states[] = { BIT_MASK_DESCR(_IRQ_PER_CPU_DEVID), BIT_MASK_DESCR(_IRQ_IS_POLLED), BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY), + BIT_MASK_DESCR(_IRQ_HIDDEN), }; static const struct irq_bit_descr irqdesc_istates[] = { diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 32c071d..72513ed 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -485,7 +485,7 @@ int show_interrupts(struct seq_file *p, void *v) rcu_read_lock(); desc = irq_to_desc(i); - if (!desc) + if (!desc || irq_settings_is_hidden(desc)) goto outsparse; if (desc->kstat_irqs) diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index e43795c..403378b 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -17,6 +17,7 @@ enum { _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID, _IRQ_IS_POLLED = IRQ_IS_POLLED, _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, + _IRQ_HIDDEN = IRQ_HIDDEN, _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, }; @@ -31,6 +32,7 @@ enum { #define IRQ_PER_CPU_DEVID GOT_YOU_MORON #define IRQ_IS_POLLED GOT_YOU_MORON #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON +#define IRQ_HIDDEN GOT_YOU_MORON #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON @@ -167,3 +169,8 @@ static inline void irq_settings_clr_disable_unlazy(struct irq_desc *desc) { desc->status_use_accessors &= ~_IRQ_DISABLE_UNLAZY; } + +static inline bool irq_settings_is_hidden(struct irq_desc *desc) +{ + return desc->status_use_accessors & _IRQ_HIDDEN; +}
[tip: irq/core] arm64: Allow IPIs to be handled as normal interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: d3afc7f12987581eb0d1215b518d719fb9d762da Gitweb: https://git.kernel.org/tip/d3afc7f12987581eb0d1215b518d719fb9d762da Author:Marc Zyngier AuthorDate:Sat, 25 Apr 2020 15:03:47 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 13 Sep 2020 17:05:24 +01:00 arm64: Allow IPIs to be handled as normal interrupts In order to deal with IPIs as normal interrupts, let's add a new way to register them with the architecture code. set_smp_ipi_range() takes a range of interrupts, and allows the arch code to request them as if the were normal interrupts. A standard handler is then called by the core IRQ code to deal with the IPI. This means that we don't need to call irq_enter/irq_exit, and that we don't need to deal with set_irq_regs either. So let's move the dispatcher into its own function, and leave handle_IPI() as a compatibility function. On the sending side, let's make use of ipi_send_mask, which already exists for this purpose. One of the major difference is that we end up, in some cases (such as when performing IRQ time accounting on the scheduler IPI), end up with nested irq_enter()/irq_exit() pairs. Other than the (relatively small) overhead, there should be no consequences to it (these pairs are designed to nest correctly, and the accounting shouldn't be off). Reviewed-by: Valentin Schneider Acked-by: Catalin Marinas Signed-off-by: Marc Zyngier --- arch/arm64/Kconfig | 1 +- arch/arm64/include/asm/smp.h | 5 ++- arch/arm64/kernel/smp.c | 93 ++- 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 6d23283..d0fdbe5 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -106,6 +106,7 @@ config ARM64 select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP + select GENERIC_IRQ_IPI select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 0eadbf9..57c5db1 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -79,6 +79,11 @@ extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int)); extern void (*__smp_cross_call)(const struct cpumask *, unsigned int); /* + * Register IPI interrupts with the arch SMP code + */ +extern void set_smp_ipi_range(int ipi_base, int nr_ipi); + +/* * Called from the secondary holding pen, this is the secondary CPU entry point. */ asmlinkage void secondary_start_kernel(void); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 355ee9e..00c9db1 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -75,6 +75,13 @@ enum ipi_msg_type { IPI_WAKEUP }; +static int ipi_irq_base __read_mostly; +static int nr_ipi __read_mostly = NR_IPI; +static struct irq_desc *ipi_desc[NR_IPI] __read_mostly; + +static void ipi_setup(int cpu); +static void ipi_teardown(int cpu); + #ifdef CONFIG_HOTPLUG_CPU static int op_cpu_kill(unsigned int cpu); #else @@ -237,6 +244,8 @@ asmlinkage notrace void secondary_start_kernel(void) */ notify_cpu_starting(cpu); + ipi_setup(cpu); + store_cpu_topology(cpu); numa_add_cpu(cpu); @@ -302,6 +311,7 @@ int __cpu_disable(void) * and we must not schedule until we're ready to give up the cpu. */ set_cpu_online(cpu, false); + ipi_teardown(cpu); /* * OK - migrate IRQs away from this CPU @@ -890,10 +900,9 @@ static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) /* * Main handler for inter-processor interrupts */ -void handle_IPI(int ipinr, struct pt_regs *regs) +static void do_handle_IPI(int ipinr) { unsigned int cpu = smp_processor_id(); - struct pt_regs *old_regs = set_irq_regs(regs); if ((unsigned)ipinr < NR_IPI) { trace_ipi_entry_rcuidle(ipi_types[ipinr]); @@ -906,21 +915,16 @@ void handle_IPI(int ipinr, struct pt_regs *regs) break; case IPI_CALL_FUNC: - irq_enter(); generic_smp_call_function_interrupt(); - irq_exit(); break; case IPI_CPU_STOP: - irq_enter(); local_cpu_stop(); - irq_exit(); break; case IPI_CPU_CRASH_STOP: if (IS_ENABLED(CONFIG_KEXEC_CORE)) { - irq_enter(); - ipi_cpu_crash_stop(cpu, regs); + ipi_cpu_crash_stop(cpu, get_irq_regs()); unreachable(); } @@ -928,17 +932,13 @@ void handle_IPI(int ipinr, struct pt_regs *regs) #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST case IPI_TIMER: -
[tip: irq/core] irqchip/armada-370-xp: Configure IPIs as standard interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: f02147dd02eb5fab31b55b73e7524f94b5f20324 Gitweb: https://git.kernel.org/tip/f02147dd02eb5fab31b55b73e7524f94b5f20324 Author:Marc Zyngier AuthorDate:Mon, 22 Jun 2020 21:23:36 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:27 +01:00 irqchip/armada-370-xp: Configure IPIs as standard interrupts To introduce IPIs as standard interrupts to the Armada 370-XP driver, let's allocate a completely separate irqdomain and irqchip combo that lives parallel to the "standard" one. This effectively should be modelled as a chained interrupt controller, but the code is in such a state that it is pretty hard to shoehorn, as it would require the rewrite of the MSI layer as well. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-armada-370-xp.c | 262 ++- 1 file changed, 178 insertions(+), 84 deletions(-) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index c9bdc52..d7eb2e9 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -310,7 +310,134 @@ static inline int armada_370_xp_msi_init(struct device_node *node, } #endif +static void armada_xp_mpic_perf_init(void) +{ + unsigned long cpuid = cpu_logical_map(smp_processor_id()); + + /* Enable Performance Counter Overflow interrupts */ + writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), + per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); +} + #ifdef CONFIG_SMP +static struct irq_domain *ipi_domain; + +static void armada_370_xp_ipi_mask(struct irq_data *d) +{ + u32 reg; + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + reg &= ~BIT(d->hwirq); + writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); +} + +static void armada_370_xp_ipi_unmask(struct irq_data *d) +{ + u32 reg; + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + reg |= BIT(d->hwirq); + writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); +} + +static void armada_370_xp_ipi_send_mask(struct irq_data *d, + const struct cpumask *mask) +{ + unsigned long map = 0; + int cpu; + + /* Convert our logical CPU mask into a physical one. */ + for_each_cpu(cpu, mask) + map |= 1 << cpu_logical_map(cpu); + + /* +* Ensure that stores to Normal memory are visible to the +* other CPUs before issuing the IPI. +*/ + dsb(); + + /* submit softirq */ + writel((map << 8) | d->hwirq, main_int_base + + ARMADA_370_XP_SW_TRIG_INT_OFFS); +} + +static void armada_370_xp_ipi_eoi(struct irq_data *d) +{ + writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); +} + +static struct irq_chip ipi_irqchip = { + .name = "IPI", + .irq_mask = armada_370_xp_ipi_mask, + .irq_unmask = armada_370_xp_ipi_unmask, + .irq_eoi= armada_370_xp_ipi_eoi, + .ipi_send_mask = armada_370_xp_ipi_send_mask, +}; + +static int armada_370_xp_ipi_alloc(struct irq_domain *d, +unsigned int virq, +unsigned int nr_irqs, void *args) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_percpu_devid(virq + i); + irq_domain_set_info(d, virq + i, i, _irqchip, + d->host_data, + handle_percpu_devid_fasteoi_ipi, + NULL, NULL); + } + + return 0; +} + +static void armada_370_xp_ipi_free(struct irq_domain *d, +unsigned int virq, +unsigned int nr_irqs) +{ + /* Not freeing IPIs */ +} + +static const struct irq_domain_ops ipi_domain_ops = { + .alloc = armada_370_xp_ipi_alloc, + .free = armada_370_xp_ipi_free, +}; + +static void ipi_resume(void) +{ + int i; + + for (i = 0; i < IPI_DOORBELL_END; i++) { + int irq; + + irq = irq_find_mapping(ipi_domain, i); + if (irq <= 0) + continue; + if (irq_percpu_is_enabled(irq)) { + struct irq_data *d; + d = irq_domain_get_irq_data(ipi_domain, irq); + armada_370_xp_ipi_unmask(d); + } + } +} + +static __init void armada_xp_ipi_init(struct device_node *node) +{ + int base_ipi; + + ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), + IPI_DOORBELL_END, + _domain_ops, NULL); + if (WARN_ON(!ipi_domain)) + return; + +
[tip: irq/core] genirq: Walk the irq_data hierarchy when resending an interrupt
The following commit has been merged into the irq/core branch of tip: Commit-ID: cd1752d34ef33d68d82ef9dcc699b4eaa17c07fc Gitweb: https://git.kernel.org/tip/cd1752d34ef33d68d82ef9dcc699b4eaa17c07fc Author:Marc Zyngier AuthorDate:Wed, 26 Aug 2020 18:37:50 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 06 Sep 2020 18:25:23 +01:00 genirq: Walk the irq_data hierarchy when resending an interrupt On resending an interrupt, we only check the outermost irqchip for a irq_retrigger callback. However, this callback could be implemented at an inner level. Use irq_chip_retrigger_hierarchy() in this case. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- kernel/irq/resend.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index c48ce19..8ccd32a 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -86,6 +86,18 @@ static int irq_sw_resend(struct irq_desc *desc) } #endif +static int try_retrigger(struct irq_desc *desc) +{ + if (desc->irq_data.chip->irq_retrigger) + return desc->irq_data.chip->irq_retrigger(>irq_data); + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + return irq_chip_retrigger_hierarchy(>irq_data); +#else + return 0; +#endif +} + /* * IRQ resend * @@ -113,8 +125,7 @@ int check_irq_resend(struct irq_desc *desc, bool inject) desc->istate &= ~IRQS_PENDING; - if (!desc->irq_data.chip->irq_retrigger || - !desc->irq_data.chip->irq_retrigger(>irq_data)) + if (!try_retrigger(desc)) err = irq_sw_resend(desc); /* If the retrigger was successfull, mark it with the REPLAY bit */
[tip: irq/core] ARM: Handle no IPI being registered in show_ipi_list()
The following commit has been merged into the irq/core branch of tip: Commit-ID: 220387048d859896ccc362c0ebf9bc1e0fa62eb9 Gitweb: https://git.kernel.org/tip/220387048d859896ccc362c0ebf9bc1e0fa62eb9 Author:Marc Zyngier AuthorDate:Fri, 25 Sep 2020 16:22:00 +01:00 Committer: Marc Zyngier CommitterDate: Mon, 28 Sep 2020 11:32:04 +01:00 ARM: Handle no IPI being registered in show_ipi_list() As SMP-on-UP is a valid configuration on 32bit ARM, do not assume that IPIs are populated in show_ipi_list(). Reported-by: Guillaume Tucker Reported-by: kernelci.org bot Tested-by: Guillaume Tucker Signed-off-by: Marc Zyngier --- arch/arm/kernel/smp.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8425da5..48099c6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -541,7 +541,12 @@ void show_ipi_list(struct seq_file *p, int prec) unsigned int cpu, i; for (i = 0; i < NR_IPI; i++) { - unsigned int irq = irq_desc_get_irq(ipi_desc[i]); + unsigned int irq; + + if (!ipi_desc[i]) + continue; + + irq = irq_desc_get_irq(ipi_desc[i]); seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); for_each_online_cpu(cpu)
[tip: irq/core] irqchip/gic: Configure SGIs as standard interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 64a267e9a41c5a91efdfa5bf55bd2509cb4f7170 Gitweb: https://git.kernel.org/tip/64a267e9a41c5a91efdfa5bf55bd2509cb4f7170 Author:Marc Zyngier AuthorDate:Sat, 25 Apr 2020 15:24:01 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:27 +01:00 irqchip/gic: Configure SGIs as standard interrupts Change the way we deal with GIC SGIs by turning them into proper IRQs, and calling into the arch code to register the interrupt range instead of a callback. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic.c | 128 + 1 file changed, 87 insertions(+), 41 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4ffd62a..66671e1 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -124,6 +124,8 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly; static struct gic_kvm_info gic_v2_kvm_info; +static DEFINE_PER_CPU(u32, sgi_intid); + #ifdef CONFIG_GIC_NON_BANKED static void __iomem *gic_get_percpu_base(union gic_base *base) { @@ -226,16 +228,26 @@ static void gic_unmask_irq(struct irq_data *d) static void gic_eoi_irq(struct irq_data *d) { - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); + u32 hwirq = gic_irq(d); + + if (hwirq < 16) + hwirq = this_cpu_read(sgi_intid); + + writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI); } static void gic_eoimode1_eoi_irq(struct irq_data *d) { + u32 hwirq = gic_irq(d); + /* Do not deactivate an IRQ forwarded to a vcpu. */ if (irqd_is_forwarded_to_vcpu(d)) return; - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE); + if (hwirq < 16) + hwirq = this_cpu_read(sgi_intid); + + writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_DEACTIVATE); } static int gic_irq_set_irqchip_state(struct irq_data *d, @@ -295,7 +307,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) - return -EINVAL; + return type == IRQ_TYPE_EDGE_RISING ? 0 : -EINVAL; /* SPIs have restrictions on the supported types */ if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && @@ -315,7 +327,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) { /* Only interrupts on the primary GIC can be forwarded to a vcpu. */ - if (cascading_gic_irq(d)) + if (cascading_gic_irq(d) || gic_irq(d) < 16) return -EINVAL; if (vcpu) @@ -335,31 +347,33 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); irqnr = irqstat & GICC_IAR_INT_ID_MASK; - if (likely(irqnr > 15 && irqnr < 1020)) { - if (static_branch_likely(_deactivate_key)) - writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); - isb(); - handle_domain_irq(gic->domain, irqnr, regs); - continue; - } - if (irqnr < 16) { + if (unlikely(irqnr >= 1020)) + break; + + if (static_branch_likely(_deactivate_key)) writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); - if (static_branch_likely(_deactivate_key)) - writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE); -#ifdef CONFIG_SMP + isb(); + + /* +* Ensure any shared data written by the CPU sending the IPI +* is read after we've read the ACK register on the GIC. +* +* Pairs with the write barrier in gic_ipi_send_mask +*/ + if (irqnr <= 15) { + smp_rmb(); + /* -* Ensure any shared data written by the CPU sending -* the IPI is read after we've read the ACK register -* on the GIC. -* -* Pairs with the write barrier in gic_raise_softirq +* The GIC encodes the source CPU in GICC_IAR, +* leading to the deactivation to fail if not +* written back as is to GICC_EOI. Stash the INTID +* away for gic_eoi_irq() to write back. This only +* works because we don't nest SGIs... */ - smp_rmb(); - handle_IPI(irqnr,
[tip: irq/core] irqchip/gic: Refactor SMP configuration
The following commit has been merged into the irq/core branch of tip: Commit-ID: 7ec46b519467852fc8eb83b6214ad568f8007846 Gitweb: https://git.kernel.org/tip/7ec46b519467852fc8eb83b6214ad568f8007846 Author:Marc Zyngier AuthorDate:Sat, 25 Apr 2020 15:24:01 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:26 +01:00 irqchip/gic: Refactor SMP configuration As we are about to change quite a lot of the SMP support code, let's start by moving it around so that it minimizes the amount of #ifdefery. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic.c | 76 -- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a27ba2c..4ffd62a 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -325,28 +325,6 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) return 0; } -#ifdef CONFIG_SMP -static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, - bool force) -{ - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); - unsigned int cpu; - - if (!force) - cpu = cpumask_any_and(mask_val, cpu_online_mask); - else - cpu = cpumask_first(mask_val); - - if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) - return -EINVAL; - - writeb_relaxed(gic_cpu_map[cpu], reg); - irq_data_update_effective_affinity(d, cpumask_of(cpu)); - - return IRQ_SET_MASK_OK_DONE; -} -#endif - static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqstat, irqnr; @@ -795,6 +773,26 @@ static int gic_pm_init(struct gic_chip_data *gic) #endif #ifdef CONFIG_SMP +static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, + bool force) +{ + void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); + unsigned int cpu; + + if (!force) + cpu = cpumask_any_and(mask_val, cpu_online_mask); + else + cpu = cpumask_first(mask_val); + + if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) + return -EINVAL; + + writeb_relaxed(gic_cpu_map[cpu], reg); + irq_data_update_effective_affinity(d, cpumask_of(cpu)); + + return IRQ_SET_MASK_OK_DONE; +} + static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { int cpu; @@ -824,6 +822,23 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) gic_unlock_irqrestore(flags); } + +static int gic_starting_cpu(unsigned int cpu) +{ + gic_cpu_init(_data[0]); + return 0; +} + +static __init void gic_smp_init(void) +{ + set_smp_cross_call(gic_raise_softirq); + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, + "irqchip/arm/gic:starting", + gic_starting_cpu, NULL); +} +#else +#define gic_smp_init() do { } while(0) +#define gic_set_affinity NULL #endif #ifdef CONFIG_BL_SWITCHER @@ -1027,12 +1042,6 @@ static int gic_irq_domain_translate(struct irq_domain *d, return -EINVAL; } -static int gic_starting_cpu(unsigned int cpu) -{ - gic_cpu_init(_data[0]); - return 0; -} - static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { @@ -1079,10 +1088,8 @@ static void gic_init_chip(struct gic_chip_data *gic, struct device *dev, gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity; } -#ifdef CONFIG_SMP if (gic == _data[0]) gic->chip.irq_set_affinity = gic_set_affinity; -#endif } static int gic_init_bases(struct gic_chip_data *gic, @@ -1199,12 +1206,7 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, */ for (i = 0; i < NR_GIC_CPU_IF; i++) gic_cpu_map[i] = 0xff; -#ifdef CONFIG_SMP - set_smp_cross_call(gic_raise_softirq); -#endif - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, - "irqchip/arm/gic:starting", - gic_starting_cpu, NULL); + set_handle_irq(gic_handle_irq); if (static_branch_likely(_deactivate_key)) pr_info("GIC: Using split EOI/Deactivate mode\n"); @@ -1221,6 +1223,8 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, ret = gic_init_bases(gic, handle); if (ret) kfree(name); + else if (gic == _data[0]) + gic_smp_init(); return ret; }
[tip: irq/core] irqchip/git-v3-its: Implement irq_retrigger callback for device-triggered LPIs
The following commit has been merged into the irq/core branch of tip: Commit-ID: 5f774f5e12512b850a611aa99b4601d7eac50edb Gitweb: https://git.kernel.org/tip/5f774f5e12512b850a611aa99b4601d7eac50edb Author:Marc Zyngier AuthorDate:Fri, 31 Jul 2020 11:33:13 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 06 Sep 2020 18:26:13 +01:00 irqchip/git-v3-its: Implement irq_retrigger callback for device-triggered LPIs It is pretty easy to provide a retrigger callback for the ITS, as it we already have the required support in terms of irq_set_irqchip_state(). Note that this only works for device-generated LPIs, and not the GICv4 doorbells, which should never have to be retriggered anyway. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 95f0974..2808545 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1720,6 +1720,11 @@ static int its_irq_set_irqchip_state(struct irq_data *d, return 0; } +static int its_irq_retrigger(struct irq_data *d) +{ + return !its_irq_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true); +} + /* * Two favourable cases: * @@ -1971,6 +1976,7 @@ static struct irq_chip its_irq_chip = { .irq_set_affinity = its_set_affinity, .irq_compose_msi_msg= its_irq_compose_msi_msg, .irq_set_irqchip_state = its_irq_set_irqchip_state, + .irq_retrigger = its_irq_retrigger, .irq_set_vcpu_affinity = its_irq_set_vcpu_affinity, };
[tip: irq/core] irqchip/gic-common: Don't enable SGIs by default
The following commit has been merged into the irq/core branch of tip: Commit-ID: 3567c6ca47546106d36d995790e4eb80e3f14632 Gitweb: https://git.kernel.org/tip/3567c6ca47546106d36d995790e4eb80e3f14632 Author:Marc Zyngier AuthorDate:Tue, 19 May 2020 09:42:46 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:27 +01:00 irqchip/gic-common: Don't enable SGIs by default The architecture code now enables the IPIs as required, so no need to enable SGIs by default in the GIC code. Reviewed-by: Valentin Schneider Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-common.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 8252000..f47b41d 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -152,9 +152,6 @@ void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)) writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i * 4 / 4); - /* Ensure all SGI interrupts are now enabled */ - writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); - if (sync_access) sync_access(); }
[tip: irq/core] arm64: Remove custom IRQ stat accounting
The following commit has been merged into the irq/core branch of tip: Commit-ID: a263881525310e10ecd46ae8e8531ac9e968b1b4 Gitweb: https://git.kernel.org/tip/a263881525310e10ecd46ae8e8531ac9e968b1b4 Author:Marc Zyngier AuthorDate:Sat, 20 Jun 2020 17:19:00 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:28 +01:00 arm64: Remove custom IRQ stat accounting Let's switch the arm64 code to the core accounting, which already does everything we need. Reviewed-by: Valentin Schneider Acked-by: Catalin Marinas Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/hardirq.h | 9 - arch/arm64/include/asm/smp.h | 5 - arch/arm64/kernel/irq.c | 11 +-- arch/arm64/kernel/smp.c | 30 -- 4 files changed, 13 insertions(+), 42 deletions(-) diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index 985493a..5ffa4ba 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h @@ -13,21 +13,12 @@ #include #include -#define NR_IPI 7 - typedef struct { unsigned int __softirq_pending; - unsigned int ipi_irqs[NR_IPI]; } cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ -#define __inc_irq_stat(cpu, member)__IRQ_STAT(cpu, member)++ -#define __get_irq_stat(cpu, member)__IRQ_STAT(cpu, member) - -u64 smp_irq_stat_cpu(unsigned int cpu); -#define arch_irq_stat_cpu smp_irq_stat_cpu - #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 struct nmi_ctx { diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index c298ad0..2e7f529 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -56,11 +56,6 @@ static inline void set_cpu_logical_map(int cpu, u64 hwid) struct seq_file; /* - * generate IPI list text - */ -extern void show_ipi_list(struct seq_file *p, int prec); - -/* * Discover the set of possible CPUs and determine their * SMP operations. */ diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 04a327c..9cf2fb8 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -10,10 +10,10 @@ * Copyright (C) 2012 ARM Ltd. */ -#include #include #include #include +#include #include #include #include @@ -22,20 +22,11 @@ #include #include -unsigned long irq_err_count; - /* Only access this in an NMI enter/exit */ DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts); DEFINE_PER_CPU(unsigned long *, irq_stack_ptr); -int arch_show_interrupts(struct seq_file *p, int prec) -{ - show_ipi_list(p, prec); - seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); - return 0; -} - #ifdef CONFIG_VMAP_STACK static void init_irq_stacks(void) { diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 58fb155..b6bde26 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -72,7 +73,8 @@ enum ipi_msg_type { IPI_CPU_CRASH_STOP, IPI_TIMER, IPI_IRQ_WORK, - IPI_WAKEUP + IPI_WAKEUP, + NR_IPI }; static int ipi_irq_base __read_mostly; @@ -795,29 +797,23 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { static void smp_cross_call(const struct cpumask *target, unsigned int ipinr); -void show_ipi_list(struct seq_file *p, int prec) +unsigned long irq_err_count; + +int arch_show_interrupts(struct seq_file *p, int prec) { unsigned int cpu, i; for (i = 0; i < NR_IPI; i++) { + unsigned int irq = irq_desc_get_irq(ipi_desc[i]); seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, prec >= 4 ? " " : ""); for_each_online_cpu(cpu) - seq_printf(p, "%10u ", - __get_irq_stat(cpu, ipi_irqs[i])); + seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu)); seq_printf(p, " %s\n", ipi_types[i]); } -} - -u64 smp_irq_stat_cpu(unsigned int cpu) -{ - u64 sum = 0; - int i; - for (i = 0; i < NR_IPI; i++) - sum += __get_irq_stat(cpu, ipi_irqs[i]); - - return sum; + seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); + return 0; } void arch_send_call_function_ipi_mask(const struct cpumask *mask) @@ -892,10 +888,8 @@ static void do_handle_IPI(int ipinr) { unsigned int cpu = smp_processor_id(); - if ((unsigned)ipinr < NR_IPI) { + if ((unsigned)ipinr < NR_IPI) trace_ipi_entry_rcuidle(ipi_types[ipinr]); - __inc_irq_stat(cpu, ipi_irqs[ipinr]); - } switch (ipinr) { case IPI_RESCHEDULE: @@ -992,7 +986,7 @@ void __init set_smp_ipi_range(int ipi_base, int n) int err; err = request_percpu_irq(ipi_base +
[tip: irq/core] irqchip/hip04: Configure IPIs as standard interrupts
The following commit has been merged into the irq/core branch of tip: Commit-ID: a2df12c5899e9bb181cb64385b04f2bc755780b6 Gitweb: https://git.kernel.org/tip/a2df12c5899e9bb181cb64385b04f2bc755780b6 Author:Marc Zyngier AuthorDate:Sat, 20 Jun 2020 20:02:18 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 17 Sep 2020 16:37:27 +01:00 irqchip/hip04: Configure IPIs as standard interrupts In order to switch the hip04 driver to provide standard interrupts for IPIs, rework the way interrupts are allocated, making sure the irqdomain covers the SGIs as well as the rest of the interrupt range. The driver is otherwise so old-school that it creates all interrupts upfront (duh!), so there is hardly anything else to change, apart from communicating the IPIs to the arch code. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-hip04.c | 89 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 130caa1..9b73dcf 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -171,6 +171,29 @@ static int hip04_irq_set_affinity(struct irq_data *d, return IRQ_SET_MASK_OK; } + +static void hip04_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) +{ + int cpu; + unsigned long flags, map = 0; + + raw_spin_lock_irqsave(_controller_lock, flags); + + /* Convert our logical CPU mask into a physical one. */ + for_each_cpu(cpu, mask) + map |= hip04_cpu_map[cpu]; + + /* +* Ensure that stores to Normal memory are visible to the +* other CPUs before they observe us issuing the IPI. +*/ + dmb(ishst); + + /* this always happens on GIC0 */ + writel_relaxed(map << 8 | d->hwirq, hip04_data.dist_base + GIC_DIST_SOFTINT); + + raw_spin_unlock_irqrestore(_controller_lock, flags); +} #endif static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs) @@ -182,19 +205,9 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs) irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); irqnr = irqstat & GICC_IAR_INT_ID_MASK; - if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) { + if (irqnr <= HIP04_MAX_IRQS) handle_domain_irq(hip04_data.domain, irqnr, regs); - continue; - } - if (irqnr < 16) { - writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); -#ifdef CONFIG_SMP - handle_IPI(irqnr, regs); -#endif - continue; - } - break; - } while (1); + } while (irqnr > HIP04_MAX_IRQS); } static struct irq_chip hip04_irq_chip = { @@ -205,6 +218,7 @@ static struct irq_chip hip04_irq_chip = { .irq_set_type = hip04_irq_set_type, #ifdef CONFIG_SMP .irq_set_affinity = hip04_irq_set_affinity, + .ipi_send_mask = hip04_ipi_send_mask, #endif .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE | @@ -279,39 +293,17 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) writel_relaxed(1, base + GIC_CPU_CTRL); } -#ifdef CONFIG_SMP -static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq) -{ - int cpu; - unsigned long flags, map = 0; - - raw_spin_lock_irqsave(_controller_lock, flags); - - /* Convert our logical CPU mask into a physical one. */ - for_each_cpu(cpu, mask) - map |= hip04_cpu_map[cpu]; - - /* -* Ensure that stores to Normal memory are visible to the -* other CPUs before they observe us issuing the IPI. -*/ - dmb(ishst); - - /* this always happens on GIC0 */ - writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT); - - raw_spin_unlock_irqrestore(_controller_lock, flags); -} -#endif - static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - if (hw < 32) { + if (hw < 16) { + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, _irq_chip, +handle_percpu_devid_fasteoi_ipi); + } else if (hw < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, _irq_chip, handle_percpu_devid_irq); - irq_set_status_flags(irq, IRQ_NOAUTOEN); } else { irq_set_chip_and_handler(irq, _irq_chip, handle_fasteoi_irq); @@ -328,10 +320,13 @@ static int hip04_irq_domain_xlate(struct irq_domain *d, unsigned long *out_hwirq,
[tip: irq/core] soc/tegra: pmc: Allow optional irq parent callbacks
The following commit has been merged into the irq/core branch of tip: Commit-ID: 8681cc33f817842df7ebe3c36558d97f5497a177 Gitweb: https://git.kernel.org/tip/8681cc33f817842df7ebe3c36558d97f5497a177 Author:Marc Zyngier AuthorDate:Sun, 04 Oct 2020 21:16:24 +01:00 Committer: Marc Zyngier CommitterDate: Sat, 10 Oct 2020 12:12:11 +01:00 soc/tegra: pmc: Allow optional irq parent callbacks Make the PMC driver resistent to variable depth interrupt hierarchy, which we are about to introduce. Signed-off-by: Marc Zyngier --- drivers/soc/tegra/pmc.c | 36 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d332e5d..b39536c 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2184,6 +2184,34 @@ static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type) return 0; } +static void tegra_irq_mask_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_mask_parent(data); +} + +static void tegra_irq_unmask_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_unmask_parent(data); +} + +static void tegra_irq_eoi_parent(struct irq_data *data) +{ + if (data->parent_data) + irq_chip_eoi_parent(data); +} + +static int tegra_irq_set_affinity_parent(struct irq_data *data, +const struct cpumask *dest, +bool force) +{ + if (data->parent_data) + return irq_chip_set_affinity_parent(data, dest, force); + + return -EINVAL; +} + static int tegra_pmc_irq_init(struct tegra_pmc *pmc) { struct irq_domain *parent = NULL; @@ -2199,10 +2227,10 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc) return 0; pmc->irq.name = dev_name(pmc->dev); - pmc->irq.irq_mask = irq_chip_mask_parent; - pmc->irq.irq_unmask = irq_chip_unmask_parent; - pmc->irq.irq_eoi = irq_chip_eoi_parent; - pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent; + pmc->irq.irq_mask = tegra_irq_mask_parent; + pmc->irq.irq_unmask = tegra_irq_unmask_parent; + pmc->irq.irq_eoi = tegra_irq_eoi_parent; + pmc->irq.irq_set_affinity = tegra_irq_set_affinity_parent; pmc->irq.irq_set_type = pmc->soc->irq_set_type; pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
[tip: irq/core] soc/tegra: pmc: Don't create fake interrupt hierarchy levels
The following commit has been merged into the irq/core branch of tip: Commit-ID: c351ab7bf2a565951172cadbdebe686137c3fd43 Gitweb: https://git.kernel.org/tip/c351ab7bf2a565951172cadbdebe686137c3fd43 Author:Marc Zyngier AuthorDate:Sun, 04 Oct 2020 18:27:04 +01:00 Committer: Marc Zyngier CommitterDate: Sat, 10 Oct 2020 12:12:11 +01:00 soc/tegra: pmc: Don't create fake interrupt hierarchy levels The Tegra PMC driver does ungodly things with the interrupt hierarchy, repeatedly corrupting it by pulling hwirq numbers out of thin air, overriding existing IRQ mappings and changing the handling flow of unsuspecting users. All of this is done in the name of preserving the interrupt hierarchy even when these levels do not exist in the HW. Together with the use of proper IRQs for IPIs, this leads to an unbootable system as the rescheduling IPI gets repeatedly repurposed for random drivers... Instead, let's simply mark the level from which the hierarchy does not make sense for the HW, and let the core code trim the usused levels from the hierarchy. Signed-off-by: Marc Zyngier --- drivers/soc/tegra/pmc.c | 55 +--- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index b39536c..b0bba8a 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1990,44 +1990,17 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, event->id, >irq, pmc); - /* -* GPIOs don't have an equivalent interrupt in the -* parent controller (GIC). However some code, such -* as the one in irq_get_irqchip_state(), require a -* valid IRQ chip to be set. Make sure that's the -* case by passing NULL here, which will install a -* dummy IRQ chip for the interrupt in the parent -* domain. -*/ - if (domain->parent) - irq_domain_set_hwirq_and_chip(domain->parent, - virq, 0, NULL, - NULL); - + /* GPIO hierarchies stop at the PMC level */ + if (!err && domain->parent) + err = irq_domain_disconnect_hierarchy(domain->parent, + virq); break; } } - /* -* For interrupts that don't have associated wake events, assign a -* dummy hardware IRQ number. This is used in the ->irq_set_type() -* and ->irq_set_wake() callbacks to return early for these IRQs. -*/ - if (i == soc->num_wake_events) { - err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, - >irq, pmc); - - /* -* Interrupts without a wake event don't have a corresponding -* interrupt in the parent controller (GIC). Pass NULL for the -* chip here, which causes a dummy IRQ chip to be installed -* for the interrupt in the parent domain, to make this -* explicit. -*/ - if (domain->parent) - irq_domain_set_hwirq_and_chip(domain->parent, virq, 0, - NULL, NULL); - } + /* If there is no wake-up event, there is no PMC mapping */ + if (i == soc->num_wake_events) + err = irq_domain_disconnect_hierarchy(domain, virq); return err; } @@ -2043,9 +2016,6 @@ static int tegra210_pmc_irq_set_wake(struct irq_data *data, unsigned int on) unsigned int offset, bit; u32 value; - if (data->hwirq == ULONG_MAX) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2080,9 +2050,6 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) unsigned int offset, bit; u32 value; - if (data->hwirq == ULONG_MAX) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2123,10 +2090,6 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on) unsigned int offset, bit; u32 value; - /* nothing to do if there's no associated wake event */ - if (WARN_ON(data->hwirq == ULONG_MAX)) - return 0; - offset = data->hwirq / 32; bit = data->hwirq % 32; @@ -2154,10 +2117,6 @@ static int
[tip: irq/urgent] irqchip: Fix probing deferal when using IRQCHIP_PLATFORM_DRIVER helpers
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 7828a3ef8646fb2e69ed45616c8453a037ca7867 Gitweb: https://git.kernel.org/tip/7828a3ef8646fb2e69ed45616c8453a037ca7867 Author:Marc Zyngier AuthorDate:Thu, 06 Aug 2020 10:57:45 +01:00 Committer: Marc Zyngier CommitterDate: Mon, 17 Aug 2020 08:06:11 +01:00 irqchip: Fix probing deferal when using IRQCHIP_PLATFORM_DRIVER helpers When probing an interrupt controller that is behind a parent, we try to check whether the parent domain is available as an indication that we can actually try to probe. Unfortunately, we are checking this with the firmware node of the about to be probed device, not the parent. This is obviously bound to fail. Instead, use the parent node. Fixes: f8410e626569 ("irqchip: Add IRQCHIP_PLATFORM_DRIVER_BEGIN/END and IRQCHIP_MATCH helper macros") Reported-by: John Stultz Tested-by: John Stultz Signed-off-by: Marc Zyngier --- drivers/irqchip/irqchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 1bb0e36..d234115 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -52,7 +52,7 @@ int platform_irqchip_probe(struct platform_device *pdev) * interrupt controller. The actual initialization callback of this * interrupt controller can check for specific domains as necessary. */ - if (par_np && !irq_find_matching_host(np, DOMAIN_BUS_ANY)) + if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; return irq_init_cb(np, par_np);
[tip: irq/urgent] irqchip: Revert modular support for drivers using IRQCHIP_PLATFORM_DRIVER helperse
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: a150dac5a8fb711fdc378c23f44bee4546f04246 Gitweb: https://git.kernel.org/tip/a150dac5a8fb711fdc378c23f44bee4546f04246 Author:Marc Zyngier AuthorDate:Tue, 25 Aug 2020 10:38:39 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 25 Aug 2020 10:48:54 +01:00 irqchip: Revert modular support for drivers using IRQCHIP_PLATFORM_DRIVER helperse It has become obvious that switching a number of irqchip drivers to being platform drivers without considering the platform was a mistake. We have multiple reports of end-point drivers not probing because the irqchip driver isn't there yet, breaking the expectations of the users. This patch reverts: 920ecb8c35cb ("irqchip/mtk-cirq: Convert to a platform driver") f97dbf48ca43 ("irqchip/mtk-sysirq: Convert to a platform driver") 5be57099d445 ("irqchip/qcom-pdc: Switch to using IRQCHIP_PLATFORM_DRIVER helper macros") 95bf9305d2e3 ("irqchip/qcom-pdc: Allow QCOM_PDC to be loadable as a permanent module") and leave QCOM PDC, MTK sysrq and cirq drivers as built-in, special purpose drivers for the time being until we have worked out a better solution. Reported-by: Enric Balletbo i Serra Reported-by: Frank Wunderlich Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/93debe6a0308b66d3f307af67ba7e...@kernel.org --- drivers/irqchip/Kconfig | 2 +- drivers/irqchip/irq-mtk-cirq.c | 4 +--- drivers/irqchip/irq-mtk-sysirq.c | 4 +--- drivers/irqchip/qcom-pdc.c | 8 +--- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index bb70b71..bfc9719 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -425,7 +425,7 @@ config GOLDFISH_PIC for Goldfish based virtual platforms. config QCOM_PDC - tristate "QCOM PDC" + bool "QCOM PDC" depends on ARCH_QCOM select IRQ_DOMAIN_HIERARCHY help diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c index 62a6127..69ba8ce 100644 --- a/drivers/irqchip/irq-mtk-cirq.c +++ b/drivers/irqchip/irq-mtk-cirq.c @@ -295,6 +295,4 @@ out_free: return ret; } -IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_cirq) -IRQCHIP_MATCH("mediatek,mtk-cirq", mtk_cirq_of_init) -IRQCHIP_PLATFORM_DRIVER_END(mtk_cirq) +IRQCHIP_DECLARE(mtk_cirq, "mediatek,mtk-cirq", mtk_cirq_of_init); diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index 7299c5a..6ff98b8 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -231,6 +231,4 @@ out_free_chip: kfree(chip_data); return ret; } -IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_sysirq) -IRQCHIP_MATCH("mediatek,mt6577-sysirq", mtk_sysirq_of_init) -IRQCHIP_PLATFORM_DRIVER_END(mtk_sysirq) +IRQCHIP_DECLARE(mtk_sysirq, "mediatek,mt6577-sysirq", mtk_sysirq_of_init); diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index c1c5dfa..6ae9e1f 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -11,11 +11,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -432,8 +430,4 @@ fail: return ret; } -IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc) -IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init) -IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc) -MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller"); -MODULE_LICENSE("GPL v2"); +IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
[tip: irq/urgent] genirq/debugfs: Add missing irqchip flags
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: aa251fc5b936d3ddb4b4c4b36427eb9aa3347c82 Gitweb: https://git.kernel.org/tip/aa251fc5b936d3ddb4b4c4b36427eb9aa3347c82 Author:Marc Zyngier AuthorDate:Sat, 25 Jul 2020 13:30:55 +01:00 Committer: Thomas Gleixner CommitterDate: Mon, 27 Jul 2020 16:20:40 +02:00 genirq/debugfs: Add missing irqchip flags Recently introduced irqchip flags lack the corresponding printouts in debugfs. Add them. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/874kpvydxc.wl-...@kernel.org --- kernel/irq/debugfs.c | 5 + 1 file changed, 5 insertions(+) diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c index 4f9f844..b95ff5d 100644 --- a/kernel/irq/debugfs.c +++ b/kernel/irq/debugfs.c @@ -112,6 +112,7 @@ static const struct irq_bit_descr irqdata_states[] = { BIT_MASK_DESCR(IRQD_AFFINITY_SET), BIT_MASK_DESCR(IRQD_SETAFFINITY_PENDING), BIT_MASK_DESCR(IRQD_AFFINITY_MANAGED), + BIT_MASK_DESCR(IRQD_AFFINITY_ON_ACTIVATE), BIT_MASK_DESCR(IRQD_MANAGED_SHUTDOWN), BIT_MASK_DESCR(IRQD_CAN_RESERVE), BIT_MASK_DESCR(IRQD_MSI_NOMASK_QUIRK), @@ -120,6 +121,10 @@ static const struct irq_bit_descr irqdata_states[] = { BIT_MASK_DESCR(IRQD_WAKEUP_STATE), BIT_MASK_DESCR(IRQD_WAKEUP_ARMED), + + BIT_MASK_DESCR(IRQD_DEFAULT_TRIGGER_SET), + + BIT_MASK_DESCR(IRQD_HANDLE_ENFORCE_IRQCTX), }; static const struct irq_bit_descr irqdesc_states[] = {
[tip: irq/urgent] irqchip/gic: Atomically update affinity
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: 005c34ae4b44f085120d7f371121ec7ded677761 Gitweb: https://git.kernel.org/tip/005c34ae4b44f085120d7f371121ec7ded677761 Author:Marc Zyngier AuthorDate:Sun, 21 Jun 2020 14:43:15 +01:00 Committer: Marc Zyngier CommitterDate: Sun, 21 Jun 2020 15:24:46 +01:00 irqchip/gic: Atomically update affinity The GIC driver uses a RMW sequence to update the affinity, and relies on the gic_lock_irqsave/gic_unlock_irqrestore sequences to update it atomically. But these sequences only expand into anything meaningful if the BL_SWITCHER option is selected, which almost never happens. It also turns out that using a RMW and locks is just as silly, as the GIC distributor supports byte accesses for the GICD_TARGETRn registers, which when used make the update atomic by definition. Drop the terminally broken code and replace it by a byte write. Fixes: 04c8b0f82c7d ("irqchip/gic: Make locking a BL_SWITCHER only feature") Cc: sta...@vger.kernel.org Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic.c | 14 +++--- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 00de05a..c17fabd 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -329,10 +329,8 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); - unsigned int cpu, shift = (gic_irq(d) % 4) * 8; - u32 val, mask, bit; - unsigned long flags; + void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); + unsigned int cpu; if (!force) cpu = cpumask_any_and(mask_val, cpu_online_mask); @@ -342,13 +340,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) return -EINVAL; - gic_lock_irqsave(flags); - mask = 0xff << shift; - bit = gic_cpu_map[cpu] << shift; - val = readl_relaxed(reg) & ~mask; - writel_relaxed(val | bit, reg); - gic_unlock_irqrestore(flags); - + writeb_relaxed(gic_cpu_map[cpu], reg); irq_data_update_effective_affinity(d, cpumask_of(cpu)); return IRQ_SET_MASK_OK_DONE;
[tip: irq/core] irqchip/gic-v3-its: Track LPI distribution on a per CPU basis
The following commit has been merged into the irq/core branch of tip: Commit-ID: 2f13ff1d1d5c0257c97ea76b86a2d9c99c44a4b9 Gitweb: https://git.kernel.org/tip/2f13ff1d1d5c0257c97ea76b86a2d9c99c44a4b9 Author:Marc Zyngier AuthorDate:Fri, 15 May 2020 17:57:51 +01:00 Committer: Marc Zyngier CommitterDate: Mon, 18 May 2020 10:30:42 +01:00 irqchip/gic-v3-its: Track LPI distribution on a per CPU basis In order to improve the distribution of LPIs among CPUs, let start by tracking the number of LPIs assigned to CPUs, both for managed and non-managed interrupts (as separate counters). Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20200515165752.121296-2-...@kernel.org --- drivers/irqchip/irq-gic-v3-its.c | 49 +-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 124251b..4eb8441 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -174,6 +174,13 @@ static struct { int next_victim; } vpe_proxy; +struct cpu_lpi_count { + atomic_tmanaged; + atomic_tunmanaged; +}; + +static DEFINE_PER_CPU(struct cpu_lpi_count, cpu_lpi_count); + static LIST_HEAD(its_nodes); static DEFINE_RAW_SPINLOCK(its_lock); static struct rdists *gic_rdists; @@ -1510,6 +1517,30 @@ static void its_unmask_irq(struct irq_data *d) lpi_update_config(d, 0, LPI_PROP_ENABLED); } +static __maybe_unused u32 its_read_lpi_count(struct irq_data *d, int cpu) +{ + if (irqd_affinity_is_managed(d)) + return atomic_read(_cpu_ptr(_lpi_count, cpu)->managed); + + return atomic_read(_cpu_ptr(_lpi_count, cpu)->unmanaged); +} + +static void its_inc_lpi_count(struct irq_data *d, int cpu) +{ + if (irqd_affinity_is_managed(d)) + atomic_inc(_cpu_ptr(_lpi_count, cpu)->managed); + else + atomic_inc(_cpu_ptr(_lpi_count, cpu)->unmanaged); +} + +static void its_dec_lpi_count(struct irq_data *d, int cpu) +{ + if (irqd_affinity_is_managed(d)) + atomic_dec(_cpu_ptr(_lpi_count, cpu)->managed); + else + atomic_dec(_cpu_ptr(_lpi_count, cpu)->unmanaged); +} + static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { @@ -1518,34 +1549,44 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, struct its_device *its_dev = irq_data_get_irq_chip_data(d); struct its_collection *target_col; u32 id = its_get_event_id(d); + int prev_cpu; /* A forwarded interrupt should use irq_set_vcpu_affinity */ if (irqd_is_forwarded_to_vcpu(d)) return -EINVAL; + prev_cpu = its_dev->event_map.col_map[id]; + its_dec_lpi_count(d, prev_cpu); + /* lpi cannot be routed to a redistributor that is on a foreign node */ if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { if (its_dev->its->numa_node >= 0) { cpu_mask = cpumask_of_node(its_dev->its->numa_node); if (!cpumask_intersects(mask_val, cpu_mask)) - return -EINVAL; + goto err; } } cpu = cpumask_any_and(mask_val, cpu_mask); if (cpu >= nr_cpu_ids) - return -EINVAL; + goto err; /* don't set the affinity when the target cpu is same as current one */ - if (cpu != its_dev->event_map.col_map[id]) { + if (cpu != prev_cpu) { target_col = _dev->its->collections[cpu]; its_send_movi(its_dev, target_col, id); its_dev->event_map.col_map[id] = cpu; irq_data_update_effective_affinity(d, cpumask_of(cpu)); } + its_inc_lpi_count(d, cpu); + return IRQ_SET_MASK_OK_DONE; + +err: + its_inc_lpi_count(d, prev_cpu); + return -EINVAL; } static u64 its_irq_get_msi_base(struct its_device *its_dev) @@ -3448,6 +3489,7 @@ static int its_irq_domain_activate(struct irq_domain *domain, cpu = cpumask_first(cpu_online_mask); } + its_inc_lpi_count(d, cpu); its_dev->event_map.col_map[event] = cpu; irq_data_update_effective_affinity(d, cpumask_of(cpu)); @@ -3462,6 +3504,7 @@ static void its_irq_domain_deactivate(struct irq_domain *domain, struct its_device *its_dev = irq_data_get_irq_chip_data(d); u32 event = its_get_event_id(d); + its_dec_lpi_count(d, its_dev->event_map.col_map[event]); /* Stop the delivery of interrupts */ its_send_discard(its_dev, event); }
[tip: irq/core] irqchip/gic-v3-its: Balance initial LPI affinity across CPUs
The following commit has been merged into the irq/core branch of tip: Commit-ID: c5d6082d35e0bcc20a26a067ffcfddcb5257e580 Gitweb: https://git.kernel.org/tip/c5d6082d35e0bcc20a26a067ffcfddcb5257e580 Author:Marc Zyngier AuthorDate:Fri, 15 May 2020 17:57:52 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 20 May 2020 11:00:00 +01:00 irqchip/gic-v3-its: Balance initial LPI affinity across CPUs When mapping a LPI, the ITS driver picks the first possible affinity, which is in most cases CPU0, assuming that if that's not suitable, someone will come and set the affinity to something more interesting. It apparently isn't the case, and people complain of poor performance when many interrupts are glued to the same CPU. So let's place the interrupts by finding the "least loaded" CPU (that is, the one that has the fewer LPIs mapped to it). So called 'managed' interrupts are an interesting case where the affinity is actually dictated by the kernel itself, and we should honor this. Reported-by: John Garry Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/1575642904-58295-1-git-send-email-john.ga...@huawei.com Link: https://lore.kernel.org/r/20200515165752.121296-3-...@kernel.org --- drivers/irqchip/irq-gic-v3-its.c | 127 +++--- 1 file changed, 100 insertions(+), 27 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 4eb8441..cd685f5 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1541,15 +1541,104 @@ static void its_dec_lpi_count(struct irq_data *d, int cpu) atomic_dec(_cpu_ptr(_lpi_count, cpu)->unmanaged); } +static unsigned int cpumask_pick_least_loaded(struct irq_data *d, + const struct cpumask *cpu_mask) +{ + unsigned int cpu = nr_cpu_ids, tmp; + int count = S32_MAX; + + for_each_cpu(tmp, cpu_mask) { + int this_count = its_read_lpi_count(d, tmp); + if (this_count < count) { + cpu = tmp; + count = this_count; + } + } + + return cpu; +} + +/* + * As suggested by Thomas Gleixner in: + * https://lore.kernel.org/r/87h80q2aoc@nanos.tec.linutronix.de + */ +static int its_select_cpu(struct irq_data *d, + const struct cpumask *aff_mask) +{ + struct its_device *its_dev = irq_data_get_irq_chip_data(d); + cpumask_var_t tmpmask; + int cpu, node; + + if (!alloc_cpumask_var(, GFP_ATOMIC)) + return -ENOMEM; + + node = its_dev->its->numa_node; + + if (!irqd_affinity_is_managed(d)) { + /* First try the NUMA node */ + if (node != NUMA_NO_NODE) { + /* +* Try the intersection of the affinity mask and the +* node mask (and the online mask, just to be safe). +*/ + cpumask_and(tmpmask, cpumask_of_node(node), aff_mask); + cpumask_and(tmpmask, tmpmask, cpu_online_mask); + + /* +* Ideally, we would check if the mask is empty, and +* try again on the full node here. +* +* But it turns out that the way ACPI describes the +* affinity for ITSs only deals about memory, and +* not target CPUs, so it cannot describe a single +* ITS placed next to two NUMA nodes. +* +* Instead, just fallback on the online mask. This +* diverges from Thomas' suggestion above. +*/ + cpu = cpumask_pick_least_loaded(d, tmpmask); + if (cpu < nr_cpu_ids) + goto out; + + /* If we can't cross sockets, give up */ + if ((its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144)) + goto out; + + /* If the above failed, expand the search */ + } + + /* Try the intersection of the affinity and online masks */ + cpumask_and(tmpmask, aff_mask, cpu_online_mask); + + /* If that doesn't fly, the online mask is the last resort */ + if (cpumask_empty(tmpmask)) + cpumask_copy(tmpmask, cpu_online_mask); + + cpu = cpumask_pick_least_loaded(d, tmpmask); + } else { + cpumask_and(tmpmask, irq_data_get_affinity_mask(d), cpu_online_mask); + + /* If we cannot cross sockets, limit the search to that node */ + if ((its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) && + node
[tip: irq/urgent] irqchip/sifive-plic: Switch to fasteoi flow
The following commit has been merged into the irq/urgent branch of tip: Commit-ID: bb0fed1c60cccbe4063b455a7228818395dac86e Gitweb: https://git.kernel.org/tip/bb0fed1c60cccbe4063b455a7228818395dac86e Author:Marc Zyngier AuthorDate:Sun, 15 Sep 2019 15:17:45 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 18 Sep 2019 12:29:52 +01:00 irqchip/sifive-plic: Switch to fasteoi flow The SiFive PLIC interrupt controller seems to have all the HW features to support the fasteoi flow, but the driver seems to be stuck in a distant past. Bring it into the 21st century. Signed-off-by: Marc Zyngier Tested-by: Palmer Dabbelt (QEMU Boot) Tested-by: Darius Rad (on 2 HW PLIC implementations) Tested-by: Paul Walmsley (HiFive Unleashed) Reviewed-by: Palmer Dabbelt Cc: sta...@vger.kernel.org Link: https://lore.kernel.org/r/8636gxskmj.wl-...@kernel.org --- drivers/irqchip/irq-sifive-plic.c | 29 +++-- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index cf75596..3e51dee 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -97,7 +97,7 @@ static inline void plic_irq_toggle(const struct cpumask *mask, } } -static void plic_irq_enable(struct irq_data *d) +static void plic_irq_unmask(struct irq_data *d) { unsigned int cpu = cpumask_any_and(irq_data_get_affinity_mask(d), cpu_online_mask); @@ -106,7 +106,7 @@ static void plic_irq_enable(struct irq_data *d) plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1); } -static void plic_irq_disable(struct irq_data *d) +static void plic_irq_mask(struct irq_data *d) { plic_irq_toggle(cpu_possible_mask, d->hwirq, 0); } @@ -125,10 +125,8 @@ static int plic_set_affinity(struct irq_data *d, if (cpu >= nr_cpu_ids) return -EINVAL; - if (!irqd_irq_disabled(d)) { - plic_irq_toggle(cpu_possible_mask, d->hwirq, 0); - plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1); - } + plic_irq_toggle(cpu_possible_mask, d->hwirq, 0); + plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1); irq_data_update_effective_affinity(d, cpumask_of(cpu)); @@ -136,14 +134,18 @@ static int plic_set_affinity(struct irq_data *d, } #endif +static void plic_irq_eoi(struct irq_data *d) +{ + struct plic_handler *handler = this_cpu_ptr(_handlers); + + writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); +} + static struct irq_chip plic_chip = { .name = "SiFive PLIC", - /* -* There is no need to mask/unmask PLIC interrupts. They are "masked" -* by reading claim and "unmasked" when writing it back. -*/ - .irq_enable = plic_irq_enable, - .irq_disable= plic_irq_disable, + .irq_mask = plic_irq_mask, + .irq_unmask = plic_irq_unmask, + .irq_eoi= plic_irq_eoi, #ifdef CONFIG_SMP .irq_set_affinity = plic_set_affinity, #endif @@ -152,7 +154,7 @@ static struct irq_chip plic_chip = { static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { - irq_set_chip_and_handler(irq, _chip, handle_simple_irq); + irq_set_chip_and_handler(irq, _chip, handle_fasteoi_irq); irq_set_chip_data(irq, NULL); irq_set_noprobe(irq); return 0; @@ -188,7 +190,6 @@ static void plic_handle_irq(struct pt_regs *regs) hwirq); else generic_handle_irq(irq); - writel(hwirq, claim); } csr_set(sie, SIE_SEIE); }
[tip: irq/core] irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
The following commit has been merged into the irq/core branch of tip: Commit-ID: c9c96e30ecaa0aafa225aa1a5392cb7db17c7a82 Gitweb: https://git.kernel.org/tip/c9c96e30ecaa0aafa225aa1a5392cb7db17c7a82 Author:Marc Zyngier AuthorDate:Thu, 05 Sep 2019 14:56:47 +01:00 Committer: Marc Zyngier CommitterDate: Thu, 05 Sep 2019 16:03:48 +01:00 irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices When allocating a range of LPIs for a Multi-MSI capable device, this allocation extended to the closest power of 2. But on the release path, the interrupts are released one by one. This results in not releasing the "extra" range, leaking the its_device. Trying to reprobe the device will then fail. Fix it by releasing the LPIs the same way we allocate them. Fixes: 8208d1708b88 ("irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size") Reported-by: Jiaxing Luo Tested-by: John Garry Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/f5e948aa-e32f-3f74-ae30-31fee06c2...@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 9380aa4..62e54f1 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2641,14 +2641,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, struct its_node *its = its_dev->its; int i; + bitmap_release_region(its_dev->event_map.lpi_map, + its_get_event_id(irq_domain_get_irq_data(domain, virq)), + get_count_order(nr_irqs)); + for (i = 0; i < nr_irqs; i++) { struct irq_data *data = irq_domain_get_irq_data(domain, virq + i); - u32 event = its_get_event_id(data); - - /* Mark interrupt index as unused */ - clear_bit(event, its_dev->event_map.lpi_map); - /* Nuke the entry in the domain */ irq_domain_reset_irq_data(data); }
[tip: irq/core] irqchip/gic-v3: Dynamically allocate PPI NMI refcounts
The following commit has been merged into the irq/core branch of tip: Commit-ID: 81a43273045b116901e569ca27ddf0f92caf Gitweb: https://git.kernel.org/tip/81a43273045b116901e569ca27ddf0f92caf Author:Marc Zyngier AuthorDate:Thu, 18 Jul 2019 12:53:05 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:34 +01:00 irqchip/gic-v3: Dynamically allocate PPI NMI refcounts As we're about to have a variable number of PPIs, let's make the allocation of the NMI refcounts dynamic. Also apply some minor cleanups (moving things around). Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 47 +-- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index f884dd9..869a805 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -88,7 +88,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */ -static refcount_t ppi_nmi_refs[16]; +static refcount_t *ppi_nmi_refs; static struct gic_kvm_info gic_v3_kvm_info; static DEFINE_PER_CPU(bool, has_rss); @@ -409,6 +409,16 @@ static void gic_irq_set_prio(struct irq_data *d, u8 prio) writeb_relaxed(prio, base + offset + index); } +static u32 gic_get_ppi_index(struct irq_data *d) +{ + switch (get_intid_range(d)) { + case PPI_RANGE: + return d->hwirq - 16; + default: + unreachable(); + } +} + static int gic_irq_nmi_setup(struct irq_data *d) { struct irq_desc *desc = irq_to_desc(d->irq); @@ -429,10 +439,12 @@ static int gic_irq_nmi_setup(struct irq_data *d) return -EINVAL; /* desc lock should already be held */ - if (gic_irq(d) < 32) { + if (gic_irq_in_rdist(d)) { + u32 idx = gic_get_ppi_index(d); + /* Setting up PPI as NMI, only switch handler for first NMI */ - if (!refcount_inc_not_zero(_nmi_refs[gic_irq(d) - 16])) { - refcount_set(_nmi_refs[gic_irq(d) - 16], 1); + if (!refcount_inc_not_zero(_nmi_refs[idx])) { + refcount_set(_nmi_refs[idx], 1); desc->handle_irq = handle_percpu_devid_fasteoi_nmi; } } else { @@ -464,9 +476,11 @@ static void gic_irq_nmi_teardown(struct irq_data *d) return; /* desc lock should already be held */ - if (gic_irq(d) < 32) { + if (gic_irq_in_rdist(d)) { + u32 idx = gic_get_ppi_index(d); + /* Tearing down NMI, only switch handler for last NMI */ - if (refcount_dec_and_test(_nmi_refs[gic_irq(d) - 16])) + if (refcount_dec_and_test(_nmi_refs[idx])) desc->handle_irq = handle_percpu_devid_irq; } else { desc->handle_irq = handle_fasteoi_irq; @@ -1394,7 +1408,19 @@ static void gic_enable_nmi_support(void) { int i; - for (i = 0; i < 16; i++) + if (!gic_prio_masking_enabled()) + return; + + if (gic_has_group0() && !gic_dist_security_disabled()) { + pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n"); + return; + } + + ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL); + if (!ppi_nmi_refs) + return; + + for (i = 0; i < gic_data.ppi_nr; i++) refcount_set(_nmi_refs[i], 0); static_branch_enable(_pseudo_nmis); @@ -1472,12 +1498,7 @@ static int __init gic_init_bases(void __iomem *dist_base, gicv2m_init(handle, gic_data.domain); } - if (gic_prio_masking_enabled()) { - if (!gic_has_group0() || gic_dist_security_disabled()) - gic_enable_nmi_support(); - else - pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n"); - } + gic_enable_nmi_support(); return 0;
[tip: irq/core] irqchip/gic-v3: Warn about inconsistent implementations of extended ranges
The following commit has been merged into the irq/core branch of tip: Commit-ID: ad5a78d3da81836c88d1f2d53310484462660997 Gitweb: https://git.kernel.org/tip/ad5a78d3da81836c88d1f2d53310484462660997 Author:Marc Zyngier AuthorDate:Thu, 25 Jul 2019 15:30:51 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:35 +01:00 irqchip/gic-v3: Warn about inconsistent implementations of extended ranges As is it usual for the GIC, it isn't disallowed to put together a system that is majorly inconsistent, with a distributor supporting the extended ranges while some of the CPUs don't. Kindly tell the user that things are sailing isn't going to be smooth. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 5 + include/linux/irqchip/arm-gic-v3.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d3727e8..8af08dd 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1014,6 +1014,11 @@ static void gic_cpu_init(void) gic_enable_redist(true); + WARN((gic_data.ppi_nr > 16 || GIC_ESPI_NR != 0) && +!(gic_read_ctlr() & ICC_CTLR_EL1_ExtRange), +"Distributor has extended ranges, but CPU%d doesn't\n", +smp_processor_id()); + rbase = gic_data_rdist_sgi_base(); /* Configure SGIs/PPIs as non-secure Group-1 */ diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 9ec3349..5cc10cf 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -496,6 +496,7 @@ #define ICC_CTLR_EL1_A3V_SHIFT 15 #define ICC_CTLR_EL1_A3V_MASK (0x1 << ICC_CTLR_EL1_A3V_SHIFT) #define ICC_CTLR_EL1_RSS (0x1 << 18) +#define ICC_CTLR_EL1_ExtRange (0x1 << 19) #define ICC_PMR_EL1_SHIFT 0 #define ICC_PMR_EL1_MASK (0xff << ICC_PMR_EL1_SHIFT) #define ICC_BPR0_EL1_SHIFT 0
[tip: irq/core] irqchip/gic: Skip DT quirks when evaluating IIDR-based quirks
The following commit has been merged into the irq/core branch of tip: Commit-ID: 25edaed6c7feca8fded25348732c628283304364 Gitweb: https://git.kernel.org/tip/25edaed6c7feca8fded25348732c628283304364 Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 17:28:49 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:35 +01:00 irqchip/gic: Skip DT quirks when evaluating IIDR-based quirks When evaluating potential quirks matched by reads of the IIDR register, skip the quirk entries that use a "compatible" property attached to them, as these are DT based. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 14110db..8252000 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -41,6 +41,8 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data) { for (; quirks->desc; quirks++) { + if (quirks->compatible) + continue; if (quirks->iidr != (quirks->mask & iidr)) continue; if (quirks->init(data))
[tip: irq/core] dt-bindings: interrupt-controller: arm,gic-v3: Describe ESPI range support
The following commit has been merged into the irq/core branch of tip: Commit-ID: 866246534836c60f706076cdefcd45072ad9eab2 Gitweb: https://git.kernel.org/tip/866246534836c60f706076cdefcd45072ad9eab2 Author:Marc Zyngier AuthorDate:Tue, 16 Jul 2019 15:18:40 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:04:09 +01:00 dt-bindings: interrupt-controller: arm,gic-v3: Describe ESPI range support GICv3.1 introduces support for new interrupt ranges, one of them being the Extended SPI range (ESPI). The DT binding is extended to deal with it as a new interrupt class. Reviewed-by: Lokesh Vutla Signed-off-by: Marc Zyngier --- Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index c34df35..98a3ecd 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -44,11 +44,12 @@ properties: be at least 4. The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI - interrupts. Other values are reserved for future use. + interrupts, 2 for interrupts in the Extended SPI range. Other values + are reserved for future use. The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the - range [0-15]. + range [0-15]. Extented SPI interrupts are in the range [0-1023]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags.
[tip: irq/core] irqdomain/debugfs: Use PAs to generate fwnode names
The following commit has been merged into the irq/core branch of tip: Commit-ID: b977fcf477c176e5f41775f0ea139f935b0f25b7 Gitweb: https://git.kernel.org/tip/b977fcf477c176e5f41775f0ea139f935b0f25b7 Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 15:13:19 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:54 +01:00 irqdomain/debugfs: Use PAs to generate fwnode names Booting a large arm64 server (HiSi D05) leads to the following shouting at boot time: [ 20.722132] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.730851] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.739560] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.748267] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.756975] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.765683] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! [ 20.774391] debugfs: File 'irqchip@(ptrval)-3' in directory 'domains' already present! and many more... Evidently, we expect something a bit more informative than ptrval, and certainly we want all of our domains, not just the first one. For that, turn the %p used to generate the fwnode name into something that won't be repainted (%pa). Given that we've now fixed all users to pass a pointer to a PA, it will actually do the right thing. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 6 +++--- kernel/irq/irqdomain.c| 9 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 07ec8b3..583e7ab 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -220,7 +220,7 @@ static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d) #ifdef CONFIG_IRQ_DOMAIN struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, - const char *name, void *data); + const char *name, phys_addr_t *pa); enum { IRQCHIP_FWNODE_REAL, @@ -241,9 +241,9 @@ struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id) NULL); } -static inline struct fwnode_handle *irq_domain_alloc_fwnode(void *data) +static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa) { - return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, data); + return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa); } void irq_domain_free_fwnode(struct fwnode_handle *fwnode); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 3078d0e..e7bbab1 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -31,7 +31,7 @@ struct irqchip_fwid { struct fwnode_handlefwnode; unsigned inttype; char*name; - void *data; + phys_addr_t *pa; }; #ifdef CONFIG_GENERIC_IRQ_DEBUGFS @@ -62,7 +62,8 @@ EXPORT_SYMBOL_GPL(irqchip_fwnode_ops); * domain struct. */ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, - const char *name, void *data) + const char *name, + phys_addr_t *pa) { struct irqchip_fwid *fwid; char *n; @@ -77,7 +78,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, n = kasprintf(GFP_KERNEL, "%s-%d", name, id); break; default: - n = kasprintf(GFP_KERNEL, "irqchip@%p", data); + n = kasprintf(GFP_KERNEL, "irqchip@%pa", pa); break; } @@ -89,7 +90,7 @@ struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, fwid->type = type; fwid->name = n; - fwid->data = data; + fwid->pa = pa; fwid->fwnode.ops = _fwnode_ops; return >fwnode; }
[tip: irq/core] irqchip/gic: Rework gic_configure_irq to take the full ICFGR base
The following commit has been merged into the irq/core branch of tip: Commit-ID: 13d22e2e1f35f2d3cc7ddc002c23e733c2782dd4 Gitweb: https://git.kernel.org/tip/13d22e2e1f35f2d3cc7ddc002c23e733c2782dd4 Author:Marc Zyngier AuthorDate:Tue, 16 Jul 2019 14:35:17 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:04:09 +01:00 irqchip/gic: Rework gic_configure_irq to take the full ICFGR base gic_configure_irq is currently passed the (re)distributor address, to which it applies an a fixed offset to get to the configuration registers. This offset is constant across all GICs, or rather it was until to v3.1... An easy way out is for the individual drivers to pass the base address of the configuration register for the considered interrupt. At the same time, move part of the error handling back to the individual drivers, as things are about to change on that front. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-common.c | 14 +- drivers/irqchip/irq-gic-v3.c | 11 ++- drivers/irqchip/irq-gic.c| 10 +- drivers/irqchip/irq-hip04.c | 7 ++- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index b0a8215..6900b6f 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -63,7 +63,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, * for "irq", depending on "type". */ raw_spin_lock_irqsave(_controller_lock, flags); - val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); + val = oldval = readl_relaxed(base + confoff); if (type & IRQ_TYPE_LEVEL_MASK) val &= ~confmask; else if (type & IRQ_TYPE_EDGE_BOTH) @@ -83,14 +83,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, * does not allow us to set the configuration or we are in a * non-secure mode, and hence it may not be catastrophic. */ - writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); - if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) { - if (WARN_ON(irq >= 32)) - ret = -EINVAL; - else - pr_warn("GIC: PPI%d is secure or misconfigured\n", - irq - 16); - } + writel_relaxed(val, base + confoff); + if (readl_relaxed(base + confoff) != val) + ret = -EINVAL; + raw_spin_unlock_irqrestore(_controller_lock, flags); if (sync_access) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index be961c2..efc5319 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -407,6 +407,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) unsigned int irq = gic_irq(d); void (*rwp_wait)(void); void __iomem *base; + int ret; /* Interrupt configuration for SGIs can't be changed */ if (irq < 16) @@ -425,7 +426,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type) rwp_wait = gic_dist_wait_for_rwp; } - return gic_configure_irq(irq, type, base, rwp_wait); + + ret = gic_configure_irq(irq, type, base + GICD_ICFGR, rwp_wait); + if (ret && irq < 32) { + /* Misconfigured PPIs are usually not fatal */ + pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); + ret = 0; + } + + return ret; } static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index b6b8573..5ca7d55 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -291,6 +291,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) { void __iomem *base = gic_dist_base(d); unsigned int gicirq = gic_irq(d); + int ret; /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) @@ -301,7 +302,14 @@ static int gic_set_type(struct irq_data *d, unsigned int type) type != IRQ_TYPE_EDGE_RISING) return -EINVAL; - return gic_configure_irq(gicirq, type, base, NULL); + ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL); + if (ret && gicirq < 32) { + /* Misconfigured PPIs are usually not fatal */ + pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16); + ret = 0; + } + + return ret; } static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index cf70582..1626131 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -130,7 +130,12 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int
[tip: irq/core] irqchip/gic-v3: Add quirks for HIP06/07 invalid GICD_TYPER erratum 161010803
The following commit has been merged into the irq/core branch of tip: Commit-ID: 7f2481b39b4c776fb9c03081ffcfe81f4961601c Gitweb: https://git.kernel.org/tip/7f2481b39b4c776fb9c03081ffcfe81f4961601c Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 17:29:33 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:35 +01:00 irqchip/gic-v3: Add quirks for HIP06/07 invalid GICD_TYPER erratum 161010803 It looks like the HIP06/07 SoCs have extra bits in their GICD_TYPER registers, which confuse the GICv3.1 code (these systems appear to expose ESPIs while they actually don't). Detect these systems as early as possible and wipe the fields that should be RES0 in the register. Tested-by: John Garry Signed-off-by: Marc Zyngier --- Documentation/arm64/silicon-errata.rst | 2 +- drivers/irqchip/irq-gic-v3.c | 56 - 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst index 3e57d09..17ea3fe 100644 --- a/Documentation/arm64/silicon-errata.rst +++ b/Documentation/arm64/silicon-errata.rst @@ -115,6 +115,8 @@ stable kernels. ++-+-+-+ | Hisilicon | Hip0{6,7} | #161010701 | N/A | ++-+-+-+ +| Hisilicon | Hip0{6,7} | #161010803 | N/A | +++-+-+-+ | Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 | ++-+-+-+ | Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A | diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 8af08dd..422664a 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1441,6 +1441,48 @@ static bool gic_enable_quirk_msm8996(void *data) return true; } +static bool gic_enable_quirk_hip06_07(void *data) +{ + struct gic_chip_data *d = data; + + /* +* HIP06 GICD_IIDR clashes with GIC-600 product number (despite +* not being an actual ARM implementation). The saving grace is +* that GIC-600 doesn't have ESPI, so nothing to do in that case. +* HIP07 doesn't even have a proper IIDR, and still pretends to +* have ESPI. In both cases, put them right. +*/ + if (d->rdists.gicd_typer & GICD_TYPER_ESPI) { + /* Zero both ESPI and the RES0 field next to it... */ + d->rdists.gicd_typer &= ~GENMASK(9, 8); + return true; + } + + return false; +} + +static const struct gic_quirk gic_quirks[] = { + { + .desc = "GICv3: Qualcomm MSM8996 broken firmware", + .compatible = "qcom,msm8996-gic-v3", + .init = gic_enable_quirk_msm8996, + }, + { + .desc = "GICv3: HIP06 erratum 161010803", + .iidr = 0x0204043b, + .mask = 0x, + .init = gic_enable_quirk_hip06_07, + }, + { + .desc = "GICv3: HIP07 erratum 161010803", + .iidr = 0x, + .mask = 0x, + .init = gic_enable_quirk_hip06_07, + }, + { + } +}; + static void gic_enable_nmi_support(void) { int i; @@ -1494,6 +1536,10 @@ static int __init gic_init_bases(void __iomem *dist_base, */ typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); gic_data.rdists.gicd_typer = typer; + + gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR), + gic_quirks, _data); + pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32); pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR); gic_data.domain = irq_domain_create_tree(handle, _irq_domain_ops, @@ -1676,16 +1722,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_set_kvm_info(_v3_kvm_info); } -static const struct gic_quirk gic_quirks[] = { - { - .desc = "GICv3: Qualcomm MSM8996 broken firmware", - .compatible = "qcom,msm8996-gic-v3", - .init = gic_enable_quirk_msm8996, - }, - { - } -}; - static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *dist_base;
[tip: irq/core] dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support
The following commit has been merged into the irq/core branch of tip: Commit-ID: 4b049063e0bcbfd302f6bf867de9d55a965d622e Gitweb: https://git.kernel.org/tip/4b049063e0bcbfd302f6bf867de9d55a965d622e Author:Marc Zyngier AuthorDate:Thu, 18 Jul 2019 13:18:51 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:35 +01:00 dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support Update the GICv3 binding to allow interrupts in the EPPI range. Signed-off-by: Marc Zyngier --- Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index 98a3ecd..1fe147d 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -44,12 +44,13 @@ properties: be at least 4. The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI - interrupts, 2 for interrupts in the Extended SPI range. Other values - are reserved for future use. + interrupts, 2 for interrupts in the Extended SPI range, 3 for the + Extended PPI range. Other values are reserved for future use. The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the range [0-15]. Extented SPI interrupts are in the range [0-1023]. + Extended PPI interrupts are in the range [0-127]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags.
[tip: irq/core] irqchip/gic-v3: Register the distributor's PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: 0d093afc2e352e15b23bca38f69aad3d689b Gitweb: https://git.kernel.org/tip/0d093afc2e352e15b23bca38f69aad3d689b Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:19 +01:00 irqchip/gic-v3: Register the distributor's PA instead of its VA in fwnode Do not expose the distributor's VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 96d927f..be961c2 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1845,7 +1845,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) if (err) goto out_redist_unmap; - domain_handle = irq_domain_alloc_fwnode(acpi_data.dist_base); + domain_handle = irq_domain_alloc_fwnode(>base_address); if (!domain_handle) { err = -ENOMEM; goto out_redist_unmap;
[tip: irq/core] irqchip/gic-v3: Add EPPI range support
The following commit has been merged into the irq/core branch of tip: Commit-ID: 5f51f803826e4f4aedff415ddaf14efa707be5a7 Gitweb: https://git.kernel.org/tip/5f51f803826e4f4aedff415ddaf14efa707be5a7 Author:Marc Zyngier AuthorDate:Thu, 18 Jul 2019 13:19:25 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:35 +01:00 irqchip/gic-v3: Add EPPI range support Expand the pre-existing PPI support to be able to deal with the Extended PPI range (EPPI). This includes obtaining the number of PPIs from each individual redistributor, and compute the minimum set (just in case someone builds something really clever...). Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 42 - include/linux/irqchip/arm-gic-v3.h | 12 - 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index f5dbdbf..d3727e8 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -104,6 +104,7 @@ static DEFINE_PER_CPU(bool, has_rss); enum gic_intid_range { PPI_RANGE, SPI_RANGE, + EPPI_RANGE, ESPI_RANGE, LPI_RANGE, __INVALID_RANGE__ @@ -116,6 +117,8 @@ static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) return PPI_RANGE; case 32 ... 1019: return SPI_RANGE; + case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63): + return EPPI_RANGE; case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023): return ESPI_RANGE; case 8192 ... GENMASK(23, 0): @@ -137,13 +140,15 @@ static inline unsigned int gic_irq(struct irq_data *d) static inline int gic_irq_in_rdist(struct irq_data *d) { - return get_intid_range(d) == PPI_RANGE; + enum gic_intid_range range = get_intid_range(d); + return range == PPI_RANGE || range == EPPI_RANGE; } static inline void __iomem *gic_dist_base(struct irq_data *d) { switch (get_intid_range(d)) { case PPI_RANGE: + case EPPI_RANGE: /* SGI+PPI -> SGI_base for this CPU */ return gic_data_rdist_sgi_base(); @@ -242,6 +247,14 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) case SPI_RANGE: *index = d->hwirq; return offset; + case EPPI_RANGE: + /* +* Contrary to the ESPI range, the EPPI range is contiguous +* to the PPI range in the registers, so let's adjust the +* displacement accordingly. Consistency is overrated. +*/ + *index = d->hwirq - EPPI_BASE_INTID + 32; + return offset; case ESPI_RANGE: *index = d->hwirq - ESPI_BASE_INTID; switch (offset) { @@ -414,6 +427,8 @@ static u32 gic_get_ppi_index(struct irq_data *d) switch (get_intid_range(d)) { case PPI_RANGE: return d->hwirq - 16; + case EPPI_RANGE: + return d->hwirq - EPPI_BASE_INTID + 16; default: unreachable(); } @@ -507,6 +522,7 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d) static int gic_set_type(struct irq_data *d, unsigned int type) { + enum gic_intid_range range; unsigned int irq = gic_irq(d); void (*rwp_wait)(void); void __iomem *base; @@ -517,9 +533,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type) if (irq < 16) return -EINVAL; + range = get_intid_range(d); + /* SPIs have restrictions on the supported types */ - if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && -type != IRQ_TYPE_EDGE_RISING) + if ((range == SPI_RANGE || range == ESPI_RANGE) && + type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) return -EINVAL; if (gic_irq_in_rdist(d)) { @@ -533,9 +551,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type) offset = convert_offset_index(d, GICD_ICFGR, ); ret = gic_configure_irq(index, type, base + offset, rwp_wait); - if (ret && irq < 32) { + if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) { /* Misconfigured PPIs are usually not fatal */ - pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); + pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq); ret = 0; } @@ -833,7 +851,7 @@ static int __gic_update_rdist_properties(struct redist_region *region, u64 typer = gic_read_typer(ptr + GICR_TYPER); gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); - gic_data.ppi_nr = 16; + gic_data.ppi_nr = min(GICR_TYPER_NR_PPIS(typer), gic_data.ppi_nr);
[tip: irq/core] irqchip/gic-v3: Add ESPI range support
The following commit has been merged into the irq/core branch of tip: Commit-ID: 211bddd210a6746e4fdfa9b6cdfbdb15026530a7 Gitweb: https://git.kernel.org/tip/211bddd210a6746e4fdfa9b6cdfbdb15026530a7 Author:Marc Zyngier AuthorDate:Tue, 16 Jul 2019 15:17:31 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:34 +01:00 irqchip/gic-v3: Add ESPI range support Add the required support for the ESPI range, which behave exactly like the SPIs of old, only with new funky INTIDs. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 85 +++-- include/linux/irqchip/arm-gic-v3.h | 17 +- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 660ec43..0afc942 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -51,13 +51,16 @@ struct gic_chip_data { u32 nr_redist_regions; u64 flags; boolhas_rss; - unsigned intirq_nr; struct partition_desc *ppi_descs[16]; }; static struct gic_chip_data gic_data __read_mostly; static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); +#define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer)) +#define GIC_LINE_NRmax(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U) +#define GIC_ESPI_NRGICD_TYPER_ESPIS(gic_data.rdists.gicd_typer) + /* * The behaviours of RPR and PMR registers differ depending on the value of * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the @@ -100,6 +103,7 @@ static DEFINE_PER_CPU(bool, has_rss); enum gic_intid_range { PPI_RANGE, SPI_RANGE, + ESPI_RANGE, LPI_RANGE, __INVALID_RANGE__ }; @@ -111,6 +115,8 @@ static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) return PPI_RANGE; case 32 ... 1019: return SPI_RANGE; + case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023): + return ESPI_RANGE; case 8192 ... GENMASK(23, 0): return LPI_RANGE; default: @@ -141,6 +147,7 @@ static inline void __iomem *gic_dist_base(struct irq_data *d) return gic_data_rdist_sgi_base(); case SPI_RANGE: + case ESPI_RANGE: /* SPI -> dist_base */ return gic_data.dist_base; @@ -234,6 +241,31 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) case SPI_RANGE: *index = d->hwirq; return offset; + case ESPI_RANGE: + *index = d->hwirq - ESPI_BASE_INTID; + switch (offset) { + case GICD_ISENABLER: + return GICD_ISENABLERnE; + case GICD_ICENABLER: + return GICD_ICENABLERnE; + case GICD_ISPENDR: + return GICD_ISPENDRnE; + case GICD_ICPENDR: + return GICD_ICPENDRnE; + case GICD_ISACTIVER: + return GICD_ISACTIVERnE; + case GICD_ICACTIVER: + return GICD_ICACTIVERnE; + case GICD_IPRIORITYR: + return GICD_IPRIORITYRnE; + case GICD_ICFGR: + return GICD_ICFGRnE; + case GICD_IROUTER: + return GICD_IROUTERnE; + default: + break; + } + break; default: break; } @@ -316,7 +348,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, { u32 reg; - if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ + if (d->hwirq >= 8192) /* PPI/SPI only */ return -EINVAL; switch (which) { @@ -343,7 +375,7 @@ static int gic_irq_set_irqchip_state(struct irq_data *d, static int gic_irq_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *val) { - if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */ + if (d->hwirq >= 8192) /* PPI/SPI only */ return -EINVAL; switch (which) { @@ -567,7 +599,12 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs gic_arch_enable_irqs(); } - if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { + /* Check for special IDs first */ + if ((irqnr >= 1020 && irqnr <= 1023)) + return; + + /* Treat anything but SGIs in a uniform way */ + if (likely(irqnr > 15)) { int err; if (static_branch_likely(_deactivate_key)) @@ -655,10 +692,26 @@ static void __init gic_dist_init(void) * do the right thing if the kernel is running in secure mode, *
[tip: irq/core] irqchip/gic-v3-its: Register the ITS' PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: 5778cc77111f09fd2033c66cdf1654f542771ed0 Gitweb: https://git.kernel.org/tip/5778cc77111f09fd2033c66cdf1654f542771ed0 Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:28 +01:00 irqchip/gic-v3-its: Register the ITS' PA instead of its VA in fwnode Do not expose the ITS' VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- 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 1b5c367..8eeb0e2 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3921,7 +3921,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1; res.flags = IORESOURCE_MEM; - dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address); + dom_handle = irq_domain_alloc_fwnode(); if (!dom_handle) { pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n", );
[tip: irq/core] irqchip/gic-v2m: Register the frame's PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: 7d5b7695c22f6e22d9a16df17f477832eef8e2b7 Gitweb: https://git.kernel.org/tip/7d5b7695c22f6e22d9a16df17f477832eef8e2b7 Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:37 +01:00 irqchip/gic-v2m: Register the frame's PA instead of its VA in fwnode Do not expose the frame's VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v2m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 7338f90..e88e75c 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -525,7 +525,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header, spi_start, nr_spis); } - fwnode = irq_domain_alloc_fwnode((void *)m->base_address); + fwnode = irq_domain_alloc_fwnode(); if (!fwnode) { pr_err("Unable to allocate GICv2m domain token\n"); return -EINVAL;
[tip: irq/core] irqchip/ixp4xx: Register the base PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: 9adc54d4e8c56ed5851bb51314ffcbaebdfbf17e Gitweb: https://git.kernel.org/tip/9adc54d4e8c56ed5851bb51314ffcbaebdfbf17e Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:41 +01:00 irqchip/ixp4xx: Register the base PA instead of its VA in fwnode Do not expose the base VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-ixp4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-ixp4xx.c b/drivers/irqchip/irq-ixp4xx.c index 6751c35..37e0749 100644 --- a/drivers/irqchip/irq-ixp4xx.c +++ b/drivers/irqchip/irq-ixp4xx.c @@ -319,7 +319,7 @@ void __init ixp4xx_irq_init(resource_size_t irqbase, pr_crit("IXP4XX: could not ioremap interrupt controller\n"); return; } - fwnode = irq_domain_alloc_fwnode(base); + fwnode = irq_domain_alloc_fwnode(); if (!fwnode) { pr_crit("IXP4XX: no domain handle\n"); return;
[tip: irq/core] PCI: hv: Allocate a named fwnode instead of an address-based one
The following commit has been merged into the irq/core branch of tip: Commit-ID: 467a3bb974320a23c0c000559cc54b64e06e9787 Gitweb: https://git.kernel.org/tip/467a3bb974320a23c0c000559cc54b64e06e9787 Author:Marc Zyngier AuthorDate:Tue, 06 Aug 2019 15:23:33 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:49 +01:00 PCI: hv: Allocate a named fwnode instead of an address-based one To allocate its fwnode that is then used to allocate an irqdomain, the driver uses irq_domain_alloc_fwnode(), passing it a VA as an identifier. This is a rather bad idea, as this address ends up published in debugfs (and we want to move away from VAs there anyway). Instead, let's allocate a named fwnode by using the device GUID as an identifier. It is allegedly unique, and can be traced back to the original device. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/pci/controller/pci-hyperv.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 40b6254..97056f3 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -2521,6 +2521,7 @@ static int hv_pci_probe(struct hv_device *hdev, const struct hv_vmbus_device_id *dev_id) { struct hv_pcibus_device *hbus; + char *name; int ret; /* @@ -2589,7 +2590,14 @@ static int hv_pci_probe(struct hv_device *hdev, goto free_config; } - hbus->sysdata.fwnode = irq_domain_alloc_fwnode(hbus); + name = kasprintf(GFP_KERNEL, "%pUL", >dev_instance); + if (!name) { + ret = -ENOMEM; + goto unmap; + } + + hbus->sysdata.fwnode = irq_domain_alloc_named_fwnode(name); + kfree(name); if (!hbus->sysdata.fwnode) { ret = -ENOMEM; goto unmap;
[tip: irq/core] irqchip/gic-v3: Add INTID range and convertion primitives
The following commit has been merged into the irq/core branch of tip: Commit-ID: e91b036e1c20d80419164ddfc32125052df3fb39 Gitweb: https://git.kernel.org/tip/e91b036e1c20d80419164ddfc32125052df3fb39 Author:Marc Zyngier AuthorDate:Tue, 16 Jul 2019 14:41:40 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:04:09 +01:00 irqchip/gic-v3: Add INTID range and convertion primitives In the beginning, life was simple. The GIC driver mostly cared about PPIs, SPIs and LPIs, all with nicely layed out ranges. We're about to change all that, with new ranges such as EPPI and ESPI interleaved in the middle of the no-irq-land between the "special IDs" and the LPI range. Boo. In order to make our life less hellish, let's introduce a set of primitives that will allow ranges to be identified easily and offsets to be remapped. So far, there is no functionnal change. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 112 +- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index efc5319..660ec43 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -97,6 +97,32 @@ static DEFINE_PER_CPU(bool, has_rss); /* Our default, arbitrary priority value. Linux only uses one anyway. */ #define DEFAULT_PMR_VALUE 0xf0 +enum gic_intid_range { + PPI_RANGE, + SPI_RANGE, + LPI_RANGE, + __INVALID_RANGE__ +}; + +static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) +{ + switch (hwirq) { + case 16 ... 31: + return PPI_RANGE; + case 32 ... 1019: + return SPI_RANGE; + case 8192 ... GENMASK(23, 0): + return LPI_RANGE; + default: + return __INVALID_RANGE__; + } +} + +static enum gic_intid_range get_intid_range(struct irq_data *d) +{ + return __get_intid_range(d->hwirq); +} + static inline unsigned int gic_irq(struct irq_data *d) { return d->hwirq; @@ -104,18 +130,23 @@ static inline unsigned int gic_irq(struct irq_data *d) static inline int gic_irq_in_rdist(struct irq_data *d) { - return gic_irq(d) < 32; + return get_intid_range(d) == PPI_RANGE; } static inline void __iomem *gic_dist_base(struct irq_data *d) { - if (gic_irq_in_rdist(d))/* SGI+PPI -> SGI_base for this CPU */ + switch (get_intid_range(d)) { + case PPI_RANGE: + /* SGI+PPI -> SGI_base for this CPU */ return gic_data_rdist_sgi_base(); - if (d->hwirq <= 1023) /* SPI -> dist_base */ + case SPI_RANGE: + /* SPI -> dist_base */ return gic_data.dist_base; - return NULL; + default: + return NULL; + } } static void gic_do_wait_for_rwp(void __iomem *base) @@ -196,24 +227,46 @@ static void gic_enable_redist(bool enable) /* * Routines to disable, enable, EOI and route interrupts */ +static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) +{ + switch (get_intid_range(d)) { + case PPI_RANGE: + case SPI_RANGE: + *index = d->hwirq; + return offset; + default: + break; + } + + WARN_ON(1); + *index = d->hwirq; + return offset; +} + static int gic_peek_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); void __iomem *base; + u32 index, mask; + + offset = convert_offset_index(d, offset, ); + mask = 1 << (index % 32); if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else base = gic_data.dist_base; - return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask); + return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask); } static void gic_poke_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); void (*rwp_wait)(void); void __iomem *base; + u32 index, mask; + + offset = convert_offset_index(d, offset, ); + mask = 1 << (index % 32); if (gic_irq_in_rdist(d)) { base = gic_data_rdist_sgi_base(); @@ -223,7 +276,7 @@ static void gic_poke_irq(struct irq_data *d, u32 offset) rwp_wait = gic_dist_wait_for_rwp; } - writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4); + writel_relaxed(mask, base + offset + (index / 32) * 4); rwp_wait(); } @@ -316,8 +369,11 @@ static int gic_irq_get_irqchip_state(struct irq_data *d, static void gic_irq_set_prio(struct irq_data *d, u8 prio) { void __iomem *base = gic_dist_base(d); + u32 offset, index; - writeb_relaxed(prio, base + GICD_IPRIORITYR + gic_irq(d)); + offset = convert_offset_index(d, GICD_IPRIORITYR, ); + +
[tip: irq/core] gpio/ixp4xx: Register the base PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: daa19fe5b082779962988a5ba9e38509004db3de Gitweb: https://git.kernel.org/tip/daa19fe5b082779962988a5ba9e38509004db3de Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:45 +01:00 gpio/ixp4xx: Register the base PA instead of its VA in fwnode Do not expose the base VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Reviewed-by: Linus Walleij Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- drivers/gpio/gpio-ixp4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index 670c2a8..cc72c9a 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -400,7 +400,7 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) g->fwnode = of_node_to_fwnode(np); } else { parent = ixp4xx_get_irq_domain(); - g->fwnode = irq_domain_alloc_fwnode(g->base); + g->fwnode = irq_domain_alloc_fwnode(>start); if (!g->fwnode) { dev_err(dev, "no domain base\n"); return -ENODEV;
[tip: irq/core] irqchip/gic: Prepare for more than 16 PPIs
The following commit has been merged into the irq/core branch of tip: Commit-ID: 1a60e1e6439164c06636dce5d32660de505d23c3 Gitweb: https://git.kernel.org/tip/1a60e1e6439164c06636dce5d32660de505d23c3 Author:Marc Zyngier AuthorDate:Thu, 18 Jul 2019 11:15:14 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:34 +01:00 irqchip/gic: Prepare for more than 16 PPIs GICv3.1 allows up to 80 PPIs (16 legaci PPIs and 64 Extended PPIs), meaning we can't just leave the old 16 hardcoded everywhere. We also need to add the infrastructure to discover the number of PPIs on a per redistributor basis, although we still pretend there is only 16 of them for now. No functional change. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-common.c | 19 --- drivers/irqchip/irq-gic-common.h | 2 +- drivers/irqchip/irq-gic-v3.c | 22 +++--- drivers/irqchip/irq-gic.c| 2 +- drivers/irqchip/irq-hip04.c | 2 +- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 6900b6f..14110db 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -128,26 +128,31 @@ void gic_dist_config(void __iomem *base, int gic_irqs, sync_access(); } -void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) +void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)) { int i; /* * Deal with the banked PPI and SGI interrupts - disable all -* PPI interrupts, ensure all SGI interrupts are enabled. -* Make sure everything is deactivated. +* private interrupts. Make sure everything is deactivated. */ - writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR); - writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); - writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); + for (i = 0; i < nr; i += 32) { + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ACTIVE_CLEAR + i / 8); + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ENABLE_CLEAR + i / 8); + } /* * Set priority on PPI and SGI interrupts */ - for (i = 0; i < 32; i += 4) + for (i = 0; i < nr; i += 4) writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i * 4 / 4); + /* Ensure all SGI interrupts are now enabled */ + writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); + if (sync_access) sync_access(); } diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index 5a46b6b..ccba8b0 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -22,7 +22,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, void __iomem *base, void (*sync_access)(void)); void gic_dist_config(void __iomem *base, int gic_irqs, void (*sync_access)(void)); -void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); +void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)); void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data); void gic_enable_of_quirks(const struct device_node *np, diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 0afc942..f884dd9 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -51,6 +51,7 @@ struct gic_chip_data { u32 nr_redist_regions; u64 flags; boolhas_rss; + unsigned intppi_nr; struct partition_desc *ppi_descs[16]; }; @@ -812,19 +813,24 @@ static int gic_populate_rdist(void) return -ENODEV; } -static int __gic_update_vlpi_properties(struct redist_region *region, - void __iomem *ptr) +static int __gic_update_rdist_properties(struct redist_region *region, +void __iomem *ptr) { u64 typer = gic_read_typer(ptr + GICR_TYPER); gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); + gic_data.ppi_nr = 16; return 1; } -static void gic_update_vlpi_properties(void) +static void gic_update_rdist_properties(void) { - gic_iterate_rdists(__gic_update_vlpi_properties); + gic_data.ppi_nr = UINT_MAX; + gic_iterate_rdists(__gic_update_rdist_properties); + if (WARN_ON(gic_data.ppi_nr == UINT_MAX)) + gic_data.ppi_nr = 0; + pr_info("%d PPIs implemented\n", gic_data.ppi_nr); pr_info("%sVLPI support,
[tip: irq/core] irqchip/gic: Register the distributor's PA instead of its VA in fwnode
The following commit has been merged into the irq/core branch of tip: Commit-ID: 188a8471ef03718709bd785d3976f6cd72bb551d Gitweb: https://git.kernel.org/tip/188a8471ef03718709bd785d3976f6cd72bb551d Author:Marc Zyngier AuthorDate:Wed, 31 Jul 2019 16:13:42 +01:00 Committer: Marc Zyngier CommitterDate: Wed, 07 Aug 2019 14:24:33 +01:00 irqchip/gic: Register the distributor's PA instead of its VA in fwnode Do not expose the distributor's VA (it appears in debugfs). Instead, record the PA, which at least can be used to precisely identify the associated irqchip and domain. Acked-by: Thomas Gleixner Signed-off-by: Marc Zyngier --- 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 e45f45e..b6b8573 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1627,7 +1627,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, /* * Initialize GIC instance zero (no multi-GIC support). */ - domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base); + domain_handle = irq_domain_alloc_fwnode(>base_address); if (!domain_handle) { pr_err("Unable to allocate domain handle\n"); gic_teardown(gic);
[tip: irq/core] irqchip/gic-v3: Dynamically allocate PPI partition descriptors
The following commit has been merged into the irq/core branch of tip: Commit-ID: 52085d3f2028d853f8d6ce7ead2f8a504f6077fa Gitweb: https://git.kernel.org/tip/52085d3f2028d853f8d6ce7ead2f8a504f6077fa Author:Marc Zyngier AuthorDate:Thu, 18 Jul 2019 13:05:17 +01:00 Committer: Marc Zyngier CommitterDate: Tue, 20 Aug 2019 10:23:34 +01:00 irqchip/gic-v3: Dynamically allocate PPI partition descriptors Again, PPIs are becoming a variable set. Let's hack the PPI partition code to make the top-level array dynamically allocated. Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 869a805..f5dbdbf 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -52,7 +52,7 @@ struct gic_chip_data { u64 flags; boolhas_rss; unsigned intppi_nr; - struct partition_desc *ppi_descs[16]; + struct partition_desc **ppi_descs; }; static struct gic_chip_data gic_data __read_mostly; @@ -1354,7 +1354,8 @@ static int gic_irq_domain_select(struct irq_domain *d, * then we need to match the partition domain. */ if (fwspec->param_count >= 4 && - fwspec->param[0] == 1 && fwspec->param[3] != 0) + fwspec->param[0] == 1 && fwspec->param[3] != 0 && + gic_data.ppi_descs) return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]); return d == gic_data.domain; @@ -1375,6 +1376,9 @@ static int partition_domain_translate(struct irq_domain *d, struct device_node *np; int ret; + if (!gic_data.ppi_descs) + return -ENOMEM; + np = of_find_node_by_phandle(fwspec->param[3]); if (WARN_ON(!np)) return -EINVAL; @@ -1531,6 +1535,10 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) if (!parts_node) return; + gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL); + if (!gic_data.ppi_descs) + return; + nr_parts = of_get_child_count(parts_node); if (!nr_parts) @@ -1582,7 +1590,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) part_idx++; } - for (i = 0; i < 16; i++) { + for (i = 0; i < gic_data.ppi_nr; i++) { unsigned int irq; struct partition_desc *desc; struct irq_fwspec ppi_fwspec = {