1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "gic_internal.h"
23#include "qapi/error.h"
24#include "hw/fdt_generic_util.h"
25
26#include "hw/fdt_generic_devices.h"
27
28static void gic_pre_save(void *opaque)
29{
30 GICState *s = (GICState *)opaque;
31 ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
32
33 if (c->pre_save) {
34 c->pre_save(s);
35 }
36}
37
38static int gic_post_load(void *opaque, int version_id)
39{
40 GICState *s = (GICState *)opaque;
41 ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
42
43 if (c->post_load) {
44 c->post_load(s);
45 }
46 return 0;
47}
48
49static const VMStateDescription vmstate_gic_irq_state = {
50 .name = "arm_gic_irq_state",
51 .version_id = 1,
52 .minimum_version_id = 1,
53 .fields = (VMStateField[]) {
54 VMSTATE_UINT8(enabled, gic_irq_state),
55 VMSTATE_UINT8(pending, gic_irq_state),
56 VMSTATE_UINT8(active, gic_irq_state),
57 VMSTATE_UINT8(level, gic_irq_state),
58 VMSTATE_BOOL(model, gic_irq_state),
59 VMSTATE_BOOL(edge_trigger, gic_irq_state),
60 VMSTATE_END_OF_LIST()
61 }
62};
63
64static const VMStateDescription vmstate_gic = {
65 .name = "arm_gic",
66 .version_id = 8,
67 .minimum_version_id = 8,
68 .pre_save = gic_pre_save,
69 .post_load = gic_post_load,
70 .fields = (VMStateField[]) {
71 VMSTATE_BOOL(enabled, GICState),
72 VMSTATE_UINT32_ARRAY(ctrl, GICState, GIC_NCPU),
73 VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
74 vmstate_gic_irq_state, gic_irq_state),
75 VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
76 VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
77 VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
78 VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
79 VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
80 VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
81 VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
82 VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
83 VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
84 VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
85 VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
86 VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
87 VMSTATE_UINT32_ARRAY(gich.hcr, GICState, GIC_N_REALCPU),
88 VMSTATE_UINT32_ARRAY(gich.vtr, GICState, GIC_N_REALCPU),
89 VMSTATE_UINT32_ARRAY(gich.misr, GICState, GIC_N_REALCPU),
90 VMSTATE_UINT64_ARRAY(gich.eisr, GICState, GIC_N_REALCPU),
91 VMSTATE_UINT64_ARRAY(gich.elrsr, GICState, GIC_N_REALCPU),
92 VMSTATE_UINT32_ARRAY(gich.apr, GICState, GIC_N_REALCPU),
93 VMSTATE_UINT32_2DARRAY(gich.lr, GICState, GIC_N_REALCPU, GICV_NR_LR),
94 VMSTATE_UINT32_ARRAY(gich.pending_prio, GICState, GIC_N_REALCPU),
95 VMSTATE_UINT8_ARRAY(gich.pending_lrn, GICState, GIC_N_REALCPU),
96 VMSTATE_END_OF_LIST()
97 }
98};
99
100static void arm_gic_common_realize(DeviceState *dev, Error **errp)
101{
102 GICState *s = ARM_GIC_COMMON(dev);
103 int num_irq = s->num_irq;
104
105 if (!s->num_cpu) {
106 s->num_cpu = fdt_generic_num_cpus;
107 }
108
109 if (s->num_cpu > GIC_NCPU) {
110 error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
111 s->num_cpu, GIC_NCPU);
112 return;
113 }
114 s->num_irq += GIC_BASE_IRQ;
115 if (s->num_irq > GIC_MAXIRQ) {
116 error_setg(errp,
117 "requested %u interrupt lines exceeds GIC maximum %d",
118 num_irq, GIC_MAXIRQ);
119 return;
120 }
121
122
123
124
125 if (s->num_irq < 32 || (s->num_irq % 32)) {
126 error_setg(errp,
127 "%d interrupt lines unsupported: not divisible by 32",
128 num_irq);
129 return;
130 }
131}
132
133static void arm_gic_common_reset(DeviceState *dev)
134{
135 GICState *s = ARM_GIC_COMMON(dev);
136 int i;
137 memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
138 for (i = 0 ; i < GIC_NCPU; i++) {
139 if (s->revision == REV_11MPCORE) {
140 s->priority_mask[i] = 0xf0;
141 } else {
142 s->priority_mask[i] = 0;
143 }
144 s->current_pending[i] = 1023;
145 s->running_irq[i] = 1023;
146 s->running_priority[i] = 0x100;
147 s->ctrl[i] = 0;
148 }
149 for (i = 0; i < GIC_NR_SGIS; i++) {
150 GIC_SET_ENABLED(i, ALL_CPU_MASK);
151 GIC_SET_EDGE_TRIGGER(i);
152 }
153 if (s->num_cpu == 1) {
154
155 for (i = 0; i < GIC_MAXIRQ; i++) {
156 s->irq_target[i] = 1;
157 }
158 }
159 if (!s->c_iidr) {
160 s->c_iidr |= s->revision << 16;
161 s->c_iidr |= 0x43B;
162 }
163 s->enabled = false;
164}
165
166static int arm_gic_common_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
167 uint32_t *cells, int ncells, int max,
168 Error **errp)
169{
170 GICState *gs = ARM_GIC_COMMON(obj);
171 int cpu = 0;
172 uint32_t idx;
173
174 if (ncells != 3) {
175 error_setg(errp, "ARM GIC requires 3 interrupt cells, %d cells given",
176 ncells);
177 return 0;
178 }
179 idx = cells[1];
180
181 switch (cells[0]) {
182 case 0:
183 if (idx >= gs->num_irq) {
184 error_setg(errp, "ARM GIC SPI has maximum index of %" PRId32 ", "
185 "index %" PRId32 " given", gs->num_irq - 1, idx);
186 return 0;
187 }
188 (*irqs) = qdev_get_gpio_in(DEVICE(obj), cells[1]);
189 return 1;
190 case 1:
191 if (idx >= 16) {
192 error_setg(errp, "ARM GIC PPI has maximum index of 15, "
193 "index %" PRId32 " given", idx);
194 return 0;
195 }
196 for (cpu = 0; cpu < max && cpu < gs->num_cpu; cpu++) {
197 if (cells[2] & 1 << (cpu + 8)) {
198 *irqs = qdev_get_gpio_in(DEVICE(obj),
199 gs->num_irq - 16 + idx + cpu * 32);
200 }
201 irqs++;
202 }
203 return cpu;
204 default:
205 error_setg(errp, "Invalid cell 0 value in interrupt binding: %d",
206 cells[0]);
207 return 0;
208 }
209}
210
211static Property arm_gic_common_properties[] = {
212 DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 0),
213 DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 96),
214
215
216
217
218 DEFINE_PROP_UINT32("revision", GICState, revision, 1),
219 DEFINE_PROP_BOOL("disable-linux-gic-init", GICState,
220 disable_linux_gic_init, false),
221 DEFINE_PROP_UINT32("map-stride", GICState, map_stride, 0x1000),
222
223 DEFINE_PROP_UINT32("int-id", GICState, c_iidr, 0),
224 DEFINE_PROP_END_OF_LIST(),
225};
226
227static void arm_gic_common_class_init(ObjectClass *klass, void *data)
228{
229 DeviceClass *dc = DEVICE_CLASS(klass);
230 FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(klass);
231
232 dc->reset = arm_gic_common_reset;
233 dc->realize = arm_gic_common_realize;
234 dc->props = arm_gic_common_properties;
235 dc->vmsd = &vmstate_gic;
236 fgic->get_irq = arm_gic_common_fdt_get_irq;
237}
238
239static const TypeInfo arm_gic_common_type = {
240 .name = TYPE_ARM_GIC_COMMON,
241 .parent = TYPE_SYS_BUS_DEVICE,
242 .instance_size = sizeof(GICState),
243 .class_size = sizeof(ARMGICCommonClass),
244 .class_init = arm_gic_common_class_init,
245 .interfaces = (InterfaceInfo[]) {
246 { TYPE_FDT_GENERIC_INTC },
247 { TYPE_FDT_GENERIC_GPIO },
248 { }
249 },
250 .abstract = true,
251};
252
253static void register_types(void)
254{
255 type_register_static(&arm_gic_common_type);
256}
257
258type_init(register_types)
259