xref: /kvm-unit-tests/lib/arm/gic.c (revision e526bc786e9878c3880ae4b09b01a4572756e492)
1 /*
2  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
3  *
4  * This work is licensed under the terms of the GNU LGPL, version 2.
5  */
6 #include <acpi.h>
7 #include <devicetree.h>
8 #include <asm/gic.h>
9 #include <asm/io.h>
10 
11 struct gicv2_data gicv2_data;
12 struct gicv3_data gicv3_data;
13 struct its_data its_data;
14 
15 struct gic_common_ops {
16 	void (*enable_defaults)(void);
17 	u32 (*read_iar)(void);
18 	u32 (*iar_irqnr)(u32 iar);
19 	void (*write_eoir)(u32 irqstat);
20 	void (*ipi_send_single)(int irq, int cpu);
21 	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
22 };
23 
24 static const struct gic_common_ops *gic_common_ops;
25 
26 static const struct gic_common_ops gicv2_common_ops = {
27 	.enable_defaults = gicv2_enable_defaults,
28 	.read_iar = gicv2_read_iar,
29 	.iar_irqnr = gicv2_iar_irqnr,
30 	.write_eoir = gicv2_write_eoir,
31 	.ipi_send_single = gicv2_ipi_send_single,
32 	.ipi_send_mask = gicv2_ipi_send_mask,
33 };
34 
35 static const struct gic_common_ops gicv3_common_ops = {
36 	.enable_defaults = gicv3_enable_defaults,
37 	.read_iar = gicv3_read_iar,
38 	.iar_irqnr = gicv3_iar_irqnr,
39 	.write_eoir = gicv3_write_eoir,
40 	.ipi_send_single = gicv3_ipi_send_single,
41 	.ipi_send_mask = gicv3_ipi_send_mask,
42 };
43 
44 /*
45  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
46  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
47  */
48 static bool
gic_get_dt_bases(const char * compatible,void ** base1,void ** base2,void ** base3)49 gic_get_dt_bases(const char *compatible, void **base1, void **base2, void **base3)
50 {
51 	struct dt_pbus_reg reg;
52 	struct dt_device gic, its;
53 	struct dt_bus bus;
54 	int node, subnode, ret, i, len;
55 	const void *fdt = dt_fdt();
56 
57 	dt_bus_init_defaults(&bus);
58 	dt_device_init(&gic, &bus, NULL);
59 
60 	node = dt_device_find_compatible(&gic, compatible);
61 	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
62 
63 	if (node == -FDT_ERR_NOTFOUND)
64 		return false;
65 
66 	dt_device_bind_node(&gic, node);
67 
68 	ret = dt_pbus_translate(&gic, 0, &reg);
69 	assert(ret == 0);
70 	*base1 = ioremap(reg.addr, reg.size);
71 
72 	for (i = 0; i < GICV3_NR_REDISTS; ++i) {
73 		ret = dt_pbus_translate(&gic, i + 1, &reg);
74 		if (ret == -FDT_ERR_NOTFOUND)
75 			break;
76 		assert(ret == 0);
77 		base2[i] = ioremap(reg.addr, reg.size);
78 	}
79 
80 	if (!base3) {
81 		assert(!strcmp(compatible, "arm,cortex-a15-gic"));
82 		return true;
83 	}
84 
85 	assert(!strcmp(compatible, "arm,gic-v3"));
86 
87 	dt_for_each_subnode(node, subnode) {
88 		const struct fdt_property *prop;
89 
90 		prop = fdt_get_property(fdt, subnode, "compatible", &len);
91 		if (!strcmp((char *)prop->data, "arm,gic-v3-its")) {
92 			dt_device_bind_node(&its, subnode);
93 			ret = dt_pbus_translate(&its, 0, &reg);
94 			assert(ret == 0);
95 			*base3 = ioremap(reg.addr, reg.size);
96 			break;
97 		}
98 	}
99 
100 	return true;
101 }
102 
gicv2_init(void)103 int gicv2_init(void)
104 {
105 	return gic_get_dt_bases("arm,cortex-a15-gic",
106 			&gicv2_data.dist_base, &gicv2_data.cpu_base, NULL);
107 }
108 
gicv3_init(void)109 int gicv3_init(void)
110 {
111 	return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
112 			&gicv3_data.redist_bases[0], &its_data.base);
113 }
114 
gic_version(void)115 int gic_version(void)
116 {
117 	if (gic_common_ops == &gicv2_common_ops)
118 		return 2;
119 	else if (gic_common_ops == &gicv3_common_ops)
120 		return 3;
121 	return 0;
122 }
123 
gic_init_fdt(void)124 static int gic_init_fdt(void)
125 {
126 	if (gicv2_init()) {
127 		gic_common_ops = &gicv2_common_ops;
128 	} else if (gicv3_init()) {
129 		gic_common_ops = &gicv3_common_ops;
130 #ifdef __aarch64__
131 		its_init();
132 #endif
133 	}
134 	return gic_version();
135 }
136 
137 #ifdef CONFIG_EFI
138 
139 #define ACPI_GICV2_DIST_MEM_SIZE	(SZ_4K)
140 #define ACPI_GIC_CPU_IF_MEM_SIZE	(SZ_8K)
141 #define ACPI_GICV3_DIST_MEM_SIZE	(SZ_64K)
142 #define ACPI_GICV3_ITS_MEM_SIZE		(SZ_128K)
143 
gic_acpi_version(struct acpi_subtable_header * header)144 static int gic_acpi_version(struct acpi_subtable_header *header)
145 {
146 	struct acpi_madt_generic_distributor *dist = (void *)header;
147 	int version = dist->version;
148 
149 	if (version == 2)
150 		gic_common_ops = &gicv2_common_ops;
151 	else if (version == 3)
152 		gic_common_ops = &gicv3_common_ops;
153 
154 	return version;
155 }
156 
gicv2_acpi_parse_madt_cpu(struct acpi_subtable_header * header)157 static int gicv2_acpi_parse_madt_cpu(struct acpi_subtable_header *header)
158 {
159 	struct acpi_madt_generic_interrupt *gicc = (void *)header;
160 	static phys_addr_t gicc_base_address;
161 
162 	if (!(gicc->flags & ACPI_MADT_ENABLED))
163 		return 0;
164 
165 	if (!gicc_base_address) {
166 		gicc_base_address = gicc->base_address;
167 		gicv2_data.cpu_base = ioremap(gicc_base_address, ACPI_GIC_CPU_IF_MEM_SIZE);
168 	}
169 	assert(gicc_base_address == gicc->base_address);
170 
171 	return 0;
172 }
173 
gicv2_acpi_parse_madt_dist(struct acpi_subtable_header * header)174 static int gicv2_acpi_parse_madt_dist(struct acpi_subtable_header *header)
175 {
176 	struct acpi_madt_generic_distributor *dist = (void *)header;
177 
178 	gicv2_data.dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
179 
180 	return 0;
181 }
182 
gicv3_acpi_parse_madt_gicc(struct acpi_subtable_header * header)183 static int gicv3_acpi_parse_madt_gicc(struct acpi_subtable_header *header)
184 {
185 	struct acpi_madt_generic_interrupt *gicc = (void *)header;
186 	static phys_addr_t gicr_base_address;
187 
188 	if (!(gicc->flags & ACPI_MADT_ENABLED))
189 		return 0;
190 
191 	if (!gicr_base_address) {
192 		gicr_base_address = gicc->gicr_base_address;
193 		gicv3_data.redist_bases[0] = ioremap(gicr_base_address, SZ_64K * 2);
194 	}
195 	assert(gicr_base_address == gicc->gicr_base_address);
196 
197 	return 0;
198 }
199 
gicv3_acpi_parse_madt_dist(struct acpi_subtable_header * header)200 static int gicv3_acpi_parse_madt_dist(struct acpi_subtable_header *header)
201 {
202 	struct acpi_madt_generic_distributor *dist = (void *)header;
203 
204 	gicv3_data.dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
205 
206 	return 0;
207 }
208 
gicv3_acpi_parse_madt_redist(struct acpi_subtable_header * header)209 static int gicv3_acpi_parse_madt_redist(struct acpi_subtable_header *header)
210 {
211 	static int i;
212 	struct acpi_madt_generic_redistributor *redist = (void *)header;
213 
214 	gicv3_data.redist_bases[i++] = ioremap(redist->base_address, redist->length);
215 
216 	return 0;
217 }
218 
gicv3_acpi_parse_madt_its(struct acpi_subtable_header * header)219 static int gicv3_acpi_parse_madt_its(struct acpi_subtable_header *header)
220 {
221 	struct acpi_madt_generic_translator *its_entry = (void *)header;
222 
223 	its_data.base = ioremap(its_entry->base_address, ACPI_GICV3_ITS_MEM_SIZE - 1);
224 
225 	return 0;
226 }
227 
gic_init_acpi(void)228 static int gic_init_acpi(void)
229 {
230 	int count;
231 
232 	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, gic_acpi_version);
233 	if (gic_version() == 2) {
234 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
235 				     gicv2_acpi_parse_madt_cpu);
236 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
237 				      gicv2_acpi_parse_madt_dist);
238 	} else if (gic_version() == 3) {
239 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
240 				      gicv3_acpi_parse_madt_dist);
241 		count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
242 					      gicv3_acpi_parse_madt_redist);
243 		if (!count)
244 			acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
245 					      gicv3_acpi_parse_madt_gicc);
246 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
247 				      gicv3_acpi_parse_madt_its);
248 #ifdef __aarch64__
249 		its_init();
250 #endif
251 	}
252 
253 	return gic_version();
254 }
255 
256 #else
257 
gic_init_acpi(void)258 static int gic_init_acpi(void)
259 {
260 	assert_msg(false, "ACPI not available");
261 }
262 
263 #endif /* CONFIG_EFI */
264 
gic_init(void)265 int gic_init(void)
266 {
267 	if (dt_available())
268 		return gic_init_fdt();
269 	else
270 		return gic_init_acpi();
271 }
272 
gic_enable_defaults(void)273 void gic_enable_defaults(void)
274 {
275 	if (!gic_common_ops) {
276 		int ret = gic_init();
277 		assert(ret != 0);
278 	} else
279 		assert(gic_common_ops->enable_defaults);
280 	gic_common_ops->enable_defaults();
281 }
282 
gic_read_iar(void)283 u32 gic_read_iar(void)
284 {
285 	assert(gic_common_ops && gic_common_ops->read_iar);
286 	return gic_common_ops->read_iar();
287 }
288 
gic_iar_irqnr(u32 iar)289 u32 gic_iar_irqnr(u32 iar)
290 {
291 	assert(gic_common_ops && gic_common_ops->iar_irqnr);
292 	return gic_common_ops->iar_irqnr(iar);
293 }
294 
gic_write_eoir(u32 irqstat)295 void gic_write_eoir(u32 irqstat)
296 {
297 	assert(gic_common_ops && gic_common_ops->write_eoir);
298 	gic_common_ops->write_eoir(irqstat);
299 }
300 
gic_ipi_send_single(int irq,int cpu)301 void gic_ipi_send_single(int irq, int cpu)
302 {
303 	assert(gic_common_ops && gic_common_ops->ipi_send_single);
304 	gic_common_ops->ipi_send_single(irq, cpu);
305 }
306 
gic_ipi_send_mask(int irq,const cpumask_t * dest)307 void gic_ipi_send_mask(int irq, const cpumask_t *dest)
308 {
309 	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
310 	gic_common_ops->ipi_send_mask(irq, dest);
311 }
312 
gic_irq_set_clr_enable(int irq,bool enable)313 void gic_irq_set_clr_enable(int irq, bool enable)
314 {
315 	u32 offset, split = 32, shift = (irq % 32);
316 	void *base;
317 
318 	assert(irq < 1020);
319 
320 	switch (gic_version()) {
321 	case 2:
322 		offset = enable ? GICD_ISENABLER : GICD_ICENABLER;
323 		base = gicv2_dist_base();
324 		break;
325 	case 3:
326 		if (irq < 32) {
327 			offset = enable ? GICR_ISENABLER0 : GICR_ICENABLER0;
328 			base = gicv3_sgi_base();
329 		} else {
330 			offset = enable ? GICD_ISENABLER : GICD_ICENABLER;
331 			base = gicv3_dist_base();
332 		}
333 		break;
334 	default:
335 		assert(0);
336 	}
337 	base += offset + (irq / split) * 4;
338 	writel(BIT(shift), base);
339 }
340 
gic_irq_state(int irq)341 enum gic_irq_state gic_irq_state(int irq)
342 {
343 	enum gic_irq_state state;
344 	void *ispendr, *isactiver;
345 	bool pending, active;
346 	int offset, mask;
347 
348 	assert(gic_common_ops);
349 	assert(irq < 1020);
350 
351 	switch (gic_version()) {
352 	case 2:
353 		ispendr = gicv2_dist_base() + GICD_ISPENDR;
354 		isactiver = gicv2_dist_base() + GICD_ISACTIVER;
355 		break;
356 	case 3:
357 		if (irq < GIC_NR_PRIVATE_IRQS) {
358 			ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
359 			isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
360 		} else {
361 			ispendr = gicv3_dist_base() + GICD_ISPENDR;
362 			isactiver = gicv3_dist_base() + GICD_ISACTIVER;
363 		}
364 		break;
365 	default:
366 		assert(0);
367 	}
368 
369 	offset = irq / 32 * 4;
370 	mask = 1 << (irq % 32);
371 	pending = readl(ispendr + offset) & mask;
372 	active = readl(isactiver + offset) & mask;
373 
374 	if (!active && !pending)
375 		state = GIC_IRQ_STATE_INACTIVE;
376 	if (pending)
377 		state = GIC_IRQ_STATE_PENDING;
378 	if (active)
379 		state = GIC_IRQ_STATE_ACTIVE;
380 	if (active && pending)
381 		state = GIC_IRQ_STATE_ACTIVE_PENDING;
382 
383 	return state;
384 }
385 
386