xref: /kvm-unit-tests/lib/arm/gic.c (revision e526bc786e9878c3880ae4b09b01a4572756e492)
100cc96f0SAndrew Jones /*
200cc96f0SAndrew Jones  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
300cc96f0SAndrew Jones  *
400cc96f0SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
500cc96f0SAndrew Jones  */
6*13182cd7SNikos Nikoleris #include <acpi.h>
700cc96f0SAndrew Jones #include <devicetree.h>
800cc96f0SAndrew Jones #include <asm/gic.h>
900cc96f0SAndrew Jones #include <asm/io.h>
1000cc96f0SAndrew Jones 
1100cc96f0SAndrew Jones struct gicv2_data gicv2_data;
1291a6c3ceSAndrew Jones struct gicv3_data gicv3_data;
13ba74b106SEric Auger struct its_data its_data;
1400cc96f0SAndrew Jones 
152e2d471dSAndrew Jones struct gic_common_ops {
162e2d471dSAndrew Jones 	void (*enable_defaults)(void);
172e2d471dSAndrew Jones 	u32 (*read_iar)(void);
182e2d471dSAndrew Jones 	u32 (*iar_irqnr)(u32 iar);
192e2d471dSAndrew Jones 	void (*write_eoir)(u32 irqstat);
202e2d471dSAndrew Jones 	void (*ipi_send_single)(int irq, int cpu);
212e2d471dSAndrew Jones 	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
222e2d471dSAndrew Jones };
232e2d471dSAndrew Jones 
242e2d471dSAndrew Jones static const struct gic_common_ops *gic_common_ops;
252e2d471dSAndrew Jones 
262e2d471dSAndrew Jones static const struct gic_common_ops gicv2_common_ops = {
272e2d471dSAndrew Jones 	.enable_defaults = gicv2_enable_defaults,
282e2d471dSAndrew Jones 	.read_iar = gicv2_read_iar,
292e2d471dSAndrew Jones 	.iar_irqnr = gicv2_iar_irqnr,
302e2d471dSAndrew Jones 	.write_eoir = gicv2_write_eoir,
312e2d471dSAndrew Jones 	.ipi_send_single = gicv2_ipi_send_single,
322e2d471dSAndrew Jones 	.ipi_send_mask = gicv2_ipi_send_mask,
332e2d471dSAndrew Jones };
342e2d471dSAndrew Jones 
352e2d471dSAndrew Jones static const struct gic_common_ops gicv3_common_ops = {
362e2d471dSAndrew Jones 	.enable_defaults = gicv3_enable_defaults,
372e2d471dSAndrew Jones 	.read_iar = gicv3_read_iar,
382e2d471dSAndrew Jones 	.iar_irqnr = gicv3_iar_irqnr,
392e2d471dSAndrew Jones 	.write_eoir = gicv3_write_eoir,
402e2d471dSAndrew Jones 	.ipi_send_single = gicv3_ipi_send_single,
412e2d471dSAndrew Jones 	.ipi_send_mask = gicv3_ipi_send_mask,
422e2d471dSAndrew Jones };
432e2d471dSAndrew Jones 
4400cc96f0SAndrew Jones /*
4500cc96f0SAndrew Jones  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
4691a6c3ceSAndrew Jones  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
4700cc96f0SAndrew Jones  */
4800cc96f0SAndrew Jones static bool
gic_get_dt_bases(const char * compatible,void ** base1,void ** base2,void ** base3)49ba74b106SEric Auger gic_get_dt_bases(const char *compatible, void **base1, void **base2, void **base3)
5000cc96f0SAndrew Jones {
5100cc96f0SAndrew Jones 	struct dt_pbus_reg reg;
52ba74b106SEric Auger 	struct dt_device gic, its;
5300cc96f0SAndrew Jones 	struct dt_bus bus;
54ba74b106SEric Auger 	int node, subnode, ret, i, len;
55ba74b106SEric Auger 	const void *fdt = dt_fdt();
5600cc96f0SAndrew Jones 
5700cc96f0SAndrew Jones 	dt_bus_init_defaults(&bus);
5800cc96f0SAndrew Jones 	dt_device_init(&gic, &bus, NULL);
5900cc96f0SAndrew Jones 
6000cc96f0SAndrew Jones 	node = dt_device_find_compatible(&gic, compatible);
6100cc96f0SAndrew Jones 	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
6200cc96f0SAndrew Jones 
6300cc96f0SAndrew Jones 	if (node == -FDT_ERR_NOTFOUND)
6400cc96f0SAndrew Jones 		return false;
6500cc96f0SAndrew Jones 
6600cc96f0SAndrew Jones 	dt_device_bind_node(&gic, node);
6700cc96f0SAndrew Jones 
6800cc96f0SAndrew Jones 	ret = dt_pbus_translate(&gic, 0, &reg);
6900cc96f0SAndrew Jones 	assert(ret == 0);
7000cc96f0SAndrew Jones 	*base1 = ioremap(reg.addr, reg.size);
7100cc96f0SAndrew Jones 
72a5a2d35cSAndrew Jones 	for (i = 0; i < GICV3_NR_REDISTS; ++i) {
73a5a2d35cSAndrew Jones 		ret = dt_pbus_translate(&gic, i + 1, &reg);
74a5a2d35cSAndrew Jones 		if (ret == -FDT_ERR_NOTFOUND)
75a5a2d35cSAndrew Jones 			break;
7600cc96f0SAndrew Jones 		assert(ret == 0);
77a5a2d35cSAndrew Jones 		base2[i] = ioremap(reg.addr, reg.size);
78a5a2d35cSAndrew Jones 	}
7900cc96f0SAndrew Jones 
80ba74b106SEric Auger 	if (!base3) {
81ba74b106SEric Auger 		assert(!strcmp(compatible, "arm,cortex-a15-gic"));
82ba74b106SEric Auger 		return true;
83ba74b106SEric Auger 	}
84ba74b106SEric Auger 
85ba74b106SEric Auger 	assert(!strcmp(compatible, "arm,gic-v3"));
86ba74b106SEric Auger 
87ba74b106SEric Auger 	dt_for_each_subnode(node, subnode) {
88ba74b106SEric Auger 		const struct fdt_property *prop;
89ba74b106SEric Auger 
90ba74b106SEric Auger 		prop = fdt_get_property(fdt, subnode, "compatible", &len);
91ba74b106SEric Auger 		if (!strcmp((char *)prop->data, "arm,gic-v3-its")) {
92ba74b106SEric Auger 			dt_device_bind_node(&its, subnode);
93ba74b106SEric Auger 			ret = dt_pbus_translate(&its, 0, &reg);
94ba74b106SEric Auger 			assert(ret == 0);
95ba74b106SEric Auger 			*base3 = ioremap(reg.addr, reg.size);
96ba74b106SEric Auger 			break;
97ba74b106SEric Auger 		}
98ba74b106SEric Auger 	}
99ba74b106SEric Auger 
10000cc96f0SAndrew Jones 	return true;
10100cc96f0SAndrew Jones }
10200cc96f0SAndrew Jones 
gicv2_init(void)10300cc96f0SAndrew Jones int gicv2_init(void)
10400cc96f0SAndrew Jones {
10500cc96f0SAndrew Jones 	return gic_get_dt_bases("arm,cortex-a15-gic",
106ba74b106SEric Auger 			&gicv2_data.dist_base, &gicv2_data.cpu_base, NULL);
10700cc96f0SAndrew Jones }
10800cc96f0SAndrew Jones 
gicv3_init(void)10991a6c3ceSAndrew Jones int gicv3_init(void)
11091a6c3ceSAndrew Jones {
11191a6c3ceSAndrew Jones 	return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
112ba74b106SEric Auger 			&gicv3_data.redist_bases[0], &its_data.base);
11391a6c3ceSAndrew Jones }
11491a6c3ceSAndrew Jones 
gic_version(void)115db198544SAndrew Jones int gic_version(void)
116db198544SAndrew Jones {
117db198544SAndrew Jones 	if (gic_common_ops == &gicv2_common_ops)
118db198544SAndrew Jones 		return 2;
119db198544SAndrew Jones 	else if (gic_common_ops == &gicv3_common_ops)
120db198544SAndrew Jones 		return 3;
121db198544SAndrew Jones 	return 0;
122db198544SAndrew Jones }
123db198544SAndrew Jones 
gic_init_fdt(void)124*13182cd7SNikos Nikoleris static int gic_init_fdt(void)
12500cc96f0SAndrew Jones {
126ba74b106SEric Auger 	if (gicv2_init()) {
1272e2d471dSAndrew Jones 		gic_common_ops = &gicv2_common_ops;
128ba74b106SEric Auger 	} else if (gicv3_init()) {
1292e2d471dSAndrew Jones 		gic_common_ops = &gicv3_common_ops;
130ba74b106SEric Auger #ifdef __aarch64__
131ba74b106SEric Auger 		its_init();
132ba74b106SEric Auger #endif
133ba74b106SEric Auger 	}
134db198544SAndrew Jones 	return gic_version();
13500cc96f0SAndrew Jones }
1362e2d471dSAndrew Jones 
137*13182cd7SNikos Nikoleris #ifdef CONFIG_EFI
138*13182cd7SNikos Nikoleris 
139*13182cd7SNikos Nikoleris #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
140*13182cd7SNikos Nikoleris #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
141*13182cd7SNikos Nikoleris #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
142*13182cd7SNikos Nikoleris #define ACPI_GICV3_ITS_MEM_SIZE		(SZ_128K)
143*13182cd7SNikos Nikoleris 
gic_acpi_version(struct acpi_subtable_header * header)144*13182cd7SNikos Nikoleris static int gic_acpi_version(struct acpi_subtable_header *header)
145*13182cd7SNikos Nikoleris {
146*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_distributor *dist = (void *)header;
147*13182cd7SNikos Nikoleris 	int version = dist->version;
148*13182cd7SNikos Nikoleris 
149*13182cd7SNikos Nikoleris 	if (version == 2)
150*13182cd7SNikos Nikoleris 		gic_common_ops = &gicv2_common_ops;
151*13182cd7SNikos Nikoleris 	else if (version == 3)
152*13182cd7SNikos Nikoleris 		gic_common_ops = &gicv3_common_ops;
153*13182cd7SNikos Nikoleris 
154*13182cd7SNikos Nikoleris 	return version;
155*13182cd7SNikos Nikoleris }
156*13182cd7SNikos Nikoleris 
gicv2_acpi_parse_madt_cpu(struct acpi_subtable_header * header)157*13182cd7SNikos Nikoleris static int gicv2_acpi_parse_madt_cpu(struct acpi_subtable_header *header)
158*13182cd7SNikos Nikoleris {
159*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_interrupt *gicc = (void *)header;
160*13182cd7SNikos Nikoleris 	static phys_addr_t gicc_base_address;
161*13182cd7SNikos Nikoleris 
162*13182cd7SNikos Nikoleris 	if (!(gicc->flags & ACPI_MADT_ENABLED))
163*13182cd7SNikos Nikoleris 		return 0;
164*13182cd7SNikos Nikoleris 
165*13182cd7SNikos Nikoleris 	if (!gicc_base_address) {
166*13182cd7SNikos Nikoleris 		gicc_base_address = gicc->base_address;
167*13182cd7SNikos Nikoleris 		gicv2_data.cpu_base = ioremap(gicc_base_address, ACPI_GIC_CPU_IF_MEM_SIZE);
168*13182cd7SNikos Nikoleris 	}
169*13182cd7SNikos Nikoleris 	assert(gicc_base_address == gicc->base_address);
170*13182cd7SNikos Nikoleris 
171*13182cd7SNikos Nikoleris 	return 0;
172*13182cd7SNikos Nikoleris }
173*13182cd7SNikos Nikoleris 
gicv2_acpi_parse_madt_dist(struct acpi_subtable_header * header)174*13182cd7SNikos Nikoleris static int gicv2_acpi_parse_madt_dist(struct acpi_subtable_header *header)
175*13182cd7SNikos Nikoleris {
176*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_distributor *dist = (void *)header;
177*13182cd7SNikos Nikoleris 
178*13182cd7SNikos Nikoleris 	gicv2_data.dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
179*13182cd7SNikos Nikoleris 
180*13182cd7SNikos Nikoleris 	return 0;
181*13182cd7SNikos Nikoleris }
182*13182cd7SNikos Nikoleris 
gicv3_acpi_parse_madt_gicc(struct acpi_subtable_header * header)183*13182cd7SNikos Nikoleris static int gicv3_acpi_parse_madt_gicc(struct acpi_subtable_header *header)
184*13182cd7SNikos Nikoleris {
185*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_interrupt *gicc = (void *)header;
186*13182cd7SNikos Nikoleris 	static phys_addr_t gicr_base_address;
187*13182cd7SNikos Nikoleris 
188*13182cd7SNikos Nikoleris 	if (!(gicc->flags & ACPI_MADT_ENABLED))
189*13182cd7SNikos Nikoleris 		return 0;
190*13182cd7SNikos Nikoleris 
191*13182cd7SNikos Nikoleris 	if (!gicr_base_address) {
192*13182cd7SNikos Nikoleris 		gicr_base_address = gicc->gicr_base_address;
193*13182cd7SNikos Nikoleris 		gicv3_data.redist_bases[0] = ioremap(gicr_base_address, SZ_64K * 2);
194*13182cd7SNikos Nikoleris 	}
195*13182cd7SNikos Nikoleris 	assert(gicr_base_address == gicc->gicr_base_address);
196*13182cd7SNikos Nikoleris 
197*13182cd7SNikos Nikoleris 	return 0;
198*13182cd7SNikos Nikoleris }
199*13182cd7SNikos Nikoleris 
gicv3_acpi_parse_madt_dist(struct acpi_subtable_header * header)200*13182cd7SNikos Nikoleris static int gicv3_acpi_parse_madt_dist(struct acpi_subtable_header *header)
201*13182cd7SNikos Nikoleris {
202*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_distributor *dist = (void *)header;
203*13182cd7SNikos Nikoleris 
204*13182cd7SNikos Nikoleris 	gicv3_data.dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
205*13182cd7SNikos Nikoleris 
206*13182cd7SNikos Nikoleris 	return 0;
207*13182cd7SNikos Nikoleris }
208*13182cd7SNikos Nikoleris 
gicv3_acpi_parse_madt_redist(struct acpi_subtable_header * header)209*13182cd7SNikos Nikoleris static int gicv3_acpi_parse_madt_redist(struct acpi_subtable_header *header)
210*13182cd7SNikos Nikoleris {
211*13182cd7SNikos Nikoleris 	static int i;
212*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_redistributor *redist = (void *)header;
213*13182cd7SNikos Nikoleris 
214*13182cd7SNikos Nikoleris 	gicv3_data.redist_bases[i++] = ioremap(redist->base_address, redist->length);
215*13182cd7SNikos Nikoleris 
216*13182cd7SNikos Nikoleris 	return 0;
217*13182cd7SNikos Nikoleris }
218*13182cd7SNikos Nikoleris 
gicv3_acpi_parse_madt_its(struct acpi_subtable_header * header)219*13182cd7SNikos Nikoleris static int gicv3_acpi_parse_madt_its(struct acpi_subtable_header *header)
220*13182cd7SNikos Nikoleris {
221*13182cd7SNikos Nikoleris 	struct acpi_madt_generic_translator *its_entry = (void *)header;
222*13182cd7SNikos Nikoleris 
223*13182cd7SNikos Nikoleris 	its_data.base = ioremap(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE - 1);
224*13182cd7SNikos Nikoleris 
225*13182cd7SNikos Nikoleris 	return 0;
226*13182cd7SNikos Nikoleris }
227*13182cd7SNikos Nikoleris 
gic_init_acpi(void)228*13182cd7SNikos Nikoleris static int gic_init_acpi(void)
229*13182cd7SNikos Nikoleris {
230*13182cd7SNikos Nikoleris 	int count;
231*13182cd7SNikos Nikoleris 
232*13182cd7SNikos Nikoleris 	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, gic_acpi_version);
233*13182cd7SNikos Nikoleris 	if (gic_version() == 2) {
234*13182cd7SNikos Nikoleris 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
235*13182cd7SNikos Nikoleris 				     gicv2_acpi_parse_madt_cpu);
236*13182cd7SNikos Nikoleris 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
237*13182cd7SNikos Nikoleris 				      gicv2_acpi_parse_madt_dist);
238*13182cd7SNikos Nikoleris 	} else if (gic_version() == 3) {
239*13182cd7SNikos Nikoleris 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
240*13182cd7SNikos Nikoleris 				      gicv3_acpi_parse_madt_dist);
241*13182cd7SNikos Nikoleris 		count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
242*13182cd7SNikos Nikoleris 					      gicv3_acpi_parse_madt_redist);
243*13182cd7SNikos Nikoleris 		if (!count)
244*13182cd7SNikos Nikoleris 			acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
245*13182cd7SNikos Nikoleris 					      gicv3_acpi_parse_madt_gicc);
246*13182cd7SNikos Nikoleris 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
247*13182cd7SNikos Nikoleris 				      gicv3_acpi_parse_madt_its);
248*13182cd7SNikos Nikoleris #ifdef __aarch64__
249*13182cd7SNikos Nikoleris 		its_init();
250*13182cd7SNikos Nikoleris #endif
251*13182cd7SNikos Nikoleris 	}
252*13182cd7SNikos Nikoleris 
253*13182cd7SNikos Nikoleris 	return gic_version();
254*13182cd7SNikos Nikoleris }
255*13182cd7SNikos Nikoleris 
256*13182cd7SNikos Nikoleris #else
257*13182cd7SNikos Nikoleris 
gic_init_acpi(void)258*13182cd7SNikos Nikoleris static int gic_init_acpi(void)
259*13182cd7SNikos Nikoleris {
260*13182cd7SNikos Nikoleris 	assert_msg(false, "ACPI not available");
261*13182cd7SNikos Nikoleris }
262*13182cd7SNikos Nikoleris 
263*13182cd7SNikos Nikoleris #endif /* CONFIG_EFI */
264*13182cd7SNikos Nikoleris 
gic_init(void)265*13182cd7SNikos Nikoleris int gic_init(void)
266*13182cd7SNikos Nikoleris {
267*13182cd7SNikos Nikoleris 	if (dt_available())
268*13182cd7SNikos Nikoleris 		return gic_init_fdt();
269*13182cd7SNikos Nikoleris 	else
270*13182cd7SNikos Nikoleris 		return gic_init_acpi();
271*13182cd7SNikos Nikoleris }
272*13182cd7SNikos Nikoleris 
gic_enable_defaults(void)2732e2d471dSAndrew Jones void gic_enable_defaults(void)
2742e2d471dSAndrew Jones {
2752e2d471dSAndrew Jones 	if (!gic_common_ops) {
2762e2d471dSAndrew Jones 		int ret = gic_init();
2772e2d471dSAndrew Jones 		assert(ret != 0);
2782e2d471dSAndrew Jones 	} else
2792e2d471dSAndrew Jones 		assert(gic_common_ops->enable_defaults);
2802e2d471dSAndrew Jones 	gic_common_ops->enable_defaults();
2812e2d471dSAndrew Jones }
2822e2d471dSAndrew Jones 
gic_read_iar(void)2832e2d471dSAndrew Jones u32 gic_read_iar(void)
2842e2d471dSAndrew Jones {
2852e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->read_iar);
2862e2d471dSAndrew Jones 	return gic_common_ops->read_iar();
2872e2d471dSAndrew Jones }
2882e2d471dSAndrew Jones 
gic_iar_irqnr(u32 iar)2892e2d471dSAndrew Jones u32 gic_iar_irqnr(u32 iar)
2902e2d471dSAndrew Jones {
2912e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->iar_irqnr);
2922e2d471dSAndrew Jones 	return gic_common_ops->iar_irqnr(iar);
2932e2d471dSAndrew Jones }
2942e2d471dSAndrew Jones 
gic_write_eoir(u32 irqstat)2952e2d471dSAndrew Jones void gic_write_eoir(u32 irqstat)
2962e2d471dSAndrew Jones {
2972e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->write_eoir);
2982e2d471dSAndrew Jones 	gic_common_ops->write_eoir(irqstat);
2992e2d471dSAndrew Jones }
3002e2d471dSAndrew Jones 
gic_ipi_send_single(int irq,int cpu)3012e2d471dSAndrew Jones void gic_ipi_send_single(int irq, int cpu)
3022e2d471dSAndrew Jones {
3032e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->ipi_send_single);
3042e2d471dSAndrew Jones 	gic_common_ops->ipi_send_single(irq, cpu);
3052e2d471dSAndrew Jones }
3062e2d471dSAndrew Jones 
gic_ipi_send_mask(int irq,const cpumask_t * dest)3072e2d471dSAndrew Jones void gic_ipi_send_mask(int irq, const cpumask_t *dest)
3082e2d471dSAndrew Jones {
3092e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
3102e2d471dSAndrew Jones 	gic_common_ops->ipi_send_mask(irq, dest);
3112e2d471dSAndrew Jones }
31256145eb8SAndrew Jones 
gic_irq_set_clr_enable(int irq,bool enable)313cb573c2fSEric Auger void gic_irq_set_clr_enable(int irq, bool enable)
314cb573c2fSEric Auger {
315cb573c2fSEric Auger 	u32 offset, split = 32, shift = (irq % 32);
316cb573c2fSEric Auger 	void *base;
317cb573c2fSEric Auger 
318cb573c2fSEric Auger 	assert(irq < 1020);
319cb573c2fSEric Auger 
320cb573c2fSEric Auger 	switch (gic_version()) {
321cb573c2fSEric Auger 	case 2:
322cb573c2fSEric Auger 		offset = enable ? GICD_ISENABLER : GICD_ICENABLER;
323cb573c2fSEric Auger 		base = gicv2_dist_base();
324cb573c2fSEric Auger 		break;
325cb573c2fSEric Auger 	case 3:
326cb573c2fSEric Auger 		if (irq < 32) {
327cb573c2fSEric Auger 			offset = enable ? GICR_ISENABLER0 : GICR_ICENABLER0;
328cb573c2fSEric Auger 			base = gicv3_sgi_base();
329cb573c2fSEric Auger 		} else {
330cb573c2fSEric Auger 			offset = enable ? GICD_ISENABLER : GICD_ICENABLER;
331cb573c2fSEric Auger 			base = gicv3_dist_base();
332cb573c2fSEric Auger 		}
333cb573c2fSEric Auger 		break;
334cb573c2fSEric Auger 	default:
335cb573c2fSEric Auger 		assert(0);
336cb573c2fSEric Auger 	}
337cb573c2fSEric Auger 	base += offset + (irq / split) * 4;
3381db00b26SShaoqin Huang 	writel(BIT(shift), base);
339cb573c2fSEric Auger }
340cb573c2fSEric Auger 
gic_irq_state(int irq)34156145eb8SAndrew Jones enum gic_irq_state gic_irq_state(int irq)
34256145eb8SAndrew Jones {
34356145eb8SAndrew Jones 	enum gic_irq_state state;
34456145eb8SAndrew Jones 	void *ispendr, *isactiver;
34556145eb8SAndrew Jones 	bool pending, active;
34656145eb8SAndrew Jones 	int offset, mask;
34756145eb8SAndrew Jones 
34856145eb8SAndrew Jones 	assert(gic_common_ops);
34956145eb8SAndrew Jones 	assert(irq < 1020);
35056145eb8SAndrew Jones 
35156145eb8SAndrew Jones 	switch (gic_version()) {
35256145eb8SAndrew Jones 	case 2:
35356145eb8SAndrew Jones 		ispendr = gicv2_dist_base() + GICD_ISPENDR;
35456145eb8SAndrew Jones 		isactiver = gicv2_dist_base() + GICD_ISACTIVER;
35556145eb8SAndrew Jones 		break;
35656145eb8SAndrew Jones 	case 3:
35756145eb8SAndrew Jones 		if (irq < GIC_NR_PRIVATE_IRQS) {
35856145eb8SAndrew Jones 			ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
35956145eb8SAndrew Jones 			isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
36056145eb8SAndrew Jones 		} else {
36156145eb8SAndrew Jones 			ispendr = gicv3_dist_base() + GICD_ISPENDR;
36256145eb8SAndrew Jones 			isactiver = gicv3_dist_base() + GICD_ISACTIVER;
36356145eb8SAndrew Jones 		}
36456145eb8SAndrew Jones 		break;
36556145eb8SAndrew Jones 	default:
36656145eb8SAndrew Jones 		assert(0);
36756145eb8SAndrew Jones 	}
36856145eb8SAndrew Jones 
36956145eb8SAndrew Jones 	offset = irq / 32 * 4;
37056145eb8SAndrew Jones 	mask = 1 << (irq % 32);
37156145eb8SAndrew Jones 	pending = readl(ispendr + offset) & mask;
37256145eb8SAndrew Jones 	active = readl(isactiver + offset) & mask;
37356145eb8SAndrew Jones 
37456145eb8SAndrew Jones 	if (!active && !pending)
37556145eb8SAndrew Jones 		state = GIC_IRQ_STATE_INACTIVE;
37656145eb8SAndrew Jones 	if (pending)
37756145eb8SAndrew Jones 		state = GIC_IRQ_STATE_PENDING;
37856145eb8SAndrew Jones 	if (active)
37956145eb8SAndrew Jones 		state = GIC_IRQ_STATE_ACTIVE;
38056145eb8SAndrew Jones 	if (active && pending)
38156145eb8SAndrew Jones 		state = GIC_IRQ_STATE_ACTIVE_PENDING;
38256145eb8SAndrew Jones 
38356145eb8SAndrew Jones 	return state;
38456145eb8SAndrew Jones }
385cb573c2fSEric Auger 
386