1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include "qemu/osdep.h"
29#include "cpu.h"
30#include "hw/hw.h"
31#include "trace.h"
32#include "qemu/timer.h"
33#include "hw/ppc/spapr.h"
34#include "hw/ppc/xics.h"
35#include "qapi/visitor.h"
36#include "qapi/error.h"
37
38
39
40
41
42static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
43 target_ulong opcode, target_ulong *args)
44{
45 CPUState *cs = CPU(cpu);
46 target_ulong cppr = args[0];
47
48 icp_set_cppr(spapr->xics, cs->cpu_index, cppr);
49 return H_SUCCESS;
50}
51
52static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
53 target_ulong opcode, target_ulong *args)
54{
55 target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
56 target_ulong mfrr = args[1];
57
58 if (server >= spapr->xics->nr_servers) {
59 return H_PARAMETER;
60 }
61
62 icp_set_mfrr(spapr->xics, server, mfrr);
63 return H_SUCCESS;
64}
65
66static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
67 target_ulong opcode, target_ulong *args)
68{
69 CPUState *cs = CPU(cpu);
70 uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index);
71
72 args[0] = xirr;
73 return H_SUCCESS;
74}
75
76static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
77 target_ulong opcode, target_ulong *args)
78{
79 CPUState *cs = CPU(cpu);
80 ICPState *ss = &spapr->xics->ss[cs->cpu_index];
81 uint32_t xirr = icp_accept(ss);
82
83 args[0] = xirr;
84 args[1] = cpu_get_host_ticks();
85 return H_SUCCESS;
86}
87
88static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
89 target_ulong opcode, target_ulong *args)
90{
91 CPUState *cs = CPU(cpu);
92 target_ulong xirr = args[0];
93
94 icp_eoi(spapr->xics, cs->cpu_index, xirr);
95 return H_SUCCESS;
96}
97
98static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
99 target_ulong opcode, target_ulong *args)
100{
101 CPUState *cs = CPU(cpu);
102 uint32_t mfrr;
103 uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr);
104
105 args[0] = xirr;
106 args[1] = mfrr;
107
108 return H_SUCCESS;
109}
110
111static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
112 uint32_t token,
113 uint32_t nargs, target_ulong args,
114 uint32_t nret, target_ulong rets)
115{
116 ICSState *ics = spapr->xics->ics;
117 uint32_t nr, server, priority;
118
119 if ((nargs != 3) || (nret != 1)) {
120 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
121 return;
122 }
123
124 nr = rtas_ld(args, 0);
125 server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1));
126 priority = rtas_ld(args, 2);
127
128 if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers)
129 || (priority > 0xff)) {
130 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
131 return;
132 }
133
134 ics_write_xive(ics, nr, server, priority, priority);
135
136 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
137}
138
139static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr,
140 uint32_t token,
141 uint32_t nargs, target_ulong args,
142 uint32_t nret, target_ulong rets)
143{
144 ICSState *ics = spapr->xics->ics;
145 uint32_t nr;
146
147 if ((nargs != 1) || (nret != 3)) {
148 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
149 return;
150 }
151
152 nr = rtas_ld(args, 0);
153
154 if (!ics_valid_irq(ics, nr)) {
155 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
156 return;
157 }
158
159 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
160 rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
161 rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
162}
163
164static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr,
165 uint32_t token,
166 uint32_t nargs, target_ulong args,
167 uint32_t nret, target_ulong rets)
168{
169 ICSState *ics = spapr->xics->ics;
170 uint32_t nr;
171
172 if ((nargs != 1) || (nret != 1)) {
173 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
174 return;
175 }
176
177 nr = rtas_ld(args, 0);
178
179 if (!ics_valid_irq(ics, nr)) {
180 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
181 return;
182 }
183
184 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
185 ics->irqs[nr - ics->offset].priority);
186
187 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
188}
189
190static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr,
191 uint32_t token,
192 uint32_t nargs, target_ulong args,
193 uint32_t nret, target_ulong rets)
194{
195 ICSState *ics = spapr->xics->ics;
196 uint32_t nr;
197
198 if ((nargs != 1) || (nret != 1)) {
199 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
200 return;
201 }
202
203 nr = rtas_ld(args, 0);
204
205 if (!ics_valid_irq(ics, nr)) {
206 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
207 return;
208 }
209
210 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
211 ics->irqs[nr - ics->offset].saved_priority,
212 ics->irqs[nr - ics->offset].saved_priority);
213
214 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
215}
216
217static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
218 Error **errp)
219{
220 xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
221}
222
223static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
224 Error **errp)
225{
226 int i;
227
228 xics->nr_servers = nr_servers;
229
230 xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState));
231 for (i = 0; i < xics->nr_servers; i++) {
232 char buffer[32];
233 object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP);
234 snprintf(buffer, sizeof(buffer), "icp[%d]", i);
235 object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]),
236 errp);
237 }
238}
239
240static void xics_spapr_realize(DeviceState *dev, Error **errp)
241{
242 XICSState *xics = XICS_SPAPR(dev);
243 Error *error = NULL;
244 int i;
245
246 if (!xics->nr_servers) {
247 error_setg(errp, "Number of servers needs to be greater 0");
248 return;
249 }
250
251
252 spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
253 spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
254 spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
255 spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on);
256
257 spapr_register_hypercall(H_CPPR, h_cppr);
258 spapr_register_hypercall(H_IPI, h_ipi);
259 spapr_register_hypercall(H_XIRR, h_xirr);
260 spapr_register_hypercall(H_XIRR_X, h_xirr_x);
261 spapr_register_hypercall(H_EOI, h_eoi);
262 spapr_register_hypercall(H_IPOLL, h_ipoll);
263
264 object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
265 if (error) {
266 error_propagate(errp, error);
267 return;
268 }
269
270 for (i = 0; i < xics->nr_servers; i++) {
271 object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized",
272 &error);
273 if (error) {
274 error_propagate(errp, error);
275 return;
276 }
277 }
278}
279
280static void xics_spapr_initfn(Object *obj)
281{
282 XICSState *xics = XICS_SPAPR(obj);
283
284 xics->ics = ICS(object_new(TYPE_ICS));
285 object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
286 xics->ics->xics = xics;
287}
288
289static void xics_spapr_class_init(ObjectClass *oc, void *data)
290{
291 DeviceClass *dc = DEVICE_CLASS(oc);
292 XICSStateClass *xsc = XICS_SPAPR_CLASS(oc);
293
294 dc->realize = xics_spapr_realize;
295 xsc->set_nr_irqs = xics_spapr_set_nr_irqs;
296 xsc->set_nr_servers = xics_spapr_set_nr_servers;
297}
298
299static const TypeInfo xics_spapr_info = {
300 .name = TYPE_XICS_SPAPR,
301 .parent = TYPE_XICS_COMMON,
302 .instance_size = sizeof(XICSState),
303 .class_size = sizeof(XICSStateClass),
304 .class_init = xics_spapr_class_init,
305 .instance_init = xics_spapr_initfn,
306};
307
308#define ICS_IRQ_FREE(ics, srcno) \
309 (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
310
311static int ics_find_free_block(ICSState *ics, int num, int alignnum)
312{
313 int first, i;
314
315 for (first = 0; first < ics->nr_irqs; first += alignnum) {
316 if (num > (ics->nr_irqs - first)) {
317 return -1;
318 }
319 for (i = first; i < first + num; ++i) {
320 if (!ICS_IRQ_FREE(ics, i)) {
321 break;
322 }
323 }
324 if (i == (first + num)) {
325 return first;
326 }
327 }
328
329 return -1;
330}
331
332int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
333 Error **errp)
334{
335 ICSState *ics = &xics->ics[src];
336 int irq;
337
338 if (irq_hint) {
339 assert(src == xics_find_source(xics, irq_hint));
340 if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) {
341 error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint);
342 return -1;
343 }
344 irq = irq_hint;
345 } else {
346 irq = ics_find_free_block(ics, 1, 1);
347 if (irq < 0) {
348 error_setg(errp, "can't allocate IRQ: no IRQ left");
349 return -1;
350 }
351 irq += ics->offset;
352 }
353
354 ics_set_irq_type(ics, irq - ics->offset, lsi);
355 trace_xics_alloc(src, irq);
356
357 return irq;
358}
359
360
361
362
363
364int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
365 bool align, Error **errp)
366{
367 int i, first = -1;
368 ICSState *ics = &xics->ics[src];
369
370 assert(src == 0);
371
372
373
374
375
376
377
378 if (align) {
379 assert((num == 1) || (num == 2) || (num == 4) ||
380 (num == 8) || (num == 16) || (num == 32));
381 first = ics_find_free_block(ics, num, num);
382 } else {
383 first = ics_find_free_block(ics, num, 1);
384 }
385 if (first < 0) {
386 error_setg(errp, "can't find a free %d-IRQ block", num);
387 return -1;
388 }
389
390 if (first >= 0) {
391 for (i = first; i < first + num; ++i) {
392 ics_set_irq_type(ics, i, lsi);
393 }
394 }
395 first += ics->offset;
396
397 trace_xics_alloc_block(src, first, num, lsi, align);
398
399 return first;
400}
401
402static void ics_free(ICSState *ics, int srcno, int num)
403{
404 int i;
405
406 for (i = srcno; i < srcno + num; ++i) {
407 if (ICS_IRQ_FREE(ics, i)) {
408 trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset);
409 }
410 memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
411 }
412}
413
414void xics_spapr_free(XICSState *xics, int irq, int num)
415{
416 int src = xics_find_source(xics, irq);
417
418 if (src >= 0) {
419 ICSState *ics = &xics->ics[src];
420
421
422 assert(src == 0);
423
424 trace_xics_ics_free(ics - xics->ics, irq, num);
425 ics_free(ics, irq - ics->offset, num);
426 }
427}
428
429static void xics_spapr_register_types(void)
430{
431 type_register_static(&xics_spapr_info);
432}
433
434type_init(xics_spapr_register_types)
435