hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/irqchip/irq-bcm2836.c
....@@ -1,17 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Root interrupt controller for the BCM2836 (Raspberry Pi 2).
34 *
45 * Copyright 2015 Broadcom
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation; either version 2 of the License, or
9
- * (at your option) any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- * GNU General Public License for more details.
156 */
167
178 #include <linux/cpu.h>
....@@ -19,6 +10,7 @@
1910 #include <linux/of_irq.h>
2011 #include <linux/irqchip.h>
2112 #include <linux/irqdomain.h>
13
+#include <linux/irqchip/chained_irq.h>
2214 #include <linux/irqchip/irq-bcm2836.h>
2315
2416 #include <asm/exception.h>
....@@ -98,12 +90,24 @@
9890 .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
9991 };
10092
93
+static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d)
94
+{
95
+}
96
+
97
+static struct irq_chip bcm2836_arm_irqchip_dummy = {
98
+ .name = "bcm2836-dummy",
99
+ .irq_eoi = bcm2836_arm_irqchip_dummy_op,
100
+};
101
+
101102 static int bcm2836_map(struct irq_domain *d, unsigned int irq,
102103 irq_hw_number_t hw)
103104 {
104105 struct irq_chip *chip;
105106
106107 switch (hw) {
108
+ case LOCAL_IRQ_MAILBOX0:
109
+ chip = &bcm2836_arm_irqchip_dummy;
110
+ break;
107111 case LOCAL_IRQ_CNTPSIRQ:
108112 case LOCAL_IRQ_CNTPNSIRQ:
109113 case LOCAL_IRQ_CNTHPIRQ:
....@@ -136,17 +140,7 @@
136140 u32 stat;
137141
138142 stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
139
- if (stat & BIT(LOCAL_IRQ_MAILBOX0)) {
140
-#ifdef CONFIG_SMP
141
- void __iomem *mailbox0 = (intc.base +
142
- LOCAL_MAILBOX0_CLR0 + 16 * cpu);
143
- u32 mbox_val = readl(mailbox0);
144
- u32 ipi = ffs(mbox_val) - 1;
145
-
146
- writel(1 << ipi, mailbox0);
147
- handle_IPI(ipi, regs);
148
-#endif
149
- } else if (stat) {
143
+ if (stat) {
150144 u32 hwirq = ffs(stat) - 1;
151145
152146 handle_domain_irq(intc.domain, hwirq, regs);
....@@ -154,8 +148,35 @@
154148 }
155149
156150 #ifdef CONFIG_SMP
157
-static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
158
- unsigned int ipi)
151
+static struct irq_domain *ipi_domain;
152
+
153
+static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
154
+{
155
+ struct irq_chip *chip = irq_desc_get_chip(desc);
156
+ int cpu = smp_processor_id();
157
+ u32 mbox_val;
158
+
159
+ chained_irq_enter(chip, desc);
160
+
161
+ mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
162
+ if (mbox_val) {
163
+ int hwirq = ffs(mbox_val) - 1;
164
+ generic_handle_irq(irq_find_mapping(ipi_domain, hwirq));
165
+ }
166
+
167
+ chained_irq_exit(chip, desc);
168
+}
169
+
170
+static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d)
171
+{
172
+ int cpu = smp_processor_id();
173
+
174
+ writel_relaxed(BIT(d->hwirq),
175
+ intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
176
+}
177
+
178
+static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d,
179
+ const struct cpumask *mask)
159180 {
160181 int cpu;
161182 void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0;
....@@ -166,10 +187,46 @@
166187 */
167188 smp_wmb();
168189
169
- for_each_cpu(cpu, mask) {
170
- writel(1 << ipi, mailbox0_base + 16 * cpu);
171
- }
190
+ for_each_cpu(cpu, mask)
191
+ writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu);
172192 }
193
+
194
+static struct irq_chip bcm2836_arm_irqchip_ipi = {
195
+ .name = "IPI",
196
+ .irq_mask = bcm2836_arm_irqchip_dummy_op,
197
+ .irq_unmask = bcm2836_arm_irqchip_dummy_op,
198
+ .irq_eoi = bcm2836_arm_irqchip_ipi_eoi,
199
+ .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask,
200
+};
201
+
202
+static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d,
203
+ unsigned int virq,
204
+ unsigned int nr_irqs, void *args)
205
+{
206
+ int i;
207
+
208
+ for (i = 0; i < nr_irqs; i++) {
209
+ irq_set_percpu_devid(virq + i);
210
+ irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi,
211
+ d->host_data,
212
+ handle_percpu_devid_fasteoi_ipi,
213
+ NULL, NULL);
214
+ }
215
+
216
+ return 0;
217
+}
218
+
219
+static void bcm2836_arm_irqchip_ipi_free(struct irq_domain *d,
220
+ unsigned int virq,
221
+ unsigned int nr_irqs)
222
+{
223
+ /* Not freeing IPIs */
224
+}
225
+
226
+static const struct irq_domain_ops ipi_domain_ops = {
227
+ .alloc = bcm2836_arm_irqchip_ipi_alloc,
228
+ .free = bcm2836_arm_irqchip_ipi_free,
229
+};
173230
174231 static int bcm2836_cpu_starting(unsigned int cpu)
175232 {
....@@ -184,25 +241,58 @@
184241 cpu);
185242 return 0;
186243 }
244
+
245
+#define BITS_PER_MBOX 32
246
+
247
+static void __init bcm2836_arm_irqchip_smp_init(void)
248
+{
249
+ struct irq_fwspec ipi_fwspec = {
250
+ .fwnode = intc.domain->fwnode,
251
+ .param_count = 1,
252
+ .param = {
253
+ [0] = LOCAL_IRQ_MAILBOX0,
254
+ },
255
+ };
256
+ int base_ipi, mux_irq;
257
+
258
+ mux_irq = irq_create_fwspec_mapping(&ipi_fwspec);
259
+ if (WARN_ON(mux_irq <= 0))
260
+ return;
261
+
262
+ ipi_domain = irq_domain_create_linear(intc.domain->fwnode,
263
+ BITS_PER_MBOX, &ipi_domain_ops,
264
+ NULL);
265
+ if (WARN_ON(!ipi_domain))
266
+ return;
267
+
268
+ ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE;
269
+ irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
270
+
271
+ base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, BITS_PER_MBOX,
272
+ NUMA_NO_NODE, NULL,
273
+ false, NULL);
274
+
275
+ if (WARN_ON(!base_ipi))
276
+ return;
277
+
278
+ set_smp_ipi_range(base_ipi, BITS_PER_MBOX);
279
+
280
+ irq_set_chained_handler_and_data(mux_irq,
281
+ bcm2836_arm_irqchip_handle_ipi, NULL);
282
+
283
+ /* Unmask IPIs to the boot CPU. */
284
+ cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING,
285
+ "irqchip/bcm2836:starting", bcm2836_cpu_starting,
286
+ bcm2836_cpu_dying);
287
+}
288
+#else
289
+#define bcm2836_arm_irqchip_smp_init() do { } while(0)
187290 #endif
188291
189292 static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
190293 .xlate = irq_domain_xlate_onetwocell,
191294 .map = bcm2836_map,
192295 };
193
-
194
-static void
195
-bcm2836_arm_irqchip_smp_init(void)
196
-{
197
-#ifdef CONFIG_SMP
198
- /* Unmask IPIs to the boot CPU. */
199
- cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING,
200
- "irqchip/bcm2836:starting", bcm2836_cpu_starting,
201
- bcm2836_cpu_dying);
202
-
203
- set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
204
-#endif
205
-}
206296
207297 /*
208298 * The LOCAL_IRQ_CNT* timer firings are based off of the external
....@@ -241,6 +331,8 @@
241331 if (!intc.domain)
242332 panic("%pOF: unable to create IRQ domain\n", node);
243333
334
+ irq_domain_update_bus_token(intc.domain, DOMAIN_BUS_WIRED);
335
+
244336 bcm2836_arm_irqchip_smp_init();
245337
246338 set_handle_irq(bcm2836_arm_irqchip_handle_irq);