Blame view

drivers/irqchip/irq-gic-v3.c 35.4 KB
021f65379   Marc Zyngier   irqchip: gic-v3: ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
   * Author: Marc Zyngier <marc.zyngier@arm.com>
   *
   * 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.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
68628bb87   Julien Grall   irqchip/gic-v3: P...
17
  #define pr_fmt(fmt)	"GICv3: " fmt
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
18
  #include <linux/acpi.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
19
  #include <linux/cpu.h>
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
20
  #include <linux/cpu_pm.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
21
22
  #include <linux/delay.h>
  #include <linux/interrupt.h>
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
23
  #include <linux/irqdomain.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
24
25
26
27
28
  #include <linux/of.h>
  #include <linux/of_address.h>
  #include <linux/of_irq.h>
  #include <linux/percpu.h>
  #include <linux/slab.h>
41a83e06e   Joel Porquet   irqchip: Prepare ...
29
  #include <linux/irqchip.h>
1839e5769   Julien Grall   irqchip/gic-v3: P...
30
  #include <linux/irqchip/arm-gic-common.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
31
  #include <linux/irqchip/arm-gic-v3.h>
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
32
  #include <linux/irqchip/irq-partition-percpu.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
33
34
35
36
  
  #include <asm/cputype.h>
  #include <asm/exception.h>
  #include <asm/smp_plat.h>
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
37
  #include <asm/virt.h>
021f65379   Marc Zyngier   irqchip: gic-v3: ...
38
39
  
  #include "irq-gic-common.h"
021f65379   Marc Zyngier   irqchip: gic-v3: ...
40

f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
41
42
43
  struct redist_region {
  	void __iomem		*redist_base;
  	phys_addr_t		phys_base;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
44
  	bool			single_redist;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
45
  };
021f65379   Marc Zyngier   irqchip: gic-v3: ...
46
  struct gic_chip_data {
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
47
  	struct fwnode_handle	*fwnode;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
48
  	void __iomem		*dist_base;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
49
50
  	struct redist_region	*redist_regions;
  	struct rdists		rdists;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
51
52
  	struct irq_domain	*domain;
  	u64			redist_stride;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
53
  	u32			nr_redist_regions;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
54
  	unsigned int		irq_nr;
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
55
  	struct partition_desc	*ppi_descs[16];
021f65379   Marc Zyngier   irqchip: gic-v3: ...
56
57
58
  };
  
  static struct gic_chip_data gic_data __read_mostly;
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
59
  static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
60

1839e5769   Julien Grall   irqchip/gic-v3: P...
61
  static struct gic_kvm_info gic_v3_kvm_info;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
62
63
  #define gic_data_rdist()		(this_cpu_ptr(gic_data.rdists.rdist))
  #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  #define gic_data_rdist_sgi_base()	(gic_data_rdist_rd_base() + SZ_64K)
  
  /* Our default, arbitrary priority value. Linux only uses one anyway. */
  #define DEFAULT_PMR_VALUE	0xf0
  
  static inline unsigned int gic_irq(struct irq_data *d)
  {
  	return d->hwirq;
  }
  
  static inline int gic_irq_in_rdist(struct irq_data *d)
  {
  	return gic_irq(d) < 32;
  }
  
  static inline void __iomem *gic_dist_base(struct irq_data *d)
  {
  	if (gic_irq_in_rdist(d))	/* SGI+PPI -> SGI_base for this CPU */
  		return gic_data_rdist_sgi_base();
  
  	if (d->hwirq <= 1023)		/* SPI -> dist_base */
  		return gic_data.dist_base;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  	return NULL;
  }
  
  static void gic_do_wait_for_rwp(void __iomem *base)
  {
  	u32 count = 1000000;	/* 1s! */
  
  	while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) {
  		count--;
  		if (!count) {
  			pr_err_ratelimited("RWP timeout, gone fishing
  ");
  			return;
  		}
  		cpu_relax();
  		udelay(1);
  	};
  }
  
  /* Wait for completion of a distributor change */
  static void gic_dist_wait_for_rwp(void)
  {
  	gic_do_wait_for_rwp(gic_data.dist_base);
  }
  
  /* Wait for completion of a redistributor change */
  static void gic_redist_wait_for_rwp(void)
  {
  	gic_do_wait_for_rwp(gic_data_rdist_rd_base());
  }
7936e914f   Jean-Philippe Brucker   irqchip/gic-v3: R...
116
  #ifdef CONFIG_ARM64
8ac2a1704   Robert Richter   irqchip/gicv3-its...
117
  static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx);
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
118
119
120
  
  static u64 __maybe_unused gic_read_iar(void)
  {
8ac2a1704   Robert Richter   irqchip/gicv3-its...
121
  	if (static_branch_unlikely(&is_cavium_thunderx))
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
122
123
124
125
  		return gic_read_iar_cavium_thunderx();
  	else
  		return gic_read_iar_common();
  }
7936e914f   Jean-Philippe Brucker   irqchip/gic-v3: R...
126
  #endif
021f65379   Marc Zyngier   irqchip: gic-v3: ...
127

a2c225101   Sudeep Holla   irqchip: gic-v3: ...
128
  static void gic_enable_redist(bool enable)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
129
130
131
132
133
134
  {
  	void __iomem *rbase;
  	u32 count = 1000000;	/* 1s! */
  	u32 val;
  
  	rbase = gic_data_rdist_rd_base();
021f65379   Marc Zyngier   irqchip: gic-v3: ...
135
  	val = readl_relaxed(rbase + GICR_WAKER);
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
136
137
138
139
140
  	if (enable)
  		/* Wake up this CPU redistributor */
  		val &= ~GICR_WAKER_ProcessorSleep;
  	else
  		val |= GICR_WAKER_ProcessorSleep;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
141
  	writel_relaxed(val, rbase + GICR_WAKER);
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
142
143
144
145
146
  	if (!enable) {		/* Check that GICR_WAKER is writeable */
  		val = readl_relaxed(rbase + GICR_WAKER);
  		if (!(val & GICR_WAKER_ProcessorSleep))
  			return;	/* No PM support in this redistributor */
  	}
d102eb5c1   Dan Carpenter   irqchip/gicv3: Ha...
147
  	while (--count) {
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
148
  		val = readl_relaxed(rbase + GICR_WAKER);
cf1d9d11e   Andrew Jones   irqchip/gic-v3: F...
149
  		if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep))
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
150
  			break;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
151
152
153
  		cpu_relax();
  		udelay(1);
  	};
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
154
155
156
157
  	if (!count)
  		pr_err_ratelimited("redistributor failed to %s...
  ",
  				   enable ? "wakeup" : "sleep");
021f65379   Marc Zyngier   irqchip: gic-v3: ...
158
159
160
161
162
  }
  
  /*
   * Routines to disable, enable, EOI and route interrupts
   */
b594c6e20   Marc Zyngier   irqchip: GICv3: A...
163
164
165
166
167
168
169
170
171
172
173
174
  static int gic_peek_irq(struct irq_data *d, u32 offset)
  {
  	u32 mask = 1 << (gic_irq(d) % 32);
  	void __iomem *base;
  
  	if (gic_irq_in_rdist(d))
  		base = gic_data_rdist_sgi_base();
  	else
  		base = gic_data.dist_base;
  
  	return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask);
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  static void gic_poke_irq(struct irq_data *d, u32 offset)
  {
  	u32 mask = 1 << (gic_irq(d) % 32);
  	void (*rwp_wait)(void);
  	void __iomem *base;
  
  	if (gic_irq_in_rdist(d)) {
  		base = gic_data_rdist_sgi_base();
  		rwp_wait = gic_redist_wait_for_rwp;
  	} else {
  		base = gic_data.dist_base;
  		rwp_wait = gic_dist_wait_for_rwp;
  	}
  
  	writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4);
  	rwp_wait();
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
192
193
194
195
  static void gic_mask_irq(struct irq_data *d)
  {
  	gic_poke_irq(d, GICD_ICENABLER);
  }
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
196
197
198
  static void gic_eoimode1_mask_irq(struct irq_data *d)
  {
  	gic_mask_irq(d);
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
199
200
201
202
203
204
205
206
  	/*
  	 * 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).
  	 */
4df7f54d1   Thomas Gleixner   irqchip/gic-v3: U...
207
  	if (irqd_is_forwarded_to_vcpu(d))
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
208
  		gic_poke_irq(d, GICD_ICACTIVER);
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
209
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
210
211
212
213
  static void gic_unmask_irq(struct irq_data *d)
  {
  	gic_poke_irq(d, GICD_ISENABLER);
  }
b594c6e20   Marc Zyngier   irqchip: GICv3: A...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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
  static int gic_irq_set_irqchip_state(struct irq_data *d,
  				     enum irqchip_irq_state which, bool val)
  {
  	u32 reg;
  
  	if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */
  		return -EINVAL;
  
  	switch (which) {
  	case IRQCHIP_STATE_PENDING:
  		reg = val ? GICD_ISPENDR : GICD_ICPENDR;
  		break;
  
  	case IRQCHIP_STATE_ACTIVE:
  		reg = val ? GICD_ISACTIVER : GICD_ICACTIVER;
  		break;
  
  	case IRQCHIP_STATE_MASKED:
  		reg = val ? GICD_ICENABLER : GICD_ISENABLER;
  		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)
  {
  	if (d->hwirq >= gic_data.irq_nr) /* PPI/SPI only */
  		return -EINVAL;
  
  	switch (which) {
  	case IRQCHIP_STATE_PENDING:
  		*val = gic_peek_irq(d, GICD_ISPENDR);
  		break;
  
  	case IRQCHIP_STATE_ACTIVE:
  		*val = gic_peek_irq(d, GICD_ISACTIVER);
  		break;
  
  	case IRQCHIP_STATE_MASKED:
  		*val = !gic_peek_irq(d, GICD_ISENABLER);
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
268
269
270
271
  static void gic_eoi_irq(struct irq_data *d)
  {
  	gic_write_eoir(gic_irq(d));
  }
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
272
273
274
  static void gic_eoimode1_eoi_irq(struct irq_data *d)
  {
  	/*
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
275
276
  	 * No need to deactivate an LPI, or an interrupt that
  	 * is is getting forwarded to a vcpu.
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
277
  	 */
4df7f54d1   Thomas Gleixner   irqchip/gic-v3: U...
278
  	if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d))
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
279
280
281
  		return;
  	gic_write_dir(gic_irq(d));
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
282
283
284
285
286
287
288
289
290
  static int gic_set_type(struct irq_data *d, unsigned int type)
  {
  	unsigned int irq = gic_irq(d);
  	void (*rwp_wait)(void);
  	void __iomem *base;
  
  	/* Interrupt configuration for SGIs can't be changed */
  	if (irq < 16)
  		return -EINVAL;
fb7e7deb7   Liviu Dudau   irqchip: gic: All...
291
292
293
  	/* SPIs have restrictions on the supported types */
  	if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
  			 type != IRQ_TYPE_EDGE_RISING)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
294
295
296
297
298
299
300
301
302
  		return -EINVAL;
  
  	if (gic_irq_in_rdist(d)) {
  		base = gic_data_rdist_sgi_base();
  		rwp_wait = gic_redist_wait_for_rwp;
  	} else {
  		base = gic_data.dist_base;
  		rwp_wait = gic_dist_wait_for_rwp;
  	}
fb7e7deb7   Liviu Dudau   irqchip: gic: All...
303
  	return gic_configure_irq(irq, type, base, rwp_wait);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
304
  }
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
305
306
  static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
  {
4df7f54d1   Thomas Gleixner   irqchip/gic-v3: U...
307
308
309
310
  	if (vcpu)
  		irqd_set_forwarded_to_vcpu(d);
  	else
  		irqd_clr_forwarded_to_vcpu(d);
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
311
312
  	return 0;
  }
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
313
  static u64 gic_mpidr_to_affinity(unsigned long mpidr)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
314
315
  {
  	u64 aff;
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
316
  	aff = ((u64)MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
021f65379   Marc Zyngier   irqchip: gic-v3: ...
317
318
319
320
321
322
323
324
325
  	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
  	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
  	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
  
  	return aff;
  }
  
  static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
  {
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
326
  	u32 irqnr;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
327
328
329
  
  	do {
  		irqnr = gic_read_iar();
da33f31de   Marc Zyngier   irqchip: GICv3: I...
330
  		if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
ebc6de005   Marc Zyngier   irqchip: gic-v3: ...
331
  			int err;
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
332
333
334
  
  			if (static_key_true(&supports_deactivate))
  				gic_write_eoir(irqnr);
ebc6de005   Marc Zyngier   irqchip: gic-v3: ...
335
336
  			err = handle_domain_irq(gic_data.domain, irqnr, regs);
  			if (err) {
da33f31de   Marc Zyngier   irqchip: GICv3: I...
337
338
  				WARN_ONCE(true, "Unexpected interrupt received!
  ");
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
339
340
341
342
343
344
  				if (static_key_true(&supports_deactivate)) {
  					if (irqnr < 8192)
  						gic_write_dir(irqnr);
  				} else {
  					gic_write_eoir(irqnr);
  				}
021f65379   Marc Zyngier   irqchip: gic-v3: ...
345
  			}
ebc6de005   Marc Zyngier   irqchip: gic-v3: ...
346
  			continue;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
347
348
349
  		}
  		if (irqnr < 16) {
  			gic_write_eoir(irqnr);
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
350
351
  			if (static_key_true(&supports_deactivate))
  				gic_write_dir(irqnr);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
352
  #ifdef CONFIG_SMP
f86c4fbd9   Will Deacon   irqchip/gic: Ensu...
353
354
355
356
357
358
359
  			/*
  			 * Unlike GICv2, we don't need an smp_rmb() here.
  			 * The control dependency from gic_read_iar to
  			 * the ISB in gic_write_eoir is enough to ensure
  			 * that any shared data read by handle_IPI will
  			 * be read after the ACK.
  			 */
021f65379   Marc Zyngier   irqchip: gic-v3: ...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  			handle_IPI(irqnr, regs);
  #else
  			WARN_ONCE(true, "Unexpected SGI received!
  ");
  #endif
  			continue;
  		}
  	} while (irqnr != ICC_IAR1_EL1_SPURIOUS);
  }
  
  static void __init gic_dist_init(void)
  {
  	unsigned int i;
  	u64 affinity;
  	void __iomem *base = gic_data.dist_base;
  
  	/* Disable the distributor */
  	writel_relaxed(0, base + GICD_CTLR);
  	gic_dist_wait_for_rwp();
7c9b97306   Marc Zyngier   irqchip/gic-v3: C...
379
380
381
382
383
384
385
386
  	/*
  	 * Configure SPIs as non-secure Group-1. This will only matter
  	 * if the GIC only has a single security state. This will not
  	 * do the right thing if the kernel is running in secure mode,
  	 * but that's not the intended use case anyway.
  	 */
  	for (i = 32; i < gic_data.irq_nr; i += 32)
  		writel_relaxed(~0, base + GICD_IGROUPR + i / 8);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
387
388
389
390
391
392
393
394
395
396
397
398
  	gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
  
  	/* Enable distributor with ARE, Group1 */
  	writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
  		       base + GICD_CTLR);
  
  	/*
  	 * Set all global interrupts to the boot CPU only. ARE must be
  	 * enabled.
  	 */
  	affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
  	for (i = 32; i < gic_data.irq_nr; i++)
72c971262   Jean-Philippe Brucker   irqchip/gic-v3: S...
399
  		gic_write_irouter(affinity, base + GICD_IROUTER + i * 8);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
400
401
402
403
  }
  
  static int gic_populate_rdist(void)
  {
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
404
  	unsigned long mpidr = cpu_logical_map(smp_processor_id());
021f65379   Marc Zyngier   irqchip: gic-v3: ...
405
406
407
408
409
410
411
412
413
414
415
416
  	u64 typer;
  	u32 aff;
  	int i;
  
  	/*
  	 * Convert affinity to a 32bit value that can be matched to
  	 * GICR_TYPER bits [63:32].
  	 */
  	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
  	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
  	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
  	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
417
418
  	for (i = 0; i < gic_data.nr_redist_regions; i++) {
  		void __iomem *ptr = gic_data.redist_regions[i].redist_base;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
419
420
421
422
423
424
425
426
427
428
429
  		u32 reg;
  
  		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
  		if (reg != GIC_PIDR2_ARCH_GICv3 &&
  		    reg != GIC_PIDR2_ARCH_GICv4) { /* We're in trouble... */
  			pr_warn("No redistributor present @%p
  ", ptr);
  			break;
  		}
  
  		do {
72c971262   Jean-Philippe Brucker   irqchip/gic-v3: S...
430
  			typer = gic_read_typer(ptr + GICR_TYPER);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
431
  			if ((typer >> 32) == aff) {
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
432
  				u64 offset = ptr - gic_data.redist_regions[i].redist_base;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
433
  				gic_data_rdist_rd_base() = ptr;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
434
  				gic_data_rdist()->phys_base = gic_data.redist_regions[i].phys_base + offset;
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
435
436
437
438
  				pr_info("CPU%d: found redistributor %lx region %d:%pa
  ",
  					smp_processor_id(), mpidr, i,
  					&gic_data_rdist()->phys_base);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
439
440
  				return 0;
  			}
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
441
442
  			if (gic_data.redist_regions[i].single_redist)
  				break;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
443
444
445
446
447
448
449
450
451
452
453
  			if (gic_data.redist_stride) {
  				ptr += gic_data.redist_stride;
  			} else {
  				ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
  				if (typer & GICR_TYPER_VLPIS)
  					ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
  			}
  		} while (!(typer & GICR_TYPER_LAST));
  	}
  
  	/* We couldn't even deal with ourselves... */
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
454
455
456
  	WARN(true, "CPU%d: mpidr %lx has no re-distributor!
  ",
  	     smp_processor_id(), mpidr);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
457
458
  	return -ENODEV;
  }
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
459
460
  static void gic_cpu_sys_reg_init(void)
  {
7cabd0086   Marc Zyngier   irqchip/gic-v3: M...
461
462
463
464
465
466
467
468
469
470
  	/*
  	 * Need to check that the SRE bit has actually been set. If
  	 * not, it means that SRE is disabled at EL2. We're going to
  	 * die painfully, and there is nothing we can do about it.
  	 *
  	 * Kindly inform the luser.
  	 */
  	if (!gic_enable_sre())
  		pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead
  ");
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
471
472
473
  
  	/* Set priority mask register */
  	gic_write_pmr(DEFAULT_PMR_VALUE);
91ef84428   Daniel Thompson   irqchip/gic-v3: R...
474
475
476
477
478
479
480
  	/*
  	 * Some firmwares hand over to the kernel with the BPR changed from
  	 * its reset value (and with a value large enough to prevent
  	 * any pre-emptive interrupts from working at all). Writing a zero
  	 * to BPR restores is reset value.
  	 */
  	gic_write_bpr1(0);
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
481
482
483
484
485
486
487
  	if (static_key_true(&supports_deactivate)) {
  		/* EOI drops priority only (mode 1) */
  		gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);
  	} else {
  		/* EOI deactivates interrupt too (mode 0) */
  		gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
  	}
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
488
489
490
491
  
  	/* ... and let's hit the road... */
  	gic_write_grpen1(1);
  }
da33f31de   Marc Zyngier   irqchip: GICv3: I...
492
493
494
495
  static int gic_dist_supports_lpis(void)
  {
  	return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS);
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
496
497
498
499
500
501
502
  static void gic_cpu_init(void)
  {
  	void __iomem *rbase;
  
  	/* Register ourselves with the rest of the world */
  	if (gic_populate_rdist())
  		return;
a2c225101   Sudeep Holla   irqchip: gic-v3: ...
503
  	gic_enable_redist(true);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
504
505
  
  	rbase = gic_data_rdist_sgi_base();
7c9b97306   Marc Zyngier   irqchip/gic-v3: C...
506
507
  	/* Configure SGIs/PPIs as non-secure Group-1 */
  	writel_relaxed(~0, rbase + GICR_IGROUPR0);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
508
  	gic_cpu_config(rbase, gic_redist_wait_for_rwp);
da33f31de   Marc Zyngier   irqchip: GICv3: I...
509
510
511
  	/* Give LPIs a spin */
  	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
  		its_cpu_init();
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
512
513
  	/* initialise system registers */
  	gic_cpu_sys_reg_init();
021f65379   Marc Zyngier   irqchip: gic-v3: ...
514
515
516
  }
  
  #ifdef CONFIG_SMP
6670a6d86   Richard Cochran   irqchip/gicv3: Co...
517
518
  
  static int gic_starting_cpu(unsigned int cpu)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
519
  {
6670a6d86   Richard Cochran   irqchip/gicv3: Co...
520
521
  	gic_cpu_init();
  	return 0;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
522
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
523
  static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
524
  				   unsigned long cluster_id)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
525
  {
727653d6c   James Morse   irqchip/gicv3: Si...
526
  	int next_cpu, cpu = *base_cpu;
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
527
  	unsigned long mpidr = cpu_logical_map(cpu);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
528
529
530
531
532
533
534
535
536
537
538
  	u16 tlist = 0;
  
  	while (cpu < nr_cpu_ids) {
  		/*
  		 * If we ever get a cluster of more than 16 CPUs, just
  		 * scream and skip that CPU.
  		 */
  		if (WARN_ON((mpidr & 0xff) >= 16))
  			goto out;
  
  		tlist |= 1 << (mpidr & 0xf);
727653d6c   James Morse   irqchip/gicv3: Si...
539
540
  		next_cpu = cpumask_next(cpu, mask);
  		if (next_cpu >= nr_cpu_ids)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
541
  			goto out;
727653d6c   James Morse   irqchip/gicv3: Si...
542
  		cpu = next_cpu;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
543
544
545
546
547
548
549
550
551
552
553
554
  
  		mpidr = cpu_logical_map(cpu);
  
  		if (cluster_id != (mpidr & ~0xffUL)) {
  			cpu--;
  			goto out;
  		}
  	}
  out:
  	*base_cpu = cpu;
  	return tlist;
  }
7e5802781   Andre Przywara   arm64: GICv3: int...
555
556
557
  #define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
  	(MPIDR_AFFINITY_LEVEL(cluster_id, level) \
  		<< ICC_SGI1R_AFFINITY_## level ##_SHIFT)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
558
559
560
  static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
  {
  	u64 val;
7e5802781   Andre Przywara   arm64: GICv3: int...
561
562
563
564
565
  	val = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
  	       MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
  	       irq << ICC_SGI1R_SGI_ID_SHIFT		|
  	       MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
  	       tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  
  	pr_debug("CPU%d: ICC_SGI1R_EL1 %llx
  ", smp_processor_id(), val);
  	gic_write_sgi1r(val);
  }
  
  static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
  {
  	int cpu;
  
  	if (WARN_ON(irq >= 16))
  		return;
  
  	/*
  	 * Ensure that stores to Normal memory are visible to the
  	 * other CPUs before issuing the IPI.
  	 */
  	smp_wmb();
f9b531fe1   Rusty Russell   drivers: fix up o...
584
  	for_each_cpu(cpu, mask) {
f6c86a41e   Jean-Philippe Brucker   irqchip/gic-v3: C...
585
  		unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
586
587
588
589
590
591
592
593
594
595
596
597
598
  		u16 tlist;
  
  		tlist = gic_compute_target_list(&cpu, mask, cluster_id);
  		gic_send_sgi(cluster_id, tlist, irq);
  	}
  
  	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
  	isb();
  }
  
  static void gic_smp_init(void)
  {
  	set_smp_cross_call(gic_raise_softirq);
6670a6d86   Richard Cochran   irqchip/gicv3: Co...
599
600
601
  	cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GICV3_STARTING,
  				  "AP_IRQ_GICV3_STARTING", gic_starting_cpu,
  				  NULL);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
  }
  
  static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
  			    bool force)
  {
  	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
  	void __iomem *reg;
  	int enabled;
  	u64 val;
  
  	if (gic_irq_in_rdist(d))
  		return -EINVAL;
  
  	/* If interrupt was enabled, disable it first */
  	enabled = gic_peek_irq(d, GICD_ISENABLER);
  	if (enabled)
  		gic_mask_irq(d);
  
  	reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8);
  	val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
72c971262   Jean-Philippe Brucker   irqchip/gic-v3: S...
622
  	gic_write_irouter(val, reg);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
623
624
625
626
627
628
629
630
631
  
  	/*
  	 * If the interrupt was enabled, enabled it again. Otherwise,
  	 * just wait for the distributor to have digested our changes.
  	 */
  	if (enabled)
  		gic_unmask_irq(d);
  	else
  		gic_dist_wait_for_rwp();
0fc6fa292   Antoine Tenart   irqchip/gic-v3: A...
632
  	return IRQ_SET_MASK_OK_DONE;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
633
634
635
636
637
  }
  #else
  #define gic_set_affinity	NULL
  #define gic_smp_init()		do { } while(0)
  #endif
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
638
  #ifdef CONFIG_CPU_PM
ccd9432a5   Sudeep Holla   irqchip/gicv3: Re...
639
640
641
642
643
  /* Check whether it's single security state view */
  static bool gic_dist_security_disabled(void)
  {
  	return readl_relaxed(gic_data.dist_base + GICD_CTLR) & GICD_CTLR_DS;
  }
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
644
645
646
647
  static int gic_cpu_pm_notifier(struct notifier_block *self,
  			       unsigned long cmd, void *v)
  {
  	if (cmd == CPU_PM_EXIT) {
ccd9432a5   Sudeep Holla   irqchip/gicv3: Re...
648
649
  		if (gic_dist_security_disabled())
  			gic_enable_redist(true);
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
650
  		gic_cpu_sys_reg_init();
ccd9432a5   Sudeep Holla   irqchip/gicv3: Re...
651
  	} else if (cmd == CPU_PM_ENTER && gic_dist_security_disabled()) {
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  		gic_write_grpen1(0);
  		gic_enable_redist(false);
  	}
  	return NOTIFY_OK;
  }
  
  static struct notifier_block gic_cpu_pm_notifier_block = {
  	.notifier_call = gic_cpu_pm_notifier,
  };
  
  static void gic_cpu_pm_init(void)
  {
  	cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
  }
  
  #else
  static inline void gic_cpu_pm_init(void) { }
  #endif /* CONFIG_CPU_PM */
021f65379   Marc Zyngier   irqchip: gic-v3: ...
670
671
672
673
674
675
676
  static struct irq_chip gic_chip = {
  	.name			= "GICv3",
  	.irq_mask		= gic_mask_irq,
  	.irq_unmask		= gic_unmask_irq,
  	.irq_eoi		= gic_eoi_irq,
  	.irq_set_type		= gic_set_type,
  	.irq_set_affinity	= gic_set_affinity,
b594c6e20   Marc Zyngier   irqchip: GICv3: A...
677
678
  	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
  	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
55963c9f2   Sudeep Holla   irqchip: gic: Sim...
679
  	.flags			= IRQCHIP_SET_TYPE_MASKED,
021f65379   Marc Zyngier   irqchip: gic-v3: ...
680
  };
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
681
682
683
684
685
686
687
688
689
  static struct irq_chip gic_eoimode1_chip = {
  	.name			= "GICv3",
  	.irq_mask		= gic_eoimode1_mask_irq,
  	.irq_unmask		= gic_unmask_irq,
  	.irq_eoi		= gic_eoimode1_eoi_irq,
  	.irq_set_type		= gic_set_type,
  	.irq_set_affinity	= gic_set_affinity,
  	.irq_get_irqchip_state	= gic_irq_get_irqchip_state,
  	.irq_set_irqchip_state	= gic_irq_set_irqchip_state,
530bf353e   Marc Zyngier   irqchip/GICv3: Do...
690
  	.irq_set_vcpu_affinity	= gic_irq_set_vcpu_affinity,
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
691
692
  	.flags			= IRQCHIP_SET_TYPE_MASKED,
  };
da33f31de   Marc Zyngier   irqchip: GICv3: I...
693
  #define GIC_ID_NR		(1U << gic_data.rdists.id_bits)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
694
695
696
  static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
  			      irq_hw_number_t hw)
  {
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
697
698
699
700
  	struct irq_chip *chip = &gic_chip;
  
  	if (static_key_true(&supports_deactivate))
  		chip = &gic_eoimode1_chip;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
701
702
703
  	/* SGIs are private to the core kernel */
  	if (hw < 16)
  		return -EPERM;
da33f31de   Marc Zyngier   irqchip: GICv3: I...
704
705
706
707
708
709
  	/* Nothing here */
  	if (hw >= gic_data.irq_nr && hw < 8192)
  		return -EPERM;
  	/* Off limits */
  	if (hw >= GIC_ID_NR)
  		return -EPERM;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
710
711
712
  	/* PPIs */
  	if (hw < 32) {
  		irq_set_percpu_devid(irq);
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
713
  		irq_domain_set_info(d, irq, hw, chip, d->host_data,
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
714
  				    handle_percpu_devid_irq, NULL, NULL);
d17cab445   Rob Herring   irqchip: Kill off...
715
  		irq_set_status_flags(irq, IRQ_NOAUTOEN);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
716
717
718
  	}
  	/* SPIs */
  	if (hw >= 32 && hw < gic_data.irq_nr) {
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
719
  		irq_domain_set_info(d, irq, hw, chip, d->host_data,
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
720
  				    handle_fasteoi_irq, NULL, NULL);
d17cab445   Rob Herring   irqchip: Kill off...
721
  		irq_set_probe(irq);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
722
  	}
da33f31de   Marc Zyngier   irqchip: GICv3: I...
723
724
725
726
  	/* LPIs */
  	if (hw >= 8192 && hw < GIC_ID_NR) {
  		if (!gic_dist_supports_lpis())
  			return -EPERM;
0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
727
  		irq_domain_set_info(d, irq, hw, chip, d->host_data,
da33f31de   Marc Zyngier   irqchip: GICv3: I...
728
  				    handle_fasteoi_irq, NULL, NULL);
da33f31de   Marc Zyngier   irqchip: GICv3: I...
729
  	}
021f65379   Marc Zyngier   irqchip: gic-v3: ...
730
731
  	return 0;
  }
f833f57ff   Marc Zyngier   irqchip: Convert ...
732
733
734
735
  static int gic_irq_domain_translate(struct irq_domain *d,
  				    struct irq_fwspec *fwspec,
  				    unsigned long *hwirq,
  				    unsigned int *type)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
736
  {
f833f57ff   Marc Zyngier   irqchip: Convert ...
737
738
739
  	if (is_of_node(fwspec->fwnode)) {
  		if (fwspec->param_count < 3)
  			return -EINVAL;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
740

db8c70ec1   Marc Zyngier   irqchip/gic-v3: F...
741
742
743
744
745
746
747
748
749
750
751
752
753
  		switch (fwspec->param[0]) {
  		case 0:			/* SPI */
  			*hwirq = fwspec->param[1] + 32;
  			break;
  		case 1:			/* PPI */
  			*hwirq = fwspec->param[1] + 16;
  			break;
  		case GIC_IRQ_TYPE_LPI:	/* LPI */
  			*hwirq = fwspec->param[1];
  			break;
  		default:
  			return -EINVAL;
  		}
f833f57ff   Marc Zyngier   irqchip: Convert ...
754
755
756
  
  		*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
  		return 0;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
757
  	}
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
758
759
760
761
762
763
764
765
  	if (is_fwnode_irqchip(fwspec->fwnode)) {
  		if(fwspec->param_count != 2)
  			return -EINVAL;
  
  		*hwirq = fwspec->param[0];
  		*type = fwspec->param[1];
  		return 0;
  	}
f833f57ff   Marc Zyngier   irqchip: Convert ...
766
  	return -EINVAL;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
767
  }
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
768
769
770
771
772
773
  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 ...
774
  	struct irq_fwspec *fwspec = arg;
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
775

f833f57ff   Marc Zyngier   irqchip: Convert ...
776
  	ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  	if (ret)
  		return ret;
  
  	for (i = 0; i < nr_irqs; i++)
  		gic_irq_domain_map(domain, virq + i, hwirq + i);
  
  	return 0;
  }
  
  static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
  				unsigned int nr_irqs)
  {
  	int i;
  
  	for (i = 0; i < nr_irqs; i++) {
  		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
  		irq_set_handler(virq + i, NULL);
  		irq_domain_reset_irq_data(d);
  	}
  }
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  static int gic_irq_domain_select(struct irq_domain *d,
  				 struct irq_fwspec *fwspec,
  				 enum irq_domain_bus_token bus_token)
  {
  	/* Not for us */
          if (fwspec->fwnode != d->fwnode)
  		return 0;
  
  	/* If this is not DT, then we have a single domain */
  	if (!is_of_node(fwspec->fwnode))
  		return 1;
  
  	/*
  	 * If this is a PPI and we have a 4th (non-null) parameter,
  	 * then we need to match the partition domain.
  	 */
  	if (fwspec->param_count >= 4 &&
  	    fwspec->param[0] == 1 && fwspec->param[3] != 0)
  		return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
  
  	return d == gic_data.domain;
  }
021f65379   Marc Zyngier   irqchip: gic-v3: ...
819
  static const struct irq_domain_ops gic_irq_domain_ops = {
f833f57ff   Marc Zyngier   irqchip: Convert ...
820
  	.translate = gic_irq_domain_translate,
443acc4f3   Marc Zyngier   irqchip: GICv3: C...
821
822
  	.alloc = gic_irq_domain_alloc,
  	.free = gic_irq_domain_free,
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
  	.select = gic_irq_domain_select,
  };
  
  static int partition_domain_translate(struct irq_domain *d,
  				      struct irq_fwspec *fwspec,
  				      unsigned long *hwirq,
  				      unsigned int *type)
  {
  	struct device_node *np;
  	int ret;
  
  	np = of_find_node_by_phandle(fwspec->param[3]);
  	if (WARN_ON(!np))
  		return -EINVAL;
  
  	ret = partition_translate_id(gic_data.ppi_descs[fwspec->param[1]],
  				     of_node_to_fwnode(np));
  	if (ret < 0)
  		return ret;
  
  	*hwirq = ret;
  	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
  
  	return 0;
  }
  
  static const struct irq_domain_ops partition_domain_ops = {
  	.translate = partition_domain_translate,
  	.select = gic_irq_domain_select,
021f65379   Marc Zyngier   irqchip: gic-v3: ...
852
  };
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
853
854
  static void gicv3_enable_quirks(void)
  {
7936e914f   Jean-Philippe Brucker   irqchip/gic-v3: R...
855
  #ifdef CONFIG_ARM64
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
856
  	if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154))
8ac2a1704   Robert Richter   irqchip/gicv3-its...
857
  		static_branch_enable(&is_cavium_thunderx);
7936e914f   Jean-Philippe Brucker   irqchip/gic-v3: R...
858
  #endif
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
859
  }
db57d7460   Tomasz Nowicki   irqchip/gic-v3: R...
860
861
862
863
864
  static int __init gic_init_bases(void __iomem *dist_base,
  				 struct redist_region *rdist_regs,
  				 u32 nr_redist_regions,
  				 u64 redist_stride,
  				 struct fwnode_handle *handle)
021f65379   Marc Zyngier   irqchip: gic-v3: ...
865
  {
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
866
  	u32 typer;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
867
868
  	int gic_irqs;
  	int err;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
869

0b6a3da96   Marc Zyngier   irqchip/GICv3: Co...
870
871
872
873
874
875
  	if (!is_hyp_mode_available())
  		static_key_slow_dec(&supports_deactivate);
  
  	if (static_key_true(&supports_deactivate))
  		pr_info("GIC: Using split EOI/Deactivate mode
  ");
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
876
  	gic_data.fwnode = handle;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
877
  	gic_data.dist_base = dist_base;
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
878
879
  	gic_data.redist_regions = rdist_regs;
  	gic_data.nr_redist_regions = nr_redist_regions;
021f65379   Marc Zyngier   irqchip: gic-v3: ...
880
  	gic_data.redist_stride = redist_stride;
6d4e11c5e   Robert Richter   irqchip/gicv3: Wo...
881
  	gicv3_enable_quirks();
021f65379   Marc Zyngier   irqchip: gic-v3: ...
882
883
884
885
  	/*
  	 * Find out how many interrupts are supported.
  	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
  	 */
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
886
887
888
  	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
  	gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
  	gic_irqs = GICD_TYPER_IRQS(typer);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
889
890
891
  	if (gic_irqs > 1020)
  		gic_irqs = 1020;
  	gic_data.irq_nr = gic_irqs;
db57d7460   Tomasz Nowicki   irqchip/gic-v3: R...
892
893
  	gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
  						 &gic_data);
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
894
  	gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
021f65379   Marc Zyngier   irqchip: gic-v3: ...
895

f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
896
  	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
021f65379   Marc Zyngier   irqchip: gic-v3: ...
897
898
899
900
901
  		err = -ENOMEM;
  		goto out_free;
  	}
  
  	set_handle_irq(gic_handle_irq);
db40f0a7a   Tomasz Nowicki   irqchip/gicv3-its...
902
903
  	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
  		its_init(handle, &gic_data.rdists, gic_data.domain);
da33f31de   Marc Zyngier   irqchip: GICv3: I...
904

021f65379   Marc Zyngier   irqchip: gic-v3: ...
905
906
907
  	gic_smp_init();
  	gic_dist_init();
  	gic_cpu_init();
3708d52fc   Sudeep Holla   irqchip: gic-v3: ...
908
  	gic_cpu_pm_init();
021f65379   Marc Zyngier   irqchip: gic-v3: ...
909
910
911
912
913
914
  
  	return 0;
  
  out_free:
  	if (gic_data.domain)
  		irq_domain_remove(gic_data.domain);
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
915
  	free_percpu(gic_data.rdists.rdist);
db57d7460   Tomasz Nowicki   irqchip/gic-v3: R...
916
917
918
919
920
921
922
923
924
925
926
927
  	return err;
  }
  
  static int __init gic_validate_dist_version(void __iomem *dist_base)
  {
  	u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
  
  	if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
  		return -ENODEV;
  
  	return 0;
  }
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
  static int get_cpu_number(struct device_node *dn)
  {
  	const __be32 *cell;
  	u64 hwid;
  	int i;
  
  	cell = of_get_property(dn, "reg", NULL);
  	if (!cell)
  		return -1;
  
  	hwid = of_read_number(cell, of_n_addr_cells(dn));
  
  	/*
  	 * Non affinity bits must be set to 0 in the DT
  	 */
  	if (hwid & ~MPIDR_HWID_BITMASK)
  		return -1;
  
  	for (i = 0; i < num_possible_cpus(); i++)
  		if (cpu_logical_map(i) == hwid)
  			return i;
  
  	return -1;
  }
  
  /* Create all possible partitions at boot time */
7beaa24ba   Linus Torvalds   Merge tag 'for-li...
954
  static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  {
  	struct device_node *parts_node, *child_part;
  	int part_idx = 0, i;
  	int nr_parts;
  	struct partition_affinity *parts;
  
  	parts_node = of_find_node_by_name(gic_node, "ppi-partitions");
  	if (!parts_node)
  		return;
  
  	nr_parts = of_get_child_count(parts_node);
  
  	if (!nr_parts)
  		return;
  
  	parts = kzalloc(sizeof(*parts) * nr_parts, GFP_KERNEL);
  	if (WARN_ON(!parts))
  		return;
  
  	for_each_child_of_node(parts_node, child_part) {
  		struct partition_affinity *part;
  		int n;
  
  		part = &parts[part_idx];
  
  		part->partition_id = of_node_to_fwnode(child_part);
  
  		pr_info("GIC: PPI partition %s[%d] { ",
  			child_part->name, part_idx);
  
  		n = of_property_count_elems_of_size(child_part, "affinity",
  						    sizeof(u32));
  		WARN_ON(n <= 0);
  
  		for (i = 0; i < n; i++) {
  			int err, cpu;
  			u32 cpu_phandle;
  			struct device_node *cpu_node;
  
  			err = of_property_read_u32_index(child_part, "affinity",
  							 i, &cpu_phandle);
  			if (WARN_ON(err))
  				continue;
  
  			cpu_node = of_find_node_by_phandle(cpu_phandle);
  			if (WARN_ON(!cpu_node))
  				continue;
  
  			cpu = get_cpu_number(cpu_node);
  			if (WARN_ON(cpu == -1))
  				continue;
  
  			pr_cont("%s[%d] ", cpu_node->full_name, cpu);
  
  			cpumask_set_cpu(cpu, &part->mask);
  		}
  
  		pr_cont("}
  ");
  		part_idx++;
  	}
  
  	for (i = 0; i < 16; i++) {
  		unsigned int irq;
  		struct partition_desc *desc;
  		struct irq_fwspec ppi_fwspec = {
  			.fwnode		= gic_data.fwnode,
  			.param_count	= 3,
  			.param		= {
  				[0]	= 1,
  				[1]	= i,
  				[2]	= IRQ_TYPE_NONE,
  			},
  		};
  
  		irq = irq_create_fwspec_mapping(&ppi_fwspec);
  		if (WARN_ON(!irq))
  			continue;
  		desc = partition_create_desc(gic_data.fwnode, parts, nr_parts,
  					     irq, &partition_domain_ops);
  		if (WARN_ON(!desc))
  			continue;
  
  		gic_data.ppi_descs[i] = desc;
  	}
  }
1839e5769   Julien Grall   irqchip/gic-v3: P...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  static void __init gic_of_setup_kvm_info(struct device_node *node)
  {
  	int ret;
  	struct resource r;
  	u32 gicv_idx;
  
  	gic_v3_kvm_info.type = GIC_V3;
  
  	gic_v3_kvm_info.maint_irq = irq_of_parse_and_map(node, 0);
  	if (!gic_v3_kvm_info.maint_irq)
  		return;
  
  	if (of_property_read_u32(node, "#redistributor-regions",
  				 &gicv_idx))
  		gicv_idx = 1;
  
  	gicv_idx += 3;	/* Also skip GICD, GICC, GICH */
  	ret = of_address_to_resource(node, gicv_idx, &r);
  	if (!ret)
  		gic_v3_kvm_info.vcpu = r;
  
  	gic_set_kvm_info(&gic_v3_kvm_info);
  }
db57d7460   Tomasz Nowicki   irqchip/gic-v3: R...
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  static int __init gic_of_init(struct device_node *node, struct device_node *parent)
  {
  	void __iomem *dist_base;
  	struct redist_region *rdist_regs;
  	u64 redist_stride;
  	u32 nr_redist_regions;
  	int err, i;
  
  	dist_base = of_iomap(node, 0);
  	if (!dist_base) {
  		pr_err("%s: unable to map gic dist registers
  ",
  			node->full_name);
  		return -ENXIO;
  	}
  
  	err = gic_validate_dist_version(dist_base);
  	if (err) {
  		pr_err("%s: no distributor detected, giving up
  ",
  			node->full_name);
  		goto out_unmap_dist;
  	}
  
  	if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
  		nr_redist_regions = 1;
  
  	rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
  	if (!rdist_regs) {
  		err = -ENOMEM;
  		goto out_unmap_dist;
  	}
  
  	for (i = 0; i < nr_redist_regions; i++) {
  		struct resource res;
  		int ret;
  
  		ret = of_address_to_resource(node, 1 + i, &res);
  		rdist_regs[i].redist_base = of_iomap(node, 1 + i);
  		if (ret || !rdist_regs[i].redist_base) {
  			pr_err("%s: couldn't map region %d
  ",
  			       node->full_name, i);
  			err = -ENODEV;
  			goto out_unmap_rdist;
  		}
  		rdist_regs[i].phys_base = res.start;
  	}
  
  	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
  		redist_stride = 0;
  
  	err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
  			     redist_stride, &node->fwnode);
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
1118
1119
1120
1121
  	if (err)
  		goto out_unmap_rdist;
  
  	gic_populate_ppi_partitions(node);
7beaa24ba   Linus Torvalds   Merge tag 'for-li...
1122
  	gic_of_setup_kvm_info(node);
e3825ba1a   Marc Zyngier   irqchip/gic-v3: A...
1123
  	return 0;
db57d7460   Tomasz Nowicki   irqchip/gic-v3: R...
1124

021f65379   Marc Zyngier   irqchip: gic-v3: ...
1125
  out_unmap_rdist:
f5c1434c2   Marc Zyngier   irqchip: GICv3: r...
1126
1127
1128
1129
  	for (i = 0; i < nr_redist_regions; i++)
  		if (rdist_regs[i].redist_base)
  			iounmap(rdist_regs[i].redist_base);
  	kfree(rdist_regs);
021f65379   Marc Zyngier   irqchip: gic-v3: ...
1130
1131
1132
1133
1134
1135
  out_unmap_dist:
  	iounmap(dist_base);
  	return err;
  }
  
  IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1136
1137
  
  #ifdef CONFIG_ACPI
611f039f5   Julien Grall   irqchip/gic-v3: G...
1138
1139
1140
1141
1142
1143
  static struct
  {
  	void __iomem *dist_base;
  	struct redist_region *redist_regs;
  	u32 nr_redist_regions;
  	bool single_redist;
1839e5769   Julien Grall   irqchip/gic-v3: P...
1144
1145
1146
  	u32 maint_irq;
  	int maint_irq_mode;
  	phys_addr_t vcpu_base;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1147
  } acpi_data __initdata;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1148
1149
1150
1151
1152
  
  static void __init
  gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base)
  {
  	static int count = 0;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1153
1154
1155
  	acpi_data.redist_regs[count].phys_base = phys_base;
  	acpi_data.redist_regs[count].redist_base = redist_base;
  	acpi_data.redist_regs[count].single_redist = acpi_data.single_redist;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1156
1157
  	count++;
  }
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1158
1159
1160
1161
1162
1163
1164
1165
  
  static int __init
  gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
  			   const unsigned long end)
  {
  	struct acpi_madt_generic_redistributor *redist =
  			(struct acpi_madt_generic_redistributor *)header;
  	void __iomem *redist_base;
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1166
1167
1168
1169
1170
1171
1172
  
  	redist_base = ioremap(redist->base_address, redist->length);
  	if (!redist_base) {
  		pr_err("Couldn't map GICR region @%llx
  ", redist->base_address);
  		return -ENOMEM;
  	}
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1173
  	gic_acpi_register_redist(redist->base_address, redist_base);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1174
1175
  	return 0;
  }
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1176
1177
1178
1179
1180
1181
  static int __init
  gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
  			 const unsigned long end)
  {
  	struct acpi_madt_generic_interrupt *gicc =
  				(struct acpi_madt_generic_interrupt *)header;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1182
  	u32 reg = readl_relaxed(acpi_data.dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
  	u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
  	void __iomem *redist_base;
  
  	redist_base = ioremap(gicc->gicr_base_address, size);
  	if (!redist_base)
  		return -ENOMEM;
  
  	gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
  	return 0;
  }
  
  static int __init gic_acpi_collect_gicr_base(void)
  {
  	acpi_tbl_entry_handler redist_parser;
  	enum acpi_madt_type type;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1198
  	if (acpi_data.single_redist) {
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  		type = ACPI_MADT_TYPE_GENERIC_INTERRUPT;
  		redist_parser = gic_acpi_parse_madt_gicc;
  	} else {
  		type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR;
  		redist_parser = gic_acpi_parse_madt_redist;
  	}
  
  	/* Collect redistributor base addresses in GICR entries */
  	if (acpi_table_parse_madt(type, redist_parser, 0) > 0)
  		return 0;
  
  	pr_info("No valid GICR entries exist
  ");
  	return -ENODEV;
  }
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1214
1215
1216
1217
1218
1219
  static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
  				  const unsigned long end)
  {
  	/* Subtable presence means that redist exists, that's it */
  	return 0;
  }
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
  				      const unsigned long end)
  {
  	struct acpi_madt_generic_interrupt *gicc =
  				(struct acpi_madt_generic_interrupt *)header;
  
  	/*
  	 * If GICC is enabled and has valid gicr base address, then it means
  	 * GICR base is presented via GICC
  	 */
  	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
  		return 0;
  
  	return -ENODEV;
  }
  
  static int __init gic_acpi_count_gicr_regions(void)
  {
  	int count;
  
  	/*
  	 * Count how many redistributor regions we have. It is not allowed
  	 * to mix redistributor description, GICR and GICC subtables have to be
  	 * mutually exclusive.
  	 */
  	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
  				      gic_acpi_match_gicr, 0);
  	if (count > 0) {
611f039f5   Julien Grall   irqchip/gic-v3: G...
1248
  		acpi_data.single_redist = false;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1249
1250
1251
1252
1253
1254
  		return count;
  	}
  
  	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
  				      gic_acpi_match_gicc, 0);
  	if (count > 0)
611f039f5   Julien Grall   irqchip/gic-v3: G...
1255
  		acpi_data.single_redist = true;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1256
1257
1258
  
  	return count;
  }
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
  static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
  					   struct acpi_probe_entry *ape)
  {
  	struct acpi_madt_generic_distributor *dist;
  	int count;
  
  	dist = (struct acpi_madt_generic_distributor *)header;
  	if (dist->version != ape->driver_data)
  		return false;
  
  	/* We need to do that exercise anyway, the sooner the better */
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1270
  	count = gic_acpi_count_gicr_regions();
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1271
1272
  	if (count <= 0)
  		return false;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1273
  	acpi_data.nr_redist_regions = count;
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1274
1275
  	return true;
  }
1839e5769   Julien Grall   irqchip/gic-v3: P...
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
  static int __init gic_acpi_parse_virt_madt_gicc(struct acpi_subtable_header *header,
  						const unsigned long end)
  {
  	struct acpi_madt_generic_interrupt *gicc =
  		(struct acpi_madt_generic_interrupt *)header;
  	int maint_irq_mode;
  	static int first_madt = true;
  
  	/* Skip unusable CPUs */
  	if (!(gicc->flags & ACPI_MADT_ENABLED))
  		return 0;
  
  	maint_irq_mode = (gicc->flags & ACPI_MADT_VGIC_IRQ_MODE) ?
  		ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
  
  	if (first_madt) {
  		first_madt = false;
  
  		acpi_data.maint_irq = gicc->vgic_interrupt;
  		acpi_data.maint_irq_mode = maint_irq_mode;
  		acpi_data.vcpu_base = gicc->gicv_base_address;
  
  		return 0;
  	}
  
  	/*
  	 * The maintenance interrupt and GICV should be the same for every CPU
  	 */
  	if ((acpi_data.maint_irq != gicc->vgic_interrupt) ||
  	    (acpi_data.maint_irq_mode != maint_irq_mode) ||
  	    (acpi_data.vcpu_base != gicc->gicv_base_address))
  		return -EINVAL;
  
  	return 0;
  }
  
  static bool __init gic_acpi_collect_virt_info(void)
  {
  	int count;
  
  	count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
  				      gic_acpi_parse_virt_madt_gicc, 0);
  
  	return (count > 0);
  }
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1321
  #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
1839e5769   Julien Grall   irqchip/gic-v3: P...
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  #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;
  
  	if (!gic_acpi_collect_virt_info()) {
  		pr_warn("Unable to get hardware information used for virtualization
  ");
  		return;
  	}
  
  	gic_v3_kvm_info.type = GIC_V3;
  
  	irq = acpi_register_gsi(NULL, acpi_data.maint_irq,
  				acpi_data.maint_irq_mode,
  				ACPI_ACTIVE_HIGH);
  	if (irq <= 0)
  		return;
  
  	gic_v3_kvm_info.maint_irq = irq;
  
  	if (acpi_data.vcpu_base) {
  		struct resource *vcpu = &gic_v3_kvm_info.vcpu;
  
  		vcpu->flags = IORESOURCE_MEM;
  		vcpu->start = acpi_data.vcpu_base;
  		vcpu->end = vcpu->start + ACPI_GICV2_VCPU_MEM_SIZE - 1;
  	}
  
  	gic_set_kvm_info(&gic_v3_kvm_info);
  }
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1355
1356
1357
1358
1359
1360
  
  static int __init
  gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
  {
  	struct acpi_madt_generic_distributor *dist;
  	struct fwnode_handle *domain_handle;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1361
  	size_t size;
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1362
  	int i, err;
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1363
1364
1365
  
  	/* Get distributor base address */
  	dist = (struct acpi_madt_generic_distributor *)header;
611f039f5   Julien Grall   irqchip/gic-v3: G...
1366
1367
1368
  	acpi_data.dist_base = ioremap(dist->base_address,
  				      ACPI_GICV3_DIST_MEM_SIZE);
  	if (!acpi_data.dist_base) {
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1369
1370
1371
1372
  		pr_err("Unable to map GICD registers
  ");
  		return -ENOMEM;
  	}
611f039f5   Julien Grall   irqchip/gic-v3: G...
1373
  	err = gic_validate_dist_version(acpi_data.dist_base);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1374
  	if (err) {
611f039f5   Julien Grall   irqchip/gic-v3: G...
1375
1376
  		pr_err("No distributor detected at @%p, giving up",
  		       acpi_data.dist_base);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1377
1378
  		goto out_dist_unmap;
  	}
611f039f5   Julien Grall   irqchip/gic-v3: G...
1379
1380
1381
  	size = sizeof(*acpi_data.redist_regs) * acpi_data.nr_redist_regions;
  	acpi_data.redist_regs = kzalloc(size, GFP_KERNEL);
  	if (!acpi_data.redist_regs) {
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1382
1383
1384
  		err = -ENOMEM;
  		goto out_dist_unmap;
  	}
b70fb7af6   Tomasz Nowicki   irqchip/gic-v3: A...
1385
1386
  	err = gic_acpi_collect_gicr_base();
  	if (err)
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1387
  		goto out_redist_unmap;
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1388

611f039f5   Julien Grall   irqchip/gic-v3: G...
1389
  	domain_handle = irq_domain_alloc_fwnode(acpi_data.dist_base);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1390
1391
1392
1393
  	if (!domain_handle) {
  		err = -ENOMEM;
  		goto out_redist_unmap;
  	}
611f039f5   Julien Grall   irqchip/gic-v3: G...
1394
1395
  	err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
  			     acpi_data.nr_redist_regions, 0, domain_handle);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1396
1397
1398
1399
  	if (err)
  		goto out_fwhandle_free;
  
  	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
1839e5769   Julien Grall   irqchip/gic-v3: P...
1400
  	gic_acpi_setup_kvm_info();
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1401
1402
1403
1404
1405
  	return 0;
  
  out_fwhandle_free:
  	irq_domain_free_fwnode(domain_handle);
  out_redist_unmap:
611f039f5   Julien Grall   irqchip/gic-v3: G...
1406
1407
1408
1409
  	for (i = 0; i < acpi_data.nr_redist_regions; i++)
  		if (acpi_data.redist_regs[i].redist_base)
  			iounmap(acpi_data.redist_regs[i].redist_base);
  	kfree(acpi_data.redist_regs);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1410
  out_dist_unmap:
611f039f5   Julien Grall   irqchip/gic-v3: G...
1411
  	iounmap(acpi_data.dist_base);
ffa7d6166   Tomasz Nowicki   irqchip/gic-v3: A...
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  	return err;
  }
  IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
  		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
  		     gic_acpi_init);
  IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
  		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
  		     gic_acpi_init);
  IRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
  		     acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
  		     gic_acpi_init);
  #endif