Blame view
drivers/irqchip/irq-mips-gic.c
19.9 KB
2299c49d6 MIPS: Code clean-... |
1 2 3 4 5 6 7 8 |
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ |
1f19aee0e irqchip/mips-gic:... |
9 10 |
#define pr_fmt(fmt) "irq-mips-gic: " fmt |
39b8d5254 [MIPS] Add suppor... |
11 |
#include <linux/bitmap.h> |
fb8f7be12 irqchip: mips-gic... |
12 |
#include <linux/clocksource.h> |
da61fcf9d irqchip: mips-gic... |
13 |
#include <linux/cpuhotplug.h> |
39b8d5254 [MIPS] Add suppor... |
14 |
#include <linux/init.h> |
18743d278 irqchip: mips-gic... |
15 |
#include <linux/interrupt.h> |
fb8f7be12 irqchip: mips-gic... |
16 |
#include <linux/irq.h> |
41a83e06e irqchip: Prepare ... |
17 |
#include <linux/irqchip.h> |
a7057270c irqchip: mips-gic... |
18 |
#include <linux/of_address.h> |
aa493737d irqchip: mips-gic... |
19 |
#include <linux/percpu.h> |
18743d278 irqchip: mips-gic... |
20 |
#include <linux/sched.h> |
631330f58 MIPS: Build fix -... |
21 |
#include <linux/smp.h> |
39b8d5254 [MIPS] Add suppor... |
22 |
|
e83f7e02a MIPS: CPS: Have a... |
23 |
#include <asm/mips-cps.h> |
98b67c37d MIPS: Add EIC sup... |
24 25 |
#include <asm/setup.h> #include <asm/traps.h> |
39b8d5254 [MIPS] Add suppor... |
26 |
|
a7057270c irqchip: mips-gic... |
27 |
#include <dt-bindings/interrupt-controller/mips-gic.h> |
b11d4c1f5 irqchip: mips-gic... |
28 |
#define GIC_MAX_INTRS 256 |
aa493737d irqchip: mips-gic... |
29 |
#define GIC_MAX_LONGS BITS_TO_LONGS(GIC_MAX_INTRS) |
98b67c37d MIPS: Add EIC sup... |
30 |
|
b11d4c1f5 irqchip: mips-gic... |
31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Add 2 to convert GIC CPU pin to core interrupt */ #define GIC_CPU_PIN_OFFSET 2 /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ #define GIC_PIN_TO_VEC_OFFSET 1 /* Convert between local/shared IRQ number and GIC HW IRQ number. */ #define GIC_LOCAL_HWIRQ_BASE 0 #define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x)) #define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE) #define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS #define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x)) #define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE) |
582e2b4ae MIPS: GIC: Introd... |
44 |
void __iomem *mips_gic_base; |
822350bc9 MIPS: GIC: move G... |
45 |
|
b0e453ffd irqchip/mips-gic:... |
46 |
static DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks); |
2af70a962 irqchip/mips-gic:... |
47 |
|
95150ae8b irqchip: mips-gic... |
48 |
static DEFINE_SPINLOCK(gic_lock); |
c49581a4d irqchip: mips-gic... |
49 |
static struct irq_domain *gic_irq_domain; |
2af70a962 irqchip/mips-gic:... |
50 |
static struct irq_domain *gic_ipi_domain; |
fbd552417 irqchip: mips-gic... |
51 |
static int gic_shared_intrs; |
3263d085a irqchip: mips-gic... |
52 |
static unsigned int gic_cpu_pin; |
1b6af71a8 IRQCHIP: mips-gic... |
53 |
static unsigned int timer_cpu_pin; |
4a6a3ea39 irqchip: mips-gic... |
54 |
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; |
61dc367e5 irqchip: mips-gic... |
55 56 |
static DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); static DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); |
39b8d5254 [MIPS] Add suppor... |
57 |
|
da61fcf9d irqchip: mips-gic... |
58 59 60 61 |
static struct gic_all_vpes_chip_data { u32 map; bool mask; } gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS]; |
7778c4b27 irqchip: mips-gic... |
62 |
static void gic_clear_pcpu_masks(unsigned int intr) |
8fa4b9306 IRQCHIP: irq-mips... |
63 |
{ |
7778c4b27 irqchip: mips-gic... |
64 |
unsigned int i; |
835d2b452 irqchip: mips-gic... |
65 |
|
7778c4b27 irqchip: mips-gic... |
66 67 68 |
/* Clear the interrupt's bit in all pcpu_masks */ for_each_possible_cpu(i) clear_bit(intr, per_cpu_ptr(pcpu_masks, i)); |
835d2b452 irqchip: mips-gic... |
69 |
} |
e9de688da irqchip: mips-gic... |
70 71 72 73 74 75 76 |
static bool gic_local_irq_is_routable(int intr) { u32 vpe_ctl; /* All local interrupts are routable in EIC mode. */ if (cpu_has_veic) return true; |
0d0cf58cd irqchip: mips-gic... |
77 |
vpe_ctl = read_gic_vl_ctl(); |
e9de688da irqchip: mips-gic... |
78 79 |
switch (intr) { case GIC_LOCAL_INT_TIMER: |
0d0cf58cd irqchip: mips-gic... |
80 |
return vpe_ctl & GIC_VX_CTL_TIMER_ROUTABLE; |
e9de688da irqchip: mips-gic... |
81 |
case GIC_LOCAL_INT_PERFCTR: |
0d0cf58cd irqchip: mips-gic... |
82 |
return vpe_ctl & GIC_VX_CTL_PERFCNT_ROUTABLE; |
e9de688da irqchip: mips-gic... |
83 |
case GIC_LOCAL_INT_FDC: |
0d0cf58cd irqchip: mips-gic... |
84 |
return vpe_ctl & GIC_VX_CTL_FDC_ROUTABLE; |
e9de688da irqchip: mips-gic... |
85 86 |
case GIC_LOCAL_INT_SWINT0: case GIC_LOCAL_INT_SWINT1: |
0d0cf58cd irqchip: mips-gic... |
87 |
return vpe_ctl & GIC_VX_CTL_SWINT_ROUTABLE; |
e9de688da irqchip: mips-gic... |
88 89 90 91 |
default: return true; } } |
3263d085a irqchip: mips-gic... |
92 |
static void gic_bind_eic_interrupt(int irq, int set) |
98b67c37d MIPS: Add EIC sup... |
93 94 95 96 97 |
{ /* Convert irq vector # to hw int # */ irq -= GIC_PIN_TO_VEC_OFFSET; /* Set irq to use shadow set */ |
0d0cf58cd irqchip: mips-gic... |
98 |
write_gic_vl_eic_shadow_set(irq, set); |
98b67c37d MIPS: Add EIC sup... |
99 |
} |
bb11cff32 MIPS: Make smp CM... |
100 |
static void gic_send_ipi(struct irq_data *d, unsigned int cpu) |
39b8d5254 [MIPS] Add suppor... |
101 |
{ |
bb11cff32 MIPS: Make smp CM... |
102 |
irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d)); |
3680746ab irqchip: mips-gic... |
103 |
write_gic_wedge(GIC_WEDGE_RW | hwirq); |
39b8d5254 [MIPS] Add suppor... |
104 |
} |
e9de688da irqchip: mips-gic... |
105 106 107 108 109 110 111 112 113 114 115 |
int gic_get_c0_compare_int(void) { if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) return MIPS_CPU_IRQ_BASE + cp0_compare_irq; return irq_create_mapping(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER)); } int gic_get_c0_perfcount_int(void) { if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) { |
7e3e6cb29 IRQCHIP: mips-gic... |
116 |
/* Is the performance counter shared with the timer? */ |
e9de688da irqchip: mips-gic... |
117 118 119 120 121 122 123 |
if (cp0_perfcount_irq < 0) return -1; return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; } return irq_create_mapping(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR)); } |
6429e2b6f IRQCHIP: mips-gic... |
124 125 126 127 128 129 130 131 |
int gic_get_c0_fdc_int(void) { if (!gic_local_irq_is_routable(GIC_LOCAL_INT_FDC)) { /* Is the FDC IRQ even present? */ if (cp0_fdc_irq < 0) return -1; return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; } |
6429e2b6f IRQCHIP: mips-gic... |
132 133 134 |
return irq_create_mapping(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); } |
1b3ed367c IRQCHIP: mips-gic... |
135 |
static void gic_handle_shared_int(bool chained) |
39b8d5254 [MIPS] Add suppor... |
136 |
{ |
e98fcb2a8 irqchip: mips-gic... |
137 |
unsigned int intr, virq; |
8f5ee79c9 irqchip: mips-gic... |
138 |
unsigned long *pcpu_mask; |
8f5ee79c9 irqchip: mips-gic... |
139 |
DECLARE_BITMAP(pending, GIC_MAX_INTRS); |
39b8d5254 [MIPS] Add suppor... |
140 141 |
/* Get per-cpu bitmaps */ |
aa493737d irqchip: mips-gic... |
142 |
pcpu_mask = this_cpu_ptr(pcpu_masks); |
d77d5ac9c irqchip: mips-gic... |
143 |
|
7778c4b27 irqchip: mips-gic... |
144 |
if (mips_cm_is64) |
e98fcb2a8 irqchip: mips-gic... |
145 146 |
__ioread64_copy(pending, addr_gic_pend(), DIV_ROUND_UP(gic_shared_intrs, 64)); |
7778c4b27 irqchip: mips-gic... |
147 |
else |
e98fcb2a8 irqchip: mips-gic... |
148 149 |
__ioread32_copy(pending, addr_gic_pend(), DIV_ROUND_UP(gic_shared_intrs, 32)); |
39b8d5254 [MIPS] Add suppor... |
150 |
|
fbd552417 irqchip: mips-gic... |
151 |
bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs); |
39b8d5254 [MIPS] Add suppor... |
152 |
|
cae750bae irqchip/mips-gic:... |
153 |
for_each_set_bit(intr, pending, gic_shared_intrs) { |
d7eb4f2ec irqchip: mips-gic... |
154 155 |
virq = irq_linear_revmap(gic_irq_domain, GIC_SHARED_TO_HWIRQ(intr)); |
1b3ed367c IRQCHIP: mips-gic... |
156 157 158 159 |
if (chained) generic_handle_irq(virq); else do_IRQ(virq); |
d7eb4f2ec irqchip: mips-gic... |
160 |
} |
39b8d5254 [MIPS] Add suppor... |
161 |
} |
161d049e8 MIPS: GIC: Conver... |
162 |
static void gic_mask_irq(struct irq_data *d) |
39b8d5254 [MIPS] Add suppor... |
163 |
{ |
7778c4b27 irqchip: mips-gic... |
164 |
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); |
90019f8fc irqchip.mips-gic:... |
165 |
write_gic_rmask(intr); |
7778c4b27 irqchip: mips-gic... |
166 |
gic_clear_pcpu_masks(intr); |
39b8d5254 [MIPS] Add suppor... |
167 |
} |
161d049e8 MIPS: GIC: Conver... |
168 |
static void gic_unmask_irq(struct irq_data *d) |
39b8d5254 [MIPS] Add suppor... |
169 |
{ |
7778c4b27 irqchip: mips-gic... |
170 171 |
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); unsigned int cpu; |
90019f8fc irqchip.mips-gic:... |
172 |
write_gic_smask(intr); |
7778c4b27 irqchip: mips-gic... |
173 174 |
gic_clear_pcpu_masks(intr); |
d9f82930a irqchip/mips-gic:... |
175 |
cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); |
7778c4b27 irqchip: mips-gic... |
176 |
set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); |
39b8d5254 [MIPS] Add suppor... |
177 |
} |
5561c9e46 irqchip: mips-gic... |
178 179 |
static void gic_ack_irq(struct irq_data *d) { |
e9de688da irqchip: mips-gic... |
180 |
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
c49581a4d irqchip: mips-gic... |
181 |
|
3680746ab irqchip: mips-gic... |
182 |
write_gic_wedge(irq); |
5561c9e46 irqchip: mips-gic... |
183 |
} |
95150ae8b irqchip: mips-gic... |
184 185 |
static int gic_set_type(struct irq_data *d, unsigned int type) { |
5af3e93e1 irqchip: mips-gic... |
186 |
unsigned int irq, pol, trig, dual; |
95150ae8b irqchip: mips-gic... |
187 |
unsigned long flags; |
5af3e93e1 irqchip: mips-gic... |
188 189 |
irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
95150ae8b irqchip: mips-gic... |
190 191 192 193 |
spin_lock_irqsave(&gic_lock, flags); switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_FALLING: |
5af3e93e1 irqchip: mips-gic... |
194 195 196 |
pol = GIC_POL_FALLING_EDGE; trig = GIC_TRIG_EDGE; dual = GIC_DUAL_SINGLE; |
95150ae8b irqchip: mips-gic... |
197 198 |
break; case IRQ_TYPE_EDGE_RISING: |
5af3e93e1 irqchip: mips-gic... |
199 200 201 |
pol = GIC_POL_RISING_EDGE; trig = GIC_TRIG_EDGE; dual = GIC_DUAL_SINGLE; |
95150ae8b irqchip: mips-gic... |
202 203 |
break; case IRQ_TYPE_EDGE_BOTH: |
5af3e93e1 irqchip: mips-gic... |
204 205 206 |
pol = 0; /* Doesn't matter */ trig = GIC_TRIG_EDGE; dual = GIC_DUAL_DUAL; |
95150ae8b irqchip: mips-gic... |
207 208 |
break; case IRQ_TYPE_LEVEL_LOW: |
5af3e93e1 irqchip: mips-gic... |
209 210 211 |
pol = GIC_POL_ACTIVE_LOW; trig = GIC_TRIG_LEVEL; dual = GIC_DUAL_SINGLE; |
95150ae8b irqchip: mips-gic... |
212 213 214 |
break; case IRQ_TYPE_LEVEL_HIGH: default: |
5af3e93e1 irqchip: mips-gic... |
215 216 217 |
pol = GIC_POL_ACTIVE_HIGH; trig = GIC_TRIG_LEVEL; dual = GIC_DUAL_SINGLE; |
95150ae8b irqchip: mips-gic... |
218 219 |
break; } |
5af3e93e1 irqchip: mips-gic... |
220 221 222 223 224 |
change_gic_pol(irq, pol); change_gic_trig(irq, trig); change_gic_dual(irq, dual); if (trig == GIC_TRIG_EDGE) |
a595fc51a irqchip/mips-gic:... |
225 226 227 228 229 |
irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller, handle_edge_irq, NULL); else irq_set_chip_handler_name_locked(d, &gic_level_irq_controller, handle_level_irq, NULL); |
95150ae8b irqchip: mips-gic... |
230 |
spin_unlock_irqrestore(&gic_lock, flags); |
39b8d5254 [MIPS] Add suppor... |
231 |
|
95150ae8b irqchip: mips-gic... |
232 233 234 235 |
return 0; } #ifdef CONFIG_SMP |
161d049e8 MIPS: GIC: Conver... |
236 237 |
static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) |
39b8d5254 [MIPS] Add suppor... |
238 |
{ |
e9de688da irqchip: mips-gic... |
239 |
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); |
07df8bfef irqchip: mips-gic... |
240 241 |
unsigned long flags; unsigned int cpu; |
39b8d5254 [MIPS] Add suppor... |
242 |
|
07df8bfef irqchip: mips-gic... |
243 244 |
cpu = cpumask_first_and(cpumask, cpu_online_mask); if (cpu >= NR_CPUS) |
14d160ab7 irqchip: mips-gic... |
245 |
return -EINVAL; |
39b8d5254 [MIPS] Add suppor... |
246 247 248 |
/* Assumption : cpumask refers to a single CPU */ spin_lock_irqsave(&gic_lock, flags); |
39b8d5254 [MIPS] Add suppor... |
249 |
|
c214c0351 MIPS: GIC: Fix gi... |
250 |
/* Re-route this IRQ */ |
07df8bfef irqchip: mips-gic... |
251 |
write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu))); |
c214c0351 MIPS: GIC: Fix gi... |
252 253 |
/* Update the pcpu_masks */ |
7778c4b27 irqchip: mips-gic... |
254 255 |
gic_clear_pcpu_masks(irq); if (read_gic_mask(irq)) |
07df8bfef irqchip: mips-gic... |
256 |
set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); |
39b8d5254 [MIPS] Add suppor... |
257 |
|
18416e45b irqchip/mips-gic:... |
258 |
irq_data_update_effective_affinity(d, cpumask_of(cpu)); |
39b8d5254 [MIPS] Add suppor... |
259 |
spin_unlock_irqrestore(&gic_lock, flags); |
7f15a6483 irqchip: mips-gic... |
260 |
return IRQ_SET_MASK_OK; |
39b8d5254 [MIPS] Add suppor... |
261 262 |
} #endif |
4a6a3ea39 irqchip: mips-gic... |
263 264 265 266 267 268 269 270 271 272 273 |
static struct irq_chip gic_level_irq_controller = { .name = "MIPS GIC", .irq_mask = gic_mask_irq, .irq_unmask = gic_unmask_irq, .irq_set_type = gic_set_type, #ifdef CONFIG_SMP .irq_set_affinity = gic_set_affinity, #endif }; static struct irq_chip gic_edge_irq_controller = { |
161d049e8 MIPS: GIC: Conver... |
274 |
.name = "MIPS GIC", |
5561c9e46 irqchip: mips-gic... |
275 |
.irq_ack = gic_ack_irq, |
161d049e8 MIPS: GIC: Conver... |
276 |
.irq_mask = gic_mask_irq, |
161d049e8 MIPS: GIC: Conver... |
277 |
.irq_unmask = gic_unmask_irq, |
95150ae8b irqchip: mips-gic... |
278 |
.irq_set_type = gic_set_type, |
39b8d5254 [MIPS] Add suppor... |
279 |
#ifdef CONFIG_SMP |
161d049e8 MIPS: GIC: Conver... |
280 |
.irq_set_affinity = gic_set_affinity, |
39b8d5254 [MIPS] Add suppor... |
281 |
#endif |
bb11cff32 MIPS: Make smp CM... |
282 |
.ipi_send_single = gic_send_ipi, |
39b8d5254 [MIPS] Add suppor... |
283 |
}; |
1b3ed367c IRQCHIP: mips-gic... |
284 |
static void gic_handle_local_int(bool chained) |
e9de688da irqchip: mips-gic... |
285 286 |
{ unsigned long pending, masked; |
d7eb4f2ec irqchip: mips-gic... |
287 |
unsigned int intr, virq; |
e9de688da irqchip: mips-gic... |
288 |
|
9da3c6458 irqchip: mips-gic... |
289 290 |
pending = read_gic_vl_pend(); masked = read_gic_vl_mask(); |
e9de688da irqchip: mips-gic... |
291 292 |
bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); |
0f4ed1580 irqchip/mips-gic:... |
293 |
for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) { |
d7eb4f2ec irqchip: mips-gic... |
294 295 |
virq = irq_linear_revmap(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(intr)); |
1b3ed367c IRQCHIP: mips-gic... |
296 297 298 299 |
if (chained) generic_handle_irq(virq); else do_IRQ(virq); |
d7eb4f2ec irqchip: mips-gic... |
300 |
} |
e9de688da irqchip: mips-gic... |
301 302 303 304 305 |
} static void gic_mask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); |
9da3c6458 irqchip: mips-gic... |
306 |
write_gic_vl_rmask(BIT(intr)); |
e9de688da irqchip: mips-gic... |
307 308 309 310 311 |
} static void gic_unmask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); |
9da3c6458 irqchip: mips-gic... |
312 |
write_gic_vl_smask(BIT(intr)); |
e9de688da irqchip: mips-gic... |
313 314 315 316 317 318 319 320 321 322 |
} static struct irq_chip gic_local_irq_controller = { .name = "MIPS GIC Local", .irq_mask = gic_mask_local_irq, .irq_unmask = gic_unmask_local_irq, }; static void gic_mask_local_irq_all_vpes(struct irq_data *d) { |
da61fcf9d irqchip: mips-gic... |
323 |
struct gic_all_vpes_chip_data *cd; |
e9de688da irqchip: mips-gic... |
324 |
unsigned long flags; |
da61fcf9d irqchip: mips-gic... |
325 326 327 328 329 |
int intr, cpu; intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); cd->mask = false; |
e9de688da irqchip: mips-gic... |
330 331 |
spin_lock_irqsave(&gic_lock, flags); |
da61fcf9d irqchip: mips-gic... |
332 333 |
for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); |
9da3c6458 irqchip: mips-gic... |
334 |
write_gic_vo_rmask(BIT(intr)); |
e9de688da irqchip: mips-gic... |
335 336 337 338 339 340 |
} spin_unlock_irqrestore(&gic_lock, flags); } static void gic_unmask_local_irq_all_vpes(struct irq_data *d) { |
da61fcf9d irqchip: mips-gic... |
341 |
struct gic_all_vpes_chip_data *cd; |
e9de688da irqchip: mips-gic... |
342 |
unsigned long flags; |
da61fcf9d irqchip: mips-gic... |
343 344 345 346 347 |
int intr, cpu; intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); cd->mask = true; |
e9de688da irqchip: mips-gic... |
348 349 |
spin_lock_irqsave(&gic_lock, flags); |
da61fcf9d irqchip: mips-gic... |
350 351 |
for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); |
9da3c6458 irqchip: mips-gic... |
352 |
write_gic_vo_smask(BIT(intr)); |
e9de688da irqchip: mips-gic... |
353 354 355 |
} spin_unlock_irqrestore(&gic_lock, flags); } |
da61fcf9d irqchip: mips-gic... |
356 357 358 359 360 361 362 |
static void gic_all_vpes_irq_cpu_online(struct irq_data *d) { struct gic_all_vpes_chip_data *cd; unsigned int intr; intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); |
6d4d367d0 irqchip/mips-gic:... |
363 |
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map); |
da61fcf9d irqchip: mips-gic... |
364 365 366 |
if (cd->mask) write_gic_vl_smask(BIT(intr)); } |
e9de688da irqchip: mips-gic... |
367 |
static struct irq_chip gic_all_vpes_local_irq_controller = { |
da61fcf9d irqchip: mips-gic... |
368 369 370 371 |
.name = "MIPS GIC Local", .irq_mask = gic_mask_local_irq_all_vpes, .irq_unmask = gic_unmask_local_irq_all_vpes, .irq_cpu_online = gic_all_vpes_irq_cpu_online, |
e9de688da irqchip: mips-gic... |
372 |
}; |
18743d278 irqchip: mips-gic... |
373 |
static void __gic_irq_dispatch(void) |
39b8d5254 [MIPS] Add suppor... |
374 |
{ |
1b3ed367c IRQCHIP: mips-gic... |
375 376 |
gic_handle_local_int(false); gic_handle_shared_int(false); |
18743d278 irqchip: mips-gic... |
377 |
} |
39b8d5254 [MIPS] Add suppor... |
378 |
|
bd0b9ac40 genirq: Remove ir... |
379 |
static void gic_irq_dispatch(struct irq_desc *desc) |
18743d278 irqchip: mips-gic... |
380 |
{ |
1b3ed367c IRQCHIP: mips-gic... |
381 382 |
gic_handle_local_int(true); gic_handle_shared_int(true); |
18743d278 irqchip: mips-gic... |
383 |
} |
e9de688da irqchip: mips-gic... |
384 |
static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, |
7778c4b27 irqchip: mips-gic... |
385 |
irq_hw_number_t hw, unsigned int cpu) |
e9de688da irqchip: mips-gic... |
386 387 |
{ int intr = GIC_HWIRQ_TO_SHARED(hw); |
d9f82930a irqchip/mips-gic:... |
388 |
struct irq_data *data; |
c49581a4d irqchip: mips-gic... |
389 |
unsigned long flags; |
d9f82930a irqchip/mips-gic:... |
390 |
data = irq_get_irq_data(virq); |
c49581a4d irqchip: mips-gic... |
391 |
spin_lock_irqsave(&gic_lock, flags); |
d3e8cf447 irqchip: mips-gic... |
392 |
write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); |
7778c4b27 irqchip: mips-gic... |
393 |
write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); |
d9f82930a irqchip/mips-gic:... |
394 |
irq_data_update_effective_affinity(data, cpumask_of(cpu)); |
c49581a4d irqchip: mips-gic... |
395 396 397 398 |
spin_unlock_irqrestore(&gic_lock, flags); return 0; } |
b87281e7f irqchip/mips-gic:... |
399 |
static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, |
c98c1822e irqchip/mips-gic:... |
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { if (intsize != 3) return -EINVAL; if (intspec[0] == GIC_SHARED) *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]); else if (intspec[0] == GIC_LOCAL) *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]); else return -EINVAL; *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } |
8ada00a65 irqchip/mips-gic:... |
417 418 |
static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) |
c98c1822e irqchip/mips-gic:... |
419 |
{ |
da61fcf9d irqchip: mips-gic... |
420 |
struct gic_all_vpes_chip_data *cd; |
63b746b19 irqchip: mips-gic... |
421 422 |
unsigned long flags; unsigned int intr; |
da61fcf9d irqchip: mips-gic... |
423 |
int err, cpu; |
63b746b19 irqchip: mips-gic... |
424 |
u32 map; |
c98c1822e irqchip/mips-gic:... |
425 |
|
8ada00a65 irqchip/mips-gic:... |
426 |
if (hwirq >= GIC_SHARED_HWIRQ_BASE) { |
b87281e7f irqchip/mips-gic:... |
427 428 429 |
/* verify that shared irqs don't conflict with an IPI irq */ if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv)) return -EBUSY; |
c98c1822e irqchip/mips-gic:... |
430 |
|
b87281e7f irqchip/mips-gic:... |
431 432 433 434 435 |
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, &gic_level_irq_controller, NULL); if (err) return err; |
18416e45b irqchip/mips-gic:... |
436 |
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq))); |
b87281e7f irqchip/mips-gic:... |
437 |
return gic_shared_irq_domain_map(d, virq, hwirq, 0); |
c98c1822e irqchip/mips-gic:... |
438 |
} |
63b746b19 irqchip: mips-gic... |
439 440 441 442 |
intr = GIC_HWIRQ_TO_LOCAL(hwirq); map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin; switch (intr) { |
b87281e7f irqchip/mips-gic:... |
443 |
case GIC_LOCAL_INT_TIMER: |
63b746b19 irqchip: mips-gic... |
444 445 |
/* CONFIG_MIPS_CMP workaround (see __gic_init) */ map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin; |
df561f668 treewide: Use fal... |
446 |
fallthrough; |
b87281e7f irqchip/mips-gic:... |
447 448 449 450 451 452 453 |
case GIC_LOCAL_INT_PERFCTR: case GIC_LOCAL_INT_FDC: /* * HACK: These are all really percpu interrupts, but * the rest of the MIPS kernel code does not use the * percpu IRQ API for them. */ |
da61fcf9d irqchip: mips-gic... |
454 455 |
cd = &gic_all_vpes_chip_data[intr]; cd->map = map; |
b87281e7f irqchip/mips-gic:... |
456 457 |
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, &gic_all_vpes_local_irq_controller, |
da61fcf9d irqchip: mips-gic... |
458 |
cd); |
b87281e7f irqchip/mips-gic:... |
459 460 |
if (err) return err; |
c98c1822e irqchip/mips-gic:... |
461 |
|
b87281e7f irqchip/mips-gic:... |
462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
irq_set_handler(virq, handle_percpu_irq); break; default: err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, &gic_local_irq_controller, NULL); if (err) return err; irq_set_handler(virq, handle_percpu_devid_irq); irq_set_percpu_devid(virq); break; } |
63b746b19 irqchip: mips-gic... |
476 477 478 479 |
if (!gic_local_irq_is_routable(intr)) return -EPERM; spin_lock_irqsave(&gic_lock, flags); |
da61fcf9d irqchip: mips-gic... |
480 481 |
for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); |
6d4d367d0 irqchip/mips-gic:... |
482 |
write_gic_vo_map(mips_gic_vx_map_reg(intr), map); |
63b746b19 irqchip: mips-gic... |
483 484 485 486 |
} spin_unlock_irqrestore(&gic_lock, flags); return 0; |
c98c1822e irqchip/mips-gic:... |
487 |
} |
8ada00a65 irqchip/mips-gic:... |
488 489 490 491 492 493 494 495 496 497 498 499 500 |
static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg) { struct irq_fwspec *fwspec = arg; irq_hw_number_t hwirq; if (fwspec->param[0] == GIC_SHARED) hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); else hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); return gic_irq_domain_map(d, virq, hwirq); } |
b87281e7f irqchip/mips-gic:... |
501 502 |
void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) |
2564970a3 irqchip/mips-gic:... |
503 |
{ |
2564970a3 irqchip/mips-gic:... |
504 |
} |
b87281e7f irqchip/mips-gic:... |
505 506 507 508 |
static const struct irq_domain_ops gic_irq_domain_ops = { .xlate = gic_irq_domain_xlate, .alloc = gic_irq_domain_alloc, .free = gic_irq_domain_free, |
8ada00a65 irqchip/mips-gic:... |
509 |
.map = gic_irq_domain_map, |
2af70a962 irqchip/mips-gic:... |
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
}; static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { /* * There's nothing to translate here. hwirq is dynamically allocated and * the irq type is always edge triggered. * */ *out_hwirq = 0; *out_type = IRQ_TYPE_EDGE_RISING; return 0; } static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg) { struct cpumask *ipimask = arg; |
b87281e7f irqchip/mips-gic:... |
531 532 |
irq_hw_number_t hwirq, base_hwirq; int cpu, ret, i; |
2af70a962 irqchip/mips-gic:... |
533 |
|
b87281e7f irqchip/mips-gic:... |
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
base_hwirq = find_first_bit(ipi_available, gic_shared_intrs); if (base_hwirq == gic_shared_intrs) return -ENOMEM; /* check that we have enough space */ for (i = base_hwirq; i < nr_irqs; i++) { if (!test_bit(i, ipi_available)) return -EBUSY; } bitmap_clear(ipi_available, base_hwirq, nr_irqs); /* map the hwirq for each cpu consecutively */ i = 0; for_each_cpu(cpu, ipimask) { hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i); ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq, &gic_edge_irq_controller, NULL); if (ret) goto error; |
2af70a962 irqchip/mips-gic:... |
555 |
|
b87281e7f irqchip/mips-gic:... |
556 |
ret = irq_domain_set_hwirq_and_chip(d->parent, virq + i, hwirq, |
2af70a962 irqchip/mips-gic:... |
557 558 559 560 561 562 563 564 |
&gic_edge_irq_controller, NULL); if (ret) goto error; ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING); if (ret) goto error; |
b87281e7f irqchip/mips-gic:... |
565 566 567 568 569 570 |
ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu); if (ret) goto error; i++; |
2af70a962 irqchip/mips-gic:... |
571 572 573 574 |
} return 0; error: |
b87281e7f irqchip/mips-gic:... |
575 |
bitmap_set(ipi_available, base_hwirq, nr_irqs); |
2af70a962 irqchip/mips-gic:... |
576 577 |
return ret; } |
b0e453ffd irqchip/mips-gic:... |
578 579 |
static void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) |
2af70a962 irqchip/mips-gic:... |
580 |
{ |
b87281e7f irqchip/mips-gic:... |
581 582 583 584 585 586 587 588 589 |
irq_hw_number_t base_hwirq; struct irq_data *data; data = irq_get_irq_data(virq); if (!data) return; base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); bitmap_set(ipi_available, base_hwirq, nr_irqs); |
2af70a962 irqchip/mips-gic:... |
590 |
} |
b0e453ffd irqchip/mips-gic:... |
591 592 |
static int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node, enum irq_domain_bus_token bus_token) |
2af70a962 irqchip/mips-gic:... |
593 594 595 596 597 598 |
{ bool is_ipi; switch (bus_token) { case DOMAIN_BUS_IPI: is_ipi = d->bus_token == bus_token; |
547aefc4d irqchip/mips-gic:... |
599 |
return (!node || to_of_node(d->fwnode) == node) && is_ipi; |
2af70a962 irqchip/mips-gic:... |
600 601 602 603 604 |
break; default: return 0; } } |
0b7e815aa irqchip/irq-mips-... |
605 |
static const struct irq_domain_ops gic_ipi_domain_ops = { |
2af70a962 irqchip/mips-gic:... |
606 607 608 609 |
.xlate = gic_ipi_domain_xlate, .alloc = gic_ipi_domain_alloc, .free = gic_ipi_domain_free, .match = gic_ipi_domain_match, |
c49581a4d irqchip: mips-gic... |
610 |
}; |
da61fcf9d irqchip: mips-gic... |
611 612 |
static int gic_cpu_startup(unsigned int cpu) { |
890f6b55e irqchip: mips-gic... |
613 614 615 |
/* Enable or disable EIC */ change_gic_vl_ctl(GIC_VX_CTL_EIC, cpu_has_veic ? GIC_VX_CTL_EIC : 0); |
25ac19e1b irqchip: mips-gic... |
616 617 |
/* Clear all local IRQ masks (ie. disable all local interrupts) */ write_gic_vl_rmask(~0); |
da61fcf9d irqchip: mips-gic... |
618 619 620 621 622 |
/* Invoke irq_cpu_online callbacks to enable desired interrupts */ irq_cpu_online(); return 0; } |
fbea75412 irqchip: mips-gic... |
623 624 625 |
static int __init gic_of_init(struct device_node *node, struct device_node *parent) |
39b8d5254 [MIPS] Add suppor... |
626 |
{ |
25c51dad6 irqchip: mips-gic... |
627 |
unsigned int cpu_vec, i, gicconfig, v[2], num_ipis; |
b2b2e584c irqchip: mips-gic... |
628 |
unsigned long reserved; |
fbea75412 irqchip: mips-gic... |
629 630 631 632 633 |
phys_addr_t gic_base; struct resource res; size_t gic_len; /* Find the first available CPU vector. */ |
b2b2e584c irqchip: mips-gic... |
634 |
i = 0; |
a08588ea4 irqchip/mips-gic:... |
635 |
reserved = (C_SW0 | C_SW1) >> __ffs(C_SW0); |
fbea75412 irqchip: mips-gic... |
636 637 638 |
while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", i++, &cpu_vec)) reserved |= BIT(cpu_vec); |
b2b2e584c irqchip: mips-gic... |
639 640 641 |
cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM)); if (cpu_vec == hweight_long(ST0_IM)) { |
1f19aee0e irqchip/mips-gic:... |
642 643 |
pr_err("No CPU vectors available "); |
fbea75412 irqchip: mips-gic... |
644 645 646 647 648 649 650 651 652 653 654 655 |
return -ENODEV; } if (of_address_to_resource(node, 0, &res)) { /* * Probe the CM for the GIC base address if not specified * in the device-tree. */ if (mips_cm_present()) { gic_base = read_gcr_gic_base() & ~CM_GCR_GIC_BASE_GICEN; gic_len = 0x20000; |
666740fde irqchip: mips-gic... |
656 657 658 |
pr_warn("Using inherited base address %pa ", &gic_base); |
fbea75412 irqchip: mips-gic... |
659 |
} else { |
1f19aee0e irqchip/mips-gic:... |
660 661 |
pr_err("Failed to get memory range "); |
fbea75412 irqchip: mips-gic... |
662 663 664 665 666 667 |
return -ENODEV; } } else { gic_base = res.start; gic_len = resource_size(&res); } |
39b8d5254 [MIPS] Add suppor... |
668 |
|
fbea75412 irqchip: mips-gic... |
669 670 671 672 673 |
if (mips_cm_present()) { write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN); /* Ensure GIC region is enabled before trying to access it */ __sync(); } |
c0a9f72c1 irqchip: irq-mips... |
674 |
|
4bdc0d676 remove ioremap_no... |
675 |
mips_gic_base = ioremap(gic_base, gic_len); |
39b8d5254 [MIPS] Add suppor... |
676 |
|
3680746ab irqchip: mips-gic... |
677 678 |
gicconfig = read_gic_config(); gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS; |
a08588ea4 irqchip/mips-gic:... |
679 |
gic_shared_intrs >>= __ffs(GIC_CONFIG_NUMINTERRUPTS); |
3680746ab irqchip: mips-gic... |
680 |
gic_shared_intrs = (gic_shared_intrs + 1) * 8; |
39b8d5254 [MIPS] Add suppor... |
681 |
|
18743d278 irqchip: mips-gic... |
682 683 684 |
if (cpu_has_veic) { /* Always use vector 1 in EIC mode */ gic_cpu_pin = 0; |
1b6af71a8 IRQCHIP: mips-gic... |
685 |
timer_cpu_pin = gic_cpu_pin; |
18743d278 irqchip: mips-gic... |
686 687 688 689 690 691 |
set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, __gic_irq_dispatch); } else { gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, gic_irq_dispatch); |
1b6af71a8 IRQCHIP: mips-gic... |
692 693 694 695 696 697 698 699 700 701 702 703 704 |
/* * With the CMP implementation of SMP (deprecated), other CPUs * are started by the bootloader and put into a timer based * waiting poll loop. We must not re-route those CPU's local * timer interrupts as the wait instruction will never finish, * so just handle whatever CPU interrupt it is routed to by * default. * * This workaround should be removed when CMP support is * dropped. */ if (IS_ENABLED(CONFIG_MIPS_CMP) && gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { |
0d0cf58cd irqchip: mips-gic... |
705 |
timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP; |
1b6af71a8 IRQCHIP: mips-gic... |
706 707 708 709 710 711 712 |
irq_set_chained_handler(MIPS_CPU_IRQ_BASE + GIC_CPU_PIN_OFFSET + timer_cpu_pin, gic_irq_dispatch); } else { timer_cpu_pin = gic_cpu_pin; } |
18743d278 irqchip: mips-gic... |
713 |
} |
a7057270c irqchip: mips-gic... |
714 |
gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + |
fbea75412 irqchip: mips-gic... |
715 |
gic_shared_intrs, 0, |
c49581a4d irqchip: mips-gic... |
716 |
&gic_irq_domain_ops, NULL); |
fbea75412 irqchip: mips-gic... |
717 |
if (!gic_irq_domain) { |
1f19aee0e irqchip/mips-gic:... |
718 |
pr_err("Failed to add IRQ domain"); |
fbea75412 irqchip: mips-gic... |
719 720 |
return -ENXIO; } |
0b271f560 MIPS: Make GIC co... |
721 |
|
2af70a962 irqchip/mips-gic:... |
722 723 724 725 |
gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain, IRQ_DOMAIN_FLAG_IPI_PER_CPU, GIC_NUM_LOCAL_INTRS + gic_shared_intrs, node, &gic_ipi_domain_ops, NULL); |
fbea75412 irqchip: mips-gic... |
726 |
if (!gic_ipi_domain) { |
1f19aee0e irqchip/mips-gic:... |
727 |
pr_err("Failed to add IPI domain"); |
fbea75412 irqchip: mips-gic... |
728 729 |
return -ENXIO; } |
2af70a962 irqchip/mips-gic:... |
730 |
|
96f0d93a4 irqchip/MSI: Use ... |
731 |
irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI); |
2af70a962 irqchip/mips-gic:... |
732 |
|
16a8083ce irqchip/mips-gic:... |
733 734 735 736 |
if (node && !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) { bitmap_set(ipi_resrv, v[0], v[1]); } else { |
25c51dad6 irqchip: mips-gic... |
737 738 739 740 741 742 |
/* * Reserve 2 interrupts per possible CPU/VP for use as IPIs, * meeting the requirements of arch/mips SMP. */ num_ipis = 2 * num_possible_cpus(); bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis); |
16a8083ce irqchip/mips-gic:... |
743 |
} |
2af70a962 irqchip/mips-gic:... |
744 |
|
f8dcd9e81 irqchip/mips-gic:... |
745 |
bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); |
a7057270c irqchip: mips-gic... |
746 |
|
87888bcbe irqchip: mips-gic... |
747 |
board_bind_eic_interrupt = &gic_bind_eic_interrupt; |
a7057270c irqchip: mips-gic... |
748 |
|
87888bcbe irqchip: mips-gic... |
749 750 751 752 |
/* Setup defaults */ for (i = 0; i < gic_shared_intrs; i++) { change_gic_pol(i, GIC_POL_ACTIVE_HIGH); change_gic_trig(i, GIC_TRIG_LEVEL); |
90019f8fc irqchip.mips-gic:... |
753 |
write_gic_rmask(i); |
a7057270c irqchip: mips-gic... |
754 |
} |
da61fcf9d irqchip: mips-gic... |
755 756 757 |
return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING, "irqchip/mips/gic:starting", gic_cpu_startup, NULL); |
a7057270c irqchip: mips-gic... |
758 759 |
} IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init); |