diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-03-09 05:12:00 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-03-09 05:12:00 -0500 |
commit | f49e0eb221f64334797b0c7fb7c6d5d94bac4510 (patch) | |
tree | 4c20fbfa5ce765f5454874eb3a386619dbe76968 | |
parent | fe2f95468e4bdf4a526be4f86efaefe48ca63b83 (diff) | |
parent | 82b0a434b436f5da69ddd24bd6a6fa5dc4484310 (diff) |
Merge tag 'gic-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core
Pull GIC updates for 4.6 from Marc Zyngier:
- Basic GICv3 ACPI support
- Alpine MSI widget on top of GICv3
- More RealView GIC support
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/al,alpine-msix.txt | 26 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt | 1 | ||||
-rw-r--r-- | drivers/irqchip/Kconfig | 6 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-alpine-msi.c | 293 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-realview.c | 44 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 10 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 349 |
8 files changed, 669 insertions, 61 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/al,alpine-msix.txt b/Documentation/devicetree/bindings/interrupt-controller/al,alpine-msix.txt new file mode 100644 index 000000000000..f6f1c14bf99b --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/al,alpine-msix.txt | |||
@@ -0,0 +1,26 @@ | |||
1 | Alpine MSIX controller | ||
2 | |||
3 | See arm,gic-v3.txt for SPI and MSI definitions. | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible: should be "al,alpine-msix" | ||
8 | - reg: physical base address and size of the registers | ||
9 | - interrupt-parent: specifies the parent interrupt controller. | ||
10 | - interrupt-controller: identifies the node as an interrupt controller | ||
11 | - msi-controller: identifies the node as an PCI Message Signaled Interrupt | ||
12 | controller | ||
13 | - al,msi-base-spi: SPI base of the MSI frame | ||
14 | - al,msi-num-spis: number of SPIs assigned to the MSI frame, relative to SPI0 | ||
15 | |||
16 | Example: | ||
17 | |||
18 | msix: msix { | ||
19 | compatible = "al,alpine-msix"; | ||
20 | reg = <0x0 0xfbe00000 0x0 0x100000>; | ||
21 | interrupt-parent = <&gic>; | ||
22 | interrupt-controller; | ||
23 | msi-controller; | ||
24 | al,msi-base-spi = <160>; | ||
25 | al,msi-num-spis = <160>; | ||
26 | }; | ||
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt index 5a1cb4bc3dfe..793c20ff8fcc 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt | |||
@@ -16,6 +16,7 @@ Main node required properties: | |||
16 | "arm,cortex-a15-gic" | 16 | "arm,cortex-a15-gic" |
17 | "arm,cortex-a7-gic" | 17 | "arm,cortex-a7-gic" |
18 | "arm,cortex-a9-gic" | 18 | "arm,cortex-a9-gic" |
19 | "arm,eb11mp-gic" | ||
19 | "arm,gic-400" | 20 | "arm,gic-400" |
20 | "arm,pl390" | 21 | "arm,pl390" |
21 | "arm,tc11mp-gic" | 22 | "arm,tc11mp-gic" |
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 00bbec6eca0b..7e8c441ff2de 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -65,6 +65,12 @@ config ARMADA_370_XP_IRQ | |||
65 | select GENERIC_IRQ_CHIP | 65 | select GENERIC_IRQ_CHIP |
66 | select PCI_MSI_IRQ_DOMAIN if PCI_MSI | 66 | select PCI_MSI_IRQ_DOMAIN if PCI_MSI |
67 | 67 | ||
68 | config ALPINE_MSI | ||
69 | bool | ||
70 | depends on PCI && PCI_MSI | ||
71 | select GENERIC_IRQ_CHIP | ||
72 | select PCI_MSI_IRQ_DOMAIN | ||
73 | |||
68 | config ATMEL_AIC_IRQ | 74 | config ATMEL_AIC_IRQ |
69 | bool | 75 | bool |
70 | select GENERIC_IRQ_CHIP | 76 | select GENERIC_IRQ_CHIP |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 8698710fda37..b03cfcbbac6b 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-$(CONFIG_IRQCHIP) += irqchip.o | 1 | obj-$(CONFIG_IRQCHIP) += irqchip.o |
2 | 2 | ||
3 | obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o | ||
3 | obj-$(CONFIG_ATH79) += irq-ath79-cpu.o | 4 | obj-$(CONFIG_ATH79) += irq-ath79-cpu.o |
4 | obj-$(CONFIG_ATH79) += irq-ath79-misc.o | 5 | obj-$(CONFIG_ATH79) += irq-ath79-misc.o |
5 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o | 6 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o |
diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c new file mode 100644 index 000000000000..f8712722a606 --- /dev/null +++ b/drivers/irqchip/irq-alpine-msi.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * Annapurna Labs MSIX support services | ||
3 | * | ||
4 | * Copyright (C) 2016, Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
5 | * | ||
6 | * Antoine Tenart <antoine.tenart@free-electrons.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | |||
15 | #include <linux/irqchip.h> | ||
16 | #include <linux/irqchip/arm-gic.h> | ||
17 | #include <linux/msi.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/of_irq.h> | ||
21 | #include <linux/of_pci.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <asm/irq.h> | ||
26 | #include <asm-generic/msi.h> | ||
27 | |||
28 | /* MSIX message address format: local GIC target */ | ||
29 | #define ALPINE_MSIX_SPI_TARGET_CLUSTER0 BIT(16) | ||
30 | |||
31 | struct alpine_msix_data { | ||
32 | spinlock_t msi_map_lock; | ||
33 | phys_addr_t addr; | ||
34 | u32 spi_first; /* The SGI number that MSIs start */ | ||
35 | u32 num_spis; /* The number of SGIs for MSIs */ | ||
36 | unsigned long *msi_map; | ||
37 | }; | ||
38 | |||
39 | static void alpine_msix_mask_msi_irq(struct irq_data *d) | ||
40 | { | ||
41 | pci_msi_mask_irq(d); | ||
42 | irq_chip_mask_parent(d); | ||
43 | } | ||
44 | |||
45 | static void alpine_msix_unmask_msi_irq(struct irq_data *d) | ||
46 | { | ||
47 | pci_msi_unmask_irq(d); | ||
48 | irq_chip_unmask_parent(d); | ||
49 | } | ||
50 | |||
51 | static struct irq_chip alpine_msix_irq_chip = { | ||
52 | .name = "MSIx", | ||
53 | .irq_mask = alpine_msix_mask_msi_irq, | ||
54 | .irq_unmask = alpine_msix_unmask_msi_irq, | ||
55 | .irq_eoi = irq_chip_eoi_parent, | ||
56 | .irq_set_affinity = irq_chip_set_affinity_parent, | ||
57 | }; | ||
58 | |||
59 | static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req) | ||
60 | { | ||
61 | int first; | ||
62 | |||
63 | spin_lock(&priv->msi_map_lock); | ||
64 | |||
65 | first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, | ||
66 | num_req, 0); | ||
67 | if (first >= priv->num_spis) { | ||
68 | spin_unlock(&priv->msi_map_lock); | ||
69 | return -ENOSPC; | ||
70 | } | ||
71 | |||
72 | bitmap_set(priv->msi_map, first, num_req); | ||
73 | |||
74 | spin_unlock(&priv->msi_map_lock); | ||
75 | |||
76 | return priv->spi_first + first; | ||
77 | } | ||
78 | |||
79 | static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi, | ||
80 | int num_req) | ||
81 | { | ||
82 | int first = sgi - priv->spi_first; | ||
83 | |||
84 | spin_lock(&priv->msi_map_lock); | ||
85 | |||
86 | bitmap_clear(priv->msi_map, first, num_req); | ||
87 | |||
88 | spin_unlock(&priv->msi_map_lock); | ||
89 | } | ||
90 | |||
91 | static void alpine_msix_compose_msi_msg(struct irq_data *data, | ||
92 | struct msi_msg *msg) | ||
93 | { | ||
94 | struct alpine_msix_data *priv = irq_data_get_irq_chip_data(data); | ||
95 | phys_addr_t msg_addr = priv->addr; | ||
96 | |||
97 | msg_addr |= (data->hwirq << 3); | ||
98 | |||
99 | msg->address_hi = upper_32_bits(msg_addr); | ||
100 | msg->address_lo = lower_32_bits(msg_addr); | ||
101 | msg->data = 0; | ||
102 | } | ||
103 | |||
104 | static struct msi_domain_info alpine_msix_domain_info = { | ||
105 | .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | | ||
106 | MSI_FLAG_PCI_MSIX, | ||
107 | .chip = &alpine_msix_irq_chip, | ||
108 | }; | ||
109 | |||
110 | static struct irq_chip middle_irq_chip = { | ||
111 | .name = "alpine_msix_middle", | ||
112 | .irq_mask = irq_chip_mask_parent, | ||
113 | .irq_unmask = irq_chip_unmask_parent, | ||
114 | .irq_eoi = irq_chip_eoi_parent, | ||
115 | .irq_set_affinity = irq_chip_set_affinity_parent, | ||
116 | .irq_compose_msi_msg = alpine_msix_compose_msi_msg, | ||
117 | }; | ||
118 | |||
119 | static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, | ||
120 | unsigned int virq, int sgi) | ||
121 | { | ||
122 | struct irq_fwspec fwspec; | ||
123 | struct irq_data *d; | ||
124 | int ret; | ||
125 | |||
126 | if (!is_of_node(domain->parent->fwnode)) | ||
127 | return -EINVAL; | ||
128 | |||
129 | fwspec.fwnode = domain->parent->fwnode; | ||
130 | fwspec.param_count = 3; | ||
131 | fwspec.param[0] = 0; | ||
132 | fwspec.param[1] = sgi; | ||
133 | fwspec.param[2] = IRQ_TYPE_EDGE_RISING; | ||
134 | |||
135 | ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); | ||
136 | if (ret) | ||
137 | return ret; | ||
138 | |||
139 | d = irq_domain_get_irq_data(domain->parent, virq); | ||
140 | d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, | ||
146 | unsigned int virq, | ||
147 | unsigned int nr_irqs, void *args) | ||
148 | { | ||
149 | struct alpine_msix_data *priv = domain->host_data; | ||
150 | int sgi, err, i; | ||
151 | |||
152 | sgi = alpine_msix_allocate_sgi(priv, nr_irqs); | ||
153 | if (sgi < 0) | ||
154 | return sgi; | ||
155 | |||
156 | for (i = 0; i < nr_irqs; i++) { | ||
157 | err = alpine_msix_gic_domain_alloc(domain, virq + i, sgi + i); | ||
158 | if (err) | ||
159 | goto err_sgi; | ||
160 | |||
161 | irq_domain_set_hwirq_and_chip(domain, virq + i, sgi + i, | ||
162 | &middle_irq_chip, priv); | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | |||
167 | err_sgi: | ||
168 | while (--i >= 0) | ||
169 | irq_domain_free_irqs_parent(domain, virq, i); | ||
170 | alpine_msix_free_sgi(priv, sgi, nr_irqs); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static void alpine_msix_middle_domain_free(struct irq_domain *domain, | ||
175 | unsigned int virq, | ||
176 | unsigned int nr_irqs) | ||
177 | { | ||
178 | struct irq_data *d = irq_domain_get_irq_data(domain, virq); | ||
179 | struct alpine_msix_data *priv = irq_data_get_irq_chip_data(d); | ||
180 | |||
181 | irq_domain_free_irqs_parent(domain, virq, nr_irqs); | ||
182 | alpine_msix_free_sgi(priv, d->hwirq, nr_irqs); | ||
183 | } | ||
184 | |||
185 | static const struct irq_domain_ops alpine_msix_middle_domain_ops = { | ||
186 | .alloc = alpine_msix_middle_domain_alloc, | ||
187 | .free = alpine_msix_middle_domain_free, | ||
188 | }; | ||
189 | |||
190 | static int alpine_msix_init_domains(struct alpine_msix_data *priv, | ||
191 | struct device_node *node) | ||
192 | { | ||
193 | struct irq_domain *middle_domain, *msi_domain, *gic_domain; | ||
194 | struct device_node *gic_node; | ||
195 | |||
196 | gic_node = of_irq_find_parent(node); | ||
197 | if (!gic_node) { | ||
198 | pr_err("Failed to find the GIC node\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | gic_domain = irq_find_host(gic_node); | ||
203 | if (!gic_domain) { | ||
204 | pr_err("Failed to find the GIC domain\n"); | ||
205 | return -ENXIO; | ||
206 | } | ||
207 | |||
208 | middle_domain = irq_domain_add_tree(NULL, | ||
209 | &alpine_msix_middle_domain_ops, | ||
210 | priv); | ||
211 | if (!middle_domain) { | ||
212 | pr_err("Failed to create the MSIX middle domain\n"); | ||
213 | return -ENOMEM; | ||
214 | } | ||
215 | |||
216 | middle_domain->parent = gic_domain; | ||
217 | |||
218 | msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), | ||
219 | &alpine_msix_domain_info, | ||
220 | middle_domain); | ||
221 | if (!msi_domain) { | ||
222 | pr_err("Failed to create MSI domain\n"); | ||
223 | irq_domain_remove(msi_domain); | ||
224 | return -ENOMEM; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int alpine_msix_init(struct device_node *node, | ||
231 | struct device_node *parent) | ||
232 | { | ||
233 | struct alpine_msix_data *priv; | ||
234 | struct resource res; | ||
235 | int ret; | ||
236 | |||
237 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
238 | if (!priv) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | spin_lock_init(&priv->msi_map_lock); | ||
242 | |||
243 | ret = of_address_to_resource(node, 0, &res); | ||
244 | if (ret) { | ||
245 | pr_err("Failed to allocate resource\n"); | ||
246 | goto err_priv; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * The 20 least significant bits of addr provide direct information | ||
251 | * regarding the interrupt destination. | ||
252 | * | ||
253 | * To select the primary GIC as the target GIC, bits [18:17] must be set | ||
254 | * to 0x0. In this case, bit 16 (SPI_TARGET_CLUSTER0) must be set. | ||
255 | */ | ||
256 | priv->addr = res.start & GENMASK_ULL(63,20); | ||
257 | priv->addr |= ALPINE_MSIX_SPI_TARGET_CLUSTER0; | ||
258 | |||
259 | if (of_property_read_u32(node, "al,msi-base-spi", &priv->spi_first)) { | ||
260 | pr_err("Unable to parse MSI base\n"); | ||
261 | ret = -EINVAL; | ||
262 | goto err_priv; | ||
263 | } | ||
264 | |||
265 | if (of_property_read_u32(node, "al,msi-num-spis", &priv->num_spis)) { | ||
266 | pr_err("Unable to parse MSI numbers\n"); | ||
267 | ret = -EINVAL; | ||
268 | goto err_priv; | ||
269 | } | ||
270 | |||
271 | priv->msi_map = kzalloc(sizeof(*priv->msi_map) * BITS_TO_LONGS(priv->num_spis), | ||
272 | GFP_KERNEL); | ||
273 | if (!priv->msi_map) { | ||
274 | ret = -ENOMEM; | ||
275 | goto err_priv; | ||
276 | } | ||
277 | |||
278 | pr_debug("Registering %d msixs, starting at %d\n", | ||
279 | priv->num_spis, priv->spi_first); | ||
280 | |||
281 | ret = alpine_msix_init_domains(priv, node); | ||
282 | if (ret) | ||
283 | goto err_map; | ||
284 | |||
285 | return 0; | ||
286 | |||
287 | err_map: | ||
288 | kfree(priv->msi_map); | ||
289 | err_priv: | ||
290 | kfree(priv); | ||
291 | return ret; | ||
292 | } | ||
293 | IRQCHIP_DECLARE(alpine_msix, "al,alpine-msix", alpine_msix_init); | ||
diff --git a/drivers/irqchip/irq-gic-realview.c b/drivers/irqchip/irq-gic-realview.c index aa46eb280a7f..54c296401525 100644 --- a/drivers/irqchip/irq-gic-realview.c +++ b/drivers/irqchip/irq-gic-realview.c | |||
@@ -10,7 +10,8 @@ | |||
10 | #include <linux/irqchip/arm-gic.h> | 10 | #include <linux/irqchip/arm-gic.h> |
11 | 11 | ||
12 | #define REALVIEW_SYS_LOCK_OFFSET 0x20 | 12 | #define REALVIEW_SYS_LOCK_OFFSET 0x20 |
13 | #define REALVIEW_PB11MP_SYS_PLD_CTRL1 0x74 | 13 | #define REALVIEW_SYS_PLD_CTRL1 0x74 |
14 | #define REALVIEW_EB_REVB_SYS_PLD_CTRL1 0xD8 | ||
14 | #define VERSATILE_LOCK_VAL 0xA05F | 15 | #define VERSATILE_LOCK_VAL 0xA05F |
15 | #define PLD_INTMODE_MASK BIT(22)|BIT(23)|BIT(24) | 16 | #define PLD_INTMODE_MASK BIT(22)|BIT(23)|BIT(24) |
16 | #define PLD_INTMODE_LEGACY 0x0 | 17 | #define PLD_INTMODE_LEGACY 0x0 |
@@ -18,26 +19,57 @@ | |||
18 | #define PLD_INTMODE_NEW_NO_DCC BIT(23) | 19 | #define PLD_INTMODE_NEW_NO_DCC BIT(23) |
19 | #define PLD_INTMODE_FIQ_ENABLE BIT(24) | 20 | #define PLD_INTMODE_FIQ_ENABLE BIT(24) |
20 | 21 | ||
22 | /* For some reason RealView EB Rev B moved this register */ | ||
23 | static const struct of_device_id syscon_pldset_of_match[] = { | ||
24 | { | ||
25 | .compatible = "arm,realview-eb11mp-revb-syscon", | ||
26 | .data = (void *)REALVIEW_EB_REVB_SYS_PLD_CTRL1, | ||
27 | }, | ||
28 | { | ||
29 | .compatible = "arm,realview-eb11mp-revc-syscon", | ||
30 | .data = (void *)REALVIEW_SYS_PLD_CTRL1, | ||
31 | }, | ||
32 | { | ||
33 | .compatible = "arm,realview-eb-syscon", | ||
34 | .data = (void *)REALVIEW_SYS_PLD_CTRL1, | ||
35 | }, | ||
36 | { | ||
37 | .compatible = "arm,realview-pb11mp-syscon", | ||
38 | .data = (void *)REALVIEW_SYS_PLD_CTRL1, | ||
39 | }, | ||
40 | {}, | ||
41 | }; | ||
42 | |||
21 | static int __init | 43 | static int __init |
22 | realview_gic_of_init(struct device_node *node, struct device_node *parent) | 44 | realview_gic_of_init(struct device_node *node, struct device_node *parent) |
23 | { | 45 | { |
24 | static struct regmap *map; | 46 | static struct regmap *map; |
47 | struct device_node *np; | ||
48 | const struct of_device_id *gic_id; | ||
49 | u32 pld1_ctrl; | ||
50 | |||
51 | np = of_find_matching_node_and_match(NULL, syscon_pldset_of_match, | ||
52 | &gic_id); | ||
53 | if (!np) | ||
54 | return -ENODEV; | ||
55 | pld1_ctrl = (u32)gic_id->data; | ||
25 | 56 | ||
26 | /* The PB11MPCore GIC needs to be configured in the syscon */ | 57 | /* The PB11MPCore GIC needs to be configured in the syscon */ |
27 | map = syscon_regmap_lookup_by_compatible("arm,realview-pb11mp-syscon"); | 58 | map = syscon_node_to_regmap(np); |
28 | if (!IS_ERR(map)) { | 59 | if (!IS_ERR(map)) { |
29 | /* new irq mode with no DCC */ | 60 | /* new irq mode with no DCC */ |
30 | regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, | 61 | regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, |
31 | VERSATILE_LOCK_VAL); | 62 | VERSATILE_LOCK_VAL); |
32 | regmap_update_bits(map, REALVIEW_PB11MP_SYS_PLD_CTRL1, | 63 | regmap_update_bits(map, pld1_ctrl, |
33 | PLD_INTMODE_NEW_NO_DCC, | 64 | PLD_INTMODE_NEW_NO_DCC, |
34 | PLD_INTMODE_MASK); | 65 | PLD_INTMODE_MASK); |
35 | regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000); | 66 | regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000); |
36 | pr_info("TC11MP GIC: set up interrupt controller to NEW mode, no DCC\n"); | 67 | pr_info("RealView GIC: set up interrupt controller to NEW mode, no DCC\n"); |
37 | } else { | 68 | } else { |
38 | pr_err("TC11MP GIC setup: could not find syscon\n"); | 69 | pr_err("RealView GIC setup: could not find syscon\n"); |
39 | return -ENXIO; | 70 | return -ENODEV; |
40 | } | 71 | } |
41 | return gic_of_init(node, parent); | 72 | return gic_of_init(node, parent); |
42 | } | 73 | } |
43 | IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init); | 74 | IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init); |
75 | IRQCHIP_DECLARE(armeb11mp_gic, "arm,eb11mp-gic", realview_gic_of_init); | ||
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 43dfd15c1dd2..39261798c59f 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -103,7 +103,6 @@ struct its_device { | |||
103 | 103 | ||
104 | static LIST_HEAD(its_nodes); | 104 | static LIST_HEAD(its_nodes); |
105 | static DEFINE_SPINLOCK(its_lock); | 105 | static DEFINE_SPINLOCK(its_lock); |
106 | static struct device_node *gic_root_node; | ||
107 | static struct rdists *gic_rdists; | 106 | static struct rdists *gic_rdists; |
108 | 107 | ||
109 | #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) | 108 | #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) |
@@ -671,7 +670,7 @@ static int its_chunk_to_lpi(int chunk) | |||
671 | return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192; | 670 | return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192; |
672 | } | 671 | } |
673 | 672 | ||
674 | static int its_lpi_init(u32 id_bits) | 673 | static int __init its_lpi_init(u32 id_bits) |
675 | { | 674 | { |
676 | lpi_chunks = its_lpi_to_chunk(1UL << id_bits); | 675 | lpi_chunks = its_lpi_to_chunk(1UL << id_bits); |
677 | 676 | ||
@@ -1430,7 +1429,8 @@ static void its_enable_quirks(struct its_node *its) | |||
1430 | gic_enable_quirks(iidr, its_quirks, its); | 1429 | gic_enable_quirks(iidr, its_quirks, its); |
1431 | } | 1430 | } |
1432 | 1431 | ||
1433 | static int its_probe(struct device_node *node, struct irq_domain *parent) | 1432 | static int __init its_probe(struct device_node *node, |
1433 | struct irq_domain *parent) | ||
1434 | { | 1434 | { |
1435 | struct resource res; | 1435 | struct resource res; |
1436 | struct its_node *its; | 1436 | struct its_node *its; |
@@ -1591,7 +1591,7 @@ static struct of_device_id its_device_id[] = { | |||
1591 | {}, | 1591 | {}, |
1592 | }; | 1592 | }; |
1593 | 1593 | ||
1594 | int its_init(struct device_node *node, struct rdists *rdists, | 1594 | int __init its_init(struct device_node *node, struct rdists *rdists, |
1595 | struct irq_domain *parent_domain) | 1595 | struct irq_domain *parent_domain) |
1596 | { | 1596 | { |
1597 | struct device_node *np; | 1597 | struct device_node *np; |
@@ -1607,8 +1607,6 @@ int its_init(struct device_node *node, struct rdists *rdists, | |||
1607 | } | 1607 | } |
1608 | 1608 | ||
1609 | gic_rdists = rdists; | 1609 | gic_rdists = rdists; |
1610 | gic_root_node = node; | ||
1611 | |||
1612 | its_alloc_lpi_tables(); | 1610 | its_alloc_lpi_tables(); |
1613 | its_lpi_init(rdists->id_bits); | 1611 | its_lpi_init(rdists->id_bits); |
1614 | 1612 | ||
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d7be6ddc34f6..5b7d3c2129d8 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -15,10 +15,12 @@ | |||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/acpi.h> | ||
18 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
19 | #include <linux/cpu_pm.h> | 20 | #include <linux/cpu_pm.h> |
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/irqdomain.h> | ||
22 | #include <linux/of.h> | 24 | #include <linux/of.h> |
23 | #include <linux/of_address.h> | 25 | #include <linux/of_address.h> |
24 | #include <linux/of_irq.h> | 26 | #include <linux/of_irq.h> |
@@ -38,6 +40,7 @@ | |||
38 | struct redist_region { | 40 | struct redist_region { |
39 | void __iomem *redist_base; | 41 | void __iomem *redist_base; |
40 | phys_addr_t phys_base; | 42 | phys_addr_t phys_base; |
43 | bool single_redist; | ||
41 | }; | 44 | }; |
42 | 45 | ||
43 | struct gic_chip_data { | 46 | struct gic_chip_data { |
@@ -434,6 +437,9 @@ static int gic_populate_rdist(void) | |||
434 | return 0; | 437 | return 0; |
435 | } | 438 | } |
436 | 439 | ||
440 | if (gic_data.redist_regions[i].single_redist) | ||
441 | break; | ||
442 | |||
437 | if (gic_data.redist_stride) { | 443 | if (gic_data.redist_stride) { |
438 | ptr += gic_data.redist_stride; | 444 | ptr += gic_data.redist_stride; |
439 | } else { | 445 | } else { |
@@ -634,7 +640,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | |||
634 | else | 640 | else |
635 | gic_dist_wait_for_rwp(); | 641 | gic_dist_wait_for_rwp(); |
636 | 642 | ||
637 | return IRQ_SET_MASK_OK; | 643 | return IRQ_SET_MASK_OK_DONE; |
638 | } | 644 | } |
639 | #else | 645 | #else |
640 | #define gic_set_affinity NULL | 646 | #define gic_set_affinity NULL |
@@ -764,6 +770,15 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
764 | return 0; | 770 | return 0; |
765 | } | 771 | } |
766 | 772 | ||
773 | if (is_fwnode_irqchip(fwspec->fwnode)) { | ||
774 | if(fwspec->param_count != 2) | ||
775 | return -EINVAL; | ||
776 | |||
777 | *hwirq = fwspec->param[0]; | ||
778 | *type = fwspec->param[1]; | ||
779 | return 0; | ||
780 | } | ||
781 | |||
767 | return -EINVAL; | 782 | return -EINVAL; |
768 | } | 783 | } |
769 | 784 | ||
@@ -811,17 +826,88 @@ static void gicv3_enable_quirks(void) | |||
811 | #endif | 826 | #endif |
812 | } | 827 | } |
813 | 828 | ||
829 | static int __init gic_init_bases(void __iomem *dist_base, | ||
830 | struct redist_region *rdist_regs, | ||
831 | u32 nr_redist_regions, | ||
832 | u64 redist_stride, | ||
833 | struct fwnode_handle *handle) | ||
834 | { | ||
835 | struct device_node *node; | ||
836 | u32 typer; | ||
837 | int gic_irqs; | ||
838 | int err; | ||
839 | |||
840 | if (!is_hyp_mode_available()) | ||
841 | static_key_slow_dec(&supports_deactivate); | ||
842 | |||
843 | if (static_key_true(&supports_deactivate)) | ||
844 | pr_info("GIC: Using split EOI/Deactivate mode\n"); | ||
845 | |||
846 | gic_data.dist_base = dist_base; | ||
847 | gic_data.redist_regions = rdist_regs; | ||
848 | gic_data.nr_redist_regions = nr_redist_regions; | ||
849 | gic_data.redist_stride = redist_stride; | ||
850 | |||
851 | gicv3_enable_quirks(); | ||
852 | |||
853 | /* | ||
854 | * Find out how many interrupts are supported. | ||
855 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) | ||
856 | */ | ||
857 | typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); | ||
858 | gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer); | ||
859 | gic_irqs = GICD_TYPER_IRQS(typer); | ||
860 | if (gic_irqs > 1020) | ||
861 | gic_irqs = 1020; | ||
862 | gic_data.irq_nr = gic_irqs; | ||
863 | |||
864 | gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, | ||
865 | &gic_data); | ||
866 | gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); | ||
867 | |||
868 | if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { | ||
869 | err = -ENOMEM; | ||
870 | goto out_free; | ||
871 | } | ||
872 | |||
873 | set_handle_irq(gic_handle_irq); | ||
874 | |||
875 | node = to_of_node(handle); | ||
876 | if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() && | ||
877 | node) /* Temp hack to prevent ITS init for ACPI */ | ||
878 | its_init(node, &gic_data.rdists, gic_data.domain); | ||
879 | |||
880 | gic_smp_init(); | ||
881 | gic_dist_init(); | ||
882 | gic_cpu_init(); | ||
883 | gic_cpu_pm_init(); | ||
884 | |||
885 | return 0; | ||
886 | |||
887 | out_free: | ||
888 | if (gic_data.domain) | ||
889 | irq_domain_remove(gic_data.domain); | ||
890 | free_percpu(gic_data.rdists.rdist); | ||
891 | return err; | ||
892 | } | ||
893 | |||
894 | static int __init gic_validate_dist_version(void __iomem *dist_base) | ||
895 | { | ||
896 | u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; | ||
897 | |||
898 | if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) | ||
899 | return -ENODEV; | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
814 | static int __init gic_of_init(struct device_node *node, struct device_node *parent) | 904 | static int __init gic_of_init(struct device_node *node, struct device_node *parent) |
815 | { | 905 | { |
816 | void __iomem *dist_base; | 906 | void __iomem *dist_base; |
817 | struct redist_region *rdist_regs; | 907 | struct redist_region *rdist_regs; |
818 | u64 redist_stride; | 908 | u64 redist_stride; |
819 | u32 nr_redist_regions; | 909 | u32 nr_redist_regions; |
820 | u32 typer; | 910 | int err, i; |
821 | u32 reg; | ||
822 | int gic_irqs; | ||
823 | int err; | ||
824 | int i; | ||
825 | 911 | ||
826 | dist_base = of_iomap(node, 0); | 912 | dist_base = of_iomap(node, 0); |
827 | if (!dist_base) { | 913 | if (!dist_base) { |
@@ -830,11 +916,10 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
830 | return -ENXIO; | 916 | return -ENXIO; |
831 | } | 917 | } |
832 | 918 | ||
833 | reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; | 919 | err = gic_validate_dist_version(dist_base); |
834 | if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) { | 920 | if (err) { |
835 | pr_err("%s: no distributor detected, giving up\n", | 921 | pr_err("%s: no distributor detected, giving up\n", |
836 | node->full_name); | 922 | node->full_name); |
837 | err = -ENODEV; | ||
838 | goto out_unmap_dist; | 923 | goto out_unmap_dist; |
839 | } | 924 | } |
840 | 925 | ||
@@ -865,63 +950,229 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
865 | if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) | 950 | if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) |
866 | redist_stride = 0; | 951 | redist_stride = 0; |
867 | 952 | ||
868 | if (!is_hyp_mode_available()) | 953 | err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, |
869 | static_key_slow_dec(&supports_deactivate); | 954 | redist_stride, &node->fwnode); |
955 | if (!err) | ||
956 | return 0; | ||
870 | 957 | ||
871 | if (static_key_true(&supports_deactivate)) | 958 | out_unmap_rdist: |
872 | pr_info("GIC: Using split EOI/Deactivate mode\n"); | 959 | for (i = 0; i < nr_redist_regions; i++) |
960 | if (rdist_regs[i].redist_base) | ||
961 | iounmap(rdist_regs[i].redist_base); | ||
962 | kfree(rdist_regs); | ||
963 | out_unmap_dist: | ||
964 | iounmap(dist_base); | ||
965 | return err; | ||
966 | } | ||
873 | 967 | ||
874 | gic_data.dist_base = dist_base; | 968 | IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); |
875 | gic_data.redist_regions = rdist_regs; | ||
876 | gic_data.nr_redist_regions = nr_redist_regions; | ||
877 | gic_data.redist_stride = redist_stride; | ||
878 | 969 | ||
879 | gicv3_enable_quirks(); | 970 | #ifdef CONFIG_ACPI |
971 | static void __iomem *dist_base; | ||
972 | static struct redist_region *redist_regs __initdata; | ||
973 | static u32 nr_redist_regions __initdata; | ||
974 | static bool single_redist; | ||
975 | |||
976 | static void __init | ||
977 | gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base) | ||
978 | { | ||
979 | static int count = 0; | ||
980 | |||
981 | redist_regs[count].phys_base = phys_base; | ||
982 | redist_regs[count].redist_base = redist_base; | ||
983 | redist_regs[count].single_redist = single_redist; | ||
984 | count++; | ||
985 | } | ||
986 | |||
987 | static int __init | ||
988 | gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, | ||
989 | const unsigned long end) | ||
990 | { | ||
991 | struct acpi_madt_generic_redistributor *redist = | ||
992 | (struct acpi_madt_generic_redistributor *)header; | ||
993 | void __iomem *redist_base; | ||
994 | |||
995 | redist_base = ioremap(redist->base_address, redist->length); | ||
996 | if (!redist_base) { | ||
997 | pr_err("Couldn't map GICR region @%llx\n", redist->base_address); | ||
998 | return -ENOMEM; | ||
999 | } | ||
1000 | |||
1001 | gic_acpi_register_redist(redist->base_address, redist_base); | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | static int __init | ||
1006 | gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, | ||
1007 | const unsigned long end) | ||
1008 | { | ||
1009 | struct acpi_madt_generic_interrupt *gicc = | ||
1010 | (struct acpi_madt_generic_interrupt *)header; | ||
1011 | u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; | ||
1012 | u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; | ||
1013 | void __iomem *redist_base; | ||
1014 | |||
1015 | redist_base = ioremap(gicc->gicr_base_address, size); | ||
1016 | if (!redist_base) | ||
1017 | return -ENOMEM; | ||
1018 | |||
1019 | gic_acpi_register_redist(gicc->gicr_base_address, redist_base); | ||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int __init gic_acpi_collect_gicr_base(void) | ||
1024 | { | ||
1025 | acpi_tbl_entry_handler redist_parser; | ||
1026 | enum acpi_madt_type type; | ||
1027 | |||
1028 | if (single_redist) { | ||
1029 | type = ACPI_MADT_TYPE_GENERIC_INTERRUPT; | ||
1030 | redist_parser = gic_acpi_parse_madt_gicc; | ||
1031 | } else { | ||
1032 | type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR; | ||
1033 | redist_parser = gic_acpi_parse_madt_redist; | ||
1034 | } | ||
1035 | |||
1036 | /* Collect redistributor base addresses in GICR entries */ | ||
1037 | if (acpi_table_parse_madt(type, redist_parser, 0) > 0) | ||
1038 | return 0; | ||
1039 | |||
1040 | pr_info("No valid GICR entries exist\n"); | ||
1041 | return -ENODEV; | ||
1042 | } | ||
1043 | |||
1044 | static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header, | ||
1045 | const unsigned long end) | ||
1046 | { | ||
1047 | /* Subtable presence means that redist exists, that's it */ | ||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, | ||
1052 | const unsigned long end) | ||
1053 | { | ||
1054 | struct acpi_madt_generic_interrupt *gicc = | ||
1055 | (struct acpi_madt_generic_interrupt *)header; | ||
880 | 1056 | ||
881 | /* | 1057 | /* |
882 | * Find out how many interrupts are supported. | 1058 | * If GICC is enabled and has valid gicr base address, then it means |
883 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) | 1059 | * GICR base is presented via GICC |
884 | */ | 1060 | */ |
885 | typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); | 1061 | if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) |
886 | gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer); | 1062 | return 0; |
887 | gic_irqs = GICD_TYPER_IRQS(typer); | ||
888 | if (gic_irqs > 1020) | ||
889 | gic_irqs = 1020; | ||
890 | gic_data.irq_nr = gic_irqs; | ||
891 | 1063 | ||
892 | gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops, | 1064 | return -ENODEV; |
893 | &gic_data); | 1065 | } |
894 | gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); | ||
895 | 1066 | ||
896 | if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { | 1067 | static int __init gic_acpi_count_gicr_regions(void) |
1068 | { | ||
1069 | int count; | ||
1070 | |||
1071 | /* | ||
1072 | * Count how many redistributor regions we have. It is not allowed | ||
1073 | * to mix redistributor description, GICR and GICC subtables have to be | ||
1074 | * mutually exclusive. | ||
1075 | */ | ||
1076 | count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, | ||
1077 | gic_acpi_match_gicr, 0); | ||
1078 | if (count > 0) { | ||
1079 | single_redist = false; | ||
1080 | return count; | ||
1081 | } | ||
1082 | |||
1083 | count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, | ||
1084 | gic_acpi_match_gicc, 0); | ||
1085 | if (count > 0) | ||
1086 | single_redist = true; | ||
1087 | |||
1088 | return count; | ||
1089 | } | ||
1090 | |||
1091 | static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header, | ||
1092 | struct acpi_probe_entry *ape) | ||
1093 | { | ||
1094 | struct acpi_madt_generic_distributor *dist; | ||
1095 | int count; | ||
1096 | |||
1097 | dist = (struct acpi_madt_generic_distributor *)header; | ||
1098 | if (dist->version != ape->driver_data) | ||
1099 | return false; | ||
1100 | |||
1101 | /* We need to do that exercise anyway, the sooner the better */ | ||
1102 | count = gic_acpi_count_gicr_regions(); | ||
1103 | if (count <= 0) | ||
1104 | return false; | ||
1105 | |||
1106 | nr_redist_regions = count; | ||
1107 | return true; | ||
1108 | } | ||
1109 | |||
1110 | #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K) | ||
1111 | |||
1112 | static int __init | ||
1113 | gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) | ||
1114 | { | ||
1115 | struct acpi_madt_generic_distributor *dist; | ||
1116 | struct fwnode_handle *domain_handle; | ||
1117 | int i, err; | ||
1118 | |||
1119 | /* Get distributor base address */ | ||
1120 | dist = (struct acpi_madt_generic_distributor *)header; | ||
1121 | dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE); | ||
1122 | if (!dist_base) { | ||
1123 | pr_err("Unable to map GICD registers\n"); | ||
1124 | return -ENOMEM; | ||
1125 | } | ||
1126 | |||
1127 | err = gic_validate_dist_version(dist_base); | ||
1128 | if (err) { | ||
1129 | pr_err("No distributor detected at @%p, giving up", dist_base); | ||
1130 | goto out_dist_unmap; | ||
1131 | } | ||
1132 | |||
1133 | redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions, | ||
1134 | GFP_KERNEL); | ||
1135 | if (!redist_regs) { | ||
897 | err = -ENOMEM; | 1136 | err = -ENOMEM; |
898 | goto out_free; | 1137 | goto out_dist_unmap; |
899 | } | 1138 | } |
900 | 1139 | ||
901 | set_handle_irq(gic_handle_irq); | 1140 | err = gic_acpi_collect_gicr_base(); |
1141 | if (err) | ||
1142 | goto out_redist_unmap; | ||
902 | 1143 | ||
903 | if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis()) | 1144 | domain_handle = irq_domain_alloc_fwnode(dist_base); |
904 | its_init(node, &gic_data.rdists, gic_data.domain); | 1145 | if (!domain_handle) { |
1146 | err = -ENOMEM; | ||
1147 | goto out_redist_unmap; | ||
1148 | } | ||
905 | 1149 | ||
906 | gic_smp_init(); | 1150 | err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0, |
907 | gic_dist_init(); | 1151 | domain_handle); |
908 | gic_cpu_init(); | 1152 | if (err) |
909 | gic_cpu_pm_init(); | 1153 | goto out_fwhandle_free; |
910 | 1154 | ||
1155 | acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); | ||
911 | return 0; | 1156 | return 0; |
912 | 1157 | ||
913 | out_free: | 1158 | out_fwhandle_free: |
914 | if (gic_data.domain) | 1159 | irq_domain_free_fwnode(domain_handle); |
915 | irq_domain_remove(gic_data.domain); | 1160 | out_redist_unmap: |
916 | free_percpu(gic_data.rdists.rdist); | ||
917 | out_unmap_rdist: | ||
918 | for (i = 0; i < nr_redist_regions; i++) | 1161 | for (i = 0; i < nr_redist_regions; i++) |
919 | if (rdist_regs[i].redist_base) | 1162 | if (redist_regs[i].redist_base) |
920 | iounmap(rdist_regs[i].redist_base); | 1163 | iounmap(redist_regs[i].redist_base); |
921 | kfree(rdist_regs); | 1164 | kfree(redist_regs); |
922 | out_unmap_dist: | 1165 | out_dist_unmap: |
923 | iounmap(dist_base); | 1166 | iounmap(dist_base); |
924 | return err; | 1167 | return err; |
925 | } | 1168 | } |
926 | 1169 | IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, | |
927 | IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); | 1170 | acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3, |
1171 | gic_acpi_init); | ||
1172 | IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, | ||
1173 | acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4, | ||
1174 | gic_acpi_init); | ||
1175 | IRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, | ||
1176 | acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE, | ||
1177 | gic_acpi_init); | ||
1178 | #endif | ||