aio-posix: remove useless parameter
[qemu/ar7.git] / hw / intc / xics_spapr.c
blob618826dacf0b15c536ed1190b1c9f2ccc091645d
1 /*
2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
4 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
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"
39 * Guest interfaces
42 static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
43 target_ulong opcode, target_ulong *args)
45 CPUState *cs = CPU(cpu);
46 target_ulong cppr = args[0];
48 icp_set_cppr(spapr->xics, cs->cpu_index, cppr);
49 return H_SUCCESS;
52 static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
53 target_ulong opcode, target_ulong *args)
55 target_ulong server = xics_get_cpu_index_by_dt_id(args[0]);
56 target_ulong mfrr = args[1];
58 if (server >= spapr->xics->nr_servers) {
59 return H_PARAMETER;
62 icp_set_mfrr(spapr->xics, server, mfrr);
63 return H_SUCCESS;
66 static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
67 target_ulong opcode, target_ulong *args)
69 CPUState *cs = CPU(cpu);
70 uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index);
72 args[0] = xirr;
73 return H_SUCCESS;
76 static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
77 target_ulong opcode, target_ulong *args)
79 CPUState *cs = CPU(cpu);
80 ICPState *ss = &spapr->xics->ss[cs->cpu_index];
81 uint32_t xirr = icp_accept(ss);
83 args[0] = xirr;
84 args[1] = cpu_get_host_ticks();
85 return H_SUCCESS;
88 static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
89 target_ulong opcode, target_ulong *args)
91 CPUState *cs = CPU(cpu);
92 target_ulong xirr = args[0];
94 icp_eoi(spapr->xics, cs->cpu_index, xirr);
95 return H_SUCCESS;
98 static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
99 target_ulong opcode, target_ulong *args)
101 CPUState *cs = CPU(cpu);
102 uint32_t mfrr;
103 uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr);
105 args[0] = xirr;
106 args[1] = mfrr;
108 return H_SUCCESS;
111 static 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)
116 ICSState *ics = spapr->xics->ics;
117 uint32_t nr, server, priority;
119 if ((nargs != 3) || (nret != 1)) {
120 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
121 return;
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);
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;
134 ics_write_xive(ics, nr, server, priority, priority);
136 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
139 static 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)
144 ICSState *ics = spapr->xics->ics;
145 uint32_t nr;
147 if ((nargs != 1) || (nret != 3)) {
148 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
149 return;
152 nr = rtas_ld(args, 0);
154 if (!ics_valid_irq(ics, nr)) {
155 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
156 return;
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);
164 static 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)
169 ICSState *ics = spapr->xics->ics;
170 uint32_t nr;
172 if ((nargs != 1) || (nret != 1)) {
173 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
174 return;
177 nr = rtas_ld(args, 0);
179 if (!ics_valid_irq(ics, nr)) {
180 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
181 return;
184 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
185 ics->irqs[nr - ics->offset].priority);
187 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
190 static 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)
195 ICSState *ics = spapr->xics->ics;
196 uint32_t nr;
198 if ((nargs != 1) || (nret != 1)) {
199 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
200 return;
203 nr = rtas_ld(args, 0);
205 if (!ics_valid_irq(ics, nr)) {
206 rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
207 return;
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);
214 rtas_st(rets, 0, RTAS_OUT_SUCCESS);
217 static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
218 Error **errp)
220 xics->nr_irqs = xics->ics->nr_irqs = nr_irqs;
223 static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers,
224 Error **errp)
226 int i;
228 xics->nr_servers = nr_servers;
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);
240 static void xics_spapr_realize(DeviceState *dev, Error **errp)
242 XICSState *xics = XICS_SPAPR(dev);
243 Error *error = NULL;
244 int i;
246 if (!xics->nr_servers) {
247 error_setg(errp, "Number of servers needs to be greater 0");
248 return;
251 /* Registration of global state belongs into realize */
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);
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);
264 object_property_set_bool(OBJECT(xics->ics), true, "realized", &error);
265 if (error) {
266 error_propagate(errp, error);
267 return;
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;
280 static void xics_spapr_initfn(Object *obj)
282 XICSState *xics = XICS_SPAPR(obj);
284 xics->ics = ICS(object_new(TYPE_ICS));
285 object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
286 xics->ics->xics = xics;
289 static void xics_spapr_class_init(ObjectClass *oc, void *data)
291 DeviceClass *dc = DEVICE_CLASS(oc);
292 XICSStateClass *xsc = XICS_SPAPR_CLASS(oc);
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;
299 static 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,
308 #define ICS_IRQ_FREE(ics, srcno) \
309 (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
311 static int ics_find_free_block(ICSState *ics, int num, int alignnum)
313 int first, i;
315 for (first = 0; first < ics->nr_irqs; first += alignnum) {
316 if (num > (ics->nr_irqs - first)) {
317 return -1;
319 for (i = first; i < first + num; ++i) {
320 if (!ICS_IRQ_FREE(ics, i)) {
321 break;
324 if (i == (first + num)) {
325 return first;
329 return -1;
332 int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi,
333 Error **errp)
335 ICSState *ics = &xics->ics[src];
336 int irq;
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;
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;
351 irq += ics->offset;
354 ics_set_irq_type(ics, irq - ics->offset, lsi);
355 trace_xics_alloc(src, irq);
357 return irq;
361 * Allocate block of consecutive IRQs, and return the number of the first IRQ in
362 * the block. If align==true, aligns the first IRQ number to num.
364 int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi,
365 bool align, Error **errp)
367 int i, first = -1;
368 ICSState *ics = &xics->ics[src];
370 assert(src == 0);
372 * MSIMesage::data is used for storing VIRQ so
373 * it has to be aligned to num to support multiple
374 * MSI vectors. MSI-X is not affected by this.
375 * The hint is used for the first IRQ, the rest should
376 * be allocated continuously.
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);
385 if (first < 0) {
386 error_setg(errp, "can't find a free %d-IRQ block", num);
387 return -1;
390 if (first >= 0) {
391 for (i = first; i < first + num; ++i) {
392 ics_set_irq_type(ics, i, lsi);
395 first += ics->offset;
397 trace_xics_alloc_block(src, first, num, lsi, align);
399 return first;
402 static void ics_free(ICSState *ics, int srcno, int num)
404 int i;
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);
410 memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
414 void xics_spapr_free(XICSState *xics, int irq, int num)
416 int src = xics_find_source(xics, irq);
418 if (src >= 0) {
419 ICSState *ics = &xics->ics[src];
421 /* FIXME: implement multiple sources */
422 assert(src == 0);
424 trace_xics_ics_free(ics - xics->ics, irq, num);
425 ics_free(ics, irq - ics->offset, num);
429 static void xics_spapr_register_types(void)
431 type_register_static(&xics_spapr_info);
434 type_init(xics_spapr_register_types)