xref: /kvm-unit-tests/lib/arm/gic.c (revision ea325c68ce3352eff179970b908fb9eb9a37c205)
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 <devicetree.h>
7 #include <asm/gic.h>
8 #include <asm/io.h>
9 
10 struct gicv2_data gicv2_data;
11 struct gicv3_data gicv3_data;
12 
13 struct gic_common_ops {
14 	int gic_version;
15 	void (*enable_defaults)(void);
16 	u32 (*read_iar)(void);
17 	u32 (*iar_irqnr)(u32 iar);
18 	void (*write_eoir)(u32 irqstat);
19 	void (*ipi_send_single)(int irq, int cpu);
20 	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
21 };
22 
23 static const struct gic_common_ops *gic_common_ops;
24 
25 static const struct gic_common_ops gicv2_common_ops = {
26 	.gic_version = 2,
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 	.gic_version = 3,
37 	.enable_defaults = gicv3_enable_defaults,
38 	.read_iar = gicv3_read_iar,
39 	.iar_irqnr = gicv3_iar_irqnr,
40 	.write_eoir = gicv3_write_eoir,
41 	.ipi_send_single = gicv3_ipi_send_single,
42 	.ipi_send_mask = gicv3_ipi_send_mask,
43 };
44 
45 /*
46  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
47  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
48  */
49 static bool
50 gic_get_dt_bases(const char *compatible, void **base1, void **base2)
51 {
52 	struct dt_pbus_reg reg;
53 	struct dt_device gic;
54 	struct dt_bus bus;
55 	int node, ret;
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 	ret = dt_pbus_translate(&gic, 1, &reg);
73 	assert(ret == 0);
74 	*base2 = ioremap(reg.addr, reg.size);
75 
76 	return true;
77 }
78 
79 int gicv2_init(void)
80 {
81 	return gic_get_dt_bases("arm,cortex-a15-gic",
82 			&gicv2_data.dist_base, &gicv2_data.cpu_base);
83 }
84 
85 int gicv3_init(void)
86 {
87 	return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
88 			&gicv3_data.redist_base[0]);
89 }
90 
91 int gic_init(void)
92 {
93 	if (gicv2_init()) {
94 		gic_common_ops = &gicv2_common_ops;
95 		return 2;
96 	} else if (gicv3_init()) {
97 		gic_common_ops = &gicv3_common_ops;
98 		return 3;
99 	}
100 	return 0;
101 }
102 
103 void gic_enable_defaults(void)
104 {
105 	if (!gic_common_ops) {
106 		int ret = gic_init();
107 		assert(ret != 0);
108 	} else
109 		assert(gic_common_ops->enable_defaults);
110 	gic_common_ops->enable_defaults();
111 }
112 
113 int gic_version(void)
114 {
115 	assert(gic_common_ops);
116 	return gic_common_ops->gic_version;
117 }
118 
119 u32 gic_read_iar(void)
120 {
121 	assert(gic_common_ops && gic_common_ops->read_iar);
122 	return gic_common_ops->read_iar();
123 }
124 
125 u32 gic_iar_irqnr(u32 iar)
126 {
127 	assert(gic_common_ops && gic_common_ops->iar_irqnr);
128 	return gic_common_ops->iar_irqnr(iar);
129 }
130 
131 void gic_write_eoir(u32 irqstat)
132 {
133 	assert(gic_common_ops && gic_common_ops->write_eoir);
134 	gic_common_ops->write_eoir(irqstat);
135 }
136 
137 void gic_ipi_send_single(int irq, int cpu)
138 {
139 	assert(gic_common_ops && gic_common_ops->ipi_send_single);
140 	gic_common_ops->ipi_send_single(irq, cpu);
141 }
142 
143 void gic_ipi_send_mask(int irq, const cpumask_t *dest)
144 {
145 	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
146 	gic_common_ops->ipi_send_mask(irq, dest);
147 }
148