Skip to content

Commit 9b64efa

Browse files
author
Marc Zyngier
committed
Merge branch 'irq/ipi-as-irq', remote-tracking branches 'origin/irq/dw' and 'origin/irq/owl' into irq/irqchip-next
Signed-off-by: Marc Zyngier <maz@kernel.org>
4 parents eff65bd + 8156b80 + aa52429 + 2203870 commit 9b64efa

10 files changed

Lines changed: 537 additions & 27 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/interrupt-controller/actions,owl-sirq.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Actions Semi Owl SoCs SIRQ interrupt controller
8+
9+
maintainers:
10+
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
11+
- Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
12+
13+
description: |
14+
This interrupt controller is found in the Actions Semi Owl SoCs (S500, S700
15+
and S900) and provides support for handling up to 3 external interrupt lines.
16+
17+
properties:
18+
compatible:
19+
enum:
20+
- actions,s500-sirq
21+
- actions,s700-sirq
22+
- actions,s900-sirq
23+
24+
reg:
25+
maxItems: 1
26+
27+
interrupt-controller: true
28+
29+
'#interrupt-cells':
30+
const: 2
31+
description:
32+
The first cell is the input IRQ number, between 0 and 2, while the second
33+
cell is the trigger type as defined in interrupt.txt in this directory.
34+
35+
'interrupts':
36+
description: |
37+
Contains the GIC SPI IRQs mapped to the external interrupt lines.
38+
They shall be specified sequentially from output 0 to 2.
39+
minItems: 3
40+
maxItems: 3
41+
42+
required:
43+
- compatible
44+
- reg
45+
- interrupt-controller
46+
- '#interrupt-cells'
47+
- 'interrupts'
48+
49+
additionalProperties: false
50+
51+
examples:
52+
- |
53+
#include <dt-bindings/interrupt-controller/arm-gic.h>
54+
55+
sirq: interrupt-controller@b01b0200 {
56+
compatible = "actions,s500-sirq";
57+
reg = <0xb01b0200 0x4>;
58+
interrupt-controller;
59+
#interrupt-cells = <2>;
60+
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>, /* SIRQ0 */
61+
<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>, /* SIRQ1 */
62+
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; /* SIRQ2 */
63+
};
64+
65+
...

Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ Synopsys DesignWare APB interrupt controller (dw_apb_ictl)
22

33
Synopsys DesignWare provides interrupt controller IP for APB known as
44
dw_apb_ictl. The IP is used as secondary interrupt controller in some SoCs with
5-
APB bus, e.g. Marvell Armada 1500.
5+
APB bus, e.g. Marvell Armada 1500. It can also be used as primary interrupt
6+
controller in some SoCs, e.g. Hisilicon SD5203.
67

78
Required properties:
89
- compatible: shall be "snps,dw-apb-ictl"
910
- reg: physical base address of the controller and length of memory mapped
1011
region starting with ENABLE_LOW register
1112
- interrupt-controller: identifies the node as an interrupt controller
1213
- #interrupt-cells: number of cells to encode an interrupt-specifier, shall be 1
14+
15+
Additional required property when it's used as secondary interrupt controller:
1316
- interrupts: interrupt reference to primary interrupt controller
1417

1518
The interrupt sources map to the corresponding bits in the interrupt
@@ -21,6 +24,7 @@ registers, i.e.
2124
- (optional) fast interrupts start at 64.
2225

2326
Example:
27+
/* dw_apb_ictl is used as secondary interrupt controller */
2428
aic: interrupt-controller@3000 {
2529
compatible = "snps,dw-apb-ictl";
2630
reg = <0x3000 0xc00>;
@@ -29,3 +33,11 @@ Example:
2933
interrupt-parent = <&gic>;
3034
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
3135
};
36+
37+
/* dw_apb_ictl is used as primary interrupt controller */
38+
vic: interrupt-controller@10130000 {
39+
compatible = "snps,dw-apb-ictl";
40+
reg = <0x10130000 0x1000>;
41+
interrupt-controller;
42+
#interrupt-cells = <1>;
43+
};

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,7 @@ F: Documentation/devicetree/bindings/arm/actions.yaml
15251525
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
15261526
F: Documentation/devicetree/bindings/dma/owl-dma.txt
15271527
F: Documentation/devicetree/bindings/i2c/i2c-owl.txt
1528+
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
15281529
F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml
15291530
F: Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
15301531
F: Documentation/devicetree/bindings/power/actions,owl-sps.txt
@@ -1536,6 +1537,7 @@ F: drivers/clk/actions/
15361537
F: drivers/clocksource/timer-owl*
15371538
F: drivers/dma/owl-dma.c
15381539
F: drivers/i2c/busses/i2c-owl.c
1540+
F: drivers/irqchip/irq-owl-sirq.c
15391541
F: drivers/mmc/host/owl-mmc.c
15401542
F: drivers/pinctrl/actions/*
15411543
F: drivers/soc/actions/

arch/arm/kernel/smp.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ static int nr_ipi __read_mostly = NR_IPI;
8585
static struct irq_desc *ipi_desc[MAX_IPI] __read_mostly;
8686

8787
static void ipi_setup(int cpu);
88-
static void ipi_teardown(int cpu);
8988

9089
static DECLARE_COMPLETION(cpu_running);
9190

@@ -236,6 +235,17 @@ int platform_can_hotplug_cpu(unsigned int cpu)
236235
return cpu != 0;
237236
}
238237

238+
static void ipi_teardown(int cpu)
239+
{
240+
int i;
241+
242+
if (WARN_ON_ONCE(!ipi_irq_base))
243+
return;
244+
245+
for (i = 0; i < nr_ipi; i++)
246+
disable_percpu_irq(ipi_irq_base + i);
247+
}
248+
239249
/*
240250
* __cpu_disable runs on the processor to be shutdown.
241251
*/
@@ -531,7 +541,12 @@ void show_ipi_list(struct seq_file *p, int prec)
531541
unsigned int cpu, i;
532542

533543
for (i = 0; i < NR_IPI; i++) {
534-
unsigned int irq = irq_desc_get_irq(ipi_desc[i]);
544+
unsigned int irq;
545+
546+
if (!ipi_desc[i])
547+
continue;
548+
549+
irq = irq_desc_get_irq(ipi_desc[i]);
535550
seq_printf(p, "%*s%u: ", prec - 1, "IPI", i);
536551

537552
for_each_online_cpu(cpu)
@@ -707,17 +722,6 @@ static void ipi_setup(int cpu)
707722
enable_percpu_irq(ipi_irq_base + i, 0);
708723
}
709724

710-
static void ipi_teardown(int cpu)
711-
{
712-
int i;
713-
714-
if (WARN_ON_ONCE(!ipi_irq_base))
715-
return;
716-
717-
for (i = 0; i < nr_ipi; i++)
718-
disable_percpu_irq(ipi_irq_base + i);
719-
}
720-
721725
void __init set_smp_ipi_range(int ipi_base, int n)
722726
{
723727
int i;

arch/arm64/kernel/smp.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ static int nr_ipi __read_mostly = NR_IPI;
8282
static struct irq_desc *ipi_desc[NR_IPI] __read_mostly;
8383

8484
static void ipi_setup(int cpu);
85-
static void ipi_teardown(int cpu);
8685

8786
#ifdef CONFIG_HOTPLUG_CPU
87+
static void ipi_teardown(int cpu);
8888
static int op_cpu_kill(unsigned int cpu);
8989
#else
9090
static inline int op_cpu_kill(unsigned int cpu)
@@ -964,6 +964,7 @@ static void ipi_setup(int cpu)
964964
enable_percpu_irq(ipi_irq_base + i, 0);
965965
}
966966

967+
#ifdef CONFIG_HOTPLUG_CPU
967968
static void ipi_teardown(int cpu)
968969
{
969970
int i;
@@ -974,6 +975,7 @@ static void ipi_teardown(int cpu)
974975
for (i = 0; i < nr_ipi; i++)
975976
disable_percpu_irq(ipi_irq_base + i);
976977
}
978+
#endif
977979

978980
void __init set_smp_ipi_range(int ipi_base, int n)
979981
{

drivers/irqchip/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ config DAVINCI_CP_INTC
148148
config DW_APB_ICTL
149149
bool
150150
select GENERIC_IRQ_CHIP
151-
select IRQ_DOMAIN
151+
select IRQ_DOMAIN_HIERARCHY
152152

153153
config FARADAY_FTINTC010
154154
bool

drivers/irqchip/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
77
obj-$(CONFIG_ATH79) += irq-ath79-misc.o
88
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
99
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
10+
obj-$(CONFIG_ARCH_ACTIONS) += irq-owl-sirq.o
1011
obj-$(CONFIG_DAVINCI_AINTC) += irq-davinci-aintc.o
1112
obj-$(CONFIG_DAVINCI_CP_INTC) += irq-davinci-cp-intc.o
1213
obj-$(CONFIG_EXYNOS_IRQ_COMBINER) += exynos-combiner.o

drivers/irqchip/irq-dw-apb-ictl.c

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/irqchip/chained_irq.h>
1818
#include <linux/of_address.h>
1919
#include <linux/of_irq.h>
20+
#include <linux/interrupt.h>
2021

2122
#define APB_INT_ENABLE_L 0x00
2223
#define APB_INT_ENABLE_H 0x04
@@ -26,7 +27,28 @@
2627
#define APB_INT_FINALSTATUS_H 0x34
2728
#define APB_INT_BASE_OFFSET 0x04
2829

29-
static void dw_apb_ictl_handler(struct irq_desc *desc)
30+
/* irq domain of the primary interrupt controller. */
31+
static struct irq_domain *dw_apb_ictl_irq_domain;
32+
33+
static void __irq_entry dw_apb_ictl_handle_irq(struct pt_regs *regs)
34+
{
35+
struct irq_domain *d = dw_apb_ictl_irq_domain;
36+
int n;
37+
38+
for (n = 0; n < d->revmap_size; n += 32) {
39+
struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n);
40+
u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L);
41+
42+
while (stat) {
43+
u32 hwirq = ffs(stat) - 1;
44+
45+
handle_domain_irq(d, hwirq, regs);
46+
stat &= ~BIT(hwirq);
47+
}
48+
}
49+
}
50+
51+
static void dw_apb_ictl_handle_irq_cascaded(struct irq_desc *desc)
3052
{
3153
struct irq_domain *d = irq_desc_get_handler_data(desc);
3254
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -43,13 +65,37 @@ static void dw_apb_ictl_handler(struct irq_desc *desc)
4365
u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
4466

4567
generic_handle_irq(virq);
46-
stat &= ~(1 << hwirq);
68+
stat &= ~BIT(hwirq);
4769
}
4870
}
4971

5072
chained_irq_exit(chip, desc);
5173
}
5274

75+
static int dw_apb_ictl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
76+
unsigned int nr_irqs, void *arg)
77+
{
78+
int i, ret;
79+
irq_hw_number_t hwirq;
80+
unsigned int type = IRQ_TYPE_NONE;
81+
struct irq_fwspec *fwspec = arg;
82+
83+
ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
84+
if (ret)
85+
return ret;
86+
87+
for (i = 0; i < nr_irqs; i++)
88+
irq_map_generic_chip(domain, virq + i, hwirq + i);
89+
90+
return 0;
91+
}
92+
93+
static const struct irq_domain_ops dw_apb_ictl_irq_domain_ops = {
94+
.translate = irq_domain_translate_onecell,
95+
.alloc = dw_apb_ictl_irq_domain_alloc,
96+
.free = irq_domain_free_irqs_top,
97+
};
98+
5399
#ifdef CONFIG_PM
54100
static void dw_apb_ictl_resume(struct irq_data *d)
55101
{
@@ -68,19 +114,27 @@ static void dw_apb_ictl_resume(struct irq_data *d)
68114
static int __init dw_apb_ictl_init(struct device_node *np,
69115
struct device_node *parent)
70116
{
117+
const struct irq_domain_ops *domain_ops;
71118
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
72119
struct resource r;
73120
struct irq_domain *domain;
74121
struct irq_chip_generic *gc;
75122
void __iomem *iobase;
76-
int ret, nrirqs, irq, i;
123+
int ret, nrirqs, parent_irq, i;
77124
u32 reg;
78125

79-
/* Map the parent interrupt for the chained handler */
80-
irq = irq_of_parse_and_map(np, 0);
81-
if (irq <= 0) {
82-
pr_err("%pOF: unable to parse irq\n", np);
83-
return -EINVAL;
126+
if (!parent) {
127+
/* Used as the primary interrupt controller */
128+
parent_irq = 0;
129+
domain_ops = &dw_apb_ictl_irq_domain_ops;
130+
} else {
131+
/* Map the parent interrupt for the chained handler */
132+
parent_irq = irq_of_parse_and_map(np, 0);
133+
if (parent_irq <= 0) {
134+
pr_err("%pOF: unable to parse irq\n", np);
135+
return -EINVAL;
136+
}
137+
domain_ops = &irq_generic_chip_ops;
84138
}
85139

86140
ret = of_address_to_resource(np, 0, &r);
@@ -120,8 +174,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
120174
else
121175
nrirqs = fls(readl_relaxed(iobase + APB_INT_ENABLE_L));
122176

123-
domain = irq_domain_add_linear(np, nrirqs,
124-
&irq_generic_chip_ops, NULL);
177+
domain = irq_domain_add_linear(np, nrirqs, domain_ops, NULL);
125178
if (!domain) {
126179
pr_err("%pOF: unable to add irq domain\n", np);
127180
ret = -ENOMEM;
@@ -146,7 +199,13 @@ static int __init dw_apb_ictl_init(struct device_node *np,
146199
gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
147200
}
148201

149-
irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain);
202+
if (parent_irq) {
203+
irq_set_chained_handler_and_data(parent_irq,
204+
dw_apb_ictl_handle_irq_cascaded, domain);
205+
} else {
206+
dw_apb_ictl_irq_domain = domain;
207+
set_handle_irq(dw_apb_ictl_handle_irq);
208+
}
150209

151210
return 0;
152211

0 commit comments

Comments
 (0)