summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-07-22 13:52:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-07-22 13:52:05 -0700
commitac7473a179d65f6c5de06a4b10d3b3d36df3f172 (patch)
treee22f4cecb139f8bb8bf760e6cd9f62a2b2df0e63
parenta362ade892e3e4de69296cddb1a23a1efe701428 (diff)
parentb7b377332b96a38bc98928d7ec2674c77a95fcb3 (diff)
downloadlinux-ac7473a179d65f6c5de06a4b10d3b3d36df3f172.tar.gz
linux-ac7473a179d65f6c5de06a4b10d3b3d36df3f172.tar.bz2
linux-ac7473a179d65f6c5de06a4b10d3b3d36df3f172.zip
Merge tag 'irq-core-2024-07-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull interrupt subsystem updates from Thomas Gleixner: "Core: - Provide a new mechanism to create interrupt domains. The existing interfaces have already too many parameters and it's a pain to expand any of this for new required functionality. The new function takes a pointer to a data structure as argument. The data structure combines all existing parameters and allows for easy extension. The first extension for this is to handle the instantiation of generic interrupt chips at the core level and to allow drivers to provide extra init/exit callbacks. This is necessary to do the full interrupt chip initialization before the new domain is published, so that concurrent usage sites won't see a half initialized interrupt domain. Similar problems exist on teardown. This has turned out to be a real problem due to the deferred and parallel probing which was added in recent years. Handling this at the core level allows to remove quite some accrued boilerplate code in existing drivers and avoids horrible workarounds at the driver level. - The usual small improvements all over the place Drivers: - Add support for LAN966x OIC and RZ/Five SoC - Split the STM ExtI driver into a microcontroller and a SMP version to allow building the latter as a module for multi-platform kernels - Enable MSI support for Armada 370XP on platforms which do not support IPIs - The usual small fixes and enhancements all over the place" * tag 'irq-core-2024-07-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (59 commits) irqdomain: Fix the kernel-doc and plug it into Documentation genirq: Set IRQF_COND_ONESHOT in request_irq() irqchip/imx-irqsteer: Handle runtime power management correctly irqchip/gic-v3: Pass #redistributor-regions to gic_of_setup_kvm_info() irqchip/bcm2835: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND irqchip/gic-v4: Make sure a VPE is locked when VMAPP is issued irqchip/gic-v4: Substitute vmovp_lock for a per-VM lock irqchip/gic-v4: Always configure affinity on VPE activation Revert "irqchip/dw-apb-ictl: Support building as module" Revert "Loongarch: Support loongarch avec" arm64: Kconfig: Allow build irq-stm32mp-exti driver as module ARM: stm32: Allow build irq-stm32mp-exti driver as module irqchip/stm32mp-exti: Allow building as module irqchip/stm32mp-exti: Rename internal symbols irqchip/stm32-exti: Split MCU and MPU code arm64: Kconfig: Select STM32MP_EXTI on STM32 platforms ARM: stm32: Use different EXTI driver on ARMv7m and ARMv7a irqchip/stm32-exti: Add CONFIG_STM32MP_EXTI irqchip/dw-apb-ictl: Support building as module irqchip/riscv-aplic: Simplify the initialization code ...
-rw-r--r--Documentation/core-api/genericirq.rst2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml55
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml17
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/arm/mach-stm32/Kconfig2
-rw-r--r--arch/arm64/Kconfig.platforms1
-rw-r--r--arch/um/drivers/virt-pci.c16
-rw-r--r--drivers/acpi/processor_core.c15
-rw-r--r--drivers/irqchip/Kconfig21
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c121
-rw-r--r--drivers/irqchip/irq-bcm2835.c4
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c52
-rw-r--r--drivers/irqchip/irq-gic-v3.c22
-rw-r--r--drivers/irqchip/irq-imx-irqsteer.c24
-rw-r--r--drivers/irqchip/irq-lan966x-oic.c278
-rw-r--r--drivers/irqchip/irq-meson-gpio.c1
-rw-r--r--drivers/irqchip/irq-mvebu-pic.c1
-rw-r--r--drivers/irqchip/irq-renesas-rzg2l.c150
-rw-r--r--drivers/irqchip/irq-riscv-aplic-main.c13
-rw-r--r--drivers/irqchip/irq-riscv-intc.c4
-rw-r--r--drivers/irqchip/irq-stm32-exti.c670
-rw-r--r--drivers/irqchip/irq-stm32mp-exti.c729
-rw-r--r--drivers/irqchip/irq-ts4800.c1
-rw-r--r--include/linux/acpi.h3
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/irq.h43
-rw-r--r--include/linux/irqchip/arm-gic-v4.h8
-rw-r--r--include/linux/irqdomain.h136
-rw-r--r--kernel/irq/debugfs.c10
-rw-r--r--kernel/irq/devres.c41
-rw-r--r--kernel/irq/generic-chip.c111
-rw-r--r--kernel/irq/internals.h10
-rw-r--r--kernel/irq/irqdomain.c287
-rw-r--r--kernel/irq/proc.c7
35 files changed, 1965 insertions, 900 deletions
diff --git a/Documentation/core-api/genericirq.rst b/Documentation/core-api/genericirq.rst
index 582bde9bf5a9..25f94dfd66fa 100644
--- a/Documentation/core-api/genericirq.rst
+++ b/Documentation/core-api/genericirq.rst
@@ -410,6 +410,8 @@ which are used in the generic IRQ layer.
.. kernel-doc:: include/linux/interrupt.h
:internal:
+.. kernel-doc:: include/linux/irqdomain.h
+
Public Functions Provided
=========================
diff --git a/Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml b/Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
new file mode 100644
index 000000000000..b2adc7174177
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/microchip,lan966x-oic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN966x outband interrupt controller
+
+maintainers:
+ - Herve Codina <herve.codina@bootlin.com>
+
+allOf:
+ - $ref: /schemas/interrupt-controller.yaml#
+
+description: |
+ The Microchip LAN966x outband interrupt controller (OIC) maps the internal
+ interrupt sources of the LAN966x device to an external interrupt.
+ When the LAN966x device is used as a PCI device, the external interrupt is
+ routed to the PCI interrupt.
+
+properties:
+ compatible:
+ const: microchip,lan966x-oic
+
+ '#interrupt-cells':
+ const: 2
+
+ interrupt-controller: true
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - '#interrupt-cells'
+ - interrupt-controller
+ - interrupts
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ interrupt-controller@e00c0120 {
+ compatible = "microchip,lan966x-oic";
+ reg = <0xe00c0120 0x190>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupts = <0>;
+ interrupt-parent = <&intc>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
index daef4ee06f4e..44b6ae5fc802 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
@@ -21,13 +21,16 @@ description: |
properties:
compatible:
- items:
- - enum:
- - renesas,r9a07g043u-irqc # RZ/G2UL
- - renesas,r9a07g044-irqc # RZ/G2{L,LC}
- - renesas,r9a07g054-irqc # RZ/V2L
- - renesas,r9a08g045-irqc # RZ/G3S
- - const: renesas,rzg2l-irqc
+ oneOf:
+ - items:
+ - enum:
+ - renesas,r9a07g043u-irqc # RZ/G2UL
+ - renesas,r9a07g044-irqc # RZ/G2{L,LC}
+ - renesas,r9a07g054-irqc # RZ/V2L
+ - renesas,r9a08g045-irqc # RZ/G3S
+ - const: renesas,rzg2l-irqc
+
+ - const: renesas,r9a07g043f-irqc # RZ/Five
'#interrupt-cells':
description: The first cell should contain a macro RZG2L_{NMI,IRQX} included in the
diff --git a/MAINTAINERS b/MAINTAINERS
index a0baccca11de..5579dac9aa64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14942,6 +14942,12 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/microchip/lan966x/*
+MICROCHIP LAN966X OIC DRIVER
+M: Herve Codina <herve.codina@bootlin.com>
+S: Maintained
+F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
+F: drivers/irqchip/irq-lan966x-oic.c
+
MICROCHIP LCDFB DRIVER
M: Nicolas Ferre <nicolas.ferre@microchip.com>
L: linux-fbdev@vger.kernel.org
diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig
index ae21a9f78f9c..630b992f32b1 100644
--- a/arch/arm/mach-stm32/Kconfig
+++ b/arch/arm/mach-stm32/Kconfig
@@ -11,7 +11,7 @@ menuconfig ARCH_STM32
select CLKSRC_STM32
select PINCTRL
select RESET_CONTROLLER
- select STM32_EXTI
+ select STM32_EXTI if ARM_SINGLE_ARMV7M
select STM32_FIREWALL
help
Support for STMicroelectronics STM32 processors.
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 56f440a06b21..6c6d11536b42 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -309,7 +309,6 @@ config ARCH_STM32
select GPIOLIB
select PINCTRL
select PINCTRL_STM32MP257
- select STM32_EXTI
select ARM_SMC_MBOX
select ARM_SCMI_PROTOCOL
select REGULATOR
diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c
index b16a75c94b8b..6100819681b5 100644
--- a/arch/um/drivers/virt-pci.c
+++ b/arch/um/drivers/virt-pci.c
@@ -988,6 +988,11 @@ static struct resource virt_platform_resource = {
static int __init um_pci_init(void)
{
+ struct irq_domain_info inner_domain_info = {
+ .size = MAX_MSI_VECTORS,
+ .hwirq_max = MAX_MSI_VECTORS,
+ .ops = &um_pci_inner_domain_ops,
+ };
int err, i;
WARN_ON(logic_iomem_add_region(&virt_cfgspace_resource,
@@ -1017,11 +1022,10 @@ static int __init um_pci_init(void)
goto free;
}
- um_pci_inner_domain = __irq_domain_add(um_pci_fwnode, MAX_MSI_VECTORS,
- MAX_MSI_VECTORS, 0,
- &um_pci_inner_domain_ops, NULL);
- if (!um_pci_inner_domain) {
- err = -ENOMEM;
+ inner_domain_info.fwnode = um_pci_fwnode;
+ um_pci_inner_domain = irq_domain_instantiate(&inner_domain_info);
+ if (IS_ERR(um_pci_inner_domain)) {
+ err = PTR_ERR(um_pci_inner_domain);
goto free;
}
@@ -1058,7 +1062,7 @@ static int __init um_pci_init(void)
goto free;
return 0;
free:
- if (um_pci_inner_domain)
+ if (!IS_ERR_OR_NULL(um_pci_inner_domain))
irq_domain_remove(um_pci_inner_domain);
if (um_pci_fwnode)
irq_domain_free_fwnode(um_pci_fwnode);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index b04b684f3190..9b6b71a2ffb5 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -216,6 +216,21 @@ phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
return rv;
}
+int __init acpi_get_madt_revision(void)
+{
+ struct acpi_table_header *madt = NULL;
+ int revision;
+
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, &madt)))
+ return -EINVAL;
+
+ revision = madt->revision;
+
+ acpi_put_table(madt);
+
+ return revision;
+}
+
static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 14464716bacb..344c484736af 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -169,6 +169,18 @@ config IXP4XX_IRQ
select IRQ_DOMAIN
select SPARSE_IRQ
+config LAN966X_OIC
+ tristate "Microchip LAN966x OIC Support"
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+ help
+ Enable support for the LAN966x Outbound Interrupt Controller.
+ This controller is present on the Microchip LAN966x PCI device and
+ maps the internal interrupts sources to PCIe interrupt.
+
+ To compile this driver as a module, choose M here: the module
+ will be called irq-lan966x-oic.
+
config MADERA_IRQ
tristate
@@ -392,6 +404,15 @@ config LS_SCFG_MSI
config PARTITION_PERCPU
bool
+config STM32MP_EXTI
+ tristate "STM32MP extended interrupts and event controller"
+ depends on (ARCH_STM32 && !ARM_SINGLE_ARMV7M) || COMPILE_TEST
+ default y
+ select IRQ_DOMAIN_HIERARCHY
+ select GENERIC_IRQ_CHIP
+ help
+ Support STM32MP EXTI (extended interrupts and event) controller.
+
config STM32_EXTI
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d9dc3d99aaa8..2df72b7b165b 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
+obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
@@ -104,6 +105,7 @@ obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
+obj-$(CONFIG_LAN966X_OIC) += irq-lan966x-oic.o
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 4b021a67bdfe..dce2b80bf439 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -13,6 +13,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -29,6 +30,7 @@
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/msi.h>
+#include <linux/types.h>
#include <asm/mach/arch.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
@@ -135,6 +137,7 @@
#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
+/* IPI and MSI interrupt definitions for IPI platforms */
#define IPI_DOORBELL_START (0)
#define IPI_DOORBELL_END (8)
#define IPI_DOORBELL_MASK 0xFF
@@ -143,6 +146,14 @@
#define PCI_MSI_DOORBELL_END (32)
#define PCI_MSI_DOORBELL_MASK 0xFFFF0000
+/* MSI interrupt definitions for non-IPI platforms */
+#define PCI_MSI_FULL_DOORBELL_START 0
+#define PCI_MSI_FULL_DOORBELL_NR 32
+#define PCI_MSI_FULL_DOORBELL_END 32
+#define PCI_MSI_FULL_DOORBELL_MASK GENMASK(31, 0)
+#define PCI_MSI_FULL_DOORBELL_SRC0_MASK GENMASK(15, 0)
+#define PCI_MSI_FULL_DOORBELL_SRC1_MASK GENMASK(31, 16)
+
static void __iomem *per_cpu_int_base;
static void __iomem *main_int_base;
static struct irq_domain *armada_370_xp_mpic_domain;
@@ -151,11 +162,46 @@ static int parent_irq;
#ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain;
static struct irq_domain *armada_370_xp_msi_inner_domain;
-static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
+static DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR);
static DEFINE_MUTEX(msi_used_lock);
static phys_addr_t msi_doorbell_addr;
#endif
+static inline bool is_ipi_available(void)
+{
+ /*
+ * We distinguish IPI availability in the IC by the IC not having a
+ * parent irq defined. If a parent irq is defined, there is a parent
+ * interrupt controller (e.g. GIC) that takes care of inter-processor
+ * interrupts.
+ */
+ return parent_irq <= 0;
+}
+
+static inline u32 msi_doorbell_mask(void)
+{
+ return is_ipi_available() ? PCI_MSI_DOORBELL_MASK :
+ PCI_MSI_FULL_DOORBELL_MASK;
+}
+
+static inline unsigned int msi_doorbell_start(void)
+{
+ return is_ipi_available() ? PCI_MSI_DOORBELL_START :
+ PCI_MSI_FULL_DOORBELL_START;
+}
+
+static inline unsigned int msi_doorbell_size(void)
+{
+ return is_ipi_available() ? PCI_MSI_DOORBELL_NR :
+ PCI_MSI_FULL_DOORBELL_NR;
+}
+
+static inline unsigned int msi_doorbell_end(void)
+{
+ return is_ipi_available() ? PCI_MSI_DOORBELL_END :
+ PCI_MSI_FULL_DOORBELL_END;
+}
+
static inline bool is_percpu_irq(irq_hw_number_t irq)
{
if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS)
@@ -213,7 +259,7 @@ static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg
msg->address_lo = lower_32_bits(msi_doorbell_addr);
msg->address_hi = upper_32_bits(msi_doorbell_addr);
- msg->data = BIT(cpu + 8) | (data->hwirq + PCI_MSI_DOORBELL_START);
+ msg->data = BIT(cpu + 8) | (data->hwirq + msi_doorbell_start());
}
static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
@@ -246,7 +292,7 @@ static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
int hwirq, i;
mutex_lock(&msi_used_lock);
- hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR,
+ hwirq = bitmap_find_free_region(msi_used, msi_doorbell_size(),
order_base_2(nr_irqs));
mutex_unlock(&msi_used_lock);
@@ -283,9 +329,10 @@ static void armada_370_xp_msi_reenable_percpu(void)
u32 reg;
/* Enable MSI doorbell mask and combined cpu local interrupt */
- reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
- | PCI_MSI_DOORBELL_MASK;
+ reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+ reg |= msi_doorbell_mask();
writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+
/* Unmask local doorbell interrupt */
writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
}
@@ -297,7 +344,7 @@ static int armada_370_xp_msi_init(struct device_node *node,
ARMADA_370_XP_SW_TRIG_INT_OFFS;
armada_370_xp_msi_inner_domain =
- irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
+ irq_domain_add_linear(NULL, msi_doorbell_size(),
&armada_370_xp_msi_domain_ops, NULL);
if (!armada_370_xp_msi_inner_domain)
return -ENOMEM;
@@ -313,6 +360,10 @@ static int armada_370_xp_msi_init(struct device_node *node,
armada_370_xp_msi_reenable_percpu();
+ /* Unmask low 16 MSI irqs on non-IPI platforms */
+ if (!is_ipi_available())
+ writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+
return 0;
}
#else
@@ -461,24 +512,18 @@ static __init void armada_xp_ipi_init(struct device_node *node)
set_smp_ipi_range(base_ipi, IPI_DOORBELL_END);
}
-static DEFINE_RAW_SPINLOCK(irq_controller_lock);
-
static int armada_xp_set_affinity(struct irq_data *d,
const struct cpumask *mask_val, bool force)
{
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- unsigned long reg, mask;
int cpu;
/* Select a single core from the affinity mask which is online */
cpu = cpumask_any_and(mask_val, cpu_online_mask);
- mask = 1UL << cpu_logical_map(cpu);
- raw_spin_lock(&irq_controller_lock);
- reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
- reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
- writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
- raw_spin_unlock(&irq_controller_lock);
+ atomic_io_modify(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq),
+ ARMADA_370_XP_INT_SOURCE_CPU_MASK,
+ BIT(cpu_logical_map(cpu)));
irq_data_update_effective_affinity(d, cpumask_of(cpu));
@@ -496,6 +541,9 @@ static void armada_xp_mpic_smp_cpu_init(void)
for (i = 0; i < nr_irqs; i++)
writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
+ if (!is_ipi_available())
+ return;
+
/* Disable all IPIs */
writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
@@ -527,7 +575,8 @@ static void armada_xp_mpic_reenable_percpu(void)
armada_370_xp_irq_unmask(data);
}
- ipi_resume();
+ if (is_ipi_available())
+ ipi_resume();
armada_370_xp_msi_reenable_percpu();
}
@@ -566,6 +615,10 @@ static struct irq_chip armada_370_xp_irq_chip = {
static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
unsigned int virq, irq_hw_number_t hw)
{
+ /* IRQs 0 and 1 cannot be mapped, they are handled internally */
+ if (hw <= 1)
+ return -EINVAL;
+
armada_370_xp_irq_mask(irq_get_irq_data(virq));
if (!is_percpu_irq(hw))
writel(hw, per_cpu_int_base +
@@ -599,20 +652,20 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
u32 msimask, msinr;
msimask = readl_relaxed(per_cpu_int_base +
- ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
- & PCI_MSI_DOORBELL_MASK;
+ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
+ msimask &= msi_doorbell_mask();
writel(~msimask, per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
- for (msinr = PCI_MSI_DOORBELL_START;
- msinr < PCI_MSI_DOORBELL_END; msinr++) {
+ for (msinr = msi_doorbell_start();
+ msinr < msi_doorbell_end(); msinr++) {
unsigned int irq;
if (!(msimask & BIT(msinr)))
continue;
- irq = msinr - PCI_MSI_DOORBELL_START;
+ irq = msinr - msi_doorbell_start();
generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq);
}
@@ -641,7 +694,7 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)))
continue;
- if (irqn == 1) {
+ if (irqn == 0 || irqn == 1) {
armada_370_xp_handle_msi_irq(NULL, true);
continue;
}
@@ -702,6 +755,7 @@ static int armada_370_xp_mpic_suspend(void)
static void armada_370_xp_mpic_resume(void)
{
+ bool src0, src1;
int nirqs;
irq_hw_number_t irq;
@@ -741,12 +795,22 @@ static void armada_370_xp_mpic_resume(void)
/* Reconfigure doorbells for IPIs and MSIs */
writel(doorbell_mask_reg,
per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
- if (doorbell_mask_reg & IPI_DOORBELL_MASK)
+
+ if (is_ipi_available()) {
+ src0 = doorbell_mask_reg & IPI_DOORBELL_MASK;
+ src1 = doorbell_mask_reg & PCI_MSI_DOORBELL_MASK;
+ } else {
+ src0 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC0_MASK;
+ src1 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC1_MASK;
+ }
+
+ if (src0)
writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
- if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
+ if (src1)
writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
- ipi_resume();
+ if (is_ipi_available())
+ ipi_resume();
}
static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
@@ -791,13 +855,18 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
BUG_ON(!armada_370_xp_mpic_domain);
irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED);
+ /*
+ * Initialize parent_irq before calling any other functions, since it is
+ * used to distinguish between IPI and non-IPI platforms.
+ */
+ parent_irq = irq_of_parse_and_map(node, 0);
+
/* Setup for the boot CPU */
armada_xp_mpic_perf_init();
armada_xp_mpic_smp_cpu_init();
armada_370_xp_msi_init(node, main_int_res.start);
- parent_irq = irq_of_parse_and_map(node, 0);
if (parent_irq <= 0) {
irq_set_default_host(armada_370_xp_mpic_domain);
set_handle_irq(armada_370_xp_handle_irq);
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index e94e2882286c..6c20604c2242 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -102,7 +102,9 @@ static void armctrl_unmask_irq(struct irq_data *d)
static struct irq_chip armctrl_chip = {
.name = "ARMCTRL-level",
.irq_mask = armctrl_mask_irq,
- .irq_unmask = armctrl_unmask_irq
+ .irq_unmask = armctrl_unmask_irq,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SKIP_SET_WAKE,
};
static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 42e63272154e..105d116b4ea0 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1317,7 +1317,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
{
struct its_cmd_desc desc = {};
struct its_node *its;
- unsigned long flags;
int col_id = vpe->col_idx;
desc.its_vmovp_cmd.vpe = vpe;
@@ -1330,6 +1329,12 @@ static void its_send_vmovp(struct its_vpe *vpe)
}
/*
+ * Protect against concurrent updates of the mapping state on
+ * individual VMs.
+ */
+ guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock);
+
+ /*
* Yet another marvel of the architecture. If using the
* its_list "feature", we need to make sure that all ITSs
* receive all VMOVP commands in the same order. The only way
@@ -1337,8 +1342,7 @@ static void its_send_vmovp(struct its_vpe *vpe)
*
* Wall <-- Head.
*/
- raw_spin_lock_irqsave(&vmovp_lock, flags);
-
+ guard(raw_spinlock)(&vmovp_lock);
desc.its_vmovp_cmd.seq_num = vmovp_seq_num++;
desc.its_vmovp_cmd.its_list = get_its_list(vpe->its_vm);
@@ -1353,8 +1357,6 @@ static void its_send_vmovp(struct its_vpe *vpe)
desc.its_vmovp_cmd.col = &its->collections[col_id];
its_send_single_vcommand(its, its_build_vmovp_cmd, &desc);
}
-
- raw_spin_unlock_irqrestore(&vmovp_lock, flags);
}
static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)
@@ -1791,12 +1793,10 @@ static bool gic_requires_eager_mapping(void)
static void its_map_vm(struct its_node *its, struct its_vm *vm)
{
- unsigned long flags;
-
if (gic_requires_eager_mapping())
return;
- raw_spin_lock_irqsave(&vmovp_lock, flags);
+ guard(raw_spinlock_irqsave)(&vm->vmapp_lock);
/*
* If the VM wasn't mapped yet, iterate over the vpes and get
@@ -1809,37 +1809,31 @@ static void its_map_vm(struct its_node *its, struct its_vm *vm)
for (i = 0; i < vm->nr_vpes; i++) {
struct its_vpe *vpe = vm->vpes[i];
- struct irq_data *d = irq_get_irq_data(vpe->irq);
- /* Map the VPE to the first possible CPU */
- vpe->col_idx = cpumask_first(cpu_online_mask);
- its_send_vmapp(its, vpe, true);
+ scoped_guard(raw_spinlock, &vpe->vpe_lock)
+ its_send_vmapp(its, vpe, true);
+
its_send_vinvall(its, vpe);
- irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx));
}
}
-
- raw_spin_unlock_irqrestore(&vmovp_lock, flags);
}
static void its_unmap_vm(struct its_node *its, struct its_vm *vm)
{
- unsigned long flags;
-
/* Not using the ITS list? Everything is always mapped. */
if (gic_requires_eager_mapping())
return;
- raw_spin_lock_irqsave(&vmovp_lock, flags);
+ guard(raw_spinlock_irqsave)(&vm->vmapp_lock);
if (!--vm->vlpi_count[its->list_nr]) {
int i;
- for (i = 0; i < vm->nr_vpes; i++)
+ for (i = 0; i < vm->nr_vpes; i++) {
+ guard(raw_spinlock)(&vm->vpes[i]->vpe_lock);
its_send_vmapp(its, vm->vpes[i], false);
+ }
}
-
- raw_spin_unlock_irqrestore(&vmovp_lock, flags);
}
static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
@@ -3926,6 +3920,8 @@ static void its_vpe_invall(struct its_vpe *vpe)
{
struct its_node *its;
+ guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock);
+
list_for_each_entry(its, &its_nodes, entry) {
if (!is_v4(its))
continue;
@@ -4531,6 +4527,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
vm->db_lpi_base = base;
vm->nr_db_lpis = nr_ids;
vm->vprop_page = vprop_page;
+ raw_spin_lock_init(&vm->vmapp_lock);
if (gic_rdists->has_rvpeid)
irqchip = &its_vpe_4_1_irq_chip;
@@ -4562,6 +4559,10 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
struct its_node *its;
+ /* Map the VPE to the first possible CPU */
+ vpe->col_idx = cpumask_first(cpu_online_mask);