Blame view

drivers/irqchip/irq-gic.c 39.7 KB
f27ecacc5   Russell King   [ARM] Add support...
1
  /*
f27ecacc5   Russell King   [ARM] Add support...
2
3
4
5
6
7
8
9
10
11
12
13
14
   *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * Interrupt architecture for the GIC:
   *
   * o There is one Interrupt Distributor, which receives interrupts
   *   from system devices and sends them to the Interrupt Controllers.
   *
   * o There is one CPU Interface per CPU, which sends interrupts sent
   *   by the Distributor, and interrupts generated locally, to the
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
15
16
17
   *   associated CPU. The base address of the CPU interface is usually
   *   aliased so that the same address points to different chips depending
   *   on the CPU it is accessed from.
f27ecacc5   Russell King   [ARM] Add support...
18
19
20
21
22
23
24
   *
   * Note that IRQs 0-31 are special - they are local to each CPU.
   * As such, the enable set/clear, pending set/clear and active bit
   * registers are banked per-cpu for these sources.
   */
  #include <linux/init.h>
  #include <linux/kernel.h>
f37a53cc5   Rob Herring   ARM: gic: fix irq...
25
  #include <linux/err.h>
7e1efcf5d   Arnd Bergmann   ARM: gic: use mod...
26
  #include <linux/module.h>
f27ecacc5   Russell King   [ARM] Add support...
27
28
  #include <linux/list.h>
  #include <linux/smp.h>
c0114709e   Catalin Marinas   irqchip: gic: Per...
29
  #include <linux/cpu.h>
254056f3b   Colin Cross   ARM: gic: Use cpu...
30
  #include <linux/cpu_pm.h>
dcb86e8cb   Catalin Marinas   [ARM] 2868/1: Inc...
31
  #include <linux/cpumask.h>
fced80c73   Russell King   [ARM] Convert asm...
32
  #include <linux/io.h>
b3f7ed032   Rob Herring   ARM: gic: add OF ...
33
34
35
  #include <linux/of.h>
  #include <linux/of_address.h>
  #include <linux/of_irq.h>
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
36
  #include <linux/acpi.h>
4294f8baa   Rob Herring   ARM: gic: add irq...
37
  #include <linux/irqdomain.h>
292b293ce   Marc Zyngier   ARM: gic: consoli...
38
39
40
  #include <linux/interrupt.h>
  #include <linux/percpu.h>
  #include <linux/slab.h>
41a83e06e   Joel Porquet   irqchip: Prepare ...
41
  #include <linux/irqchip.h>
de88cbb7b   Catalin Marinas   arm: Move chained...
42
  #include <linux/irqchip/chained_irq.h>
520f7bd73   Rob Herring   irqchip: Move ARM...
43
  #include <linux/irqchip/arm-gic.h>
f27ecacc5   Russell King   [ARM] Add support...
44

29e697b11   Tomasz Figa   irqchip: gic: Fix...
45
  #include <asm/cputype.h>
f27ecacc5   Russell King   [ARM] Add support...
46
  #include <asm/irq.h>
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
47
  #include <asm/exception.h>
eb50439b9   Will Deacon   ARM: 7293/1: logi...
48
  #include <asm/smp_plat.h>
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
49
  #include <asm/virt.h>
f27ecacc5   Russell King   [ARM] Add support...
50

d51d0af43   Marc Zyngier   irqchip: gic: Mov...
51
  #include "irq-gic-common.h"
f27ecacc5   Russell King   [ARM] Add support...
52

76e52dd01   Marc Zyngier   irqchip/gic: Warn...
53
54
55
56
57
  #ifdef CONFIG_ARM64
  #include <asm/cpufeature.h>
  
  static void gic_check_cpu_features(void)
  {
25fc11aea   Marc Zyngier   irqchip/gic: Rest...
58
  	WARN_TAINT_ONCE(this_cpu_has_cap(ARM64_HAS_SYSREG_GIC_CPUIF),
76e52dd01   Marc Zyngier   irqchip/gic: Warn...
59
60
61
62
63
64
65
  			TAINT_CPU_OUT_OF_SPEC,
  			"GICv3 system registers enabled, broken firmware!
  ");
  }
  #else
  #define gic_check_cpu_features()	do { } while(0)
  #endif
db0d4db22   Marc Zyngier   ARM: gic: allow G...
66
67
  union gic_base {
  	void __iomem *common_base;
6859358e4   Stephen Boyd   irqchip: gic: Sil...
68
  	void __percpu * __iomem *percpu_base;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
69
70
71
  };
  
  struct gic_chip_data {
58b896499   Linus Walleij   irqchip/gic: Assi...
72
  	struct irq_chip chip;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
73
74
  	union gic_base dist_base;
  	union gic_base cpu_base;
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
75
76
77
  	void __iomem *raw_dist_base;
  	void __iomem *raw_cpu_base;
  	u32 percpu_offset;
9c8edddfc   Jon Hunter   irqchip/gic: Add ...
78
  #if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM)
db0d4db22   Marc Zyngier   ARM: gic: allow G...
79
  	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
80
  	u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
db0d4db22   Marc Zyngier   ARM: gic: allow G...
81
82
83
  	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
  	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
  	u32 __percpu *saved_ppi_enable;
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
84
  	u32 __percpu *saved_ppi_active;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
85
86
  	u32 __percpu *saved_ppi_conf;
  #endif
75294957b   Grant Likely   irq_domain: Remov...
87
  	struct irq_domain *domain;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
88
89
90
91
92
  	unsigned int gic_irqs;
  #ifdef CONFIG_GIC_NON_BANKED
  	void __iomem *(*get_base)(union gic_base *);
  #endif
  };
04c8b0f82   Marc Zyngier   irqchip/gic: Make...
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  #ifdef CONFIG_BL_SWITCHER
  
  static DEFINE_RAW_SPINLOCK(cpu_map_lock);
  
  #define gic_lock_irqsave(f)		\
  	raw_spin_lock_irqsave(&cpu_map_lock, (f))
  #define gic_unlock_irqrestore(f)	\
  	raw_spin_unlock_irqrestore(&cpu_map_lock, (f))
  
  #define gic_lock()			raw_spin_lock(&cpu_map_lock)
  #define gic_unlock()			raw_spin_unlock(&cpu_map_lock)
  
  #else
  
  #define gic_lock_irqsave(f)		do { (void)(f); } while(0)
  #define gic_unlock_irqrestore(f)	do { (void)(f); } while(0)
  
  #define gic_lock()			do { } while(0)
  #define gic_unlock()			do { } while(0)
  
  #endif
f27ecacc5   Russell King   [ARM] Add support...
114

d7ed36a4e   Santosh Shilimkar   ARM: 6777/1: gic:...
115
  /*
384a29028   Nicolas Pitre   ARM: gic: use a p...
116
117
118
119
120
121
   * The GIC mapping of CPU interfaces does not necessarily match
   * the logical CPU numbering.  Let's use a mapping as returned
   * by the GIC itself.
   */
  #define NR_GIC_CPU_IF 8
  static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
122
  static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
a27d21e03   Linus Walleij   irqchip/gic: Kcon...
123
  static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
124

502d6df11   Julien Grall   irqchip/gic-v2: P...
125
  static struct gic_kvm_info gic_v2_kvm_info;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
126
127
128
  #ifdef CONFIG_GIC_NON_BANKED
  static void __iomem *gic_get_percpu_base(union gic_base *base)
  {
513d1a288   Christoph Lameter   irqchip: Properly...
129
  	return raw_cpu_read(*base->percpu_base);
db0d4db22   Marc Zyngier   ARM: gic: allow G...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  }
  
  static void __iomem *gic_get_common_base(union gic_base *base)
  {
  	return base->common_base;
  }
  
  static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
  {
  	return data->get_base(&data->dist_base);
  }
  
  static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
  {
  	return data->get_base(&data->cpu_base);
  }
  
  static inline void gic_set_base_accessor(struct gic_chip_data *data,
  					 void __iomem *(*f)(union gic_base *))
  {
  	data->get_base = f;
  }
  #else
  #define gic_data_dist_base(d)	((d)->dist_base.common_base)
  #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
46f101df7   Sachin Kamat   irqchip: irq-gic:...
155
  #define gic_set_base_accessor(d, f)
db0d4db22   Marc Zyngier   ARM: gic: allow G...
156
  #endif
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
157
  static inline void __iomem *gic_dist_base(struct irq_data *d)
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
158
  {
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
159
  	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
db0d4db22   Marc Zyngier   ARM: gic: allow G...
160
  	return gic_data_dist_base(gic_data);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
161
  }
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
162
  static inline void __iomem *gic_cpu_base(struct irq_data *d)
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
163
  {
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
164
  	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
db0d4db22   Marc Zyngier   ARM: gic: allow G...
165
  	return gic_data_cpu_base(gic_data);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
166
  }
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
167
  static inline unsigned int gic_irq(struct irq_data *d)
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
168
  {
4294f8baa   Rob Herring   ARM: gic: add irq...
169
  	return d->hwirq;
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
170
  }
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
171
172
173
174
175
  static inline bool cascading_gic_irq(struct irq_data *d)
  {
  	void *data = irq_data_get_irq_handler_data(d);
  
  	/*
714665351   Thomas Gleixner   irqchip/gic: Use ...
176
177
  	 * If handler_data is set, this is a cascading interrupt, and
  	 * it cannot possibly be forwarded.
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
178
  	 */
714665351   Thomas Gleixner   irqchip/gic: Use ...
179
  	return data != NULL;
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
180
  }
f27ecacc5   Russell King   [ARM] Add support...
181
182
  /*
   * Routines to acknowledge, disable and enable interrupts
f27ecacc5   Russell King   [ARM] Add support...
183
   */
567178077   Marc Zyngier   irqchip: GIC: Add...
184
185
186
187
188
189
190
  static void gic_poke_irq(struct irq_data *d, u32 offset)
  {
  	u32 mask = 1 << (gic_irq(d) % 32);
  	writel_relaxed(mask, gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4);
  }
  
  static int gic_peek_irq(struct irq_data *d, u32 offset)
f27ecacc5   Russell King   [ARM] Add support...
191
  {
4294f8baa   Rob Herring   ARM: gic: add irq...
192
  	u32 mask = 1 << (gic_irq(d) % 32);
567178077   Marc Zyngier   irqchip: GIC: Add...
193
194
195
196
197
  	return !!(readl_relaxed(gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4) & mask);
  }
  
  static void gic_mask_irq(struct irq_data *d)
  {
567178077   Marc Zyngier   irqchip: GIC: Add...
198
  	gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR);
f27ecacc5   Russell King   [ARM] Add support...
199
  }
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
200
201
202
  static void gic_eoimode1_mask_irq(struct irq_data *d)
  {
  	gic_mask_irq(d);
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
203
204
205
206
207
208
209
210
  	/*
  	 * When masking a forwarded interrupt, make sure it is
  	 * deactivated as well.
  	 *
  	 * This ensures that an interrupt that is getting
  	 * disabled/masked will not get "stuck", because there is
  	 * noone to deactivate it (guest is being terminated).
  	 */
714665351   Thomas Gleixner   irqchip/gic: Use ...
211
  	if (irqd_is_forwarded_to_vcpu(d))
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
212
  		gic_poke_irq(d, GIC_DIST_ACTIVE_CLEAR);
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
213
  }
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
214
  static void gic_unmask_irq(struct irq_data *d)
f27ecacc5   Russell King   [ARM] Add support...
215
  {
567178077   Marc Zyngier   irqchip: GIC: Add...
216
  	gic_poke_irq(d, GIC_DIST_ENABLE_SET);
f27ecacc5   Russell King   [ARM] Add support...
217
  }
1a01753ed   Will Deacon   ARM: gic: use han...
218
219
  static void gic_eoi_irq(struct irq_data *d)
  {
6ac77e469   Santosh Shilimkar   ARM: GIC: Convert...
220
  	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
1a01753ed   Will Deacon   ARM: gic: use han...
221
  }
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
222
223
  static void gic_eoimode1_eoi_irq(struct irq_data *d)
  {
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
224
  	/* Do not deactivate an IRQ forwarded to a vcpu. */
714665351   Thomas Gleixner   irqchip/gic: Use ...
225
  	if (irqd_is_forwarded_to_vcpu(d))
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
226
  		return;
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
227
228
  	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE);
  }
567178077   Marc Zyngier   irqchip: GIC: Add...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  static int gic_irq_set_irqchip_state(struct irq_data *d,
  				     enum irqchip_irq_state which, bool val)
  {
  	u32 reg;
  
  	switch (which) {
  	case IRQCHIP_STATE_PENDING:
  		reg = val ? GIC_DIST_PENDING_SET : GIC_DIST_PENDING_CLEAR;
  		break;
  
  	case IRQCHIP_STATE_ACTIVE:
  		reg = val ? GIC_DIST_ACTIVE_SET : GIC_DIST_ACTIVE_CLEAR;
  		break;
  
  	case IRQCHIP_STATE_MASKED:
  		reg = val ? GIC_DIST_ENABLE_CLEAR : GIC_DIST_ENABLE_SET;
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	gic_poke_irq(d, reg);
  	return 0;
  }
  
  static int gic_irq_get_irqchip_state(struct irq_data *d,
  				      enum irqchip_irq_state which, bool *val)
  {
  	switch (which) {
  	case IRQCHIP_STATE_PENDING:
  		*val = gic_peek_irq(d, GIC_DIST_PENDING_SET);
  		break;
  
  	case IRQCHIP_STATE_ACTIVE:
  		*val = gic_peek_irq(d, GIC_DIST_ACTIVE_SET);
  		break;
  
  	case IRQCHIP_STATE_MASKED:
  		*val = !gic_peek_irq(d, GIC_DIST_ENABLE_SET);
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
277
  static int gic_set_type(struct irq_data *d, unsigned int type)
5c0c1f08a   Rabin Vincent   ARM: 6150/1: gic:...
278
  {
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
279
280
  	void __iomem *base = gic_dist_base(d);
  	unsigned int gicirq = gic_irq(d);
5c0c1f08a   Rabin Vincent   ARM: 6150/1: gic:...
281
282
283
284
  
  	/* Interrupt configuration for SGIs can't be changed */
  	if (gicirq < 16)
  		return -EINVAL;
fb7e7deb7   Liviu Dudau   irqchip: gic: All...
285
286
287
  	/* SPIs have restrictions on the supported types */
  	if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
  			    type != IRQ_TYPE_EDGE_RISING)
5c0c1f08a   Rabin Vincent   ARM: 6150/1: gic:...
288
  		return -EINVAL;
1dcc73d7b   Marc Zyngier   irqchip: gic: Dro...
289
  	return gic_configure_irq(gicirq, type, base, NULL);
d7ed36a4e   Santosh Shilimkar   ARM: 6777/1: gic:...
290
  }
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
291
292
293
294
295
  static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
  {
  	/* Only interrupts on the primary GIC can be forwarded to a vcpu. */
  	if (cascading_gic_irq(d))
  		return -EINVAL;
714665351   Thomas Gleixner   irqchip/gic: Use ...
296
297
298
299
  	if (vcpu)
  		irqd_set_forwarded_to_vcpu(d);
  	else
  		irqd_clr_forwarded_to_vcpu(d);
01f779f48   Marc Zyngier   irqchip/GIC: Don'...
300
301
  	return 0;
  }
a06f5466c   Catalin Marinas   [ARM] 2942/1: Fix...
302
  #ifdef CONFIG_SMP
c191789c7   Russell King   ARM: irq migratio...
303
304
  static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
  			    bool force)
f27ecacc5   Russell King   [ARM] Add support...
305
  {
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
306
  	void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
ffde1de64   Thomas Gleixner   irqchip: Gic: Sup...
307
  	unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
c191789c7   Russell King   ARM: irq migratio...
308
  	u32 val, mask, bit;
cf6138719   Marc Zyngier   irqchip: gic: Fix...
309
  	unsigned long flags;
f27ecacc5   Russell King   [ARM] Add support...
310

ffde1de64   Thomas Gleixner   irqchip: Gic: Sup...
311
312
313
314
  	if (!force)
  		cpu = cpumask_any_and(mask_val, cpu_online_mask);
  	else
  		cpu = cpumask_first(mask_val);
384a29028   Nicolas Pitre   ARM: gic: use a p...
315
  	if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
87507500b   Chao Xie   ARM: 6524/1: GIC ...
316
  		return -EINVAL;
c191789c7   Russell King   ARM: irq migratio...
317

04c8b0f82   Marc Zyngier   irqchip/gic: Make...
318
  	gic_lock_irqsave(flags);
c191789c7   Russell King   ARM: irq migratio...
319
  	mask = 0xff << shift;
384a29028   Nicolas Pitre   ARM: gic: use a p...
320
  	bit = gic_cpu_map[cpu] << shift;
6ac77e469   Santosh Shilimkar   ARM: GIC: Convert...
321
322
  	val = readl_relaxed(reg) & ~mask;
  	writel_relaxed(val | bit, reg);
04c8b0f82   Marc Zyngier   irqchip/gic: Make...
323
  	gic_unlock_irqrestore(flags);
d5dedd450   Yinghai Lu   irq: change ->set...
324

0407dacee   Marc Zyngier   irqchip/gic: Retu...
325
  	return IRQ_SET_MASK_OK_DONE;
f27ecacc5   Russell King   [ARM] Add support...
326
  }
a06f5466c   Catalin Marinas   [ARM] 2942/1: Fix...
327
  #endif
f27ecacc5   Russell King   [ARM] Add support...
328

8783dd3a3   Stephen Boyd   irqchip: Remove a...
329
  static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
330
331
332
333
334
335
336
  {
  	u32 irqstat, irqnr;
  	struct gic_chip_data *gic = &gic_data[0];
  	void __iomem *cpu_base = gic_data_cpu_base(gic);
  
  	do {
  		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
b8802f76f   Haojian Zhuang   irqchip: gic: Use...
337
  		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
338

327ebe1f3   Marc Zyngier   irqchip/gic: Make...
339
  		if (likely(irqnr > 15 && irqnr < 1020)) {
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
340
341
  			if (static_key_true(&supports_deactivate))
  				writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
60031b4ef   Marc Zyngier   irqchip: gic: Con...
342
  			handle_domain_irq(gic->domain, irqnr, regs);
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
343
344
345
346
  			continue;
  		}
  		if (irqnr < 16) {
  			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
347
348
  			if (static_key_true(&supports_deactivate))
  				writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
349
  #ifdef CONFIG_SMP
f86c4fbd9   Will Deacon   irqchip/gic: Ensu...
350
351
352
353
354
355
356
357
  			/*
  			 * Ensure any shared data written by the CPU sending
  			 * the IPI is read after we've read the ACK register
  			 * on the GIC.
  			 *
  			 * Pairs with the write barrier in gic_raise_softirq
  			 */
  			smp_rmb();
562e0027d   Marc Zyngier   ARM: GIC: Add glo...
358
359
360
361
362
363
364
  			handle_IPI(irqnr, regs);
  #endif
  			continue;
  		}
  		break;
  	} while (1);
  }
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
365
  static void gic_handle_cascade_irq(struct irq_desc *desc)
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
366
  {
5b29264c6   Jiang Liu   irqchip: Use irq_...
367
368
  	struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc);
  	struct irq_chip *chip = irq_desc_get_chip(desc);
0f347bb91   Russell King   [ARM] gic: Fix gi...
369
  	unsigned int cascade_irq, gic_irq;
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
370
  	unsigned long status;
1a01753ed   Will Deacon   ARM: gic: use han...
371
  	chained_irq_enter(chip, desc);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
372

db0d4db22   Marc Zyngier   ARM: gic: allow G...
373
  	status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
374

e5f81539f   Feng Kan   irqchip: gic: Rep...
375
376
  	gic_irq = (status & GICC_IAR_INT_ID_MASK);
  	if (gic_irq == GICC_INT_SPURIOUS)
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
377
  		goto out;
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
378

75294957b   Grant Likely   irq_domain: Remov...
379
380
  	cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
  	if (unlikely(gic_irq < 32 || gic_irq > 1020))
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
381
  		handle_bad_irq(desc);
0f347bb91   Russell King   [ARM] gic: Fix gi...
382
383
  	else
  		generic_handle_irq(cascade_irq);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
384
385
  
   out:
1a01753ed   Will Deacon   ARM: gic: use han...
386
  	chained_irq_exit(chip, desc);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
387
  }
38c677cb9   David Brownell   [ARM] 3739/1: gen...
388
  static struct irq_chip gic_chip = {
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
389
390
  	.irq_mask		= gic_mask_irq,
  	.irq_unmask		= gic_unmask_irq,
1a01753ed   Will Deacon   ARM: gic: use han...
391
  	.irq_eoi		= gic_eoi_irq,
7d1f4288a   Lennert Buytenhek   ARM: gic: irq_dat...
392
  	.irq_set_type		= gic_set_type,
567178077   Marc Zyngier   irqchip: GIC: Add...
393
394
  	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
  	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
aec89ef72   Sudeep Holla   irqchip/gic: Enab...
395
396
397
  	.flags			= IRQCHIP_SET_TYPE_MASKED |
  				  IRQCHIP_SKIP_SET_WAKE |
  				  IRQCHIP_MASK_ON_SUSPEND,
f27ecacc5   Russell King   [ARM] Add support...
398
  };
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
399
400
  void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
  {
a27d21e03   Linus Walleij   irqchip/gic: Kcon...
401
  	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
4d83fcf8d   Thomas Gleixner   irqchip/gic: Cons...
402
403
  	irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq,
  					 &gic_data[gic_nr]);
b3a1bde4d   Catalin Marinas   [ARM] 4108/2: Al...
404
  }
2bb313516   Russell King   ARM: GIC: fix GIC...
405
406
407
408
409
410
411
412
413
414
415
416
  static u8 gic_get_cpumask(struct gic_chip_data *gic)
  {
  	void __iomem *base = gic_data_dist_base(gic);
  	u32 mask, i;
  
  	for (i = mask = 0; i < 32; i += 4) {
  		mask = readl_relaxed(base + GIC_DIST_TARGET + i);
  		mask |= mask >> 16;
  		mask |= mask >> 8;
  		if (mask)
  			break;
  	}
6e3aca441   Stephen Boyd   irqchip: gic: Don...
417
  	if (!mask && num_possible_cpus() > 1)
2bb313516   Russell King   ARM: GIC: fix GIC...
418
419
420
421
422
  		pr_crit("GIC CPU mask not found - kernel will fail to boot.
  ");
  
  	return mask;
  }
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
423
  static void gic_cpu_if_up(struct gic_chip_data *gic)
322895062   Feng Kan   irqchip: gic: Pre...
424
  {
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
425
  	void __iomem *cpu_base = gic_data_cpu_base(gic);
322895062   Feng Kan   irqchip: gic: Pre...
426
  	u32 bypass = 0;
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
427
  	u32 mode = 0;
389a00d3a   Jon Hunter   irqchip/gic: Only...
428
  	if (gic == &gic_data[0] && static_key_true(&supports_deactivate))
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
429
  		mode = GIC_CPU_CTRL_EOImodeNS;
322895062   Feng Kan   irqchip: gic: Pre...
430
431
432
433
434
435
  
  	/*
  	* Preserve bypass disable bits to be written back later
  	*/
  	bypass = readl(cpu_base + GIC_CPU_CTRL);
  	bypass &= GICC_DIS_BYPASS_MASK;
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
436
  	writel_relaxed(bypass | mode | GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
322895062   Feng Kan   irqchip: gic: Pre...
437
  }
cdbb813db   Jon Hunter   irqchip/gic: Prep...
438
  static void gic_dist_init(struct gic_chip_data *gic)
f27ecacc5   Russell King   [ARM] Add support...
439
  {
75294957b   Grant Likely   irq_domain: Remov...
440
  	unsigned int i;
267840f33   Will Deacon   ARM: 7061/1: gic:...
441
  	u32 cpumask;
4294f8baa   Rob Herring   ARM: gic: add irq...
442
  	unsigned int gic_irqs = gic->gic_irqs;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
443
  	void __iomem *base = gic_data_dist_base(gic);
f27ecacc5   Russell King   [ARM] Add support...
444

e5f81539f   Feng Kan   irqchip: gic: Rep...
445
  	writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL);
f27ecacc5   Russell King   [ARM] Add support...
446
447
  
  	/*
f27ecacc5   Russell King   [ARM] Add support...
448
449
  	 * Set all global interrupts to this CPU only.
  	 */
2bb313516   Russell King   ARM: GIC: fix GIC...
450
451
452
  	cpumask = gic_get_cpumask(gic);
  	cpumask |= cpumask << 8;
  	cpumask |= cpumask << 16;
e6afec9b6   Pawel Moll   ARM: 6496/1: GIC:...
453
  	for (i = 32; i < gic_irqs; i += 4)
6ac77e469   Santosh Shilimkar   ARM: GIC: Convert...
454
  		writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
f27ecacc5   Russell King   [ARM] Add support...
455

d51d0af43   Marc Zyngier   irqchip: gic: Mov...
456
  	gic_dist_config(base, gic_irqs, NULL);
f27ecacc5   Russell King   [ARM] Add support...
457

e5f81539f   Feng Kan   irqchip: gic: Rep...
458
  	writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
f27ecacc5   Russell King   [ARM] Add support...
459
  }
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
460
  static int gic_cpu_init(struct gic_chip_data *gic)
f27ecacc5   Russell King   [ARM] Add support...
461
  {
db0d4db22   Marc Zyngier   ARM: gic: allow G...
462
463
  	void __iomem *dist_base = gic_data_dist_base(gic);
  	void __iomem *base = gic_data_cpu_base(gic);
384a29028   Nicolas Pitre   ARM: gic: use a p...
464
  	unsigned int cpu_mask, cpu = smp_processor_id();
9395f6ea3   Russell King   ARM: GIC: don't d...
465
  	int i;
9395f6ea3   Russell King   ARM: GIC: don't d...
466
  	/*
567e5a014   Jon Hunter   irqchip/gic: Only...
467
468
469
  	 * Setting up the CPU map is only relevant for the primary GIC
  	 * because any nested/secondary GICs do not directly interface
  	 * with the CPU(s).
384a29028   Nicolas Pitre   ARM: gic: use a p...
470
  	 */
567e5a014   Jon Hunter   irqchip/gic: Only...
471
472
473
474
  	if (gic == &gic_data[0]) {
  		/*
  		 * Get what the GIC says our CPU mask is.
  		 */
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
475
476
  		if (WARN_ON(cpu >= NR_GIC_CPU_IF))
  			return -EINVAL;
25fc11aea   Marc Zyngier   irqchip/gic: Rest...
477
  		gic_check_cpu_features();
567e5a014   Jon Hunter   irqchip/gic: Only...
478
479
  		cpu_mask = gic_get_cpumask(gic);
  		gic_cpu_map[cpu] = cpu_mask;
384a29028   Nicolas Pitre   ARM: gic: use a p...
480

567e5a014   Jon Hunter   irqchip/gic: Only...
481
482
483
484
485
486
487
488
  		/*
  		 * Clear our mask from the other map entries in case they're
  		 * still undefined.
  		 */
  		for (i = 0; i < NR_GIC_CPU_IF; i++)
  			if (i != cpu)
  				gic_cpu_map[i] &= ~cpu_mask;
  	}
384a29028   Nicolas Pitre   ARM: gic: use a p...
489

d51d0af43   Marc Zyngier   irqchip: gic: Mov...
490
  	gic_cpu_config(dist_base, NULL);
9395f6ea3   Russell King   ARM: GIC: don't d...
491

e5f81539f   Feng Kan   irqchip: gic: Rep...
492
  	writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
493
  	gic_cpu_if_up(gic);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
494
495
  
  	return 0;
f27ecacc5   Russell King   [ARM] Add support...
496
  }
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
497
  int gic_cpu_if_down(unsigned int gic_nr)
10d9eb8a1   Nicolas Pitre   drivers: irq-chip...
498
  {
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
499
  	void __iomem *cpu_base;
322895062   Feng Kan   irqchip: gic: Pre...
500
  	u32 val = 0;
a27d21e03   Linus Walleij   irqchip/gic: Kcon...
501
  	if (gic_nr >= CONFIG_ARM_GIC_MAX_NR)
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
502
503
504
  		return -EINVAL;
  
  	cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
322895062   Feng Kan   irqchip: gic: Pre...
505
506
507
  	val = readl(cpu_base + GIC_CPU_CTRL);
  	val &= ~GICC_ENABLE;
  	writel_relaxed(val, cpu_base + GIC_CPU_CTRL);
4c2880b31   Jon Hunter   irqchip/gic: Ensu...
508
509
  
  	return 0;
10d9eb8a1   Nicolas Pitre   drivers: irq-chip...
510
  }
9c8edddfc   Jon Hunter   irqchip/gic: Add ...
511
  #if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM)
254056f3b   Colin Cross   ARM: gic: Use cpu...
512
513
514
515
516
517
  /*
   * Saves the GIC distributor registers during suspend or idle.  Must be called
   * with interrupts disabled but before powering down the GIC.  After calling
   * this function, no interrupts will be delivered by the GIC, and another
   * platform-specific wakeup source must be enabled.
   */
cdbb813db   Jon Hunter   irqchip/gic: Prep...
518
  void gic_dist_save(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
519
520
521
522
  {
  	unsigned int gic_irqs;
  	void __iomem *dist_base;
  	int i;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
523
524
  	if (WARN_ON(!gic))
  		return;
254056f3b   Colin Cross   ARM: gic: Use cpu...
525

6e5b5924d   Jon Hunter   irqchip/gic: Pass...
526
527
  	gic_irqs = gic->gic_irqs;
  	dist_base = gic_data_dist_base(gic);
254056f3b   Colin Cross   ARM: gic: Use cpu...
528
529
530
531
532
  
  	if (!dist_base)
  		return;
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
533
  		gic->saved_spi_conf[i] =
254056f3b   Colin Cross   ARM: gic: Use cpu...
534
535
536
  			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
537
  		gic->saved_spi_target[i] =
254056f3b   Colin Cross   ARM: gic: Use cpu...
538
539
540
  			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
541
  		gic->saved_spi_enable[i] =
254056f3b   Colin Cross   ARM: gic: Use cpu...
542
  			readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
543
544
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
545
  		gic->saved_spi_active[i] =
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
546
  			readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
254056f3b   Colin Cross   ARM: gic: Use cpu...
547
548
549
550
551
552
553
554
555
  }
  
  /*
   * Restores the GIC distributor registers during resume or when coming out of
   * idle.  Must be called before enabling interrupts.  If a level interrupt
   * that occured while the GIC was suspended is still present, it will be
   * handled normally, but any edge interrupts that occured will not be seen by
   * the GIC and need to be handled by the platform-specific wakeup source.
   */
cdbb813db   Jon Hunter   irqchip/gic: Prep...
556
  void gic_dist_restore(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
557
558
559
560
  {
  	unsigned int gic_irqs;
  	unsigned int i;
  	void __iomem *dist_base;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
561
562
  	if (WARN_ON(!gic))
  		return;
254056f3b   Colin Cross   ARM: gic: Use cpu...
563

6e5b5924d   Jon Hunter   irqchip/gic: Pass...
564
565
  	gic_irqs = gic->gic_irqs;
  	dist_base = gic_data_dist_base(gic);
254056f3b   Colin Cross   ARM: gic: Use cpu...
566
567
568
  
  	if (!dist_base)
  		return;
e5f81539f   Feng Kan   irqchip: gic: Rep...
569
  	writel_relaxed(GICD_DISABLE, dist_base + GIC_DIST_CTRL);
254056f3b   Colin Cross   ARM: gic: Use cpu...
570
571
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
572
  		writel_relaxed(gic->saved_spi_conf[i],
254056f3b   Colin Cross   ARM: gic: Use cpu...
573
574
575
  			dist_base + GIC_DIST_CONFIG + i * 4);
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
e5f81539f   Feng Kan   irqchip: gic: Rep...
576
  		writel_relaxed(GICD_INT_DEF_PRI_X4,
254056f3b   Colin Cross   ARM: gic: Use cpu...
577
578
579
  			dist_base + GIC_DIST_PRI + i * 4);
  
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
580
  		writel_relaxed(gic->saved_spi_target[i],
254056f3b   Colin Cross   ARM: gic: Use cpu...
581
  			dist_base + GIC_DIST_TARGET + i * 4);
92eda4ad4   Marc Zyngier   irqchip/gic: Clea...
582
583
584
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
  		writel_relaxed(GICD_INT_EN_CLR_X32,
  			dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
585
  		writel_relaxed(gic->saved_spi_enable[i],
254056f3b   Colin Cross   ARM: gic: Use cpu...
586
  			dist_base + GIC_DIST_ENABLE_SET + i * 4);
92eda4ad4   Marc Zyngier   irqchip/gic: Clea...
587
  	}
254056f3b   Colin Cross   ARM: gic: Use cpu...
588

1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
589
590
591
  	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
  		writel_relaxed(GICD_INT_EN_CLR_X32,
  			dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
592
  		writel_relaxed(gic->saved_spi_active[i],
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
593
594
  			dist_base + GIC_DIST_ACTIVE_SET + i * 4);
  	}
e5f81539f   Feng Kan   irqchip: gic: Rep...
595
  	writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
254056f3b   Colin Cross   ARM: gic: Use cpu...
596
  }
cdbb813db   Jon Hunter   irqchip/gic: Prep...
597
  void gic_cpu_save(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
598
599
600
601
602
  {
  	int i;
  	u32 *ptr;
  	void __iomem *dist_base;
  	void __iomem *cpu_base;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
603
604
  	if (WARN_ON(!gic))
  		return;
254056f3b   Colin Cross   ARM: gic: Use cpu...
605

6e5b5924d   Jon Hunter   irqchip/gic: Pass...
606
607
  	dist_base = gic_data_dist_base(gic);
  	cpu_base = gic_data_cpu_base(gic);
254056f3b   Colin Cross   ARM: gic: Use cpu...
608
609
610
  
  	if (!dist_base || !cpu_base)
  		return;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
611
  	ptr = raw_cpu_ptr(gic->saved_ppi_enable);
254056f3b   Colin Cross   ARM: gic: Use cpu...
612
613
  	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
  		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
614
  	ptr = raw_cpu_ptr(gic->saved_ppi_active);
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
615
616
  	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
  		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
617
  	ptr = raw_cpu_ptr(gic->saved_ppi_conf);
254056f3b   Colin Cross   ARM: gic: Use cpu...
618
619
620
621
  	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
  		ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
  
  }
cdbb813db   Jon Hunter   irqchip/gic: Prep...
622
  void gic_cpu_restore(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
623
624
625
626
627
  {
  	int i;
  	u32 *ptr;
  	void __iomem *dist_base;
  	void __iomem *cpu_base;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
628
629
  	if (WARN_ON(!gic))
  		return;
254056f3b   Colin Cross   ARM: gic: Use cpu...
630

6e5b5924d   Jon Hunter   irqchip/gic: Pass...
631
632
  	dist_base = gic_data_dist_base(gic);
  	cpu_base = gic_data_cpu_base(gic);
254056f3b   Colin Cross   ARM: gic: Use cpu...
633
634
635
  
  	if (!dist_base || !cpu_base)
  		return;
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
636
  	ptr = raw_cpu_ptr(gic->saved_ppi_enable);
92eda4ad4   Marc Zyngier   irqchip/gic: Clea...
637
638
639
  	for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
  		writel_relaxed(GICD_INT_EN_CLR_X32,
  			       dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
254056f3b   Colin Cross   ARM: gic: Use cpu...
640
  		writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
92eda4ad4   Marc Zyngier   irqchip/gic: Clea...
641
  	}
254056f3b   Colin Cross   ARM: gic: Use cpu...
642

6e5b5924d   Jon Hunter   irqchip/gic: Pass...
643
  	ptr = raw_cpu_ptr(gic->saved_ppi_active);
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
644
645
646
647
648
  	for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
  		writel_relaxed(GICD_INT_EN_CLR_X32,
  			       dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
  		writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4);
  	}
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
649
  	ptr = raw_cpu_ptr(gic->saved_ppi_conf);
254056f3b   Colin Cross   ARM: gic: Use cpu...
650
651
652
653
  	for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
  		writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
  
  	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
e5f81539f   Feng Kan   irqchip: gic: Rep...
654
655
  		writel_relaxed(GICD_INT_DEF_PRI_X4,
  					dist_base + GIC_DIST_PRI + i * 4);
254056f3b   Colin Cross   ARM: gic: Use cpu...
656

e5f81539f   Feng Kan   irqchip: gic: Rep...
657
  	writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
658
  	gic_cpu_if_up(gic);
254056f3b   Colin Cross   ARM: gic: Use cpu...
659
660
661
662
663
  }
  
  static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
  {
  	int i;
a27d21e03   Linus Walleij   irqchip/gic: Kcon...
664
  	for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
db0d4db22   Marc Zyngier   ARM: gic: allow G...
665
666
667
668
669
  #ifdef CONFIG_GIC_NON_BANKED
  		/* Skip over unused GICs */
  		if (!gic_data[i].get_base)
  			continue;
  #endif
254056f3b   Colin Cross   ARM: gic: Use cpu...
670
671
  		switch (cmd) {
  		case CPU_PM_ENTER:
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
672
  			gic_cpu_save(&gic_data[i]);
254056f3b   Colin Cross   ARM: gic: Use cpu...
673
674
675
  			break;
  		case CPU_PM_ENTER_FAILED:
  		case CPU_PM_EXIT:
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
676
  			gic_cpu_restore(&gic_data[i]);
254056f3b   Colin Cross   ARM: gic: Use cpu...
677
678
  			break;
  		case CPU_CLUSTER_PM_ENTER:
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
679
  			gic_dist_save(&gic_data[i]);
254056f3b   Colin Cross   ARM: gic: Use cpu...
680
681
682
  			break;
  		case CPU_CLUSTER_PM_ENTER_FAILED:
  		case CPU_CLUSTER_PM_EXIT:
6e5b5924d   Jon Hunter   irqchip/gic: Pass...
683
  			gic_dist_restore(&gic_data[i]);
254056f3b   Colin Cross   ARM: gic: Use cpu...
684
685
686
687
688
689
690
691
692
693
  			break;
  		}
  	}
  
  	return NOTIFY_OK;
  }
  
  static struct notifier_block gic_notifier_block = {
  	.notifier_call = gic_notifier,
  };
cdbb813db   Jon Hunter   irqchip/gic: Prep...
694
  static int gic_pm_init(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
695
696
697
  {
  	gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
  		sizeof(u32));
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
698
699
  	if (WARN_ON(!gic->saved_ppi_enable))
  		return -ENOMEM;
254056f3b   Colin Cross   ARM: gic: Use cpu...
700

1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
701
702
  	gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
  		sizeof(u32));
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
703
704
  	if (WARN_ON(!gic->saved_ppi_active))
  		goto free_ppi_enable;
1c7d4dd46   Marc Zyngier   irqchip/gic: Add ...
705

254056f3b   Colin Cross   ARM: gic: Use cpu...
706
707
  	gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
  		sizeof(u32));
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
708
709
  	if (WARN_ON(!gic->saved_ppi_conf))
  		goto free_ppi_active;
254056f3b   Colin Cross   ARM: gic: Use cpu...
710

abdd7b91d   Marc Zyngier   ARM: 7176/1: cpu_...
711
712
  	if (gic == &gic_data[0])
  		cpu_pm_register_notifier(&gic_notifier_block);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
713
714
715
716
717
718
719
720
721
  
  	return 0;
  
  free_ppi_active:
  	free_percpu(gic->saved_ppi_active);
  free_ppi_enable:
  	free_percpu(gic->saved_ppi_enable);
  
  	return -ENOMEM;
254056f3b   Colin Cross   ARM: gic: Use cpu...
722
723
  }
  #else
cdbb813db   Jon Hunter   irqchip/gic: Prep...
724
  static int gic_pm_init(struct gic_chip_data *gic)
254056f3b   Colin Cross   ARM: gic: Use cpu...
725
  {
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
726
  	return 0;
254056f3b   Colin Cross   ARM: gic: Use cpu...
727
728
  }
  #endif
b1cffebf1   Rob Herring   ARM: GIC: remove ...
729
  #ifdef CONFIG_SMP
6859358e4   Stephen Boyd   irqchip: gic: Sil...
730
  static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
b1cffebf1   Rob Herring   ARM: GIC: remove ...
731
732
  {
  	int cpu;
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
733
  	unsigned long flags, map = 0;
059e23208   Marc Zyngier   irqchip/gic: Allo...
734
735
736
737
738
739
  	if (unlikely(nr_cpu_ids == 1)) {
  		/* Only one CPU? let's do a self-IPI... */
  		writel_relaxed(2 << 24 | irq,
  			       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
  		return;
  	}
04c8b0f82   Marc Zyngier   irqchip/gic: Make...
740
  	gic_lock_irqsave(flags);
b1cffebf1   Rob Herring   ARM: GIC: remove ...
741
742
743
  
  	/* Convert our logical CPU mask into a physical one. */
  	for_each_cpu(cpu, mask)
91bdf0d0c   Javi Merino   irqchip: fix typo...
744
  		map |= gic_cpu_map[cpu];
b1cffebf1   Rob Herring   ARM: GIC: remove ...
745
746
747
  
  	/*
  	 * Ensure that stores to Normal memory are visible to the
8adbf57fc   Will Deacon   irqchip: gic: use...
748
  	 * other CPUs before they observe us issuing the IPI.
b1cffebf1   Rob Herring   ARM: GIC: remove ...
749
  	 */
8adbf57fc   Will Deacon   irqchip: gic: use...
750
  	dmb(ishst);
b1cffebf1   Rob Herring   ARM: GIC: remove ...
751
752
753
  
  	/* this always happens on GIC0 */
  	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
754

04c8b0f82   Marc Zyngier   irqchip/gic: Make...
755
  	gic_unlock_irqrestore(flags);
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
756
757
758
759
760
  }
  #endif
  
  #ifdef CONFIG_BL_SWITCHER
  /*
14d2ca615   Nicolas Pitre   ARM: GIC: interfa...
761
762
763
764
765
766
767
768
769
770
771
772
773
774
   * gic_send_sgi - send a SGI directly to given CPU interface number
   *
   * cpu_id: the ID for the destination CPU interface
   * irq: the IPI number to send a SGI for
   */
  void gic_send_sgi(unsigned int cpu_id, unsigned int irq)
  {
  	BUG_ON(cpu_id >= NR_GIC_CPU_IF);
  	cpu_id = 1 << cpu_id;
  	/* this always happens on GIC0 */
  	writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
  }
  
  /*
ed96762e3   Nicolas Pitre   ARM: bL_switcher:...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
   * gic_get_cpu_id - get the CPU interface ID for the specified CPU
   *
   * @cpu: the logical CPU number to get the GIC ID for.
   *
   * Return the CPU interface ID for the given logical CPU number,
   * or -1 if the CPU number is too large or the interface ID is
   * unknown (more than one bit set).
   */
  int gic_get_cpu_id(unsigned int cpu)
  {
  	unsigned int cpu_bit;
  
  	if (cpu >= NR_GIC_CPU_IF)
  		return -1;
  	cpu_bit = gic_cpu_map[cpu];
  	if (cpu_bit & (cpu_bit - 1))
  		return -1;
  	return __ffs(cpu_bit);
  }
  
  /*
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
   * gic_migrate_target - migrate IRQs to another CPU interface
   *
   * @new_cpu_id: the CPU target ID to migrate IRQs to
   *
   * Migrate all peripheral interrupts with a target matching the current CPU
   * to the interface corresponding to @new_cpu_id.  The CPU interface mapping
   * is also updated.  Targets to other CPU interfaces are unchanged.
   * This must be called with IRQs locally disabled.
   */
  void gic_migrate_target(unsigned int new_cpu_id)
  {
  	unsigned int cur_cpu_id, gic_irqs, gic_nr = 0;
  	void __iomem *dist_base;
  	int i, ror_val, cpu = smp_processor_id();
  	u32 val, cur_target_mask, active_mask;
a27d21e03   Linus Walleij   irqchip/gic: Kcon...
811
  	BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
812
813
814
815
816
817
818
819
820
  
  	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
  	if (!dist_base)
  		return;
  	gic_irqs = gic_data[gic_nr].gic_irqs;
  
  	cur_cpu_id = __ffs(gic_cpu_map[cpu]);
  	cur_target_mask = 0x01010101 << cur_cpu_id;
  	ror_val = (cur_cpu_id - new_cpu_id) & 31;
04c8b0f82   Marc Zyngier   irqchip/gic: Make...
821
  	gic_lock();
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  
  	/* Update the target interface for this logical CPU */
  	gic_cpu_map[cpu] = 1 << new_cpu_id;
  
  	/*
  	 * Find all the peripheral interrupts targetting the current
  	 * CPU interface and migrate them to the new CPU interface.
  	 * We skip DIST_TARGET 0 to 7 as they are read-only.
  	 */
  	for (i = 8; i < DIV_ROUND_UP(gic_irqs, 4); i++) {
  		val = readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
  		active_mask = val & cur_target_mask;
  		if (active_mask) {
  			val &= ~active_mask;
  			val |= ror32(active_mask, ror_val);
  			writel_relaxed(val, dist_base + GIC_DIST_TARGET + i*4);
  		}
  	}
04c8b0f82   Marc Zyngier   irqchip/gic: Make...
840
  	gic_unlock();
1a6b69b65   Nicolas Pitre   ARM: gic: add CPU...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  
  	/*
  	 * Now let's migrate and clear any potential SGIs that might be
  	 * pending for us (cur_cpu_id).  Since GIC_DIST_SGI_PENDING_SET
  	 * is a banked register, we can only forward the SGI using
  	 * GIC_DIST_SOFTINT.  The original SGI source is lost but Linux
  	 * doesn't use that information anyway.
  	 *
  	 * For the same reason we do not adjust SGI source information
  	 * for previously sent SGIs by us to other CPUs either.
  	 */
  	for (i = 0; i < 16; i += 4) {
  		int j;
  		val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i);
  		if (!val)
  			continue;
  		writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i);
  		for (j = i; j < i + 4; j++) {
  			if (val & 0xff)
  				writel_relaxed((1 << (new_cpu_id + 16)) | j,
  						dist_base + GIC_DIST_SOFTINT);
  			val >>= 8;
  		}
  	}
b1cffebf1   Rob Herring   ARM: GIC: remove ...
865
  }
eeb446581   Nicolas Pitre   ARM: GIC: functio...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
  
  /*
   * gic_get_sgir_physaddr - get the physical address for the SGI register
   *
   * REturn the physical address of the SGI register to be used
   * by some early assembly code when the kernel is not yet available.
   */
  static unsigned long gic_dist_physaddr;
  
  unsigned long gic_get_sgir_physaddr(void)
  {
  	if (!gic_dist_physaddr)
  		return 0;
  	return gic_dist_physaddr + GIC_DIST_SOFTINT;
  }
89c59cca4   Baoyou Xie   irqchip/gic: Mark...
881
  static void __init gic_init_physaddr(struct device_node *node)
eeb446581   Nicolas Pitre   ARM: GIC: functio...
882
883
884
885
886
887
888
889
890
891
892
  {
  	struct resource res;
  	if (of_address_to_resource(node, 0, &res) == 0) {
  		gic_dist_physaddr = res.start;
  		pr_info("GIC physical location is %#lx
  ", gic_dist_physaddr);
  	}
  }
  
  #else
  #define gic_init_physaddr(node)  do { } while (0)
b1cffebf1   Rob Herring   ARM: GIC: remove ...
893
  #endif
75294957b   Grant Likely   irq_domain: Remov...
894
895
896
  static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
  				irq_hw_number_t hw)
  {
58b896499   Linus Walleij   irqchip/gic: Assi...
897
  	struct gic_chip_data *gic = d->host_data;
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
898

75294957b   Grant Likely   irq_domain: Remov...
899
900
  	if (hw < 32) {
  		irq_set_percpu_devid(irq);
58b896499   Linus Walleij   irqchip/gic: Assi...
901
  		irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
902
  				    handle_percpu_devid_irq, NULL, NULL);
d17cab445   Rob Herring   irqchip: Kill off...
903
  		irq_set_status_flags(irq, IRQ_NOAUTOEN);
75294957b   Grant Likely   irq_domain: Remov...
904
  	} else {
58b896499   Linus Walleij   irqchip/gic: Assi...
905
  		irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
906
  				    handle_fasteoi_irq, NULL, NULL);
d17cab445   Rob Herring   irqchip: Kill off...
907
  		irq_set_probe(irq);
75294957b   Grant Likely   irq_domain: Remov...
908
  	}
75294957b   Grant Likely   irq_domain: Remov...
909
910
  	return 0;
  }
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
911
912
  static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
  {
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
913
  }
f833f57ff   Marc Zyngier   irqchip: Convert ...
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
  static int gic_irq_domain_translate(struct irq_domain *d,
  				    struct irq_fwspec *fwspec,
  				    unsigned long *hwirq,
  				    unsigned int *type)
  {
  	if (is_of_node(fwspec->fwnode)) {
  		if (fwspec->param_count < 3)
  			return -EINVAL;
  
  		/* Get the interrupt number and add 16 to skip over SGIs */
  		*hwirq = fwspec->param[1] + 16;
  
  		/*
  		 * For SPIs, we need to add 16 more to get the GIC irq
  		 * ID number
  		 */
  		if (!fwspec->param[0])
  			*hwirq += 16;
  
  		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
  		return 0;
  	}
75aba7b0e   Suravee Suthikulpanit   irqdomain: Introd...
936
  	if (is_fwnode_irqchip(fwspec->fwnode)) {
891ae7694   Marc Zyngier   irqchip/gic: Swit...
937
938
939
940
941
942
943
  		if(fwspec->param_count != 2)
  			return -EINVAL;
  
  		*hwirq = fwspec->param[0];
  		*type = fwspec->param[1];
  		return 0;
  	}
f833f57ff   Marc Zyngier   irqchip: Convert ...
944
945
  	return -EINVAL;
  }
93131f7a9   Richard Cochran   irqchip/gic: Conv...
946
  static int gic_starting_cpu(unsigned int cpu)
c0114709e   Catalin Marinas   irqchip: gic: Per...
947
  {
93131f7a9   Richard Cochran   irqchip/gic: Conv...
948
949
  	gic_cpu_init(&gic_data[0]);
  	return 0;
c0114709e   Catalin Marinas   irqchip: gic: Per...
950
  }
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
951
952
953
954
955
956
  static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
  				unsigned int nr_irqs, void *arg)
  {
  	int i, ret;
  	irq_hw_number_t hwirq;
  	unsigned int type = IRQ_TYPE_NONE;
f833f57ff   Marc Zyngier   irqchip: Convert ...
957
  	struct irq_fwspec *fwspec = arg;
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
958

f833f57ff   Marc Zyngier   irqchip: Convert ...
959
  	ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
960
961
962
963
964
965
966
967
968
969
  	if (ret)
  		return ret;
  
  	for (i = 0; i < nr_irqs; i++)
  		gic_irq_domain_map(domain, virq + i, hwirq + i);
  
  	return 0;
  }
  
  static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
f833f57ff   Marc Zyngier   irqchip: Convert ...
970
  	.translate = gic_irq_domain_translate,
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
971
972
973
  	.alloc = gic_irq_domain_alloc,
  	.free = irq_domain_free_irqs_top,
  };
6859358e4   Stephen Boyd   irqchip: gic: Sil...
974
  static const struct irq_domain_ops gic_irq_domain_ops = {
75294957b   Grant Likely   irq_domain: Remov...
975
  	.map = gic_irq_domain_map,
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
976
  	.unmap = gic_irq_domain_unmap,
4294f8baa   Rob Herring   ARM: gic: add irq...
977
  };
faea64558   Jon Hunter   irqchip/gic: Add ...
978
979
  static void gic_init_chip(struct gic_chip_data *gic, struct device *dev,
  			  const char *name, bool use_eoimode1)
b580b899d   Russell King   ARM: GIC: provide...
980
  {
58b896499   Linus Walleij   irqchip/gic: Assi...
981
  	/* Initialize irq_chip */
c2baa2f3f   Jon Hunter   irqchip/gic: Remo...
982
  	gic->chip = gic_chip;
faea64558   Jon Hunter   irqchip/gic: Add ...
983
984
  	gic->chip.name = name;
  	gic->chip.parent_device = dev;
c2baa2f3f   Jon Hunter   irqchip/gic: Remo...
985

faea64558   Jon Hunter   irqchip/gic: Add ...
986
  	if (use_eoimode1) {
c2baa2f3f   Jon Hunter   irqchip/gic: Remo...
987
988
989
  		gic->chip.irq_mask = gic_eoimode1_mask_irq;
  		gic->chip.irq_eoi = gic_eoimode1_eoi_irq;
  		gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
58b896499   Linus Walleij   irqchip/gic: Assi...
990
  	}
7bf29d3af   Jon Hunter   irqchip/gic: Only...
991
  #ifdef CONFIG_SMP
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
992
  	if (gic == &gic_data[0])
7bf29d3af   Jon Hunter   irqchip/gic: Only...
993
994
  		gic->chip.irq_set_affinity = gic_set_affinity;
  #endif
faea64558   Jon Hunter   irqchip/gic: Add ...
995
996
997
998
999
1000
1001
  }
  
  static int gic_init_bases(struct gic_chip_data *gic, int irq_start,
  			  struct fwnode_handle *handle)
  {
  	irq_hw_number_t hwirq_base;
  	int gic_irqs, irq_base, ret;
7bf29d3af   Jon Hunter   irqchip/gic: Only...
1002

f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1003
  	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1004
  		/* Frankein-GIC without banked registers... */
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1005
1006
1007
1008
1009
1010
  		unsigned int cpu;
  
  		gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
  		gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
  		if (WARN_ON(!gic->dist_base.percpu_base ||
  			    !gic->cpu_base.percpu_base)) {
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1011
1012
  			ret = -ENOMEM;
  			goto error;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1013
1014
1015
  		}
  
  		for_each_possible_cpu(cpu) {
29e697b11   Tomasz Figa   irqchip: gic: Fix...
1016
1017
  			u32 mpidr = cpu_logical_map(cpu);
  			u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1018
1019
1020
1021
1022
  			unsigned long offset = gic->percpu_offset * core_id;
  			*per_cpu_ptr(gic->dist_base.percpu_base, cpu) =
  				gic->raw_dist_base + offset;
  			*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) =
  				gic->raw_cpu_base + offset;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1023
1024
1025
  		}
  
  		gic_set_base_accessor(gic, gic_get_percpu_base);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1026
1027
  	} else {
  		/* Normal, sane GIC... */
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1028
  		WARN(gic->percpu_offset,
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1029
  		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1030
1031
1032
  		     gic->percpu_offset);
  		gic->dist_base.common_base = gic->raw_dist_base;
  		gic->cpu_base.common_base = gic->raw_cpu_base;
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1033
1034
  		gic_set_base_accessor(gic, gic_get_common_base);
  	}
bef8f9ee3   Russell King   ARM: GIC: move gi...
1035

4294f8baa   Rob Herring   ARM: gic: add irq...
1036
  	/*
4294f8baa   Rob Herring   ARM: gic: add irq...
1037
1038
1039
  	 * Find out how many interrupts are supported.
  	 * The GIC only supports up to 1020 interrupt sources.
  	 */
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1040
  	gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
4294f8baa   Rob Herring   ARM: gic: add irq...
1041
1042
1043
1044
  	gic_irqs = (gic_irqs + 1) * 32;
  	if (gic_irqs > 1020)
  		gic_irqs = 1020;
  	gic->gic_irqs = gic_irqs;
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1045
1046
1047
1048
1049
  	if (handle) {		/* DT/ACPI */
  		gic->domain = irq_domain_create_linear(handle, gic_irqs,
  						       &gic_irq_domain_hierarchy_ops,
  						       gic);
  	} else {		/* Legacy support */
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
1050
1051
1052
1053
  		/*
  		 * For primary GICs, skip over SGIs.
  		 * For secondary GICs, skip over PPIs, too.
  		 */
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1054
  		if (gic == &gic_data[0] && (irq_start & 31) > 0) {
9a1091ef0   Yingjoe Chen   irqchip: gic: Sup...
1055
1056
1057
1058
1059
1060
1061
1062
  			hwirq_base = 16;
  			if (irq_start != -1)
  				irq_start = (irq_start & ~31) + 16;
  		} else {
  			hwirq_base = 32;
  		}
  
  		gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
1063

006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
1064
1065
  		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
  					   numa_node_id());
287980e49   Arnd Bergmann   remove lots of IS...
1066
  		if (irq_base < 0) {
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
1067
1068
1069
1070
1071
  			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated
  ",
  			     irq_start);
  			irq_base = irq_start;
  		}
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1072
  		gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base,
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
1073
  					hwirq_base, &gic_irq_domain_ops, gic);
f37a53cc5   Rob Herring   ARM: gic: fix irq...
1074
  	}
006e983bb   Sricharan R   DRIVERS: IRQCHIP:...
1075

dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1076
1077
1078
1079
  	if (WARN_ON(!gic->domain)) {
  		ret = -ENODEV;
  		goto error;
  	}
bef8f9ee3   Russell King   ARM: GIC: move gi...
1080

4294f8baa   Rob Herring   ARM: gic: add irq...
1081
  	gic_dist_init(gic);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  	ret = gic_cpu_init(gic);
  	if (ret)
  		goto error;
  
  	ret = gic_pm_init(gic);
  	if (ret)
  		goto error;
  
  	return 0;
  
  error:
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1093
  	if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1094
1095
1096
  		free_percpu(gic->dist_base.percpu_base);
  		free_percpu(gic->cpu_base.percpu_base);
  	}
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1097
  	return ret;
b580b899d   Russell King   ARM: GIC: provide...
1098
  }
d6ce564ce   Jon Hunter   irqchip/gic: Isol...
1099
1100
1101
1102
  static int __init __gic_init_bases(struct gic_chip_data *gic,
  				   int irq_start,
  				   struct fwnode_handle *handle)
  {
faea64558   Jon Hunter   irqchip/gic: Add ...
1103
1104
  	char *name;
  	int i, ret;
d6ce564ce   Jon Hunter   irqchip/gic: Isol...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  
  	if (WARN_ON(!gic || gic->domain))
  		return -EINVAL;
  
  	if (gic == &gic_data[0]) {
  		/*
  		 * Initialize the CPU interface map to all CPUs.
  		 * It will be refined as each CPU probes its ID.
  		 * This is only necessary for the primary GIC.
  		 */
  		for (i = 0; i < NR_GIC_CPU_IF; i++)
  			gic_cpu_map[i] = 0xff;
  #ifdef CONFIG_SMP
  		set_smp_cross_call(gic_raise_softirq);
d6ce564ce   Jon Hunter   irqchip/gic: Isol...
1119
  #endif
93131f7a9   Richard Cochran   irqchip/gic: Conv...
1120
1121
1122
  		cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
  					  "AP_IRQ_GIC_STARTING",
  					  gic_starting_cpu, NULL);
d6ce564ce   Jon Hunter   irqchip/gic: Isol...
1123
1124
1125
1126
1127
  		set_handle_irq(gic_handle_irq);
  		if (static_key_true(&supports_deactivate))
  			pr_info("GIC: Using split EOI/Deactivate mode
  ");
  	}
faea64558   Jon Hunter   irqchip/gic: Add ...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  	if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) {
  		name = kasprintf(GFP_KERNEL, "GICv2");
  		gic_init_chip(gic, NULL, name, true);
  	} else {
  		name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic-&gic_data[0]));
  		gic_init_chip(gic, NULL, name, false);
  	}
  
  	ret = gic_init_bases(gic, irq_start, handle);
  	if (ret)
  		kfree(name);
  
  	return ret;
d6ce564ce   Jon Hunter   irqchip/gic: Isol...
1141
  }
e81a7cd96   Marc Zyngier   irqchip/gic: Get ...
1142
1143
  void __init gic_init(unsigned int gic_nr, int irq_start,
  		     void __iomem *dist_base, void __iomem *cpu_base)
4a6ac3044   Marc Zyngier   irqchip/GIC: Fix ...
1144
  {
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1145
1146
1147
1148
  	struct gic_chip_data *gic;
  
  	if (WARN_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR))
  		return;
4a6ac3044   Marc Zyngier   irqchip/GIC: Fix ...
1149
1150
1151
1152
1153
  	/*
  	 * Non-DT/ACPI systems won't run a hypervisor, so let's not
  	 * bother with these...
  	 */
  	static_key_slow_dec(&supports_deactivate);
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1154
1155
1156
1157
1158
1159
  
  	gic = &gic_data[gic_nr];
  	gic->raw_dist_base = dist_base;
  	gic->raw_cpu_base = cpu_base;
  
  	__gic_init_bases(gic, irq_start, NULL);
4a6ac3044   Marc Zyngier   irqchip/GIC: Fix ...
1160
  }
d6490461a   Jon Hunter   irqchip/gic: Add ...
1161
1162
1163
1164
1165
1166
1167
1168
1169
  static void gic_teardown(struct gic_chip_data *gic)
  {
  	if (WARN_ON(!gic))
  		return;
  
  	if (gic->raw_dist_base)
  		iounmap(gic->raw_dist_base);
  	if (gic->raw_cpu_base)
  		iounmap(gic->raw_cpu_base);
4a6ac3044   Marc Zyngier   irqchip/GIC: Fix ...
1170
  }
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1171
  #ifdef CONFIG_OF
46f101df7   Sachin Kamat   irqchip: irq-gic:...
1172
  static int gic_cnt __initdata;
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1173

12e14066f   Marc Zyngier   irqchip/GIC: Add ...
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
  static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
  {
  	struct resource cpuif_res;
  
  	of_address_to_resource(node, 1, &cpuif_res);
  
  	if (!is_hyp_mode_available())
  		return false;
  	if (resource_size(&cpuif_res) < SZ_8K)
  		return false;
  	if (resource_size(&cpuif_res) == SZ_128K) {
  		u32 val_low, val_high;
  
  		/*
  		 * Verify that we have the first 4kB of a GIC400
  		 * aliased over the first 64kB by checking the
  		 * GICC_IIDR register on both ends.
  		 */
  		val_low = readl_relaxed(*base + GIC_CPU_IDENT);
  		val_high = readl_relaxed(*base + GIC_CPU_IDENT + 0xf000);
  		if ((val_low & 0xffff0fff) != 0x0202043B ||
  		    val_low != val_high)
  			return false;
  
  		/*
  		 * Move the base up by 60kB, so that we have a 8kB
  		 * contiguous region, which allows us to use GICC_DIR
  		 * at its normal offset. Please pass me that bucket.
  		 */
  		*base += 0xf000;
  		cpuif_res.start += 0xf000;
fd5bed48b   Marc Zyngier   irqchip/gic: Add ...
1205
1206
  		pr_warn("GIC: Adjusting CPU interface base to %pa
  ",
12e14066f   Marc Zyngier   irqchip/GIC: Add ...
1207
1208
1209
1210
1211
  			&cpuif_res.start);
  	}
  
  	return true;
  }
9c8edddfc   Jon Hunter   irqchip/gic: Add ...
1212
  static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node)
d6490461a   Jon Hunter   irqchip/gic: Add ...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  {
  	if (!gic || !node)
  		return -EINVAL;
  
  	gic->raw_dist_base = of_iomap(node, 0);
  	if (WARN(!gic->raw_dist_base, "unable to map gic dist registers
  "))
  		goto error;
  
  	gic->raw_cpu_base = of_iomap(node, 1);
  	if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers
  "))
  		goto error;
  
  	if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
  		gic->percpu_offset = 0;
  
  	return 0;
  
  error:
  	gic_teardown(gic);
  
  	return -ENOMEM;
  }
9c8edddfc   Jon Hunter   irqchip/gic: Add ...
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq)
  {
  	int ret;
  
  	if (!dev || !dev->of_node || !gic || !irq)
  		return -EINVAL;
  
  	*gic = devm_kzalloc(dev, sizeof(**gic), GFP_KERNEL);
  	if (!*gic)
  		return -ENOMEM;
  
  	gic_init_chip(*gic, dev, dev->of_node->name, false);
  
  	ret = gic_of_setup(*gic, dev->of_node);
  	if (ret)
  		return ret;
  
  	ret = gic_init_bases(*gic, -1, &dev->of_node->fwnode);
  	if (ret) {
  		gic_teardown(*gic);
  		return ret;
  	}
  
  	irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, *gic);
  
  	return 0;
  }
502d6df11   Julien Grall   irqchip/gic-v2: P...
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
  static void __init gic_of_setup_kvm_info(struct device_node *node)
  {
  	int ret;
  	struct resource *vctrl_res = &gic_v2_kvm_info.vctrl;
  	struct resource *vcpu_res = &gic_v2_kvm_info.vcpu;
  
  	gic_v2_kvm_info.type = GIC_V2;
  
  	gic_v2_kvm_info.maint_irq = irq_of_parse_and_map(node, 0);
  	if (!gic_v2_kvm_info.maint_irq)
  		return;
  
  	ret = of_address_to_resource(node, 2, vctrl_res);
  	if (ret)
  		return;
  
  	ret = of_address_to_resource(node, 3, vcpu_res);
  	if (ret)
  		return;
  
  	gic_set_kvm_info(&gic_v2_kvm_info);
  }
8673c1d7e   Linus Walleij   irqchip/gic: Supp...
1286
  int __init
6859358e4   Stephen Boyd   irqchip: gic: Sil...
1287
  gic_of_init(struct device_node *node, struct device_node *parent)
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1288
  {
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1289
  	struct gic_chip_data *gic;
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1290
  	int irq, ret;
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1291
1292
1293
  
  	if (WARN_ON(!node))
  		return -ENODEV;
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1294
1295
1296
1297
  	if (WARN_ON(gic_cnt >= CONFIG_ARM_GIC_MAX_NR))
  		return -EINVAL;
  
  	gic = &gic_data[gic_cnt];
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1298

d6490461a   Jon Hunter   irqchip/gic: Add ...
1299
1300
1301
  	ret = gic_of_setup(gic, node);
  	if (ret)
  		return ret;
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1302

0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
1303
1304
1305
1306
  	/*
  	 * Disable split EOI/Deactivate if either HYP is not available
  	 * or the CPU interface is too small.
  	 */
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1307
  	if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
1308
  		static_key_slow_dec(&supports_deactivate);
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1309
  	ret = __gic_init_bases(gic, -1, &node->fwnode);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1310
  	if (ret) {
d6490461a   Jon Hunter   irqchip/gic: Add ...
1311
  		gic_teardown(gic);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1312
1313
  		return ret;
  	}
db0d4db22   Marc Zyngier   ARM: gic: allow G...
1314

502d6df11   Julien Grall   irqchip/gic-v2: P...
1315
  	if (!gic_cnt) {
eeb446581   Nicolas Pitre   ARM: GIC: functio...
1316
  		gic_init_physaddr(node);
502d6df11   Julien Grall   irqchip/gic-v2: P...
1317
1318
  		gic_of_setup_kvm_info(node);
  	}
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1319
1320
1321
1322
1323
  
  	if (parent) {
  		irq = irq_of_parse_and_map(node, 0);
  		gic_cascade_irq(gic_cnt, irq);
  	}
853a33ce6   Suravee Suthikulpanit   irqchip: gic-v2m:...
1324
1325
  
  	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
0644b3dac   Suravee Suthikulpanit   irqchip/gic-v2m: ...
1326
  		gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);
853a33ce6   Suravee Suthikulpanit   irqchip: gic-v2m:...
1327

b3f7ed032   Rob Herring   ARM: gic: add OF ...
1328
1329
1330
  	gic_cnt++;
  	return 0;
  }
144cb0886   Suravee Suthikulpanit   irqchip: gic: Add...
1331
  IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
fa6e2eec1   Linus Walleij   ARM: realview: ba...
1332
1333
  IRQCHIP_DECLARE(arm11mp_gic, "arm,arm11mp-gic", gic_of_init);
  IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,arm1176jzf-devchip-gic", gic_of_init);
81243e444   Rob Herring   irqchip: Move ARM...
1334
1335
  IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
  IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
a97e8027b   Matthias Brugger   irqchip: gic: Add...
1336
  IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
81243e444   Rob Herring   irqchip: Move ARM...
1337
1338
  IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
  IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
8709b9eb3   Geert Uytterhoeven   irqchip/gic: Add ...
1339
  IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init);
9c8edddfc   Jon Hunter   irqchip/gic: Add ...
1340
1341
1342
1343
1344
  #else
  int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq)
  {
  	return -ENOTSUPP;
  }
b3f7ed032   Rob Herring   ARM: gic: add OF ...
1345
  #endif
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1346
1347
  
  #ifdef CONFIG_ACPI
bafa9193d   Julien Grall   irqchip/gic-v2: G...
1348
1349
1350
  static struct
  {
  	phys_addr_t cpu_phys_base;
502d6df11   Julien Grall   irqchip/gic-v2: P...
1351
1352
1353
1354
  	u32 maint_irq;
  	int maint_irq_mode;
  	phys_addr_t vctrl_base;
  	phys_addr_t vcpu_base;
bafa9193d   Julien Grall   irqchip/gic-v2: G...
1355
  } acpi_data __initdata;
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
  
  static int __init
  gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
  			const unsigned long end)
  {
  	struct acpi_madt_generic_interrupt *processor;
  	phys_addr_t gic_cpu_base;
  	static int cpu_base_assigned;
  
  	processor = (struct acpi_madt_generic_interrupt *)header;
99e3e3ae3   Al Stone   ACPI / ARM64 : us...
1366
  	if (BAD_MADT_GICC_ENTRY(processor, end))
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1367
1368
1369
1370
1371
1372
1373
  		return -EINVAL;
  
  	/*
  	 * There is no support for non-banked GICv1/2 register in ACPI spec.
  	 * All CPU interface addresses have to be the same.
  	 */
  	gic_cpu_base = processor->base_address;
bafa9193d   Julien Grall   irqchip/gic-v2: G...
1374
  	if (cpu_base_assigned && gic_cpu_base != acpi_data.cpu_phys_base)
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1375
  		return -EINVAL;
bafa9193d   Julien Grall   irqchip/gic-v2: G...
1376
  	acpi_data.cpu_phys_base = gic_cpu_base;
502d6df11   Julien Grall   irqchip/gic-v2: P...
1377
1378
1379
1380
1381
  	acpi_data.maint_irq = processor->vgic_interrupt;
  	acpi_data.maint_irq_mode = (processor->flags & ACPI_MADT_VGIC_IRQ_MODE) ?
  				    ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
  	acpi_data.vctrl_base = processor->gich_base_address;
  	acpi_data.vcpu_base = processor->gicv_base_address;
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1382
1383
1384
  	cpu_base_assigned = 1;
  	return 0;
  }
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1385
1386
1387
  /* The things you have to do to just *count* something... */
  static int __init acpi_dummy_func(struct acpi_subtable_header *header,
  				  const unsigned long end)
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1388
  {
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1389
1390
  	return 0;
  }
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1391

f26527b14   Marc Zyngier   irqchip / GIC: Co...
1392
1393
1394
1395
1396
  static bool __init acpi_gic_redist_is_present(void)
  {
  	return acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
  				     acpi_dummy_func, 0) > 0;
  }
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1397

f26527b14   Marc Zyngier   irqchip / GIC: Co...
1398
1399
1400
1401
1402
  static bool __init gic_validate_dist(struct acpi_subtable_header *header,
  				     struct acpi_probe_entry *ape)
  {
  	struct acpi_madt_generic_distributor *dist;
  	dist = (struct acpi_madt_generic_distributor *)header;
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1403

f26527b14   Marc Zyngier   irqchip / GIC: Co...
1404
1405
1406
  	return (dist->version == ape->driver_data &&
  		(dist->version != ACPI_MADT_GIC_VERSION_NONE ||
  		 !acpi_gic_redist_is_present()));
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1407
  }
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1408
1409
  #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
  #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
502d6df11   Julien Grall   irqchip/gic-v2: P...
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
  #define ACPI_GICV2_VCTRL_MEM_SIZE	(SZ_4K)
  #define ACPI_GICV2_VCPU_MEM_SIZE	(SZ_8K)
  
  static void __init gic_acpi_setup_kvm_info(void)
  {
  	int irq;
  	struct resource *vctrl_res = &gic_v2_kvm_info.vctrl;
  	struct resource *vcpu_res = &gic_v2_kvm_info.vcpu;
  
  	gic_v2_kvm_info.type = GIC_V2;
  
  	if (!acpi_data.vctrl_base)
  		return;
  
  	vctrl_res->flags = IORESOURCE_MEM;
  	vctrl_res->start = acpi_data.vctrl_base;
  	vctrl_res->end = vctrl_res->start + ACPI_GICV2_VCTRL_MEM_SIZE - 1;
  
  	if (!acpi_data.vcpu_base)
  		return;
  
  	vcpu_res->flags = IORESOURCE_MEM;
  	vcpu_res->start = acpi_data.vcpu_base;
  	vcpu_res->end = vcpu_res->start + ACPI_GICV2_VCPU_MEM_SIZE - 1;
  
  	irq = acpi_register_gsi(NULL, acpi_data.maint_irq,
  				acpi_data.maint_irq_mode,
  				ACPI_ACTIVE_HIGH);
  	if (irq <= 0)
  		return;
  
  	gic_v2_kvm_info.maint_irq = irq;
  
  	gic_set_kvm_info(&gic_v2_kvm_info);
  }
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1445
1446
1447
  
  static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
  				   const unsigned long end)
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1448
  {
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1449
  	struct acpi_madt_generic_distributor *dist;
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1450
  	struct fwnode_handle *domain_handle;
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1451
  	struct gic_chip_data *gic = &gic_data[0];
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1452
  	int count, ret;
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1453
1454
  
  	/* Collect CPU base addresses */
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1455
1456
  	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
  				      gic_acpi_parse_madt_cpu, 0);
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1457
1458
1459
1460
1461
  	if (count <= 0) {
  		pr_err("No valid GICC entries exist
  ");
  		return -EINVAL;
  	}
7beaa24ba   Linus Torvalds   Merge tag 'for-li...
1462
  	gic->raw_cpu_base = ioremap(acpi_data.cpu_phys_base, ACPI_GIC_CPU_IF_MEM_SIZE);
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1463
  	if (!gic->raw_cpu_base) {
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1464
1465
1466
1467
  		pr_err("Unable to map GICC registers
  ");
  		return -ENOMEM;
  	}
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1468
  	dist = (struct acpi_madt_generic_distributor *)header;
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1469
1470
1471
  	gic->raw_dist_base = ioremap(dist->base_address,
  				     ACPI_GICV2_DIST_MEM_SIZE);
  	if (!gic->raw_dist_base) {
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1472
1473
  		pr_err("Unable to map GICD registers
  ");
d6490461a   Jon Hunter   irqchip/gic: Add ...
1474
  		gic_teardown(gic);
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1475
1476
1477
1478
  		return -ENOMEM;
  	}
  
  	/*
0b996fd35   Marc Zyngier   irqchip/GIC: Conv...
1479
1480
1481
1482
1483
1484
1485
1486
  	 * Disable split EOI/Deactivate if HYP is not available. ACPI
  	 * guarantees that we'll always have a GICv2, so the CPU
  	 * interface will always be the right size.
  	 */
  	if (!is_hyp_mode_available())
  		static_key_slow_dec(&supports_deactivate);
  
  	/*
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1487
  	 * Initialize GIC instance zero (no multi-GIC support).
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1488
  	 */
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1489
  	domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base);
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1490
1491
1492
  	if (!domain_handle) {
  		pr_err("Unable to allocate domain handle
  ");
d6490461a   Jon Hunter   irqchip/gic: Add ...
1493
  		gic_teardown(gic);
891ae7694   Marc Zyngier   irqchip/gic: Swit...
1494
1495
  		return -ENOMEM;
  	}
f673b9b5c   Jon Hunter   irqchip/gic: Stor...
1496
  	ret = __gic_init_bases(gic, -1, domain_handle);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1497
1498
1499
1500
  	if (ret) {
  		pr_err("Failed to initialise GIC
  ");
  		irq_domain_free_fwnode(domain_handle);
d6490461a   Jon Hunter   irqchip/gic: Add ...
1501
  		gic_teardown(gic);
dc9722cc5   Jon Hunter   irqchip/gic: Retu...
1502
1503
  		return ret;
  	}
d8f4f161e   Lorenzo Pieralisi   ACPI: move arm64 ...
1504

891ae7694   Marc Zyngier   irqchip/gic: Swit...
1505
  	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
0644b3dac   Suravee Suthikulpanit   irqchip/gic-v2m: ...
1506
1507
1508
  
  	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
  		gicv2m_init(NULL, gic_data[0].domain);
502d6df11   Julien Grall   irqchip/gic-v2: P...
1509
  	gic_acpi_setup_kvm_info();
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1510
1511
  	return 0;
  }
f26527b14   Marc Zyngier   irqchip / GIC: Co...
1512
1513
1514
1515
1516
1517
  IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
  		     gic_validate_dist, ACPI_MADT_GIC_VERSION_V2,
  		     gic_v2_acpi_init);
  IRQCHIP_ACPI_DECLARE(gic_v2_maybe, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
  		     gic_validate_dist, ACPI_MADT_GIC_VERSION_NONE,
  		     gic_v2_acpi_init);
d60fc3892   Tomasz Nowicki   irqchip: Add GICv...
1518
  #endif