.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Hisilicon HiP04 INTC |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2002-2014 ARM Limited. |
---|
5 | 6 | * Copyright (c) 2013-2014 Hisilicon Ltd. |
---|
6 | 7 | * Copyright (c) 2013-2014 Linaro Ltd. |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | * |
---|
12 | 9 | * Interrupt architecture for the HIP04 INTC: |
---|
13 | 10 | * |
---|
.. | .. |
---|
133 | 130 | |
---|
134 | 131 | raw_spin_lock(&irq_controller_lock); |
---|
135 | 132 | |
---|
136 | | - ret = gic_configure_irq(irq, type, base, NULL); |
---|
| 133 | + ret = gic_configure_irq(irq, type, base + GIC_DIST_CONFIG, NULL); |
---|
| 134 | + if (ret && irq < 32) { |
---|
| 135 | + /* Misconfigured PPIs are usually not fatal */ |
---|
| 136 | + pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); |
---|
| 137 | + ret = 0; |
---|
| 138 | + } |
---|
137 | 139 | |
---|
138 | 140 | raw_spin_unlock(&irq_controller_lock); |
---|
139 | 141 | |
---|
.. | .. |
---|
169 | 171 | |
---|
170 | 172 | return IRQ_SET_MASK_OK; |
---|
171 | 173 | } |
---|
| 174 | + |
---|
| 175 | +static void hip04_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) |
---|
| 176 | +{ |
---|
| 177 | + int cpu; |
---|
| 178 | + unsigned long flags, map = 0; |
---|
| 179 | + |
---|
| 180 | + raw_spin_lock_irqsave(&irq_controller_lock, flags); |
---|
| 181 | + |
---|
| 182 | + /* Convert our logical CPU mask into a physical one. */ |
---|
| 183 | + for_each_cpu(cpu, mask) |
---|
| 184 | + map |= hip04_cpu_map[cpu]; |
---|
| 185 | + |
---|
| 186 | + /* |
---|
| 187 | + * Ensure that stores to Normal memory are visible to the |
---|
| 188 | + * other CPUs before they observe us issuing the IPI. |
---|
| 189 | + */ |
---|
| 190 | + dmb(ishst); |
---|
| 191 | + |
---|
| 192 | + /* this always happens on GIC0 */ |
---|
| 193 | + writel_relaxed(map << 8 | d->hwirq, hip04_data.dist_base + GIC_DIST_SOFTINT); |
---|
| 194 | + |
---|
| 195 | + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); |
---|
| 196 | +} |
---|
172 | 197 | #endif |
---|
173 | 198 | |
---|
174 | 199 | static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs) |
---|
.. | .. |
---|
180 | 205 | irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); |
---|
181 | 206 | irqnr = irqstat & GICC_IAR_INT_ID_MASK; |
---|
182 | 207 | |
---|
183 | | - if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) { |
---|
| 208 | + if (irqnr <= HIP04_MAX_IRQS) |
---|
184 | 209 | handle_domain_irq(hip04_data.domain, irqnr, regs); |
---|
185 | | - continue; |
---|
186 | | - } |
---|
187 | | - if (irqnr < 16) { |
---|
188 | | - writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); |
---|
189 | | -#ifdef CONFIG_SMP |
---|
190 | | - handle_IPI(irqnr, regs); |
---|
191 | | -#endif |
---|
192 | | - continue; |
---|
193 | | - } |
---|
194 | | - break; |
---|
195 | | - } while (1); |
---|
| 210 | + } while (irqnr > HIP04_MAX_IRQS); |
---|
196 | 211 | } |
---|
197 | 212 | |
---|
198 | 213 | static struct irq_chip hip04_irq_chip = { |
---|
.. | .. |
---|
203 | 218 | .irq_set_type = hip04_irq_set_type, |
---|
204 | 219 | #ifdef CONFIG_SMP |
---|
205 | 220 | .irq_set_affinity = hip04_irq_set_affinity, |
---|
| 221 | + .ipi_send_mask = hip04_ipi_send_mask, |
---|
206 | 222 | #endif |
---|
207 | 223 | .flags = IRQCHIP_SET_TYPE_MASKED | |
---|
208 | 224 | IRQCHIP_SKIP_SET_WAKE | |
---|
.. | .. |
---|
271 | 287 | if (i != cpu) |
---|
272 | 288 | hip04_cpu_map[i] &= ~cpu_mask; |
---|
273 | 289 | |
---|
274 | | - gic_cpu_config(dist_base, NULL); |
---|
| 290 | + gic_cpu_config(dist_base, 32, NULL); |
---|
275 | 291 | |
---|
276 | 292 | writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); |
---|
277 | 293 | writel_relaxed(1, base + GIC_CPU_CTRL); |
---|
278 | 294 | } |
---|
279 | 295 | |
---|
280 | | -#ifdef CONFIG_SMP |
---|
281 | | -static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq) |
---|
282 | | -{ |
---|
283 | | - int cpu; |
---|
284 | | - unsigned long flags, map = 0; |
---|
285 | | - |
---|
286 | | - raw_spin_lock_irqsave(&irq_controller_lock, flags); |
---|
287 | | - |
---|
288 | | - /* Convert our logical CPU mask into a physical one. */ |
---|
289 | | - for_each_cpu(cpu, mask) |
---|
290 | | - map |= hip04_cpu_map[cpu]; |
---|
291 | | - |
---|
292 | | - /* |
---|
293 | | - * Ensure that stores to Normal memory are visible to the |
---|
294 | | - * other CPUs before they observe us issuing the IPI. |
---|
295 | | - */ |
---|
296 | | - dmb(ishst); |
---|
297 | | - |
---|
298 | | - /* this always happens on GIC0 */ |
---|
299 | | - writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT); |
---|
300 | | - |
---|
301 | | - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); |
---|
302 | | -} |
---|
303 | | -#endif |
---|
304 | | - |
---|
305 | 296 | static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, |
---|
306 | 297 | irq_hw_number_t hw) |
---|
307 | 298 | { |
---|
308 | | - if (hw < 32) { |
---|
| 299 | + if (hw < 16) { |
---|
| 300 | + irq_set_percpu_devid(irq); |
---|
| 301 | + irq_set_chip_and_handler(irq, &hip04_irq_chip, |
---|
| 302 | + handle_percpu_devid_fasteoi_ipi); |
---|
| 303 | + } else if (hw < 32) { |
---|
309 | 304 | irq_set_percpu_devid(irq); |
---|
310 | 305 | irq_set_chip_and_handler(irq, &hip04_irq_chip, |
---|
311 | 306 | handle_percpu_devid_irq); |
---|
312 | | - irq_set_status_flags(irq, IRQ_NOAUTOEN); |
---|
313 | 307 | } else { |
---|
314 | 308 | irq_set_chip_and_handler(irq, &hip04_irq_chip, |
---|
315 | 309 | handle_fasteoi_irq); |
---|
.. | .. |
---|
326 | 320 | unsigned long *out_hwirq, |
---|
327 | 321 | unsigned int *out_type) |
---|
328 | 322 | { |
---|
329 | | - unsigned long ret = 0; |
---|
330 | | - |
---|
331 | 323 | if (irq_domain_get_of_node(d) != controller) |
---|
332 | 324 | return -EINVAL; |
---|
| 325 | + if (intsize == 1 && intspec[0] < 16) { |
---|
| 326 | + *out_hwirq = intspec[0]; |
---|
| 327 | + *out_type = IRQ_TYPE_EDGE_RISING; |
---|
| 328 | + return 0; |
---|
| 329 | + } |
---|
333 | 330 | if (intsize < 3) |
---|
334 | 331 | return -EINVAL; |
---|
335 | 332 | |
---|
.. | .. |
---|
342 | 339 | |
---|
343 | 340 | *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; |
---|
344 | 341 | |
---|
345 | | - return ret; |
---|
| 342 | + return 0; |
---|
346 | 343 | } |
---|
347 | 344 | |
---|
348 | 345 | static int hip04_irq_starting_cpu(unsigned int cpu) |
---|
.. | .. |
---|
359 | 356 | static int __init |
---|
360 | 357 | hip04_of_init(struct device_node *node, struct device_node *parent) |
---|
361 | 358 | { |
---|
362 | | - irq_hw_number_t hwirq_base = 16; |
---|
363 | 359 | int nr_irqs, irq_base, i; |
---|
364 | 360 | |
---|
365 | 361 | if (WARN_ON(!node)) |
---|
.. | .. |
---|
388 | 384 | nr_irqs = HIP04_MAX_IRQS; |
---|
389 | 385 | hip04_data.nr_irqs = nr_irqs; |
---|
390 | 386 | |
---|
391 | | - nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */ |
---|
392 | | - |
---|
393 | | - irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id()); |
---|
| 387 | + irq_base = irq_alloc_descs(-1, 0, nr_irqs, numa_node_id()); |
---|
394 | 388 | if (irq_base < 0) { |
---|
395 | 389 | pr_err("failed to allocate IRQ numbers\n"); |
---|
396 | 390 | return -EINVAL; |
---|
397 | 391 | } |
---|
398 | 392 | |
---|
399 | 393 | hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base, |
---|
400 | | - hwirq_base, |
---|
| 394 | + 0, |
---|
401 | 395 | &hip04_irq_domain_ops, |
---|
402 | 396 | &hip04_data); |
---|
403 | | - |
---|
404 | 397 | if (WARN_ON(!hip04_data.domain)) |
---|
405 | 398 | return -EINVAL; |
---|
406 | 399 | |
---|
407 | 400 | #ifdef CONFIG_SMP |
---|
408 | | - set_smp_cross_call(hip04_raise_softirq); |
---|
| 401 | + set_smp_ipi_range(irq_base, 16); |
---|
409 | 402 | #endif |
---|
410 | 403 | set_handle_irq(hip04_handle_irq); |
---|
411 | 404 | |
---|