summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 14:01:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 14:01:13 -0400
commit2a1ccd31420a7b1acd6ca37b2bec2d723aa093e4 (patch)
tree43946f0c4afc7dce86fc055df48d661f8ed3999c
parente0e86b111bca6bbf746c03ec5cf3e6a61fa3f8e9 (diff)
parent3a1d24ca9573fbc74a3d32c972c333b161e0e9dc (diff)
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner: "The irq departement provides the usual mixed bag: Core: - Further improvements to the irq timings code which aims to predict the next interrupt for power state selection to achieve better latency/power balance - Add interrupt statistics to the core NMI handlers - The usual small fixes and cleanups Drivers: - Support for Renesas RZ/A1, Annapurna Labs FIC, Meson-G12A SoC and Amazon Gravition AMR/GIC interrupt controllers. - Rework of the Renesas INTC controller driver - ACPI support for Socionext SoCs - Enhancements to the CSKY interrupt controller - The usual small fixes and cleanups" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (39 commits) irq/irqdomain: Fix comment typo genirq: Update irq stats from NMI handlers irqchip/gic-pm: Remove PM_CLK dependency irqchip/al-fic: Introduce Amazon's Annapurna Labs Fabric Interrupt Controller Driver dt-bindings: interrupt-controller: Add Amazon's Annapurna Labs FIC softirq: Use __this_cpu_write() in takeover_tasklets() irqchip/mbigen: Stop printing kernel addresses irqchip/gic: Add dependency for ARM_GIC_MAX_NR genirq/affinity: Remove unused argument from [__]irq_build_affinity_masks() genirq/timings: Add selftest for next event computation genirq/timings: Add selftest for irqs circular buffer genirq/timings: Add selftest for circular array genirq/timings: Encapsulate storing function genirq/timings: Encapsulate timings push genirq/timings: Optimize the period detection speed genirq/timings: Fix timings buffer inspection genirq/timings: Fix next event index function irqchip/qcom: Use struct_size() in devm_kzalloc() irqchip/irq-csky-mpintc: Remove unnecessary loop in interrupt handler dt-bindings: interrupt-controller: Update csky mpintc ...
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt29
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt1
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/csky,mpintc.txt20
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,rza1-irqc.txt43
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/acpi/irq.c26
-rw-r--r--drivers/gpio/gpio-mb86s7x.c51
-rw-r--r--drivers/irqchip/Kconfig32
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-al-fic.c278
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c86
-rw-r--r--drivers/irqchip/irq-gic-v2m.c85
-rw-r--r--drivers/irqchip/irq-gic-v3.c3
-rw-r--r--drivers/irqchip/irq-mbigen.c3
-rw-r--r--drivers/irqchip/irq-meson-gpio.c1
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c3
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c91
-rw-r--r--drivers/irqchip/irq-renesas-rza1.c283
-rw-r--r--drivers/irqchip/irq-sni-exiu.c142
-rw-r--r--drivers/irqchip/qcom-irq-combiner.c5
-rw-r--r--include/linux/acpi.h7
-rw-r--r--include/linux/irqchip/arm-gic-common.h5
-rw-r--r--include/linux/irqchip/arm-gic.h3
-rw-r--r--kernel/irq/Makefile3
-rw-r--r--kernel/irq/affinity.c12
-rw-r--r--kernel/irq/chip.c4
-rw-r--r--kernel/irq/internals.h21
-rw-r--r--kernel/irq/irqdesc.c8
-rw-r--r--kernel/irq/irqdomain.c4
-rw-r--r--kernel/irq/timings.c453
-rw-r--r--kernel/softirq.c2
-rw-r--r--lib/Kconfig.debug8
32 files changed, 1528 insertions, 192 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt b/Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
new file mode 100644
index 000000000000..4e82fd575cec
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
@@ -0,0 +1,29 @@
1Amazon's Annapurna Labs Fabric Interrupt Controller
2
3Required properties:
4
5- compatible: should be "amazon,al-fic"
6- reg: physical base address and size of the registers
7- interrupt-controller: identifies the node as an interrupt controller
8- #interrupt-cells: must be 2.
9 First cell defines the index of the interrupt within the controller.
10 Second cell is used to specify the trigger type and must be one of the
11 following:
12 - bits[3:0] trigger type and level flags
13 1 = low-to-high edge triggered
14 4 = active high level-sensitive
15- interrupt-parent: specifies the parent interrupt controller.
16- interrupts: describes which input line in the interrupt parent, this
17 fic's output is connected to. This field property depends on the parent's
18 binding
19
20Example:
21
22amazon_fic: interrupt-controller@0xfd8a8500 {
23 compatible = "amazon,al-fic";
24 interrupt-controller;
25 #interrupt-cells = <2>;
26 reg = <0x0 0xfd8a8500 0x0 0x1000>;
27 interrupt-parent = <&gic>;
28 interrupts = <GIC_SPI 0x0 IRQ_TYPE_LEVEL_HIGH>;
29};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
index 1502a51548bb..7d531d5fff29 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
@@ -15,6 +15,7 @@ Required properties:
15 "amlogic,meson-gxbb-gpio-intc" for GXBB SoCs (S905) or 15 "amlogic,meson-gxbb-gpio-intc" for GXBB SoCs (S905) or
16 "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912) 16 "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912)
17 "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X) 17 "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X)
18 "amlogic,meson-g12a-gpio-intc" for G12A SoCs (S905D2, S905X2, S905Y2)
18- reg : Specifies base physical address and size of the registers. 19- reg : Specifies base physical address and size of the registers.
19- interrupt-controller : Identifies the node as an interrupt controller. 20- interrupt-controller : Identifies the node as an interrupt controller.
20- #interrupt-cells : Specifies the number of cells needed to encode an 21- #interrupt-cells : Specifies the number of cells needed to encode an
diff --git a/Documentation/devicetree/bindings/interrupt-controller/csky,mpintc.txt b/Documentation/devicetree/bindings/interrupt-controller/csky,mpintc.txt
index ab921f1698fb..e13405355166 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/csky,mpintc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/csky,mpintc.txt
@@ -6,11 +6,16 @@ C-SKY Multi-processors Interrupt Controller is designed for ck807/ck810/ck860
6SMP soc, and it also could be used in non-SMP system. 6SMP soc, and it also could be used in non-SMP system.
7 7
8Interrupt number definition: 8Interrupt number definition:
9
10 0-15 : software irq, and we use 15 as our IPI_IRQ. 9 0-15 : software irq, and we use 15 as our IPI_IRQ.
11 16-31 : private irq, and we use 16 as the co-processor timer. 10 16-31 : private irq, and we use 16 as the co-processor timer.
12 31-1024: common irq for soc ip. 11 31-1024: common irq for soc ip.
13 12
13Interrupt triger mode: (Defined in dt-bindings/interrupt-controller/irq.h)
14 IRQ_TYPE_LEVEL_HIGH (default)
15 IRQ_TYPE_LEVEL_LOW
16 IRQ_TYPE_EDGE_RISING
17 IRQ_TYPE_EDGE_FALLING
18
14============================= 19=============================
15intc node bindings definition 20intc node bindings definition
16============================= 21=============================
@@ -26,15 +31,22 @@ intc node bindings definition
26 - #interrupt-cells 31 - #interrupt-cells
27 Usage: required 32 Usage: required
28 Value type: <u32> 33 Value type: <u32>
29 Definition: must be <1> 34 Definition: <2>
30 - interrupt-controller: 35 - interrupt-controller:
31 Usage: required 36 Usage: required
32 37
33Examples: 38Examples: ("interrupts = <irq_num IRQ_TYPE_XXX>")
34--------- 39---------
40#include <dt-bindings/interrupt-controller/irq.h>
35 41
36 intc: interrupt-controller { 42 intc: interrupt-controller {
37 compatible = "csky,mpintc"; 43 compatible = "csky,mpintc";
38 #interrupt-cells = <1>; 44 #interrupt-cells = <2>;
39 interrupt-controller; 45 interrupt-controller;
40 }; 46 };
47
48 device: device-example {
49 ...
50 interrupts = <34 IRQ_TYPE_EDGE_RISING>;
51 interrupt-parent = <&intc>;
52 };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rza1-irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,rza1-irqc.txt
new file mode 100644
index 000000000000..727b7e4cd6e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rza1-irqc.txt
@@ -0,0 +1,43 @@
1DT bindings for the Renesas RZ/A1 Interrupt Controller
2
3The RZ/A1 Interrupt Controller is a front-end for the GIC found on Renesas
4RZ/A1 and RZ/A2 SoCs:
5 - IRQ sense select for 8 external interrupts, 1:1-mapped to 8 GIC SPI
6 interrupts,
7 - NMI edge select.
8
9Required properties:
10 - compatible: Must be "renesas,<soctype>-irqc", and "renesas,rza1-irqc" as
11 fallback.
12 Examples with soctypes are:
13 - "renesas,r7s72100-irqc" (RZ/A1H)
14 - "renesas,r7s9210-irqc" (RZ/A2M)
15 - #interrupt-cells: Must be 2 (an interrupt index and flags, as defined
16 in interrupts.txt in this directory)
17 - #address-cells: Must be zero
18 - interrupt-controller: Marks the device as an interrupt controller
19 - reg: Base address and length of the memory resource used by the interrupt
20 controller
21 - interrupt-map: Specifies the mapping from external interrupts to GIC
22 interrupts
23 - interrupt-map-mask: Must be <7 0>
24
25Example:
26
27 irqc: interrupt-controller@fcfef800 {
28 compatible = "renesas,r7s72100-irqc", "renesas,rza1-irqc";
29 #interrupt-cells = <2>;
30 #address-cells = <0>;
31 interrupt-controller;
32 reg = <0xfcfef800 0x6>;
33 interrupt-map =
34 <0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
35 <1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
36 <2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
37 <3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
38 <4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
39 <5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
40 <6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
41 <7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
42 interrupt-map-mask = <7 0>;
43 };
diff --git a/MAINTAINERS b/MAINTAINERS
index badf7e89b072..bcb37428522a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1306,6 +1306,12 @@ S: Maintained
1306F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt 1306F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt
1307F: drivers/irqchip/irq-vic.c 1307F: drivers/irqchip/irq-vic.c
1308 1308
1309AMAZON ANNAPURNA LABS FIC DRIVER
1310M: Talel Shenhar <talel@amazon.com>
1311S: Maintained
1312F: Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
1313F: drivers/irqchip/irq-al-fic.c
1314
1309ARM SMMU DRIVERS 1315ARM SMMU DRIVERS
1310M: Will Deacon <will@kernel.org> 1316M: Will Deacon <will@kernel.org>
1311R: Robin Murphy <robin.murphy@arm.com> 1317R: Robin Murphy <robin.murphy@arm.com>
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index 89690a471360..e209081d644b 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -292,3 +292,29 @@ void __init acpi_set_irq_model(enum acpi_irq_model_id model,
292 acpi_irq_model = model; 292 acpi_irq_model = model;
293 acpi_gsi_domain_id = fwnode; 293 acpi_gsi_domain_id = fwnode;
294} 294}
295
296/**
297 * acpi_irq_create_hierarchy - Create a hierarchical IRQ domain with the default
298 * GSI domain as its parent.
299 * @flags: Irq domain flags associated with the domain
300 * @size: Size of the domain.
301 * @fwnode: Optional fwnode of the interrupt controller
302 * @ops: Pointer to the interrupt domain callbacks
303 * @host_data: Controller private data pointer
304 */
305struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
306 unsigned int size,
307 struct fwnode_handle *fwnode,
308 const struct irq_domain_ops *ops,
309 void *host_data)
310{
311 struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id,
312 DOMAIN_BUS_ANY);
313
314 if (!d)
315 return NULL;
316
317 return irq_domain_create_hierarchy(d, flags, size, fwnode, ops,
318 host_data);
319}
320EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index 9bfff171f9fe..8f466993cd24 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 2015 Linaro Ltd. 6 * Copyright (C) 2015 Linaro Ltd.
7 */ 7 */
8 8
9#include <linux/acpi.h>
9#include <linux/io.h> 10#include <linux/io.h>
10#include <linux/init.h> 11#include <linux/init.h>
11#include <linux/clk.h> 12#include <linux/clk.h>
@@ -19,6 +20,8 @@
19#include <linux/spinlock.h> 20#include <linux/spinlock.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
21 22
23#include "gpiolib.h"
24
22/* 25/*
23 * Only first 8bits of a register correspond to each pin, 26 * Only first 8bits of a register correspond to each pin,
24 * so there are 4 registers for 32 pins. 27 * so there are 4 registers for 32 pins.
@@ -135,6 +138,20 @@ static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
135 spin_unlock_irqrestore(&gchip->lock, flags); 138 spin_unlock_irqrestore(&gchip->lock, flags);
136} 139}
137 140
141static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
142{
143 int irq, index;
144
145 for (index = 0;; index++) {
146 irq = platform_get_irq(to_platform_device(gc->parent), index);
147 if (irq <= 0)
148 break;
149 if (irq_get_irq_data(irq)->hwirq == offset)
150 return irq;
151 }
152 return -EINVAL;
153}
154
138static int mb86s70_gpio_probe(struct platform_device *pdev) 155static int mb86s70_gpio_probe(struct platform_device *pdev)
139{ 156{
140 struct mb86s70_gpio_chip *gchip; 157 struct mb86s70_gpio_chip *gchip;
@@ -150,13 +167,15 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
150 if (IS_ERR(gchip->base)) 167 if (IS_ERR(gchip->base))
151 return PTR_ERR(gchip->base); 168 return PTR_ERR(gchip->base);
152 169
153 gchip->clk = devm_clk_get(&pdev->dev, NULL); 170 if (!has_acpi_companion(&pdev->dev)) {
154 if (IS_ERR(gchip->clk)) 171 gchip->clk = devm_clk_get(&pdev->dev, NULL);
155 return PTR_ERR(gchip->clk); 172 if (IS_ERR(gchip->clk))
173 return PTR_ERR(gchip->clk);
156 174
157 ret = clk_prepare_enable(gchip->clk); 175 ret = clk_prepare_enable(gchip->clk);
158 if (ret) 176 if (ret)
159 return ret; 177 return ret;
178 }
160 179
161 spin_lock_init(&gchip->lock); 180 spin_lock_init(&gchip->lock);
162 181
@@ -172,19 +191,28 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
172 gchip->gc.parent = &pdev->dev; 191 gchip->gc.parent = &pdev->dev;
173 gchip->gc.base = -1; 192 gchip->gc.base = -1;
174 193
194 if (has_acpi_companion(&pdev->dev))
195 gchip->gc.to_irq = mb86s70_gpio_to_irq;
196
175 ret = gpiochip_add_data(&gchip->gc, gchip); 197 ret = gpiochip_add_data(&gchip->gc, gchip);
176 if (ret) { 198 if (ret) {
177 dev_err(&pdev->dev, "couldn't register gpio driver\n"); 199 dev_err(&pdev->dev, "couldn't register gpio driver\n");
178 clk_disable_unprepare(gchip->clk); 200 clk_disable_unprepare(gchip->clk);
201 return ret;
179 } 202 }
180 203
181 return ret; 204 if (has_acpi_companion(&pdev->dev))
205 acpi_gpiochip_request_interrupts(&gchip->gc);
206
207 return 0;
182} 208}
183 209
184static int mb86s70_gpio_remove(struct platform_device *pdev) 210static int mb86s70_gpio_remove(struct platform_device *pdev)
185{ 211{
186 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); 212 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
187 213
214 if (has_acpi_companion(&pdev->dev))
215 acpi_gpiochip_free_interrupts(&gchip->gc);
188 gpiochip_remove(&gchip->gc); 216 gpiochip_remove(&gchip->gc);
189 clk_disable_unprepare(gchip->clk); 217 clk_disable_unprepare(gchip->clk);
190 218
@@ -197,10 +225,19 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = {
197}; 225};
198MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); 226MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
199 227
228#ifdef CONFIG_ACPI
229static const struct acpi_device_id mb86s70_gpio_acpi_ids[] = {
230 { "SCX0007" },
231 { /* sentinel */ }
232};
233MODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids);
234#endif
235
200static struct platform_driver mb86s70_gpio_driver = { 236static struct platform_driver mb86s70_gpio_driver = {
201 .driver = { 237 .driver = {
202 .name = "mb86s70-gpio", 238 .name = "mb86s70-gpio",
203 .of_match_table = mb86s70_gpio_dt_ids, 239 .of_match_table = mb86s70_gpio_dt_ids,
240 .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
204 }, 241 },
205 .probe = mb86s70_gpio_probe, 242 .probe = mb86s70_gpio_probe,
206 .remove = mb86s70_gpio_remove, 243 .remove = mb86s70_gpio_remove,
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 659c5e0fb835..80e10f4e213a 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -15,10 +15,10 @@ config ARM_GIC_PM
15 bool 15 bool
16 depends on PM 16 depends on PM
17 select ARM_GIC 17 select ARM_GIC
18 select PM_CLK
19 18
20config ARM_GIC_MAX_NR 19config ARM_GIC_MAX_NR
21 int 20 int
21 depends on ARM_GIC
22 default 2 if ARCH_REALVIEW 22 default 2 if ARCH_REALVIEW
23 default 1 23 default 1
24 24
@@ -87,6 +87,14 @@ config ALPINE_MSI
87 select PCI_MSI 87 select PCI_MSI
88 select GENERIC_IRQ_CHIP 88 select GENERIC_IRQ_CHIP
89 89
90config AL_FIC
91 bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
92 depends on OF || COMPILE_TEST
93 select GENERIC_IRQ_CHIP
94 select IRQ_DOMAIN
95 help
96 Support Amazon's Annapurna Labs Fabric Interrupt Controller.
97
90config ATMEL_AIC_IRQ 98config ATMEL_AIC_IRQ
91 bool 99 bool
92 select GENERIC_IRQ_CHIP 100 select GENERIC_IRQ_CHIP
@@ -217,13 +225,26 @@ config RDA_INTC
217 select IRQ_DOMAIN 225 select IRQ_DOMAIN
218 226
219config RENESAS_INTC_IRQPIN 227config RENESAS_INTC_IRQPIN
220 bool 228 bool "Renesas INTC External IRQ Pin Support" if COMPILE_TEST
221 select IRQ_DOMAIN 229 select IRQ_DOMAIN
230 help
231 Enable support for the Renesas Interrupt Controller for external
232 interrupt pins, as found on SH/R-Mobile and R-Car Gen1 SoCs.
222 233
223config RENESAS_IRQC 234config RENESAS_IRQC
224 bool 235 bool "Renesas R-Mobile APE6 and R-Car IRQC support" if COMPILE_TEST
225 select GENERIC_IRQ_CHIP 236 select GENERIC_IRQ_CHIP
226 select IRQ_DOMAIN 237 select IRQ_DOMAIN
238 help
239 Enable support for the Renesas Interrupt Controller for external
240 devices, as found on R-Mobile APE6, R-Car Gen2, and R-Car Gen3 SoCs.
241
242config RENESAS_RZA1_IRQC
243 bool "Renesas RZ/A1 IRQC support" if COMPILE_TEST
244 select IRQ_DOMAIN_HIERARCHY
245 help
246 Enable support for the Renesas RZ/A1 Interrupt Controller, to use up
247 to 8 external interrupts with configurable sense select.
227 248
228config ST_IRQCHIP 249config ST_IRQCHIP
229 bool 250 bool
@@ -299,8 +320,11 @@ config RENESAS_H8300H_INTC
299 select IRQ_DOMAIN 320 select IRQ_DOMAIN
300 321
301config RENESAS_H8S_INTC 322config RENESAS_H8S_INTC
302 bool 323 bool "Renesas H8S Interrupt Controller Support" if COMPILE_TEST
303 select IRQ_DOMAIN 324 select IRQ_DOMAIN
325 help
326 Enable support for the Renesas H8/300 Interrupt Controller, as found
327 on Renesas H8S SoCs.
304 328
305config IMX_GPCV2 329config IMX_GPCV2
306 bool 330 bool
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 606a003a0000..8d0fcec6ab23 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,6 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2obj-$(CONFIG_IRQCHIP) += irqchip.o 2obj-$(CONFIG_IRQCHIP) += irqchip.o
3 3
4obj-$(CONFIG_AL_FIC) += irq-al-fic.o
4obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o 5obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
5obj-$(CONFIG_ATH79) += irq-ath79-cpu.o 6obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
6obj-$(CONFIG_ATH79) += irq-ath79-misc.o 7obj-$(CONFIG_ATH79) += irq-ath79-misc.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o
49obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o 50obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o
50obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o 51obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
51obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o 52obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
53obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o
52obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o 54obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
53obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o 55obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
54obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o 56obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
new file mode 100644
index 000000000000..1a57cee3efab
--- /dev/null
+++ b/drivers/irqchip/irq-al-fic.c
@@ -0,0 +1,278 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 */
5
6#include <linux/bitfield.h>
7#include <linux/irq.h>
8#include <linux/irqchip.h>
9#include <linux/irqchip/chained_irq.h>
10#include <linux/irqdomain.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/of_address.h>
14#include <linux/of_irq.h>
15
16/* FIC Registers */
17#define AL_FIC_CAUSE 0x00
18#define AL_FIC_MASK 0x10
19#define AL_FIC_CONTROL 0x28
20
21#define CONTROL_TRIGGER_RISING BIT(3)
22#define CONTROL_MASK_MSI_X BIT(5)
23
24#define NR_FIC_IRQS 32
25
26MODULE_AUTHOR("Talel Shenhar");
27MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver");
28MODULE_LICENSE("GPL v2");
29
30enum al_fic_state {
31 AL_FIC_UNCONFIGURED = 0,
32 AL_FIC_CONFIGURED_LEVEL,
33 AL_FIC_CONFIGURED_RISING_EDGE,
34};
35
36struct al_fic {
37 void __iomem *base;
38 struct irq_domain *domain;
39 const char *name;
40 unsigned int parent_irq;
41 enum al_fic_state state;
42};
43
44static void al_fic_set_trigger(struct al_fic *fic,
45 struct irq_chip_generic *gc,
46 enum al_fic_state new_state)
47{
48 irq_flow_handler_t handler;
49 u32 control = readl_relaxed(fic->base + AL_FIC_CONTROL);
50
51 if (new_state == AL_FIC_CONFIGURED_LEVEL) {
52 handler = handle_level_irq;
53 control &= ~CONTROL_TRIGGER_RISING;
54 } else {
55 handler = handle_edge_irq;
56 control |= CONTROL_TRIGGER_RISING;
57 }
58 gc->chip_types->handler = handler;
59 fic->state = new_state;
60 writel_relaxed(control, fic->base + AL_FIC_CONTROL);
61}
62
63static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
64{
65 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
66 struct al_fic *fic = gc->private;
67 enum al_fic_state new_state;
68 int ret = 0;
69
70 irq_gc_lock(gc);
71
72 if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) &&
73 ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) {
74 pr_debug("fic doesn't support flow type %d\n", flow_type);
75 ret = -EINVAL;
76 goto err;
77 }
78
79 new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ?
80 AL_FIC_CONFIGURED_LEVEL : AL_FIC_CONFIGURED_RISING_EDGE;
81
82 /*
83 * A given FIC instance can be either all level or all edge triggered.
84 * This is generally fixed depending on what pieces of HW it's wired up
85 * to.
86 *
87 * We configure it based on the sensitivity of the first source
88 * being setup, and reject any subsequent attempt at configuring it in a
89 * different way.
90 */
91 if (fic->state == AL_FIC_UNCONFIGURED) {
92 al_fic_set_trigger(fic, gc, new_state);
93 } else if (fic->state != new_state) {
94 pr_debug("fic %s state already configured to %d\n",
95 fic->name, fic->state);
96 ret = -EINVAL;
97 goto err;
98 }
99
100err:
101 irq_gc_unlock(gc);
102
103 return ret;
104}
105
106static void al_fic_irq_handler(struct irq_desc *desc)
107{
108 struct al_fic *fic = irq_desc_get_handler_data(desc);
109 struct irq_domain *domain = fic->domain;
110 struct irq_chip *irqchip = irq_desc_get_chip(desc);
111 struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
112 unsigned long pending;
113 unsigned int irq;
114 u32 hwirq;
115
116 chained_irq_enter(irqchip, desc);
117
118 pending = readl_relaxed(fic->base + AL_FIC_CAUSE);
119 pending &= ~gc->mask_cache;
120
121 for_each_set_bit(hwirq, &pending, NR_FIC_IRQS) {
122 irq = irq_find_mapping(domain, hwirq);
123 generic_handle_irq(irq);
124 }
125
126 chained_irq_exit(irqchip, desc);
127}
128
129static int al_fic_register(struct device_node *node,
130 struct al_fic *fic)
131{
132 struct irq_chip_generic *gc;
133 int ret;
134
135 fic->domain = irq_domain_add_linear(node,
136 NR_FIC_IRQS,
137 &irq_generic_chip_ops,
138 fic);
139 if (!fic->domain) {
140 pr_err("fail to add irq domain\n");
141 return -ENOMEM;
142 }
143
144 ret = irq_alloc_domain_generic_chips(fic->domain,
145 NR_FIC_IRQS,
146 1, fic->name,
147 handle_level_irq,
148 0, 0, IRQ_GC_INIT_MASK_CACHE);
149 if (ret) {
150 pr_err("fail to allocate generic chip (%d)\n", ret);
151 goto err_domain_remove;
152 }
153
154 gc = irq_get_domain_generic_chip(fic->domain, 0);
155 gc->reg_base = fic->base;
156 gc->chip_types->regs.mask = AL_FIC_MASK;
157 gc->chip_types->regs.ack = AL_FIC_CAUSE;
158 gc->chip_types->chip.irq_mask = irq_gc_mask_set_bit;
159 gc->chip_types->chip.irq_unmask = irq_gc_mask_clr_bit;
160 gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit;
161 gc->chip_types->chip.irq_set_type = al_fic_irq_set_type;
162 gc->chip_types->chip.flags = IRQCHIP_SKIP_SET_WAKE;
163 gc->private = fic;
164
165 irq_set_chained_handler_and_data(fic->parent_irq,
166 al_fic_irq_handler,
167 fic);
168 return 0;
169
170err_domain_remove:
171 irq_domain_remove(fic->domain);
172
173 return ret;
174}
175
176/*
177 * al_fic_wire_init() - initialize and configure fic in wire mode
178 * @of_node: optional pointer to interrupt controller's device tree node.
179 * @base: mmio to fic register
180 * @name: name of the fic
181 * @parent_irq: interrupt of parent
182 *
183 * This API will configure the fic hardware to to work in wire mode.
184 * In wire mode, fic hardware is generating a wire ("wired") interrupt.
185 * Interrupt can be generated based on positive edge or level - configuration is
186 * to be determined based on connected hardware to this fic.
187 */
188static struct al_fic *al_fic_wire_init(struct device_node *node,
189 void __iomem *base,
190 const char *name,
191 unsigned int parent_irq)
192{
193 struct al_fic *fic;
194 int ret;
195 u32 control = CONTROL_MASK_MSI_X;
196
197 fic = kzalloc(sizeof(*fic), GFP_KERNEL);
198 if (!fic)
199 return ERR_PTR(-ENOMEM);
200
201 fic->base = base;
202 fic->parent_irq = parent_irq;
203 fic->name = name;
204
205 /* mask out all interrupts */
206 writel_relaxed(0xFFFFFFFF, fic->base + AL_FIC_MASK);
207
208 /* clear any pending interrupt */
209 writel_relaxed(0, fic->base + AL_FIC_CAUSE);
210
211 writel_relaxed(control, fic->base + AL_FIC_CONTROL);
212
213 ret = al_fic_register(node, fic);
214 if (ret) {
215 pr_err("fail to register irqchip\n");
216 goto err_free;
217 }
218
219 pr_debug("%s initialized successfully in Legacy mode (parent-irq=%u)\n",
220 fic->name, parent_irq);
221
222 return fic;
223
224err_free:
225 kfree(fic);
226 return ERR_PTR(ret);
227}
228
229static int __init al_fic_init_dt(struct device_node *node,
230 struct device_node *parent)
231{
232 int ret;
233 void __iomem *base;
234 unsigned int parent_irq;
235 struct al_fic *fic;
236
237 if (!parent) {
238 pr_err("%s: unsupported - device require a parent\n",
239 node->name);
240 return -EINVAL;
241 }
242
243 base = of_iomap(node, 0);
244 if (!base) {
245 pr_err("%s: fail to map memory\n", node->name);
246 return -ENOMEM;
247 }
248
249 parent_irq = irq_of_parse_and_map(node, 0);
250 if (!parent_irq) {
251 pr_err("%s: fail to map irq\n", node->name);
252 ret = -EINVAL;
253 goto err_unmap;
254 }
255
256 fic = al_fic_wire_init(node,
257 base,
258 node->name,
259 parent_irq);
260 if (IS_ERR(fic)) {
261 pr_err("%s: fail to initialize irqchip (%lu)\n",
262 node->name,
263 PTR_ERR(fic));
264 ret = PTR_ERR(fic);
265 goto err_irq_dispose;
266 }
267
268 return 0;
269
270err_irq_dispose:
271 irq_dispose_mapping(parent_irq);
272err_unmap:
273 iounmap(base);
274
275 return ret;
276}
277
278IRQCHIP_DECLARE(al_fic, "amazon,al-fic", al_fic_init_dt);
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
index a4c1aacba1ff..a1534edef7fa 100644
--- a/drivers/irqchip/irq-csky-mpintc.c
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -32,8 +32,8 @@ static void __iomem *INTCL_base;
32#define INTCG_CIDSTR 0x1000 32#define INTCG_CIDSTR 0x1000
33 33
34#define INTCL_PICTLR 0x0 34#define INTCL_PICTLR 0x0
35#define INTCL_CFGR 0x14
35#define INTCL_SIGR 0x60 36#define INTCL_SIGR 0x60
36#define INTCL_HPPIR 0x68
37#define INTCL_RDYIR 0x6c 37#define INTCL_RDYIR 0x6c
38#define INTCL_SENR 0xa0 38#define INTCL_SENR 0xa0
39#define INTCL_CENR 0xa4 39#define INTCL_CENR 0xa4
@@ -41,21 +41,49 @@ static void __iomem *INTCL_base;
41 41
42static DEFINE_PER_CPU(void __iomem *, intcl_reg); 42static DEFINE_PER_CPU(void __iomem *, intcl_reg);
43 43
44static unsigned long *__trigger;
45
46#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE))
47
48#define TRIG_BYTE_OFFSET(i) ((((i) * 2) / 32) * 4)
49#define TRIG_BIT_OFFSET(i) (((i) * 2) % 32)
50
51#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))
52#define TRIG_VAL_MSK(irq) (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))))
53
54#define TRIG_BASE(irq) \
55 (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
56 (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR)))
57
58static DEFINE_SPINLOCK(setup_lock);
59static void setup_trigger(unsigned long irq, unsigned long trigger)
60{
61 unsigned int tmp;
62
63 spin_lock(&setup_lock);
64
65 /* setup trigger */
66 tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq);
67
68 writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq));
69
70 spin_unlock(&setup_lock);
71}
72
44static void csky_mpintc_handler(struct pt_regs *regs) 73static void csky_mpintc_handler(struct pt_regs *regs)
45{ 74{
46 void __iomem *reg_base = this_cpu_read(intcl_reg); 75 void __iomem *reg_base = this_cpu_read(intcl_reg);
47 76
48 do { 77 handle_domain_irq(root_domain,
49 handle_domain_irq(root_domain, 78 readl_relaxed(reg_base + INTCL_RDYIR), regs);
50 readl_relaxed(reg_base + INTCL_RDYIR),
51 regs);
52 } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31));
53} 79}
54 80
55static void csky_mpintc_enable(struct irq_data *d) 81static void csky_mpintc_enable(struct irq_data *d)
56{ 82{
57 void __iomem *reg_base = this_cpu_read(intcl_reg); 83 void __iomem *reg_base = this_cpu_read(intcl_reg);
58 84
85 setup_trigger(d->hwirq, __trigger[d->hwirq]);
86
59 writel_relaxed(d->hwirq, reg_base + INTCL_SENR); 87 writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
60} 88}
61 89
@@ -73,6 +101,28 @@ static void csky_mpintc_eoi(struct irq_data *d)
73 writel_relaxed(d->hwirq, reg_base + INTCL_CACR); 101 writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
74} 102}
75 103
104static int csky_mpintc_set_type(struct irq_data *d, unsigned int type)
105{
106 switch (type & IRQ_TYPE_SENSE_MASK) {
107 case IRQ_TYPE_LEVEL_HIGH:
108 __trigger[d->hwirq] = 0;
109 break;
110 case IRQ_TYPE_LEVEL_LOW:
111 __trigger[d->hwirq] = 1;
112 break;
113 case IRQ_TYPE_EDGE_RISING:
114 __trigger[d->hwirq] = 2;
115 break;
116 case IRQ_TYPE_EDGE_FALLING:
117 __trigger[d->hwirq] = 3;
118 break;
119 default:
120 return -EINVAL;
121 }
122
123 return 0;
124}
125
76#ifdef CONFIG_SMP 126#ifdef CONFIG_SMP
77static int csky_irq_set_affinity(struct irq_data *d, 127static int csky_irq_set_affinity(struct irq_data *d,
78 const struct cpumask *mask_val, 128 const struct cpumask *mask_val,
@@ -116,6 +166,7 @@ static struct irq_chip csky_irq_chip = {
116 .irq_eoi = csky_mpintc_eoi, 166 .irq_eoi = csky_mpintc_eoi,
117 .irq_enable = csky_mpintc_enable, 167 .irq_enable = csky_mpintc_enable,
118 .irq_disable = csky_mpintc_disable, 168 .irq_disable = csky_mpintc_disable,
169 .irq_set_type = csky_mpintc_set_type,
119#ifdef CONFIG_SMP 170#ifdef CONFIG_SMP
120 .irq_set_affinity = csky_irq_set_affinity, 171 .irq_set_affinity = csky_irq_set_affinity,
121#endif 172#endif
@@ -136,9 +187,26 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
136 return 0; 187 return 0;
137} 188}
138 189
190static int csky_irq_domain_xlate_cells(struct irq_domain *d,
191 struct device_node *ctrlr, const u32 *intspec,
192 unsigned int intsize, unsigned long *out_hwirq,
193 unsigned int *out_type)
194{
195 if (WARN_ON(intsize < 1))
196 return -EINVAL;
197
198 *out_hwirq = intspec[0];
199 if (intsize > 1)
200 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
201 else
202 *out_type = IRQ_TYPE_LEVEL_HIGH;
203
204 return 0;
205}
206
139static const struct irq_domain_ops csky_irqdomain_ops = { 207static const struct irq_domain_ops csky_irqdomain_ops = {
140 .map = csky_irqdomain_map, 208 .map = csky_irqdomain_map,
141 .xlate = irq_domain_xlate_onecell, 209 .xlate = csky_irq_domain_xlate_cells,
142}; 210};
143 211
144#ifdef CONFIG_SMP 212#ifdef CONFIG_SMP
@@ -172,6 +240,10 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent)
172 if (ret < 0) 240 if (ret < 0)
173 nr_irq = INTC_IRQS; 241 nr_irq = INTC_IRQS;
174 242
243 __trigger = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
244 if (__trigger == NULL)
245 return -ENXIO;
246
175 if (INTCG_base == NULL) { 247 if (INTCG_base == NULL) {
176 INTCG_base = ioremap(mfcr("cr<31, 14>"), 248 INTCG_base = ioremap(mfcr("cr<31, 14>"),
177 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE); 249 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 875ac80f690b..7338f90b2f9e 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -53,6 +53,7 @@
53 53
54/* List of flags for specific v2m implementation */ 54/* List of flags for specific v2m implementation */
55#define GICV2M_NEEDS_SPI_OFFSET 0x00000001 55#define GICV2M_NEEDS_SPI_OFFSET 0x00000001
56#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
56 57
57static LIST_HEAD(v2m_nodes); 58static LIST_HEAD(v2m_nodes);
58static DEFINE_SPINLOCK(v2m_lock); 59static DEFINE_SPINLOCK(v2m_lock);
@@ -95,15 +96,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
95 .chip = &gicv2m_msi_irq_chip, 96 .chip = &gicv2m_msi_irq_chip,
96}; 97};
97 98
99static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq)
100{
101 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
102 return v2m->res.start | ((hwirq - 32) << 3);
103 else
104 return v2m->res.start + V2M_MSI_SETSPI_NS;
105}
106
98static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 107static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
99{ 108{
100 struct v2m_data *v2m = irq_data_get_irq_chip_data(data); 109 struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
101 phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS; 110 phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq);
102 111
103 msg->address_hi = upper_32_bits(addr); 112 msg->address_hi = upper_32_bits(addr);
104 msg->address_lo = lower_32_bits(addr); 113 msg->address_lo = lower_32_bits(addr);
105 msg->data = data->hwirq;
106 114
115 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
116 msg->data = 0;
117 else
118 msg->data = data->hwirq;
107 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) 119 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
108 msg->data -= v2m->spi_offset; 120 msg->data -= v2m->spi_offset;
109 121
@@ -185,7 +197,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
185 hwirq = v2m->spi_start + offset; 197 hwirq = v2m->spi_start + offset;
186 198
187 err = iommu_dma_prepare_msi(info->desc, 199 err = iommu_dma_prepare_msi(info->desc,
188 v2m->res.start + V2M_MSI_SETSPI_NS); 200 gicv2m_get_msi_addr(v2m, hwirq));
189 if (err) 201 if (err)
190 return err; 202 return err;
191 203
@@ -304,7 +316,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
304 316
305static int __init gicv2m_init_one(struct fwnode_handle *fwnode, 317static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
306 u32 spi_start, u32 nr_spis, 318 u32 spi_start, u32 nr_spis,
307 struct resource *res) 319 struct resource *res, u32 flags)
308{ 320{
309 int ret; 321 int ret;
310 struct v2m_data *v2m; 322 struct v2m_data *v2m;
@@ -317,6 +329,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
317 329
318 INIT_LIST_HEAD(&v2m->entry); 330 INIT_LIST_HEAD(&v2m->entry);
319 v2m->fwnode = fwnode; 331 v2m->fwnode = fwnode;
332 v2m->flags = flags;
320 333
321 memcpy(&v2m->res, res, sizeof(struct resource)); 334 memcpy(&v2m->res, res, sizeof(struct resource));
322 335
@@ -331,7 +344,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
331 v2m->spi_start = spi_start; 344 v2m->spi_start = spi_start;
332 v2m->nr_spis = nr_spis; 345 v2m->nr_spis = nr_spis;
333 } else { 346 } else {
334 u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); 347 u32 typer;
348
349 /* Graviton should always have explicit spi_start/nr_spis */
350 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) {
351 ret = -EINVAL;
352 goto err_iounmap;
353 }
354 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
335 355
336 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); 356 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
337 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer); 357 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
@@ -352,18 +372,21 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
352 * 372 *
353 * Broadom NS2 GICv2m implementation has an erratum where the MSI data 373 * Broadom NS2 GICv2m implementation has an erratum where the MSI data
354 * is 'spi_number - 32' 374 * is 'spi_number - 32'
375 *
376 * Reading that register fails on the Graviton implementation
355 */ 377 */
356 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) { 378 if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) {
357 case XGENE_GICV2M_MSI_IIDR: 379 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
358 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; 380 case XGENE_GICV2M_MSI_IIDR:
359 v2m->spi_offset = v2m->spi_start; 381 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
360 break; 382 v2m->spi_offset = v2m->spi_start;
361 case BCM_NS2_GICV2M_MSI_IIDR: 383 break;
362 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; 384 case BCM_NS2_GICV2M_MSI_IIDR:
363 v2m->spi_offset = 32; 385 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
364 break; 386 v2m->spi_offset = 32;
387 break;
388 }
365 } 389 }
366
367 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long), 390 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),
368 GFP_KERNEL); 391 GFP_KERNEL);
369 if (!v2m->bm) { 392 if (!v2m->bm) {
@@ -416,7 +439,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
416 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n", 439 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
417 spi_start, nr_spis); 440 spi_start, nr_spis);
418 441
419 ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res); 442 ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis,
443 &res, 0);
420 if (ret) { 444 if (ret) {
421 of_node_put(child); 445 of_node_put(child);
422 break; 446 break;
@@ -448,6 +472,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
448 return data->fwnode; 472 return data->fwnode;
449} 473}
450 474
475static bool acpi_check_amazon_graviton_quirks(void)
476{
477 static struct acpi_table_madt *madt;
478 acpi_status status;
479 bool rc = false;
480
481#define ACPI_AMZN_OEM_ID "AMAZON"
482
483 status = acpi_get_table(ACPI_SIG_MADT, 0,
484 (struct acpi_table_header **)&madt);
485
486 if (ACPI_FAILURE(status) || !madt)
487 return rc;
488 rc = !memcmp(madt->header.oem_id, ACPI_AMZN_OEM_ID, ACPI_OEM_ID_SIZE);
489 acpi_put_table((struct acpi_table_header *)madt);
490
491 return rc;
492}
493
451static int __init 494static int __init
452acpi_parse_madt_msi(union acpi_subtable_headers *header, 495acpi_parse_madt_msi(union acpi_subtable_headers *header,
453 const unsigned long end) 496 const unsigned long end)
@@ -457,6 +500,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
457 u32 spi_start = 0, nr_spis = 0; 500 u32 spi_start = 0, nr_spis = 0;
458 struct acpi_madt_generic_msi_frame *m; 501 struct acpi_madt_generic_msi_frame *m;
459 struct fwnode_handle *fwnode; 502 struct fwnode_handle *fwnode;
503 u32 flags = 0;
460 504
461 m = (struct acpi_madt_generic_msi_frame *)header; 505 m = (struct acpi_madt_generic_msi_frame *)header;
462 if (BAD_MADT_ENTRY(m, end)) 506 if (BAD_MADT_ENTRY(m, end))
@@ -466,6 +510,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
466 res.end = m->base_address + SZ_4K - 1; 510 res.end = m->base_address + SZ_4K - 1;
467 res.flags = IORESOURCE_MEM; 511 res.flags = IORESOURCE_MEM;
468 512
513 if (acpi_check_amazon_graviton_quirks()) {
514 pr_info("applying Amazon Graviton quirk\n");
515 res.end = res.start + SZ_8K - 1;
516 flags |= GICV2M_GRAVITON_ADDRESS_ONLY;
517 gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI;
518 }
519
469 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { 520 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
470 spi_start = m->spi_base; 521 spi_start = m->spi_base;
471 nr_spis = m->spi_count; 522 nr_spis = m->spi_count;
@@ -480,7 +531,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
480 return -EINVAL; 531 return -EINVAL;
481 } 532 }
482 533
483 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); 534 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags);
484 if (ret) 535 if (ret)
485 irq_domain_free_fwnode(fwnode); 536 irq_domain_free_fwnode(fwnode);
486 537
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f3e44d6d9255..9bca4896fa6f 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1339,6 +1339,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
1339 if (gic_dist_supports_lpis()) { 1339 if (gic_dist_supports_lpis()) {
1340 its_init(handle, &gic_data.rdists, gic_data.domain); 1340 its_init(handle, &gic_data.rdists, gic_data.domain);
1341 its_cpu_init(); 1341 its_cpu_init();
1342 } else {
1343 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1344 gicv2m_init(handle, gic_data.domain);
1342 } 1345 }
1343 1346
1344 if (gic_prio_masking_enabled()) { 1347 if (gic_prio_masking_enabled()) {
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index a89c693d5b90..3dd28382d5f5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -344,8 +344,7 @@ static int mbigen_device_probe(struct platform_device *pdev)
344 err = -EINVAL; 344 err = -EINVAL;
345 345
346 if (err) { 346 if (err) {
347 dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", 347 dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n");
348 mgn_chip->base);
349 return err; 348 return err;
350 } 349 }
351 350
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 8eb92eb98f54..dcdc23b9dce6 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -60,6 +60,7 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
60 { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, 60 { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
61 { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, 61 { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
62 { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, 62 { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
63 { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
63 { } 64 { }
64}; 65};
65 66
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 04c05a18600c..f82bc60a6793 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -508,7 +508,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
508 } 508 }
509 509
510 irq_chip = &p->irq_chip; 510 irq_chip = &p->irq_chip;
511 irq_chip->name = name; 511 irq_chip->name = "intc-irqpin";
512 irq_chip->parent_device = dev;
512 irq_chip->irq_mask = disable_fn; 513 irq_chip->irq_mask = disable_fn;
513 irq_chip->irq_unmask = enable_fn; 514 irq_chip->irq_unmask = enable_fn;
514 irq_chip->irq_set_type = intc_irqpin_irq_set_type; 515 irq_chip->irq_set_type = intc_irqpin_irq_set_type;
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index a449a7c839b3..11abc09ef76c 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -7,7 +7,6 @@
7 7
8#include <linux/init.h> 8#include <linux/init.h>
9#include <linux/platform_device.h> 9#include <linux/platform_device.h>
10#include <linux/spinlock.h>
11#include <linux/interrupt.h> 10#include <linux/interrupt.h>
12#include <linux/ioport.h> 11#include <linux/ioport.h>
13#include <linux/io.h> 12#include <linux/io.h>
@@ -48,7 +47,7 @@ struct irqc_priv {
48 void __iomem *cpu_int_base; 47 void __iomem *cpu_int_base;
49 struct irqc_irq irq[IRQC_IRQ_MAX]; 48 struct irqc_irq irq[IRQC_IRQ_MAX];
50 unsigned int number_of_irqs; 49 unsigned int number_of_irqs;
51 struct platform_device *pdev; 50 struct device *dev;
52 struct irq_chip_generic *gc; 51 struct irq_chip_generic *gc;
53 struct irq_domain *irq_domain; 52 struct irq_domain *irq_domain;
54 atomic_t wakeup_path; 53 atomic_t wakeup_path;
@@ -61,8 +60,7 @@ static struct irqc_priv *irq_data_to_priv(struct irq_data *data)
61 60
62static void irqc_dbg(struct irqc_irq *i, char *str) 61static void irqc_dbg(struct irqc_irq *i, char *str)
63{ 62{
64 dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", 63 dev_dbg(i->p->dev, "%s (%d:%d)\n", str, i->requested_irq, i->hw_irq);
65 str, i->requested_irq, i->hw_irq);
66} 64}
67 65
68static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { 66static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = {
@@ -125,33 +123,22 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
125 123
126static int irqc_probe(struct platform_device *pdev) 124static int irqc_probe(struct platform_device *pdev)
127{ 125{
126 struct device *dev = &pdev->dev;
127 const char *name = dev_name(dev);
128 struct irqc_priv *p; 128 struct irqc_priv *p;
129 struct resource *io;
130 struct resource *irq; 129 struct resource *irq;
131 const char *name = dev_name(&pdev->dev);
132 int ret; 130 int ret;
133 int k; 131 int k;
134 132
135 p = kzalloc(sizeof(*p), GFP_KERNEL); 133 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
136 if (!p) { 134 if (!p)
137 dev_err(&pdev->dev, "failed to allocate driver data\n"); 135 return -ENOMEM;
138 ret = -ENOMEM;
139 goto err0;
140 }
141 136
142 p->pdev = pdev; 137 p->dev = dev;
143 platform_set_drvdata(pdev, p); 138 platform_set_drvdata(pdev, p);
144 139
145 pm_runtime_enable(&pdev->dev); 140 pm_runtime_enable(dev);
146 pm_runtime_get_sync(&pdev->dev); 141 pm_runtime_get_sync(dev);
147
148 /* get hold of manadatory IOMEM */
149 io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
150 if (!io) {
151 dev_err(&pdev->dev, "not enough IOMEM resources\n");
152 ret = -EINVAL;
153 goto err1;
154 }
155 142
156 /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */ 143 /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
157 for (k = 0; k < IRQC_IRQ_MAX; k++) { 144 for (k = 0; k < IRQC_IRQ_MAX; k++) {
@@ -166,42 +153,41 @@ static int irqc_probe(struct platform_device *pdev)
166 153
167 p->number_of_irqs = k; 154 p->number_of_irqs = k;
168 if (p->number_of_irqs < 1) { 155 if (p->number_of_irqs < 1) {
169 dev_err(&pdev->dev, "not enough IRQ resources\n"); 156 dev_err(dev, "not enough IRQ resources\n");
170 ret = -EINVAL; 157 ret = -EINVAL;
171 goto err1; 158 goto err_runtime_pm_disable;
172 } 159 }
173 160
174 /* ioremap IOMEM and setup read/write callbacks */ 161 /* ioremap IOMEM and setup read/write callbacks */
175 p->iomem = ioremap_nocache(io->start, resource_size(io)); 162 p->iomem = devm_platform_ioremap_resource(pdev, 0);
176 if (!p->iomem) { 163 if (IS_ERR(p->iomem)) {
177 dev_err(&pdev->dev, "failed to remap IOMEM\n"); 164 ret = PTR_ERR(p->iomem);
178 ret = -ENXIO; 165 goto err_runtime_pm_disable;
179 goto err2;
180 } 166 }
181 167
182 p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ 168 p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */
183 169
184 p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 170 p->irq_domain = irq_domain_add_linear(dev->of_node, p->number_of_irqs,
185 p->number_of_irqs,
186 &irq_generic_chip_ops, p); 171 &irq_generic_chip_ops, p);
187 if (!p->irq_domain) { 172 if (!p->irq_domain) {
188 ret = -ENXIO; 173 ret = -ENXIO;
189 dev_err(&pdev->dev, "cannot initialize irq domain\n"); 174 dev_err(dev, "cannot initialize irq domain\n");
190 goto err2; 175 goto err_runtime_pm_disable;
191 } 176 }
192 177
193 ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs, 178 ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs,
194 1, name, handle_level_irq, 179 1, "irqc", handle_level_irq,
195 0, 0, IRQ_GC_INIT_NESTED_LOCK); 180 0, 0, IRQ_GC_INIT_NESTED_LOCK);
196 if (ret) { 181 if (ret) {
197 dev_err(&pdev->dev, "cannot allocate generic chip\n"); 182 dev_err(dev, "cannot allocate generic chip\n");
198 goto err3; 183 goto err_remove_domain;
199 } 184 }
200 185
201 p->gc = irq_get_domain_generic_chip(p->irq_domain, 0); 186 p->gc = irq_get_domain_generic_chip(p->irq_domain, 0);
202 p->gc->reg_base = p->cpu_int_base; 187 p->gc->reg_base = p->cpu_int_base;
203 p->gc->chip_types[0].regs.enable = IRQC_EN_SET; 188 p->gc->chip_types[0].regs.enable = IRQC_EN_SET;
204 p->gc->chip_types[0].regs.disable = IRQC_EN_STS; 189 p->gc->chip_types[0].regs.disable = IRQC_EN_STS;
190 p->gc->chip_types[0].chip.parent_device = dev;
205 p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 191 p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
206 p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 192 p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
207 p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type; 193 p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type;
@@ -210,46 +196,33 @@ static int irqc_probe(struct platform_device *pdev)
210 196
211 /* request interrupts one by one */ 197 /* request interrupts one by one */
212 for (k = 0; k < p->number_of_irqs; k++) { 198 for (k = 0; k < p->number_of_irqs; k++) {
213 if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, 199 if (devm_request_irq(dev, p->irq[k].requested_irq,
214 0, name, &p->irq[k])) { 200 irqc_irq_handler, 0, name, &p->irq[k])) {
215 dev_err(&pdev->dev, "failed to request IRQ\n"); 201 dev_err(dev, "failed to request IRQ\n");
216 ret = -ENOENT; 202 ret = -ENOENT;
217 goto err4; 203 goto err_remove_domain;
218 } 204 }
219 } 205 }
220 206
221 dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); 207 dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
222 208
223 return 0; 209 return 0;
224err4:
225 while (--k >= 0)
226 free_irq(p->irq[k].requested_irq, &p->irq[k]);
227 210
228err3: 211err_remove_domain:
229 irq_domain_remove(p->irq_domain); 212 irq_domain_remove(p->irq_domain);
230err2: 213err_runtime_pm_disable:
231 iounmap(p->iomem); 214 pm_runtime_put(dev);
232err1: 215 pm_runtime_disable(dev);
233 pm_runtime_put(&pdev->dev);
234 pm_runtime_disable(&pdev->dev);
235 kfree(p);
236err0:
237 return ret; 216 return ret;
238} 217}
239 218
240static int irqc_remove(struct platform_device *pdev) 219static int irqc_remove(struct platform_device *pdev)
241{ 220{
242 struct irqc_priv *p = platform_get_drvdata(pdev); 221 struct irqc_priv *p = platform_get_drvdata(pdev);
243 int k;
244
245 for (k = 0; k < p->number_of_irqs; k++)
246 free_irq(p->irq[k].requested_irq, &p->irq[k]);
247 222
248 irq_domain_remove(p->irq_domain); 223 irq_domain_remove(p->irq_domain);
249 iounmap(p->iomem);
250 pm_runtime_put(&pdev->dev); 224 pm_runtime_put(&pdev->dev);
251 pm_runtime_disable(&pdev->dev); 225 pm_runtime_disable(&pdev->dev);
252 kfree(p);
253 return 0; 226 return 0;
254} 227}
255 228
diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c
new file mode 100644
index 000000000000..b1f19b210190
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-rza1.c
@@ -0,0 +1,283 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Renesas RZ/A1 IRQC Driver
4 *
5 * Copyright (C) 2019 Glider bvba
6 */
7
8#include <linux/err.h>
9#include <linux/init.h>
10#include <linux/interrupt.h>
11#include <linux/io.h>
12#include <linux/irqdomain.h>
13#include <linux/irq.h>
14#include <linux/module.h>
15#include <linux/of_irq.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18
19#include <dt-bindings/interrupt-controller/arm-gic.h>
20
21#define IRQC_NUM_IRQ 8
22
23#define ICR0 0 /* Interrupt Control Register 0 */
24
25#define ICR0_NMIL BIT(15) /* NMI Input Level (0=low, 1=high) */
26#define ICR0_NMIE BIT(8) /* Edge Select (0=falling, 1=rising) */
27#define ICR0_NMIF BIT(1) /* NMI Interrupt Request */
28
29#define ICR1 2 /* Interrupt Control Register 1 */
30
31#define ICR1_IRQS(n, sense) ((sense) << ((n) * 2)) /* IRQ Sense Select */
32#define ICR1_IRQS_LEVEL_LOW 0
33#define ICR1_IRQS_EDGE_FALLING 1
34#define ICR1_IRQS_EDGE_RISING 2
35#define ICR1_IRQS_EDGE_BOTH 3
36#define ICR1_IRQS_MASK(n) ICR1_IRQS((n), 3)
37
38#define IRQRR 4 /* IRQ Interrupt Request Register */
39
40
41struct rza1_irqc_priv {
42 struct device *dev;
43 void __iomem *base;
44 struct irq_chip chip;
45 struct irq_domain *irq_domain;
46 struct of_phandle_args map[IRQC_NUM_IRQ];
47};
48
49static struct rza1_irqc_priv *irq_data_to_priv(struct irq_data *data)
50{
51 return data->domain->host_data;
52}
53
54static void rza1_irqc_eoi(struct irq_data *d)
55{
56 struct rza1_irqc_priv *priv = irq_data_to_priv(d);
57 u16 bit = BIT(irqd_to_hwirq(d));
58 u16 tmp;
59
60 tmp = readw_relaxed(priv->base + IRQRR);
61 if (tmp & bit)
62 writew_relaxed(GENMASK(IRQC_NUM_IRQ - 1, 0) & ~bit,
63 priv->base + IRQRR);
64
65 irq_chip_eoi_parent(d);
66}
67
68static int rza1_irqc_set_type(struct irq_data *d, unsigned int type)
69{
70 struct rza1_irqc_priv *priv = irq_data_to_priv(d);
71 unsigned int hw_irq = irqd_to_hwirq(d);
72 u16 sense, tmp;
73
74 switch (type & IRQ_TYPE_SENSE_MASK) {
75 case IRQ_TYPE_LEVEL_LOW:
76 sense = ICR1_IRQS_LEVEL_LOW;
77 break;
78
79 case IRQ_TYPE_EDGE_FALLING:
80 sense = ICR1_IRQS_EDGE_FALLING;
81 break;
82
83 case IRQ_TYPE_EDGE_RISING:
84 sense = ICR1_IRQS_EDGE_RISING;
85 break;
86
87 case IRQ_TYPE_EDGE_BOTH:
88 sense = ICR1_IRQS_EDGE_BOTH;
89 break;
90
91 default:
92 return -EINVAL;
93 }
94
95 tmp = readw_relaxed(priv->base + ICR1);
96 tmp &= ~ICR1_IRQS_MASK(hw_irq);
97 tmp |= ICR1_IRQS(hw_irq, sense);
98 writew_relaxed(tmp, priv->base + ICR1);
99 return 0;
100}
101
102static int rza1_irqc_alloc(struct irq_domain *domain, unsigned int virq,
103 unsigned int nr_irqs, void *arg)
104{
105 struct rza1_irqc_priv *priv = domain->host_data;
106 struct irq_fwspec *fwspec = arg;
107 unsigned int hwirq = fwspec->param[0];
108 struct irq_fwspec spec;
109 unsigned int i;
110 int ret;
111
112 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &priv->chip,
113 priv);
114 if (ret)
115 return ret;
116
117 spec.fwnode = &priv->dev->of_node->fwnode;
118 spec.param_count = priv->map[hwirq].args_count;
119 for (i = 0; i < spec.param_count; i++)
120 spec.param[i] = priv->map[hwirq].args[i];
121
122 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &spec);
123}
124
125static int rza1_irqc_translate(struct irq_domain *domain,
126 struct irq_fwspec *fwspec, unsigned long *hwirq,
127 unsigned int *type)
128{
129 if (fwspec->param_count != 2 || fwspec->param[0] >= IRQC_NUM_IRQ)
130 return -EINVAL;
131
132 *hwirq = fwspec->param[0];
133 *type = fwspec->param[1];
134 return 0;
135}
136
137static const struct irq_domain_ops rza1_irqc_domain_ops = {
138 .alloc = rza1_irqc_alloc,
139 .translate = rza1_irqc_translate,
140};
141
142static int rza1_irqc_parse_map(struct rza1_irqc_priv *priv,
143 struct device_node *gic_node)
144{
145 unsigned int imaplen, i, j, ret;
146 struct device *dev = priv->dev;
147 struct device_node *ipar;
148 const __be32 *imap;
149 u32 intsize;
150
151 imap = of_get_property(dev->of_node, "interrupt-map", &imaplen);
152 if (!imap)
153 return -EINVAL;
154
155 for (i = 0; i < IRQC_NUM_IRQ; i++) {
156 if (imaplen < 3)
157 return -EINVAL;
158
159 /* Check interrupt number, ignore sense */
160 if (be32_to_cpup(imap) != i)
161 return -EINVAL;
162
163 ipar = of_find_node_by_phandle(be32_to_cpup(imap + 2));
164 if (ipar != gic_node) {
165 of_node_put(ipar);
166 return -EINVAL;
167 }
168
169 imap += 3;
170 imaplen -= 3;
171
172 ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
173 of_node_put(ipar);
174 if (ret)
175 return ret;
176
177 if (imaplen < intsize)
178 return -EINVAL;
179
180 priv->map[i].args_count = intsize;
181 for (j = 0; j < intsize; j++)
182 priv->map[i].args[j] = be32_to_cpup(imap++);
183
184 imaplen -= intsize;
185 }
186
187 return 0;
188}
189
190static int rza1_irqc_probe(struct platform_device *pdev)
191{
192 struct device *dev = &pdev->dev;
193 struct device_node *np = dev->of_node;
194 struct irq_domain *parent = NULL;
195 struct device_node *gic_node;
196 struct rza1_irqc_priv *priv;
197 int ret;
198
199 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
200 if (!priv)
201 return -ENOMEM;
202
203 platform_set_drvdata(pdev, priv);
204 priv->dev = dev;
205
206 priv->base = devm_platform_ioremap_resource(pdev, 0);
207 if (IS_ERR(priv->base))
208 return PTR_ERR(priv->base);
209
210 gic_node = of_irq_find_parent(np);
211 if (gic_node) {
212 parent = irq_find_host(gic_node);
213 of_node_put(gic_node);
214 }
215
216 if (!parent) {
217 dev_err(dev, "cannot find parent domain\n");
218 return -ENODEV;
219 }
220
221 ret = rza1_irqc_parse_map(priv, gic_node);
222 if (ret) {
223 dev_err(dev, "cannot parse %s: %d\n", "interrupt-map", ret);
224 return ret;
225 }
226
227 priv->chip.name = "rza1-irqc",
228 priv->chip.irq_mask = irq_chip_mask_parent,
229 priv->chip.irq_unmask = irq_chip_unmask_parent,
230 priv->chip.irq_eoi = rza1_irqc_eoi,
231 priv->chip.irq_retrigger = irq_chip_retrigger_hierarchy,
232 priv->chip.irq_set_type = rza1_irqc_set_type,
233 priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
234
235 priv->irq_domain = irq_domain_add_hierarchy(parent, 0, IRQC_NUM_IRQ,
236 np, &rza1_irqc_domain_ops,
237 priv);
238 if (!priv->irq_domain) {
239 dev_err(dev, "cannot initialize irq domain\n");
240 return -ENOMEM;
241 }
242
243 return 0;
244}
245
246static int rza1_irqc_remove(struct platform_device *pdev)
247{
248 struct rza1_irqc_priv *priv = platform_get_drvdata(pdev);
249
250 irq_domain_remove(priv->irq_domain);
251 return 0;
252}
253
254static const struct of_device_id rza1_irqc_dt_ids[] = {
255 { .compatible = "renesas,rza1-irqc" },
256 {},
257};
258MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids);
259
260static struct platform_driver rza1_irqc_device_driver = {
261 .probe = rza1_irqc_probe,
262 .remove = rza1_irqc_remove,
263 .driver = {
264 .name = "renesas_rza1_irqc",
265 .of_match_table = rza1_irqc_dt_ids,
266 }
267};
268
269static int __init rza1_irqc_init(void)
270{
271 return platform_driver_register(&rza1_irqc_device_driver);
272}
273postcore_initcall(rza1_irqc_init);
274
275static void __exit rza1_irqc_exit(void)
276{
277 platform_driver_unregister(&rza1_irqc_device_driver);
278}
279module_exit(rza1_irqc_exit);
280
281MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
282MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver");
283MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
index 4e983bc6cf93..1d027623c776 100644
--- a/drivers/irqchip/irq-sni-exiu.c
+++ b/drivers/irqchip/irq-sni-exiu.c
@@ -2,7 +2,7 @@
2/* 2/*
3 * Driver for Socionext External Interrupt Unit (EXIU) 3 * Driver for Socionext External Interrupt Unit (EXIU)
4 * 4 *
5 * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org> 5 * Copyright (c) 2017-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
6 * 6 *
7 * Based on irq-tegra.c: 7 * Based on irq-tegra.c:
8 * Copyright (C) 2011 Google, Inc. 8 * Copyright (C) 2011 Google, Inc.
@@ -17,6 +17,7 @@
17#include <linux/of.h> 17#include <linux/of.h>
18#include <linux/of_address.h> 18#include <linux/of_address.h>
19#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/platform_device.h>
20 21
21#include <dt-bindings/interrupt-controller/arm-gic.h> 22#include <dt-bindings/interrupt-controller/arm-gic.h>
22 23
@@ -131,9 +132,13 @@ static int exiu_domain_translate(struct irq_domain *domain,
131 132
132 *hwirq = fwspec->param[1] - info->spi_base; 133 *hwirq = fwspec->param[1] - info->spi_base;
133 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; 134 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
134 return 0; 135 } else {
136 if (fwspec->param_count != 2)
137 return -EINVAL;
138 *hwirq = fwspec->param[0];
139 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
135 } 140 }
136 return -EINVAL; 141 return 0;
137} 142}
138 143
139static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, 144static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
@@ -144,16 +149,21 @@ static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
144 struct exiu_irq_data *info = dom->host_data; 149 struct exiu_irq_data *info = dom->host_data;
145 irq_hw_number_t hwirq; 150 irq_hw_number_t hwirq;
146 151
147 if (fwspec->param_count != 3) 152 parent_fwspec = *fwspec;
148 return -EINVAL; /* Not GIC compliant */ 153 if (is_of_node(dom->parent->fwnode)) {
149 if (fwspec->param[0] != GIC_SPI) 154 if (fwspec->param_count != 3)
150 return -EINVAL; /* No PPI should point to this domain */ 155 return -EINVAL; /* Not GIC compliant */
156 if (fwspec->param[0] != GIC_SPI)
157 return -EINVAL; /* No PPI should point to this domain */
151 158
159 hwirq = fwspec->param[1] - info->spi_base;
160 } else {
161 hwirq = fwspec->param[0];
162 parent_fwspec.param[0] = hwirq + info->spi_base + 32;
163 }
152 WARN_ON(nr_irqs != 1); 164 WARN_ON(nr_irqs != 1);
153 hwirq = fwspec->param[1] - info->spi_base;
154 irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info); 165 irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
155 166
156 parent_fwspec = *fwspec;
157 parent_fwspec.fwnode = dom->parent->fwnode; 167 parent_fwspec.fwnode = dom->parent->fwnode;
158 return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec); 168 return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
159} 169}
@@ -164,35 +174,23 @@ static const struct irq_domain_ops exiu_domain_ops = {
164 .free = irq_domain_free_irqs_common, 174 .free = irq_domain_free_irqs_common,
165}; 175};
166 176
167static int __init exiu_init(struct device_node *node, 177static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode,
168 struct device_node *parent) 178 struct resource *res)
169{ 179{
170 struct irq_domain *parent_domain, *domain;
171 struct exiu_irq_data *data; 180 struct exiu_irq_data *data;
172 int err; 181 int err;
173 182
174 if (!parent) {
175 pr_err("%pOF: no parent, giving up\n", node);
176 return -ENODEV;
177 }
178
179 parent_domain = irq_find_host(parent);
180 if (!parent_domain) {
181 pr_err("%pOF: unable to obtain parent domain\n", node);
182 return -ENXIO;
183 }
184
185 data = kzalloc(sizeof(*data), GFP_KERNEL); 183 data = kzalloc(sizeof(*data), GFP_KERNEL);
186 if (!data) 184 if (!data)
187 return -ENOMEM; 185 return ERR_PTR(-ENOMEM);
188 186
189 if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) { 187 if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base",
190 pr_err("%pOF: failed to parse 'spi-base' property\n", node); 188 &data->spi_base, 1)) {
191 err = -ENODEV; 189 err = -ENODEV;
192 goto out_free; 190 goto out_free;
193 } 191 }
194 192
195 data->base = of_iomap(node, 0); 193 data->base = ioremap(res->start, resource_size(res));
196 if (!data->base) { 194 if (!data->base) {
197 err = -ENODEV; 195 err = -ENODEV;
198 goto out_free; 196 goto out_free;
@@ -202,11 +200,44 @@ static int __init exiu_init(struct device_node *node,
202 writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR); 200 writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
203 writel_relaxed(0xFFFFFFFF, data->base + EIMASK); 201 writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
204 202
203 return data;
204
205out_free:
206 kfree(data);
207 return ERR_PTR(err);
208}
209
210static int __init exiu_dt_init(struct device_node *node,
211 struct device_node *parent)
212{
213 struct irq_domain *parent_domain, *domain;
214 struct exiu_irq_data *data;
215 struct resource res;
216
217 if (!parent) {
218 pr_err("%pOF: no parent, giving up\n", node);
219 return -ENODEV;
220 }
221
222 parent_domain = irq_find_host(parent);
223 if (!parent_domain) {
224 pr_err("%pOF: unable to obtain parent domain\n", node);
225 return -ENXIO;
226 }
227
228 if (of_address_to_resource(node, 0, &res)) {
229 pr_err("%pOF: failed to parse memory resource\n", node);
230 return -ENXIO;
231 }
232
233 data = exiu_init(of_node_to_fwnode(node), &res);
234 if (IS_ERR(data))
235 return PTR_ERR(data);
236
205 domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node, 237 domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
206 &exiu_domain_ops, data); 238 &exiu_domain_ops, data);
207 if (!domain) { 239 if (!domain) {
208 pr_err("%pOF: failed to allocate domain\n", node); 240 pr_err("%pOF: failed to allocate domain\n", node);
209 err = -ENOMEM;
210 goto out_unmap; 241 goto out_unmap;
211 } 242 }
212 243
@@ -217,8 +248,57 @@ static int __init exiu_init(struct device_node *node,
217 248
218out_unmap: 249out_unmap:
219 iounmap(data->base); 250 iounmap(data->base);
220out_free:
221 kfree(data); 251 kfree(data);
222 return err; 252 return -ENOMEM;
223} 253}
224IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init); 254IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);
255
256#ifdef CONFIG_ACPI
257static int exiu_acpi_probe(struct platform_device *pdev)
258{
259 struct irq_domain *domain;
260 struct exiu_irq_data *data;
261 struct resource *res;
262
263 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
264 if (!res) {
265 dev_err(&pdev->dev, "failed to parse memory resource\n");
266 return -ENXIO;
267 }
268
269 data = exiu_init(dev_fwnode(&pdev->dev), res);
270 if (IS_ERR(data))
271 return PTR_ERR(data);
272
273 domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
274 &exiu_domain_ops, data);
275 if (!domain) {
276 dev_err(&pdev->dev, "failed to create IRQ domain\n");
277 goto out_unmap;
278 }
279
280 dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
281
282 return 0;
283
284out_unmap:
285 iounmap(data->base);
286 kfree(data);
287 return -ENOMEM;
288}
289
290static const struct acpi_device_id exiu_acpi_ids[] = {
291 { "SCX0008" },
292 { /* sentinel */ }
293};
294MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);
295
296static struct platform_driver exiu_driver = {
297 .driver = {
298 .name = "exiu",
299 .acpi_match_table = exiu_acpi_ids,
300 },
301 .probe = exiu_acpi_probe,
302};
303builtin_platform_driver(exiu_driver);
304#endif
diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c
index 067337ab3f20..d88e993aa66d 100644
--- a/drivers/irqchip/qcom-irq-combiner.c
+++ b/drivers/irqchip/qcom-irq-combiner.c
@@ -229,7 +229,6 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb)
229static int __init combiner_probe(struct platform_device *pdev) 229static int __init combiner_probe(struct platform_device *pdev)
230{ 230{
231 struct combiner *combiner; 231 struct combiner *combiner;
232 size_t alloc_sz;
233 int nregs; 232 int nregs;
234 int err; 233 int err;
235 234
@@ -239,8 +238,8 @@ static int __init combiner_probe(struct platform_device *pdev)
239 return -EINVAL; 238 return -EINVAL;
240 } 239 }
241 240
242 alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs; 241 combiner = devm_kzalloc(&pdev->dev, struct_size(combiner, regs, nregs),
243 combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL); 242 GFP_KERNEL);
244 if (!combiner) 243 if (!combiner)
245 return -ENOMEM; 244 return -ENOMEM;
246 245
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 5bcd23e5ccd6..469be6844703 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -10,6 +10,7 @@
10 10
11#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/ioport.h> /* for struct resource */ 12#include <linux/ioport.h> /* for struct resource */
13#include <linux/irqdomain.h>
13#include <linux/resource_ext.h> 14#include <linux/resource_ext.h>
14#include <linux/device.h> 15#include <linux/device.h>
15#include <linux/property.h> 16#include <linux/property.h>
@@ -314,6 +315,12 @@ int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
314void acpi_set_irq_model(enum acpi_irq_model_id model, 315void acpi_set_irq_model(enum acpi_irq_model_id model,
315 struct fwnode_handle *fwnode); 316 struct fwnode_handle *fwnode);
316 317
318struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
319 unsigned int size,
320 struct fwnode_handle *fwnode,
321 const struct irq_domain_ops *ops,
322 void *host_data);
323
317#ifdef CONFIG_X86_IO_APIC 324#ifdef CONFIG_X86_IO_APIC
318extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity); 325extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
319#else 326#else
diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h
index 626283858563..b9850f5f1906 100644
--- a/include/linux/irqchip/arm-gic-common.h
+++ b/include/linux/irqchip/arm-gic-common.h
@@ -36,4 +36,9 @@ struct gic_kvm_info {
36 36
37const struct gic_kvm_info *gic_get_kvm_info(void); 37const struct gic_kvm_info *gic_get_kvm_info(void);
38 38
39struct irq_domain;
40struct fwnode_handle;
41int gicv2m_init(struct fwnode_handle *parent_handle,
42 struct irq_domain *parent);
43
39#endif /* __LINUX_IRQCHIP_ARM_GIC_COMMON_H */ 44#endif /* __LINUX_IRQCHIP_ARM_GIC_COMMON_H */
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 316087da1d09..5686711b0f40 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -157,9 +157,6 @@ int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq);
157 */ 157 */
158void gic_init(void __iomem *dist , void __iomem *cpu); 158void gic_init(void __iomem *dist , void __iomem *cpu);
159 159
160int gicv2m_init(struct fwnode_handle *parent_handle,
161 struct irq_domain *parent);
162
163void gic_send_sgi(unsigned int cpu_id, unsigned int irq); 160void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
164int gic_get_cpu_id(unsigned int cpu); 161int gic_get_cpu_id(unsigned int cpu);
165void gic_migrate_target(unsigned int new_cpu_id); 162void gic_migrate_target(unsigned int new_cpu_id);
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index ff6e352e3a6c..b4f53717d143 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -2,6 +2,9 @@
2 2
3obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o 3obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
4obj-$(CONFIG_IRQ_TIMINGS) += timings.o 4obj-$(CONFIG_IRQ_TIMINGS) += timings.o
5ifeq ($(CONFIG_TEST_IRQ_TIMINGS),y)
6 CFLAGS_timings.o += -DDEBUG
7endif
5obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o 8obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
6obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o 9obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
7obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o 10obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
index f18cd5aa33e8..4352b08ae48d 100644
--- a/kernel/irq/affinity.c
+++ b/kernel/irq/affinity.c
@@ -94,8 +94,7 @@ static int get_nodes_in_cpumask(cpumask_var_t *node_to_cpumask,
94 return nodes; 94 return nodes;
95} 95}
96 96
97static int __irq_build_affinity_masks(const struct irq_affinity *affd, 97static int __irq_build_affinity_masks(unsigned int startvec,
98 unsigned int startvec,
99 unsigned int numvecs, 98 unsigned int numvecs,
100 unsigned int firstvec, 99 unsigned int firstvec,
101 cpumask_var_t *node_to_cpumask, 100 cpumask_var_t *node_to_cpumask,
@@ -171,8 +170,7 @@ static int __irq_build_affinity_masks(const struct irq_affinity *affd,
171 * 1) spread present CPU on these vectors 170 * 1) spread present CPU on these vectors
172 * 2) spread other possible CPUs on these vectors 171 * 2) spread other possible CPUs on these vectors
173 */ 172 */
174static int irq_build_affinity_masks(const struct irq_affinity *affd, 173static int irq_build_affinity_masks(unsigned int startvec, unsigned int numvecs,
175 unsigned int startvec, unsigned int numvecs,
176 unsigned int firstvec, 174 unsigned int firstvec,
177 struct irq_affinity_desc *masks) 175 struct irq_affinity_desc *masks)
178{ 176{
@@ -197,7 +195,7 @@ static int irq_build_affinity_masks(const struct irq_affinity *affd,
197 build_node_to_cpumask(node_to_cpumask); 195 build_node_to_cpumask(node_to_cpumask);
198 196
199 /* Spread on present CPUs starting from affd->pre_vectors */ 197 /* Spread on present CPUs starting from affd->pre_vectors */
200 nr_present = __irq_build_affinity_masks(affd, curvec, numvecs, 198 nr_present = __irq_build_affinity_masks(curvec, numvecs,
201 firstvec, node_to_cpumask, 199 firstvec, node_to_cpumask,
202 cpu_present_mask, nmsk, masks); 200 cpu_present_mask, nmsk, masks);
203 201
@@ -212,7 +210,7 @@ static int irq_build_affinity_masks(const struct irq_affinity *affd,
212 else 210 else
213 curvec = firstvec + nr_present; 211 curvec = firstvec + nr_present;
214 cpumask_andnot(npresmsk, cpu_possible_mask, cpu_present_mask); 212 cpumask_andnot(npresmsk, cpu_possible_mask, cpu_present_mask);
215 nr_others = __irq_build_affinity_masks(affd, curvec, numvecs, 213 nr_others = __irq_build_affinity_masks(curvec, numvecs,
216 firstvec, node_to_cpumask, 214 firstvec, node_to_cpumask,
217 npresmsk, nmsk, masks); 215 npresmsk, nmsk, masks);
218 put_online_cpus(); 216 put_online_cpus();
@@ -295,7 +293,7 @@ irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
295 unsigned int this_vecs = affd->set_size[i]; 293 unsigned int this_vecs = affd->set_size[i];
296 int ret; 294 int ret;
297 295
298 ret = irq_build_affinity_masks(affd, curvec, this_vecs, 296 ret = irq_build_affinity_masks(curvec, this_vecs,
299 curvec, masks); 297 curvec, masks);
300 if (ret) { 298 if (ret) {
301 kfree(masks); 299 kfree(masks);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 29d6c7d070b4..04c850fb70cb 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -748,6 +748,8 @@ void handle_fasteoi_nmi(struct irq_desc *desc)
748 unsigned int irq = irq_desc_get_irq(desc); 748 unsigned int irq = irq_desc_get_irq(desc);
749 irqreturn_t res; 749 irqreturn_t res;
750 750
751 __kstat_incr_irqs_this_cpu(desc);
752
751 trace_irq_handler_entry(irq, action); 753 trace_irq_handler_entry(irq, action);
752 /* 754 /*
753 * NMIs cannot be shared, there is only one action. 755 * NMIs cannot be shared, there is only one action.
@@ -962,6 +964,8 @@ void handle_percpu_devid_fasteoi_nmi(struct irq_desc *desc)
962 unsigned int irq = irq_desc_get_irq(desc); 964 unsigned int irq = irq_desc_get_irq(desc);
963 irqreturn_t res; 965 irqreturn_t res;
964 966
967 __kstat_incr_irqs_this_cpu(desc);
968
965 trace_irq_handler_entry(irq, action); 969 trace_irq_handler_entry(irq, action);
966 res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id)); 970 res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
967 trace_irq_handler_exit(irq, action, res); 971 trace_irq_handler_exit(irq, action, res);
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 70c3053bc1f6..21f9927ff5ad 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -354,6 +354,16 @@ static inline int irq_timing_decode(u64 value, u64 *timestamp)
354 return value & U16_MAX; 354 return value & U16_MAX;
355} 355}
356 356
357static __always_inline void irq_timings_push(u64 ts, int irq)
358{
359 struct irq_timings *timings = this_cpu_ptr(&irq_timings);
360
361 timings->values[timings->count & IRQ_TIMINGS_MASK] =
362 irq_timing_encode(ts, irq);
363
364 timings->count++;
365}
366
357/* 367/*
358 * The function record_irq_time is only called in one place in the 368 * The function record_irq_time is only called in one place in the
359 * interrupts handler. We want this function always inline so the code 369 * interrupts handler. We want this function always inline so the code
@@ -367,15 +377,8 @@ static __always_inline void record_irq_time(struct irq_desc *desc)
367 if (!static_branch_likely(&irq_timing_enabled)) 377 if (!static_branch_likely(&irq_timing_enabled))
368 return; 378 return;
369 379
370 if (desc->istate & IRQS_TIMINGS) { 380 if (desc->istate & IRQS_TIMINGS)
371 struct irq_timings *timings = this_cpu_ptr(&irq_timings); 381 irq_timings_push(local_clock(), irq_desc_get_irq(desc));
372
373 timings->values[timings->count & IRQ_TIMINGS_MASK] =
374 irq_timing_encode(local_clock(),
375 irq_desc_get_irq(desc));
376
377 timings->count++;
378 }
379} 382}
380#else 383#else
381static inline void irq_remove_timings(struct irq_desc *desc) {} 384static inline void irq_remove_timings(struct irq_desc *desc) {}
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index a92b33593b8d..9484e88dabc2 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -950,6 +950,11 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
950 *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; 950 *per_cpu_ptr(desc->kstat_irqs, cpu) : 0;
951} 951}
952 952
953static bool irq_is_nmi(struct irq_desc *desc)
954{
955 return desc->istate & IRQS_NMI;
956}
957
953/** 958/**
954 * kstat_irqs - Get the statistics for an interrupt 959 * kstat_irqs - Get the statistics for an interrupt
955 * @irq: The interrupt number 960 * @irq: The interrupt number
@@ -967,7 +972,8 @@ unsigned int kstat_irqs(unsigned int irq)
967 if (!desc || !desc->kstat_irqs) 972 if (!desc || !desc->kstat_irqs)
968 return 0; 973 return 0;
969 if (!irq_settings_is_per_cpu_devid(desc) && 974 if (!irq_settings_is_per_cpu_devid(desc) &&
970 !irq_settings_is_per_cpu(desc)) 975 !irq_settings_is_per_cpu(desc) &&
976 !irq_is_nmi(desc))
971 return desc->tot_count; 977 return desc->tot_count;
972 978
973 for_each_possible_cpu(cpu) 979 for_each_possible_cpu(cpu)
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index a453e229f99c..3078d0e48bba 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -123,7 +123,7 @@ EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
123 * @ops: domain callbacks 123 * @ops: domain callbacks
124 * @host_data: Controller private data pointer 124 * @host_data: Controller private data pointer
125 * 125 *
126 * Allocates and initialize and irq_domain structure. 126 * Allocates and initializes an irq_domain structure.
127 * Returns pointer to IRQ domain, or NULL on failure. 127 * Returns pointer to IRQ domain, or NULL on failure.
128 */ 128 */
129struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, 129struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
@@ -139,7 +139,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
139 139
140 domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), 140 domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
141 GFP_KERNEL, of_node_to_nid(of_node)); 141 GFP_KERNEL, of_node_to_nid(of_node));
142 if (WARN_ON(!domain)) 142 if (!domain)
143 return NULL; 143 return NULL;
144 144
145 if (fwnode && is_fwnode_irqchip(fwnode)) { 145 if (fwnode && is_fwnode_irqchip(fwnode)) {
diff --git a/kernel/irq/timings.c b/kernel/irq/timings.c
index 90c735da15d0..e960d7ce7bcc 100644
--- a/kernel/irq/timings.c
+++ b/kernel/irq/timings.c
@@ -1,10 +1,12 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 2// Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
3#define pr_fmt(fmt) "irq_timings: " fmt
3 4
4#include <linux/kernel.h> 5#include <linux/kernel.h>
5#include <linux/percpu.h> 6#include <linux/percpu.h>
6#include <linux/slab.h> 7#include <linux/slab.h>
7#include <linux/static_key.h> 8#include <linux/static_key.h>
9#include <linux/init.h>
8#include <linux/interrupt.h> 10#include <linux/interrupt.h>
9#include <linux/idr.h> 11#include <linux/idr.h>
10#include <linux/irq.h> 12#include <linux/irq.h>
@@ -261,12 +263,29 @@ void irq_timings_disable(void)
261#define EMA_ALPHA_VAL 64 263#define EMA_ALPHA_VAL 64
262#define EMA_ALPHA_SHIFT 7 264#define EMA_ALPHA_SHIFT 7
263 265
264#define PREDICTION_PERIOD_MIN 2 266#define PREDICTION_PERIOD_MIN 3
265#define PREDICTION_PERIOD_MAX 5 267#define PREDICTION_PERIOD_MAX 5
266#define PREDICTION_FACTOR 4 268#define PREDICTION_FACTOR 4
267#define PREDICTION_MAX 10 /* 2 ^ PREDICTION_MAX useconds */ 269#define PREDICTION_MAX 10 /* 2 ^ PREDICTION_MAX useconds */
268#define PREDICTION_BUFFER_SIZE 16 /* slots for EMAs, hardly more than 16 */ 270#define PREDICTION_BUFFER_SIZE 16 /* slots for EMAs, hardly more than 16 */
269 271
272/*
273 * Number of elements in the circular buffer: If it happens it was
274 * flushed before, then the number of elements could be smaller than
275 * IRQ_TIMINGS_SIZE, so the count is used, otherwise the array size is
276 * used as we wrapped. The index begins from zero when we did not
277 * wrap. That could be done in a nicer way with the proper circular
278 * array structure type but with the cost of extra computation in the
279 * interrupt handler hot path. We choose efficiency.
280 */
281#define for_each_irqts(i, irqts) \
282 for (i = irqts->count < IRQ_TIMINGS_SIZE ? \
283 0 : irqts->count & IRQ_TIMINGS_MASK, \
284 irqts->count = min(IRQ_TIMINGS_SIZE, \
285 irqts->count); \
286 irqts->count > 0; irqts->count--, \
287 i = (i + 1) & IRQ_TIMINGS_MASK)
288
270struct irqt_stat { 289struct irqt_stat {
271 u64 last_ts; 290 u64 last_ts;
272 u64 ema_time[PREDICTION_BUFFER_SIZE]; 291 u64 ema_time[PREDICTION_BUFFER_SIZE];
@@ -297,7 +316,16 @@ static u64 irq_timings_ema_new(u64 value, u64 ema_old)
297 316
298static int irq_timings_next_event_index(int *buffer, size_t len, int period_max) 317static int irq_timings_next_event_index(int *buffer, size_t len, int period_max)
299{ 318{
300 int i; 319 int period;
320
321 /*
322 * Move the beginning pointer to the end minus the max period x 3.
323 * We are at the point we can begin searching the pattern
324 */
325 buffer = &buffer[len - (period_max * 3)];
326
327 /* Adjust the length to the maximum allowed period x 3 */
328 len = period_max * 3;
301 329
302 /* 330 /*
303 * The buffer contains the suite of intervals, in a ilog2 331 * The buffer contains the suite of intervals, in a ilog2
@@ -306,21 +334,45 @@ static int irq_timings_next_event_index(int *buffer, size_t len, int period_max)
306 * period beginning at the end of the buffer. We do that for 334 * period beginning at the end of the buffer. We do that for
307 * each suffix. 335 * each suffix.
308 */ 336 */
309 for (i = period_max; i >= PREDICTION_PERIOD_MIN ; i--) { 337 for (period = period_max; period >= PREDICTION_PERIOD_MIN; period--) {
310 338
311 int *begin = &buffer[len - (i * 3)]; 339 /*
312 int *ptr = begin; 340 * The first comparison always succeed because the
341 * suffix is deduced from the first n-period bytes of
342 * the buffer and we compare the initial suffix with
343 * itself, so we can skip the first iteration.
344 */
345 int idx = period;
346 size_t size = period;
313 347
314 /* 348 /*
315 * We look if the suite with period 'i' repeat 349 * We look if the suite with period 'i' repeat
316 * itself. If it is truncated at the end, as it 350 * itself. If it is truncated at the end, as it
317 * repeats we can use the period to find out the next 351 * repeats we can use the period to find out the next
318 * element. 352 * element with the modulo.
319 */ 353 */
320 while (!memcmp(ptr, begin, i * sizeof(*ptr))) { 354 while (!memcmp(buffer, &buffer[idx], size * sizeof(int))) {
321 ptr += i; 355
322 if (ptr >= &buffer[len]) 356 /*
323 return begin[((i * 3) % i)]; 357 * Move the index in a period basis
358 */
359 idx += size;
360
361 /*
362 * If this condition is reached, all previous
363 * memcmp were successful, so the period is
364 * found.
365 */
366 if (idx == len)
367 return buffer[len % period];
368
369 /*
370 * If the remaining elements to compare are
371 * smaller than the period, readjust the size
372 * of the comparison for the last iteration.
373 */
374 if (len - idx < period)
375 size = len - idx;
324 } 376 }
325 } 377 }
326 378
@@ -380,11 +432,43 @@ static u64 __irq_timings_next_event(struct irqt_stat *irqs, int irq, u64 now)
380 return irqs->last_ts + irqs->ema_time[index]; 432 return irqs->last_ts + irqs->ema_time[index];
381} 433}
382 434
435static __always_inline int irq_timings_interval_index(u64 interval)
436{
437 /*
438 * The PREDICTION_FACTOR increase the interval size for the
439 * array of exponential average.
440 */
441 u64 interval_us = (interval >> 10) / PREDICTION_FACTOR;
442
443 return likely(interval_us) ? ilog2(interval_us) : 0;
444}
445
446static __always_inline void __irq_timings_store(int irq, struct irqt_stat *irqs,
447 u64 interval)
448{
449 int index;
450
451 /*
452 * Get the index in the ema table for this interrupt.
453 */
454 index = irq_timings_interval_index(interval);
455
456 /*
457 * Store the index as an element of the pattern in another
458 * circular array.
459 */
460 irqs->circ_timings[irqs->count & IRQ_TIMINGS_MASK] = index;
461
462 irqs->ema_time[index] = irq_timings_ema_new(interval,
463 irqs->ema_time[index]);
464
465 irqs->count++;
466}
467
383static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts) 468static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts)
384{ 469{
385 u64 old_ts = irqs->last_ts; 470 u64 old_ts = irqs->last_ts;
386 u64 interval; 471 u64 interval;
387 int index;
388 472
389 /* 473 /*
390 * The timestamps are absolute time values, we need to compute 474 * The timestamps are absolute time values, we need to compute
@@ -415,24 +499,7 @@ static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts)
415 return; 499 return;
416 } 500 }
417 501
418 /* 502 __irq_timings_store(irq, irqs, interval);
419 * Get the index in the ema table for this interrupt. The
420 * PREDICTION_FACTOR increase the interval size for the array
421 * of exponential average.
422 */
423 index = likely(interval) ?
424 ilog2((interval >> 10) / PREDICTION_FACTOR) : 0;
425
426 /*
427 * Store the index as an element of the pattern in another
428 * circular array.
429 */
430 irqs->circ_timings[irqs->count & IRQ_TIMINGS_MASK] = index;
431
432 irqs->ema_time[index] = irq_timings_ema_new(interval,
433 irqs->ema_time[index]);
434
435 irqs->count++;
436} 503}
437 504
438/** 505/**
@@ -493,11 +560,7 @@ u64 irq_timings_next_event(u64 now)
493 * model while decrementing the counter because we consume the 560 * model while decrementing the counter because we consume the
494 * data from our circular buffer. 561 * data from our circular buffer.
495 */ 562 */
496 563 for_each_irqts(i, irqts) {
497 i = (irqts->count & IRQ_TIMINGS_MASK) - 1;
498 irqts->count = min(IRQ_TIMINGS_SIZE, irqts->count);
499
500 for (; irqts->count > 0; irqts->count--, i = (i + 1) & IRQ_TIMINGS_MASK) {
501 irq = irq_timing_decode(irqts->values[i], &ts); 564 irq = irq_timing_decode(irqts->values[i], &ts);
502 s = idr_find(&irqt_stats, irq); 565 s = idr_find(&irqt_stats, irq);
503 if (s) 566 if (s)
@@ -564,3 +627,325 @@ int irq_timings_alloc(int irq)
564 627
565 return 0; 628 return 0;
566} 629}
630
631#ifdef CONFIG_TEST_IRQ_TIMINGS
632struct timings_intervals {
633 u64 *intervals;
634 size_t count;
635};
636
637/*
638 * Intervals are given in nanosecond base
639 */
640static u64 intervals0[] __initdata = {
641 10000, 50000, 200000, 500000,
642 10000, 50000, 200000, 500000,
643 10000, 50000, 200000, 500000,
644 10000, 50000, 200000, 500000,
645 10000, 50000, 200000, 500000,
646 10000, 50000, 200000, 500000,
647 10000, 50000, 200000, 500000,
648 10000, 50000, 200000, 500000,
649 10000, 50000, 200000,
650};
651
652static u64 intervals1[] __initdata = {
653 223947000, 1240000, 1384000, 1386000, 1386000,
654 217416000, 1236000, 1384000, 1386000, 1387000,
655 214719000, 1241000, 1386000, 1387000, 1384000,
656 213696000, 1234000, 1384000, 1386000, 1388000,
657 219904000, 1240000, 1385000, 1389000, 1385000,
658 212240000, 1240000, 1386000, 1386000, 1386000,
659 214415000, 1236000, 1384000, 1386000, 1387000,
660 214276000, 1234000,
661};
662
663static u64 intervals2[] __initdata = {
664 4000, 3000, 5000, 100000,
665 3000, 3000, 5000, 117000,
666 4000, 4000, 5000, 112000,
667 4000, 3000, 4000, 110000,
668 3000, 5000, 3000, 117000,
669 4000, 4000, 5000, 112000,
670 4000, 3000, 4000, 110000,
671 3000, 4000, 5000, 112000,
672 4000,
673};
674
675static u64 intervals3[] __initdata = {
676 1385000, 212240000, 1240000,
677 1386000, 214415000, 1236000,
678 1384000, 214276000, 1234000,
679 1386000, 214415000, 1236000,
680 1385000, 212240000, 1240000,
681 1386000, 214415000, 1236000,
682 1384000, 214276000, 1234000,
683 1386000, 214415000, 1236000,
684 1385000, 212240000, 1240000,
685};
686
687static u64 intervals4[] __initdata = {
688 10000, 50000, 10000, 50000,
689 10000, 50000, 10000, 50000,
690 10000, 50000, 10000, 50000,
691 10000, 50000, 10000, 50000,
692 10000, 50000, 10000, 50000,
693 10000, 50000, 10000, 50000,
694 10000, 50000, 10000, 50000,
695 10000, 50000, 10000, 50000,
696 10000,
697};
698
699static struct timings_intervals tis[] __initdata = {
700 { intervals0, ARRAY_SIZE(intervals0) },
701 { intervals1, ARRAY_SIZE(intervals1) },
702 { intervals2, ARRAY_SIZE(intervals2) },
703 { intervals3, ARRAY_SIZE(intervals3) },
704 { intervals4, ARRAY_SIZE(intervals4) },
705};
706
707static int __init irq_timings_test_next_index(struct timings_intervals *ti)
708{
709 int _buffer[IRQ_TIMINGS_SIZE];
710 int buffer[IRQ_TIMINGS_SIZE];
711 int index, start, i, count, period_max;
712
713 count = ti->count - 1;
714
715 period_max = count > (3 * PREDICTION_PERIOD_MAX) ?
716 PREDICTION_PERIOD_MAX : count / 3;
717
718 /*
719 * Inject all values except the last one which will be used
720 * to compare with the next index result.
721 */
722 pr_debug("index suite: ");
723
724 for (i = 0; i < count; i++) {
725 index = irq_timings_interval_index(ti->intervals[i]);
726 _buffer[i & IRQ_TIMINGS_MASK] = index;
727 pr_cont("%d ", index);
728 }
729
730 start = count < IRQ_TIMINGS_SIZE ? 0 :
731 count & IRQ_TIMINGS_MASK;
732
733 count = min_t(int, count, IRQ_TIMINGS_SIZE);
734
735 for (i = 0; i < count; i++) {
736 int index = (start + i) & IRQ_TIMINGS_MASK;
737 buffer[i] = _buffer[index];
738 }
739
740 index = irq_timings_next_event_index(buffer, count, period_max);
741 i = irq_timings_interval_index(ti->intervals[ti->count - 1]);
742
743 if (index != i) {
744 pr_err("Expected (%d) and computed (%d) next indexes differ\n",
745 i, index);
746 return -EINVAL;
747 }
748
749 return 0;
750}
751
752static int __init irq_timings_next_index_selftest(void)
753{
754 int i, ret;
755
756 for (i = 0; i < ARRAY_SIZE(tis); i++) {
757
758 pr_info("---> Injecting intervals number #%d (count=%zd)\n",
759 i, tis[i].count);
760
761 ret = irq_timings_test_next_index(&tis[i]);
762 if (ret)
763 break;
764 }
765
766 return ret;
767}
768
769static int __init irq_timings_test_irqs(struct timings_intervals *ti)
770{
771 struct irqt_stat __percpu *s;
772 struct irqt_stat *irqs;
773 int i, index, ret, irq = 0xACE5;
774
775 ret = irq_timings_alloc(irq);
776 if (ret) {
777 pr_err("Failed to allocate irq timings\n");
778 return ret;
779 }
780
781 s = idr_find(&irqt_stats, irq);
782 if (!s) {
783 ret = -EIDRM;
784 goto out;
785 }
786
787 irqs = this_cpu_ptr(s);
788
789 for (i = 0; i < ti->count; i++) {
790
791 index = irq_timings_interval_index(ti->intervals[i]);
792 pr_debug("%d: interval=%llu ema_index=%d\n",
793 i, ti->intervals[i], index);
794
795 __irq_timings_store(irq, irqs, ti->intervals[i]);
796 if (irqs->circ_timings[i & IRQ_TIMINGS_MASK] != index) {
797 pr_err("Failed to store in the circular buffer\n");
798 goto out;
799 }
800 }
801
802 if (irqs->count != ti->count) {
803 pr_err("Count differs\n");
804 goto out;
805 }
806
807 ret = 0;
808out:
809 irq_timings_free(irq);
810
811 return ret;
812}
813
814static int __init irq_timings_irqs_selftest(void)
815{
816 int i, ret;
817
818 for (i = 0; i < ARRAY_SIZE(tis); i++) {
819 pr_info("---> Injecting intervals number #%d (count=%zd)\n",
820 i, tis[i].count);
821 ret = irq_timings_test_irqs(&tis[i]);
822 if (ret)
823 break;
824 }
825
826 return ret;
827}
828
829static int __init irq_timings_test_irqts(struct irq_timings *irqts,
830 unsigned count)
831{
832 int start = count >= IRQ_TIMINGS_SIZE ? count - IRQ_TIMINGS_SIZE : 0;
833 int i, irq, oirq = 0xBEEF;
834 u64 ots = 0xDEAD, ts;
835
836 /*
837 * Fill the circular buffer by using the dedicated function.
838 */
839 for (i = 0; i < count; i++) {
840 pr_debug("%d: index=%d, ts=%llX irq=%X\n",
841 i, i & IRQ_TIMINGS_MASK, ots + i, oirq + i);
842
843 irq_timings_push(ots + i, oirq + i);
844 }
845
846 /*
847 * Compute the first elements values after the index wrapped
848 * up or not.
849 */
850 ots += start;
851 oirq += start;
852
853 /*
854 * Test the circular buffer count is correct.
855 */
856 pr_debug("---> Checking timings array count (%d) is right\n", count);
857 if (WARN_ON(irqts->count != count))
858 return -EINVAL;
859
860 /*
861 * Test the macro allowing to browse all the irqts.
862 */
863 pr_debug("---> Checking the for_each_irqts() macro\n");
864 for_each_irqts(i, irqts) {
865
866 irq = irq_timing_decode(irqts->values[i], &ts);
867
868 pr_debug("index=%d, ts=%llX / %llX, irq=%X / %X\n",
869 i, ts, ots, irq, oirq);
870
871 if (WARN_ON(ts != ots || irq != oirq))
872 return -EINVAL;
873
874 ots++; oirq++;
875 }
876
877 /*
878 * The circular buffer should have be flushed when browsed
879 * with for_each_irqts
880 */
881 pr_debug("---> Checking timings array is empty after browsing it\n");
882 if (WARN_ON(irqts->count))
883 return -EINVAL;
884
885 return 0;
886}
887
888static int __init irq_timings_irqts_selftest(void)
889{
890 struct irq_timings *irqts = this_cpu_ptr(&irq_timings);
891 int i, ret;
892
893 /*
894 * Test the circular buffer with different number of
895 * elements. The purpose is to test at the limits (empty, half
896 * full, full, wrapped with the cursor at the boundaries,
897 * wrapped several times, etc ...
898 */
899 int count[] = { 0,
900 IRQ_TIMINGS_SIZE >> 1,
901 IRQ_TIMINGS_SIZE,
902 IRQ_TIMINGS_SIZE + (IRQ_TIMINGS_SIZE >> 1),
903 2 * IRQ_TIMINGS_SIZE,
904 (2 * IRQ_TIMINGS_SIZE) + 3,
905 };
906
907 for (i = 0; i < ARRAY_SIZE(count); i++) {
908
909 pr_info("---> Checking the timings with %d/%d values\n",
910 count[i], IRQ_TIMINGS_SIZE);
911
912 ret = irq_timings_test_irqts(irqts, count[i]);
913 if (ret)
914 break;
915 }
916
917 return ret;
918}
919
920static int __init irq_timings_selftest(void)
921{
922 int ret;
923
924 pr_info("------------------- selftest start -----------------\n");
925
926 /*
927 * At this point, we don't except any subsystem to use the irq
928 * timings but us, so it should not be enabled.
929 */
930 if (static_branch_unlikely(&irq_timing_enabled)) {
931 pr_warn("irq timings already initialized, skipping selftest\n");
932 return 0;
933 }
934
935 ret = irq_timings_irqts_selftest();
936 if (ret)
937 goto out;
938
939 ret = irq_timings_irqs_selftest();
940 if (ret)
941 goto out;
942
943 ret = irq_timings_next_index_selftest();
944out:
945 pr_info("---------- selftest end with %s -----------\n",
946 ret ? "failure" : "success");
947
948 return ret;
949}
950early_initcall(irq_timings_selftest);
951#endif
diff --git a/kernel/softirq.c b/kernel/softirq.c
index a6b81c6b6bff..0427a86743a4 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -649,7 +649,7 @@ static int takeover_tasklets(unsigned int cpu)
649 /* Find end, append list for that CPU. */ 649 /* Find end, append list for that CPU. */
650 if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) { 650 if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
651 *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head; 651 *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head;
652 this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail); 652 __this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail);
653 per_cpu(tasklet_vec, cpu).head = NULL; 653 per_cpu(tasklet_vec, cpu).head = NULL;
654 per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head; 654 per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
655 } 655 }
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index b0d71d9293dc..6629cab453e8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1870,6 +1870,14 @@ config TEST_PARMAN
1870 1870
1871 If unsure, say N. 1871 If unsure, say N.
1872 1872
1873config TEST_IRQ_TIMINGS
1874 bool "IRQ timings selftest"
1875 depends on IRQ_TIMINGS
1876 help
1877 Enable this option to test the irq timings code on boot.
1878
1879 If unsure, say N.
1880
1873config TEST_LKM 1881config TEST_LKM
1874 tristate "Test module loading with 'hello world' module" 1882 tristate "Test module loading with 'hello world' module"
1875 depends on m 1883 depends on m