]> git.proxmox.com Git - qemu.git/blame - hw/intc/xics.c
xics: replace fprintf with error_report
[qemu.git] / hw / intc / xics.c
CommitLineData
b5cec4c5
DG
1/*
2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
3 *
4 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
5 *
6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 */
27
83c9f4ca 28#include "hw/hw.h"
500efa23 29#include "trace.h"
0d09e41a
PB
30#include "hw/ppc/spapr.h"
31#include "hw/ppc/xics.h"
9ccff2a4 32#include "qemu/error-report.h"
b5cec4c5 33
8ffe04ed
AK
34void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
35{
36 CPUState *cs = CPU(cpu);
37 CPUPPCState *env = &cpu->env;
38 ICPState *ss = &icp->ss[cs->cpu_index];
39
40 assert(cs->cpu_index < icp->nr_servers);
41
42 switch (PPC_INPUT(env)) {
43 case PPC_FLAGS_INPUT_POWER7:
44 ss->output = env->irq_inputs[POWER7_INPUT_INT];
45 break;
46
47 case PPC_FLAGS_INPUT_970:
48 ss->output = env->irq_inputs[PPC970_INPUT_INT];
49 break;
50
51 default:
9ccff2a4
AK
52 error_report("XICS interrupt controller does not support this CPU "
53 "bus model");
8ffe04ed
AK
54 abort();
55 }
56}
57
58static void xics_reset(DeviceState *d)
59{
60 XICSState *icp = XICS(d);
61 int i;
62
63 for (i = 0; i < icp->nr_servers; i++) {
64 device_reset(DEVICE(&icp->ss[i]));
65 }
66
67 device_reset(DEVICE(icp->ics));
68}
69
b5cec4c5
DG
70/*
71 * ICP: Presentation layer
72 */
73
b5cec4c5
DG
74#define XISR_MASK 0x00ffffff
75#define CPPR_MASK 0xff000000
76
77#define XISR(ss) (((ss)->xirr) & XISR_MASK)
78#define CPPR(ss) (((ss)->xirr) >> 24)
79
c04d6cfa
AL
80static void ics_reject(ICSState *ics, int nr);
81static void ics_resend(ICSState *ics);
82static void ics_eoi(ICSState *ics, int nr);
b5cec4c5 83
c04d6cfa 84static void icp_check_ipi(XICSState *icp, int server)
b5cec4c5 85{
c04d6cfa 86 ICPState *ss = icp->ss + server;
b5cec4c5
DG
87
88 if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
89 return;
90 }
91
500efa23
DG
92 trace_xics_icp_check_ipi(server, ss->mfrr);
93
b5cec4c5
DG
94 if (XISR(ss)) {
95 ics_reject(icp->ics, XISR(ss));
96 }
97
98 ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
99 ss->pending_priority = ss->mfrr;
100 qemu_irq_raise(ss->output);
101}
102
c04d6cfa 103static void icp_resend(XICSState *icp, int server)
b5cec4c5 104{
c04d6cfa 105 ICPState *ss = icp->ss + server;
b5cec4c5
DG
106
107 if (ss->mfrr < CPPR(ss)) {
108 icp_check_ipi(icp, server);
109 }
110 ics_resend(icp->ics);
111}
112
c04d6cfa 113static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
b5cec4c5 114{
c04d6cfa 115 ICPState *ss = icp->ss + server;
b5cec4c5
DG
116 uint8_t old_cppr;
117 uint32_t old_xisr;
118
119 old_cppr = CPPR(ss);
120 ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
121
122 if (cppr < old_cppr) {
123 if (XISR(ss) && (cppr <= ss->pending_priority)) {
124 old_xisr = XISR(ss);
125 ss->xirr &= ~XISR_MASK; /* Clear XISR */
e03c902c 126 ss->pending_priority = 0xff;
b5cec4c5
DG
127 qemu_irq_lower(ss->output);
128 ics_reject(icp->ics, old_xisr);
129 }
130 } else {
131 if (!XISR(ss)) {
132 icp_resend(icp, server);
133 }
134 }
135}
136
c04d6cfa 137static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
b5cec4c5 138{
c04d6cfa 139 ICPState *ss = icp->ss + server;
b5cec4c5
DG
140
141 ss->mfrr = mfrr;
142 if (mfrr < CPPR(ss)) {
bf0175de 143 icp_check_ipi(icp, server);
b5cec4c5
DG
144 }
145}
146
c04d6cfa 147static uint32_t icp_accept(ICPState *ss)
b5cec4c5 148{
500efa23 149 uint32_t xirr = ss->xirr;
b5cec4c5
DG
150
151 qemu_irq_lower(ss->output);
b5cec4c5 152 ss->xirr = ss->pending_priority << 24;
e03c902c 153 ss->pending_priority = 0xff;
500efa23
DG
154
155 trace_xics_icp_accept(xirr, ss->xirr);
156
b5cec4c5
DG
157 return xirr;
158}
159
c04d6cfa 160static void icp_eoi(XICSState *icp, int server, uint32_t xirr)
b5cec4c5 161{
c04d6cfa 162 ICPState *ss = icp->ss + server;
b5cec4c5 163
b5cec4c5
DG
164 /* Send EOI -> ICS */
165 ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
500efa23 166 trace_xics_icp_eoi(server, xirr, ss->xirr);
d07fee7e 167 ics_eoi(icp->ics, xirr & XISR_MASK);
b5cec4c5
DG
168 if (!XISR(ss)) {
169 icp_resend(icp, server);
170 }
171}
172
c04d6cfa 173static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority)
b5cec4c5 174{
c04d6cfa 175 ICPState *ss = icp->ss + server;
b5cec4c5 176
500efa23
DG
177 trace_xics_icp_irq(server, nr, priority);
178
b5cec4c5
DG
179 if ((priority >= CPPR(ss))
180 || (XISR(ss) && (ss->pending_priority <= priority))) {
181 ics_reject(icp->ics, nr);
182 } else {
183 if (XISR(ss)) {
184 ics_reject(icp->ics, XISR(ss));
185 }
186 ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
187 ss->pending_priority = priority;
500efa23 188 trace_xics_icp_raise(ss->xirr, ss->pending_priority);
b5cec4c5
DG
189 qemu_irq_raise(ss->output);
190 }
191}
192
c04d6cfa
AL
193static const VMStateDescription vmstate_icp_server = {
194 .name = "icp/server",
195 .version_id = 1,
196 .minimum_version_id = 1,
197 .minimum_version_id_old = 1,
198 .fields = (VMStateField []) {
199 /* Sanity check */
200 VMSTATE_UINT32(xirr, ICPState),
201 VMSTATE_UINT8(pending_priority, ICPState),
202 VMSTATE_UINT8(mfrr, ICPState),
203 VMSTATE_END_OF_LIST()
204 },
b5cec4c5
DG
205};
206
c04d6cfa
AL
207static void icp_reset(DeviceState *dev)
208{
209 ICPState *icp = ICP(dev);
210
211 icp->xirr = 0;
212 icp->pending_priority = 0xff;
213 icp->mfrr = 0xff;
214
215 /* Make all outputs are deasserted */
216 qemu_set_irq(icp->output, 0);
217}
218
219static void icp_class_init(ObjectClass *klass, void *data)
220{
221 DeviceClass *dc = DEVICE_CLASS(klass);
222
223 dc->reset = icp_reset;
224 dc->vmsd = &vmstate_icp_server;
225}
226
227static TypeInfo icp_info = {
228 .name = TYPE_ICP,
229 .parent = TYPE_DEVICE,
230 .instance_size = sizeof(ICPState),
231 .class_init = icp_class_init,
b5cec4c5
DG
232};
233
c04d6cfa
AL
234/*
235 * ICS: Source layer
236 */
237static int ics_valid_irq(ICSState *ics, uint32_t nr)
b5cec4c5
DG
238{
239 return (nr >= ics->offset)
240 && (nr < (ics->offset + ics->nr_irqs));
241}
242
c04d6cfa 243static void resend_msi(ICSState *ics, int srcno)
d07fee7e 244{
c04d6cfa 245 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e
DG
246
247 /* FIXME: filter by server#? */
98ca8c02
DG
248 if (irq->status & XICS_STATUS_REJECTED) {
249 irq->status &= ~XICS_STATUS_REJECTED;
d07fee7e
DG
250 if (irq->priority != 0xff) {
251 icp_irq(ics->icp, irq->server, srcno + ics->offset,
252 irq->priority);
253 }
254 }
255}
256
c04d6cfa 257static void resend_lsi(ICSState *ics, int srcno)
d07fee7e 258{
c04d6cfa 259 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 260
98ca8c02
DG
261 if ((irq->priority != 0xff)
262 && (irq->status & XICS_STATUS_ASSERTED)
263 && !(irq->status & XICS_STATUS_SENT)) {
264 irq->status |= XICS_STATUS_SENT;
d07fee7e
DG
265 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
266 }
267}
268
c04d6cfa 269static void set_irq_msi(ICSState *ics, int srcno, int val)
b5cec4c5 270{
c04d6cfa 271 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 272
500efa23
DG
273 trace_xics_set_irq_msi(srcno, srcno + ics->offset);
274
b5cec4c5
DG
275 if (val) {
276 if (irq->priority == 0xff) {
98ca8c02 277 irq->status |= XICS_STATUS_MASKED_PENDING;
500efa23 278 trace_xics_masked_pending();
b5cec4c5 279 } else {
cc67b9c8 280 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
281 }
282 }
283}
284
c04d6cfa 285static void set_irq_lsi(ICSState *ics, int srcno, int val)
b5cec4c5 286{
c04d6cfa 287 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 288
500efa23 289 trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
98ca8c02
DG
290 if (val) {
291 irq->status |= XICS_STATUS_ASSERTED;
292 } else {
293 irq->status &= ~XICS_STATUS_ASSERTED;
294 }
d07fee7e 295 resend_lsi(ics, srcno);
b5cec4c5
DG
296}
297
d07fee7e 298static void ics_set_irq(void *opaque, int srcno, int val)
b5cec4c5 299{
c04d6cfa 300 ICSState *ics = (ICSState *)opaque;
b5cec4c5 301
22a2611c 302 if (ics->islsi[srcno]) {
d07fee7e
DG
303 set_irq_lsi(ics, srcno, val);
304 } else {
305 set_irq_msi(ics, srcno, val);
306 }
307}
b5cec4c5 308
c04d6cfa 309static void write_xive_msi(ICSState *ics, int srcno)
d07fee7e 310{
c04d6cfa 311 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 312
98ca8c02
DG
313 if (!(irq->status & XICS_STATUS_MASKED_PENDING)
314 || (irq->priority == 0xff)) {
d07fee7e 315 return;
b5cec4c5 316 }
d07fee7e 317
98ca8c02 318 irq->status &= ~XICS_STATUS_MASKED_PENDING;
d07fee7e 319 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
320}
321
c04d6cfa 322static void write_xive_lsi(ICSState *ics, int srcno)
b5cec4c5 323{
d07fee7e
DG
324 resend_lsi(ics, srcno);
325}
326
c04d6cfa 327static void ics_write_xive(ICSState *ics, int nr, int server,
3fe719f4 328 uint8_t priority, uint8_t saved_priority)
d07fee7e
DG
329{
330 int srcno = nr - ics->offset;
c04d6cfa 331 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5
DG
332
333 irq->server = server;
334 irq->priority = priority;
3fe719f4 335 irq->saved_priority = saved_priority;
b5cec4c5 336
500efa23
DG
337 trace_xics_ics_write_xive(nr, srcno, server, priority);
338
22a2611c 339 if (ics->islsi[srcno]) {
d07fee7e
DG
340 write_xive_lsi(ics, srcno);
341 } else {
342 write_xive_msi(ics, srcno);
b5cec4c5 343 }
b5cec4c5
DG
344}
345
c04d6cfa 346static void ics_reject(ICSState *ics, int nr)
b5cec4c5 347{
c04d6cfa 348 ICSIRQState *irq = ics->irqs + nr - ics->offset;
d07fee7e 349
500efa23 350 trace_xics_ics_reject(nr, nr - ics->offset);
98ca8c02
DG
351 irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
352 irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
b5cec4c5
DG
353}
354
c04d6cfa 355static void ics_resend(ICSState *ics)
b5cec4c5 356{
d07fee7e
DG
357 int i;
358
359 for (i = 0; i < ics->nr_irqs; i++) {
d07fee7e 360 /* FIXME: filter by server#? */
22a2611c 361 if (ics->islsi[i]) {
d07fee7e
DG
362 resend_lsi(ics, i);
363 } else {
364 resend_msi(ics, i);
365 }
366 }
b5cec4c5
DG
367}
368
c04d6cfa 369static void ics_eoi(ICSState *ics, int nr)
b5cec4c5 370{
d07fee7e 371 int srcno = nr - ics->offset;
c04d6cfa 372 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 373
500efa23
DG
374 trace_xics_ics_eoi(nr);
375
22a2611c 376 if (ics->islsi[srcno]) {
98ca8c02 377 irq->status &= ~XICS_STATUS_SENT;
d07fee7e 378 }
b5cec4c5
DG
379}
380
c04d6cfa
AL
381static void ics_reset(DeviceState *dev)
382{
383 ICSState *ics = ICS(dev);
384 int i;
385
386 memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
387 for (i = 0; i < ics->nr_irqs; i++) {
388 ics->irqs[i].priority = 0xff;
389 ics->irqs[i].saved_priority = 0xff;
390 }
391}
392
393static int ics_post_load(void *opaque, int version_id)
394{
395 int i;
396 ICSState *ics = opaque;
397
398 for (i = 0; i < ics->icp->nr_servers; i++) {
399 icp_resend(ics->icp, i);
400 }
401
402 return 0;
403}
404
405static const VMStateDescription vmstate_ics_irq = {
406 .name = "ics/irq",
407 .version_id = 1,
408 .minimum_version_id = 1,
409 .minimum_version_id_old = 1,
410 .fields = (VMStateField []) {
411 VMSTATE_UINT32(server, ICSIRQState),
412 VMSTATE_UINT8(priority, ICSIRQState),
413 VMSTATE_UINT8(saved_priority, ICSIRQState),
414 VMSTATE_UINT8(status, ICSIRQState),
415 VMSTATE_END_OF_LIST()
416 },
417};
418
419static const VMStateDescription vmstate_ics = {
420 .name = "ics",
421 .version_id = 1,
422 .minimum_version_id = 1,
423 .minimum_version_id_old = 1,
424 .post_load = ics_post_load,
425 .fields = (VMStateField []) {
426 /* Sanity check */
427 VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
428
429 VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
430 vmstate_ics_irq, ICSIRQState),
431 VMSTATE_END_OF_LIST()
432 },
433};
434
435static int ics_realize(DeviceState *dev)
436{
437 ICSState *ics = ICS(dev);
438
439 ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
440 ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
441 ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
442
443 return 0;
444}
445
446static void ics_class_init(ObjectClass *klass, void *data)
447{
448 DeviceClass *dc = DEVICE_CLASS(klass);
449
450 dc->init = ics_realize;
451 dc->vmsd = &vmstate_ics;
452 dc->reset = ics_reset;
453}
454
455static TypeInfo ics_info = {
456 .name = TYPE_ICS,
457 .parent = TYPE_DEVICE,
458 .instance_size = sizeof(ICSState),
459 .class_init = ics_class_init,
460};
461
b5cec4c5
DG
462/*
463 * Exported functions
464 */
465
c04d6cfa 466qemu_irq xics_get_qirq(XICSState *icp, int irq)
b5cec4c5 467{
1ecbbab4 468 if (!ics_valid_irq(icp->ics, irq)) {
b5cec4c5
DG
469 return NULL;
470 }
471
a307d594
AK
472 return icp->ics->qirqs[irq - icp->ics->offset];
473}
474
c04d6cfa 475void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
a307d594 476{
1ecbbab4 477 assert(ics_valid_irq(icp->ics, irq));
d07fee7e 478
22a2611c 479 icp->ics->islsi[irq - icp->ics->offset] = lsi;
b5cec4c5
DG
480}
481
c04d6cfa
AL
482/*
483 * Guest interfaces
484 */
485
b13ce26d 486static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
487 target_ulong opcode, target_ulong *args)
488{
55e5c285 489 CPUState *cs = CPU(cpu);
b5cec4c5
DG
490 target_ulong cppr = args[0];
491
55e5c285 492 icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
b5cec4c5
DG
493 return H_SUCCESS;
494}
495
b13ce26d 496static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
497 target_ulong opcode, target_ulong *args)
498{
499 target_ulong server = args[0];
500 target_ulong mfrr = args[1];
501
502 if (server >= spapr->icp->nr_servers) {
503 return H_PARAMETER;
504 }
505
506 icp_set_mfrr(spapr->icp, server, mfrr);
507 return H_SUCCESS;
b5cec4c5
DG
508}
509
b13ce26d 510static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
511 target_ulong opcode, target_ulong *args)
512{
55e5c285
AF
513 CPUState *cs = CPU(cpu);
514 uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
b5cec4c5
DG
515
516 args[0] = xirr;
517 return H_SUCCESS;
518}
519
b13ce26d 520static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
521 target_ulong opcode, target_ulong *args)
522{
55e5c285 523 CPUState *cs = CPU(cpu);
b5cec4c5
DG
524 target_ulong xirr = args[0];
525
55e5c285 526 icp_eoi(spapr->icp, cs->cpu_index, xirr);
b5cec4c5
DG
527 return H_SUCCESS;
528}
529
210b580b
AL
530static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
531 uint32_t token,
b5cec4c5
DG
532 uint32_t nargs, target_ulong args,
533 uint32_t nret, target_ulong rets)
534{
c04d6cfa 535 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
536 uint32_t nr, server, priority;
537
538 if ((nargs != 3) || (nret != 1)) {
539 rtas_st(rets, 0, -3);
540 return;
541 }
542
543 nr = rtas_ld(args, 0);
544 server = rtas_ld(args, 1);
545 priority = rtas_ld(args, 2);
546
547 if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
548 || (priority > 0xff)) {
549 rtas_st(rets, 0, -3);
550 return;
551 }
552
3fe719f4 553 ics_write_xive(ics, nr, server, priority, priority);
b5cec4c5
DG
554
555 rtas_st(rets, 0, 0); /* Success */
556}
557
210b580b
AL
558static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
559 uint32_t token,
b5cec4c5
DG
560 uint32_t nargs, target_ulong args,
561 uint32_t nret, target_ulong rets)
562{
c04d6cfa 563 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
564 uint32_t nr;
565
566 if ((nargs != 1) || (nret != 3)) {
567 rtas_st(rets, 0, -3);
568 return;
569 }
570
571 nr = rtas_ld(args, 0);
572
573 if (!ics_valid_irq(ics, nr)) {
574 rtas_st(rets, 0, -3);
575 return;
576 }
577
578 rtas_st(rets, 0, 0); /* Success */
579 rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
580 rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
581}
582
210b580b
AL
583static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
584 uint32_t token,
b5cec4c5
DG
585 uint32_t nargs, target_ulong args,
586 uint32_t nret, target_ulong rets)
587{
c04d6cfa 588 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
589 uint32_t nr;
590
591 if ((nargs != 1) || (nret != 1)) {
592 rtas_st(rets, 0, -3);
593 return;
594 }
595
596 nr = rtas_ld(args, 0);
597
598 if (!ics_valid_irq(ics, nr)) {
599 rtas_st(rets, 0, -3);
600 return;
601 }
602
3fe719f4
DG
603 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
604 ics->irqs[nr - ics->offset].priority);
b5cec4c5
DG
605
606 rtas_st(rets, 0, 0); /* Success */
607}
608
210b580b
AL
609static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
610 uint32_t token,
b5cec4c5
DG
611 uint32_t nargs, target_ulong args,
612 uint32_t nret, target_ulong rets)
613{
c04d6cfa 614 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
615 uint32_t nr;
616
617 if ((nargs != 1) || (nret != 1)) {
618 rtas_st(rets, 0, -3);
619 return;
620 }
621
622 nr = rtas_ld(args, 0);
623
624 if (!ics_valid_irq(ics, nr)) {
625 rtas_st(rets, 0, -3);
626 return;
627 }
628
3fe719f4
DG
629 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
630 ics->irqs[nr - ics->offset].saved_priority,
631 ics->irqs[nr - ics->offset].saved_priority);
b5cec4c5
DG
632
633 rtas_st(rets, 0, 0); /* Success */
634}
635
c04d6cfa
AL
636/*
637 * XICS
638 */
639
c04d6cfa 640static void xics_realize(DeviceState *dev, Error **errp)
7b565160 641{
c04d6cfa
AL
642 XICSState *icp = XICS(dev);
643 ICSState *ics = icp->ics;
644 int i;
b5cec4c5 645
33a0e5d8
AK
646 /* Registration of global state belongs into realize */
647 spapr_rtas_register("ibm,set-xive", rtas_set_xive);
648 spapr_rtas_register("ibm,get-xive", rtas_get_xive);
649 spapr_rtas_register("ibm,int-off", rtas_int_off);
650 spapr_rtas_register("ibm,int-on", rtas_int_on);
651
652 spapr_register_hypercall(H_CPPR, h_cppr);
653 spapr_register_hypercall(H_IPI, h_ipi);
654 spapr_register_hypercall(H_XIRR, h_xirr);
655 spapr_register_hypercall(H_EOI, h_eoi);
656
c04d6cfa 657 ics->nr_irqs = icp->nr_irqs;
bf3bc4c4 658 ics->offset = XICS_IRQ_BASE;
b5cec4c5 659 ics->icp = icp;
c04d6cfa 660 qdev_init_nofail(DEVICE(ics));
b5cec4c5 661
c04d6cfa
AL
662 icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
663 for (i = 0; i < icp->nr_servers; i++) {
664 char buffer[32];
213f0c4f 665 object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
c04d6cfa
AL
666 snprintf(buffer, sizeof(buffer), "icp[%d]", i);
667 object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL);
668 qdev_init_nofail(DEVICE(&icp->ss[i]));
669 }
670}
b5cec4c5 671
c04d6cfa
AL
672static void xics_initfn(Object *obj)
673{
674 XICSState *xics = XICS(obj);
675
676 xics->ics = ICS(object_new(TYPE_ICS));
677 object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
678}
679
680static Property xics_properties[] = {
681 DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1),
682 DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1),
683 DEFINE_PROP_END_OF_LIST(),
684};
685
686static void xics_class_init(ObjectClass *oc, void *data)
687{
688 DeviceClass *dc = DEVICE_CLASS(oc);
689
690 dc->realize = xics_realize;
691 dc->props = xics_properties;
692 dc->reset = xics_reset;
c04d6cfa
AL
693}
694
695static const TypeInfo xics_info = {
696 .name = TYPE_XICS,
697 .parent = TYPE_SYS_BUS_DEVICE,
698 .instance_size = sizeof(XICSState),
699 .class_init = xics_class_init,
700 .instance_init = xics_initfn,
701};
256b408a 702
c04d6cfa
AL
703static void xics_register_types(void)
704{
705 type_register_static(&xics_info);
706 type_register_static(&ics_info);
707 type_register_static(&icp_info);
b5cec4c5 708}
c04d6cfa
AL
709
710type_init(xics_register_types)