]> Git Repo - qemu.git/blame - hw/intc/xics.c
xics: split to xics and xics-common
[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"
5a3d7b23 33#include "qapi/visitor.h"
b5cec4c5 34
8ffe04ed
AK
35void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
36{
37 CPUState *cs = CPU(cpu);
38 CPUPPCState *env = &cpu->env;
39 ICPState *ss = &icp->ss[cs->cpu_index];
40
41 assert(cs->cpu_index < icp->nr_servers);
42
43 switch (PPC_INPUT(env)) {
44 case PPC_FLAGS_INPUT_POWER7:
45 ss->output = env->irq_inputs[POWER7_INPUT_INT];
46 break;
47
48 case PPC_FLAGS_INPUT_970:
49 ss->output = env->irq_inputs[PPC970_INPUT_INT];
50 break;
51
52 default:
9ccff2a4
AK
53 error_report("XICS interrupt controller does not support this CPU "
54 "bus model");
8ffe04ed
AK
55 abort();
56 }
57}
58
5a3d7b23
AK
59/*
60 * XICS Common class - parent for emulated XICS and KVM-XICS
61 */
62static void xics_common_reset(DeviceState *d)
8ffe04ed 63{
5a3d7b23 64 XICSState *icp = XICS_COMMON(d);
8ffe04ed
AK
65 int i;
66
67 for (i = 0; i < icp->nr_servers; i++) {
68 device_reset(DEVICE(&icp->ss[i]));
69 }
70
71 device_reset(DEVICE(icp->ics));
72}
73
5a3d7b23
AK
74static void xics_prop_get_nr_irqs(Object *obj, Visitor *v,
75 void *opaque, const char *name, Error **errp)
76{
77 XICSState *icp = XICS_COMMON(obj);
78 int64_t value = icp->nr_irqs;
79
80 visit_type_int(v, &value, name, errp);
81}
82
83static void xics_prop_set_nr_irqs(Object *obj, Visitor *v,
84 void *opaque, const char *name, Error **errp)
85{
86 XICSState *icp = XICS_COMMON(obj);
87 XICSStateClass *info = XICS_COMMON_GET_CLASS(icp);
88 Error *error = NULL;
89 int64_t value;
90
91 visit_type_int(v, &value, name, &error);
92 if (error) {
93 error_propagate(errp, error);
94 return;
95 }
96 if (icp->nr_irqs) {
97 error_setg(errp, "Number of interrupts is already set to %u",
98 icp->nr_irqs);
99 return;
100 }
101
102 assert(info->set_nr_irqs);
103 assert(icp->ics);
104 info->set_nr_irqs(icp, value, errp);
105}
106
107static void xics_prop_get_nr_servers(Object *obj, Visitor *v,
108 void *opaque, const char *name,
109 Error **errp)
110{
111 XICSState *icp = XICS_COMMON(obj);
112 int64_t value = icp->nr_servers;
113
114 visit_type_int(v, &value, name, errp);
115}
116
117static void xics_prop_set_nr_servers(Object *obj, Visitor *v,
118 void *opaque, const char *name,
119 Error **errp)
120{
121 XICSState *icp = XICS_COMMON(obj);
122 XICSStateClass *info = XICS_COMMON_GET_CLASS(icp);
123 Error *error = NULL;
124 int64_t value;
125
126 visit_type_int(v, &value, name, &error);
127 if (error) {
128 error_propagate(errp, error);
129 return;
130 }
131 if (icp->nr_servers) {
132 error_setg(errp, "Number of servers is already set to %u",
133 icp->nr_servers);
134 return;
135 }
136
137 assert(info->set_nr_servers);
138 info->set_nr_servers(icp, value, errp);
139}
140
141static void xics_common_initfn(Object *obj)
142{
143 object_property_add(obj, "nr_irqs", "int",
144 xics_prop_get_nr_irqs, xics_prop_set_nr_irqs,
145 NULL, NULL, NULL);
146 object_property_add(obj, "nr_servers", "int",
147 xics_prop_get_nr_servers, xics_prop_set_nr_servers,
148 NULL, NULL, NULL);
149}
150
151static void xics_common_class_init(ObjectClass *oc, void *data)
152{
153 DeviceClass *dc = DEVICE_CLASS(oc);
154
155 dc->reset = xics_common_reset;
156}
157
158static const TypeInfo xics_common_info = {
159 .name = TYPE_XICS_COMMON,
160 .parent = TYPE_SYS_BUS_DEVICE,
161 .instance_size = sizeof(XICSState),
162 .class_size = sizeof(XICSStateClass),
163 .instance_init = xics_common_initfn,
164 .class_init = xics_common_class_init,
165};
166
b5cec4c5
DG
167/*
168 * ICP: Presentation layer
169 */
170
b5cec4c5
DG
171#define XISR_MASK 0x00ffffff
172#define CPPR_MASK 0xff000000
173
174#define XISR(ss) (((ss)->xirr) & XISR_MASK)
175#define CPPR(ss) (((ss)->xirr) >> 24)
176
c04d6cfa
AL
177static void ics_reject(ICSState *ics, int nr);
178static void ics_resend(ICSState *ics);
179static void ics_eoi(ICSState *ics, int nr);
b5cec4c5 180
c04d6cfa 181static void icp_check_ipi(XICSState *icp, int server)
b5cec4c5 182{
c04d6cfa 183 ICPState *ss = icp->ss + server;
b5cec4c5
DG
184
185 if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
186 return;
187 }
188
500efa23
DG
189 trace_xics_icp_check_ipi(server, ss->mfrr);
190
b5cec4c5
DG
191 if (XISR(ss)) {
192 ics_reject(icp->ics, XISR(ss));
193 }
194
195 ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
196 ss->pending_priority = ss->mfrr;
197 qemu_irq_raise(ss->output);
198}
199
c04d6cfa 200static void icp_resend(XICSState *icp, int server)
b5cec4c5 201{
c04d6cfa 202 ICPState *ss = icp->ss + server;
b5cec4c5
DG
203
204 if (ss->mfrr < CPPR(ss)) {
205 icp_check_ipi(icp, server);
206 }
207 ics_resend(icp->ics);
208}
209
c04d6cfa 210static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
b5cec4c5 211{
c04d6cfa 212 ICPState *ss = icp->ss + server;
b5cec4c5
DG
213 uint8_t old_cppr;
214 uint32_t old_xisr;
215
216 old_cppr = CPPR(ss);
217 ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
218
219 if (cppr < old_cppr) {
220 if (XISR(ss) && (cppr <= ss->pending_priority)) {
221 old_xisr = XISR(ss);
222 ss->xirr &= ~XISR_MASK; /* Clear XISR */
e03c902c 223 ss->pending_priority = 0xff;
b5cec4c5
DG
224 qemu_irq_lower(ss->output);
225 ics_reject(icp->ics, old_xisr);
226 }
227 } else {
228 if (!XISR(ss)) {
229 icp_resend(icp, server);
230 }
231 }
232}
233
c04d6cfa 234static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
b5cec4c5 235{
c04d6cfa 236 ICPState *ss = icp->ss + server;
b5cec4c5
DG
237
238 ss->mfrr = mfrr;
239 if (mfrr < CPPR(ss)) {
bf0175de 240 icp_check_ipi(icp, server);
b5cec4c5
DG
241 }
242}
243
c04d6cfa 244static uint32_t icp_accept(ICPState *ss)
b5cec4c5 245{
500efa23 246 uint32_t xirr = ss->xirr;
b5cec4c5
DG
247
248 qemu_irq_lower(ss->output);
b5cec4c5 249 ss->xirr = ss->pending_priority << 24;
e03c902c 250 ss->pending_priority = 0xff;
500efa23
DG
251
252 trace_xics_icp_accept(xirr, ss->xirr);
253
b5cec4c5
DG
254 return xirr;
255}
256
c04d6cfa 257static void icp_eoi(XICSState *icp, int server, uint32_t xirr)
b5cec4c5 258{
c04d6cfa 259 ICPState *ss = icp->ss + server;
b5cec4c5 260
b5cec4c5
DG
261 /* Send EOI -> ICS */
262 ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
500efa23 263 trace_xics_icp_eoi(server, xirr, ss->xirr);
d07fee7e 264 ics_eoi(icp->ics, xirr & XISR_MASK);
b5cec4c5
DG
265 if (!XISR(ss)) {
266 icp_resend(icp, server);
267 }
268}
269
c04d6cfa 270static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority)
b5cec4c5 271{
c04d6cfa 272 ICPState *ss = icp->ss + server;
b5cec4c5 273
500efa23
DG
274 trace_xics_icp_irq(server, nr, priority);
275
b5cec4c5
DG
276 if ((priority >= CPPR(ss))
277 || (XISR(ss) && (ss->pending_priority <= priority))) {
278 ics_reject(icp->ics, nr);
279 } else {
280 if (XISR(ss)) {
281 ics_reject(icp->ics, XISR(ss));
282 }
283 ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
284 ss->pending_priority = priority;
500efa23 285 trace_xics_icp_raise(ss->xirr, ss->pending_priority);
b5cec4c5
DG
286 qemu_irq_raise(ss->output);
287 }
288}
289
d1b5682d
AK
290static void icp_dispatch_pre_save(void *opaque)
291{
292 ICPState *ss = opaque;
293 ICPStateClass *info = ICP_GET_CLASS(ss);
294
295 if (info->pre_save) {
296 info->pre_save(ss);
297 }
298}
299
300static int icp_dispatch_post_load(void *opaque, int version_id)
301{
302 ICPState *ss = opaque;
303 ICPStateClass *info = ICP_GET_CLASS(ss);
304
305 if (info->post_load) {
306 return info->post_load(ss, version_id);
307 }
308
309 return 0;
310}
311
c04d6cfa
AL
312static const VMStateDescription vmstate_icp_server = {
313 .name = "icp/server",
314 .version_id = 1,
315 .minimum_version_id = 1,
316 .minimum_version_id_old = 1,
d1b5682d
AK
317 .pre_save = icp_dispatch_pre_save,
318 .post_load = icp_dispatch_post_load,
c04d6cfa
AL
319 .fields = (VMStateField []) {
320 /* Sanity check */
321 VMSTATE_UINT32(xirr, ICPState),
322 VMSTATE_UINT8(pending_priority, ICPState),
323 VMSTATE_UINT8(mfrr, ICPState),
324 VMSTATE_END_OF_LIST()
325 },
b5cec4c5
DG
326};
327
c04d6cfa
AL
328static void icp_reset(DeviceState *dev)
329{
330 ICPState *icp = ICP(dev);
331
332 icp->xirr = 0;
333 icp->pending_priority = 0xff;
334 icp->mfrr = 0xff;
335
336 /* Make all outputs are deasserted */
337 qemu_set_irq(icp->output, 0);
338}
339
340static void icp_class_init(ObjectClass *klass, void *data)
341{
342 DeviceClass *dc = DEVICE_CLASS(klass);
343
344 dc->reset = icp_reset;
345 dc->vmsd = &vmstate_icp_server;
346}
347
456df19c 348static const TypeInfo icp_info = {
c04d6cfa
AL
349 .name = TYPE_ICP,
350 .parent = TYPE_DEVICE,
351 .instance_size = sizeof(ICPState),
352 .class_init = icp_class_init,
d1b5682d 353 .class_size = sizeof(ICPStateClass),
b5cec4c5
DG
354};
355
c04d6cfa
AL
356/*
357 * ICS: Source layer
358 */
359static int ics_valid_irq(ICSState *ics, uint32_t nr)
b5cec4c5
DG
360{
361 return (nr >= ics->offset)
362 && (nr < (ics->offset + ics->nr_irqs));
363}
364
c04d6cfa 365static void resend_msi(ICSState *ics, int srcno)
d07fee7e 366{
c04d6cfa 367 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e
DG
368
369 /* FIXME: filter by server#? */
98ca8c02
DG
370 if (irq->status & XICS_STATUS_REJECTED) {
371 irq->status &= ~XICS_STATUS_REJECTED;
d07fee7e
DG
372 if (irq->priority != 0xff) {
373 icp_irq(ics->icp, irq->server, srcno + ics->offset,
374 irq->priority);
375 }
376 }
377}
378
c04d6cfa 379static void resend_lsi(ICSState *ics, int srcno)
d07fee7e 380{
c04d6cfa 381 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 382
98ca8c02
DG
383 if ((irq->priority != 0xff)
384 && (irq->status & XICS_STATUS_ASSERTED)
385 && !(irq->status & XICS_STATUS_SENT)) {
386 irq->status |= XICS_STATUS_SENT;
d07fee7e
DG
387 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
388 }
389}
390
c04d6cfa 391static void set_irq_msi(ICSState *ics, int srcno, int val)
b5cec4c5 392{
c04d6cfa 393 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 394
500efa23
DG
395 trace_xics_set_irq_msi(srcno, srcno + ics->offset);
396
b5cec4c5
DG
397 if (val) {
398 if (irq->priority == 0xff) {
98ca8c02 399 irq->status |= XICS_STATUS_MASKED_PENDING;
500efa23 400 trace_xics_masked_pending();
b5cec4c5 401 } else {
cc67b9c8 402 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
403 }
404 }
405}
406
c04d6cfa 407static void set_irq_lsi(ICSState *ics, int srcno, int val)
b5cec4c5 408{
c04d6cfa 409 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 410
500efa23 411 trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
98ca8c02
DG
412 if (val) {
413 irq->status |= XICS_STATUS_ASSERTED;
414 } else {
415 irq->status &= ~XICS_STATUS_ASSERTED;
416 }
d07fee7e 417 resend_lsi(ics, srcno);
b5cec4c5
DG
418}
419
d07fee7e 420static void ics_set_irq(void *opaque, int srcno, int val)
b5cec4c5 421{
c04d6cfa 422 ICSState *ics = (ICSState *)opaque;
b5cec4c5 423
22a2611c 424 if (ics->islsi[srcno]) {
d07fee7e
DG
425 set_irq_lsi(ics, srcno, val);
426 } else {
427 set_irq_msi(ics, srcno, val);
428 }
429}
b5cec4c5 430
c04d6cfa 431static void write_xive_msi(ICSState *ics, int srcno)
d07fee7e 432{
c04d6cfa 433 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 434
98ca8c02
DG
435 if (!(irq->status & XICS_STATUS_MASKED_PENDING)
436 || (irq->priority == 0xff)) {
d07fee7e 437 return;
b5cec4c5 438 }
d07fee7e 439
98ca8c02 440 irq->status &= ~XICS_STATUS_MASKED_PENDING;
d07fee7e 441 icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
442}
443
c04d6cfa 444static void write_xive_lsi(ICSState *ics, int srcno)
b5cec4c5 445{
d07fee7e
DG
446 resend_lsi(ics, srcno);
447}
448
c04d6cfa 449static void ics_write_xive(ICSState *ics, int nr, int server,
3fe719f4 450 uint8_t priority, uint8_t saved_priority)
d07fee7e
DG
451{
452 int srcno = nr - ics->offset;
c04d6cfa 453 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5
DG
454
455 irq->server = server;
456 irq->priority = priority;
3fe719f4 457 irq->saved_priority = saved_priority;
b5cec4c5 458
500efa23
DG
459 trace_xics_ics_write_xive(nr, srcno, server, priority);
460
22a2611c 461 if (ics->islsi[srcno]) {
d07fee7e
DG
462 write_xive_lsi(ics, srcno);
463 } else {
464 write_xive_msi(ics, srcno);
b5cec4c5 465 }
b5cec4c5
DG
466}
467
c04d6cfa 468static void ics_reject(ICSState *ics, int nr)
b5cec4c5 469{
c04d6cfa 470 ICSIRQState *irq = ics->irqs + nr - ics->offset;
d07fee7e 471
500efa23 472 trace_xics_ics_reject(nr, nr - ics->offset);
98ca8c02
DG
473 irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
474 irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
b5cec4c5
DG
475}
476
c04d6cfa 477static void ics_resend(ICSState *ics)
b5cec4c5 478{
d07fee7e
DG
479 int i;
480
481 for (i = 0; i < ics->nr_irqs; i++) {
d07fee7e 482 /* FIXME: filter by server#? */
22a2611c 483 if (ics->islsi[i]) {
d07fee7e
DG
484 resend_lsi(ics, i);
485 } else {
486 resend_msi(ics, i);
487 }
488 }
b5cec4c5
DG
489}
490
c04d6cfa 491static void ics_eoi(ICSState *ics, int nr)
b5cec4c5 492{
d07fee7e 493 int srcno = nr - ics->offset;
c04d6cfa 494 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 495
500efa23
DG
496 trace_xics_ics_eoi(nr);
497
22a2611c 498 if (ics->islsi[srcno]) {
98ca8c02 499 irq->status &= ~XICS_STATUS_SENT;
d07fee7e 500 }
b5cec4c5
DG
501}
502
c04d6cfa
AL
503static void ics_reset(DeviceState *dev)
504{
505 ICSState *ics = ICS(dev);
506 int i;
507
508 memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
509 for (i = 0; i < ics->nr_irqs; i++) {
510 ics->irqs[i].priority = 0xff;
511 ics->irqs[i].saved_priority = 0xff;
512 }
513}
514
d1b5682d 515static int ics_post_load(ICSState *ics, int version_id)
c04d6cfa
AL
516{
517 int i;
c04d6cfa
AL
518
519 for (i = 0; i < ics->icp->nr_servers; i++) {
520 icp_resend(ics->icp, i);
521 }
522
523 return 0;
524}
525
d1b5682d
AK
526static void ics_dispatch_pre_save(void *opaque)
527{
528 ICSState *ics = opaque;
529 ICSStateClass *info = ICS_GET_CLASS(ics);
530
531 if (info->pre_save) {
532 info->pre_save(ics);
533 }
534}
535
536static int ics_dispatch_post_load(void *opaque, int version_id)
537{
538 ICSState *ics = opaque;
539 ICSStateClass *info = ICS_GET_CLASS(ics);
540
541 if (info->post_load) {
542 return info->post_load(ics, version_id);
543 }
544
545 return 0;
546}
547
c04d6cfa
AL
548static const VMStateDescription vmstate_ics_irq = {
549 .name = "ics/irq",
550 .version_id = 1,
551 .minimum_version_id = 1,
552 .minimum_version_id_old = 1,
553 .fields = (VMStateField []) {
554 VMSTATE_UINT32(server, ICSIRQState),
555 VMSTATE_UINT8(priority, ICSIRQState),
556 VMSTATE_UINT8(saved_priority, ICSIRQState),
557 VMSTATE_UINT8(status, ICSIRQState),
558 VMSTATE_END_OF_LIST()
559 },
560};
561
562static const VMStateDescription vmstate_ics = {
563 .name = "ics",
564 .version_id = 1,
565 .minimum_version_id = 1,
566 .minimum_version_id_old = 1,
d1b5682d
AK
567 .pre_save = ics_dispatch_pre_save,
568 .post_load = ics_dispatch_post_load,
c04d6cfa
AL
569 .fields = (VMStateField []) {
570 /* Sanity check */
571 VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
572
573 VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
574 vmstate_ics_irq, ICSIRQState),
575 VMSTATE_END_OF_LIST()
576 },
577};
578
5a3d7b23
AK
579static void ics_initfn(Object *obj)
580{
581 ICSState *ics = ICS(obj);
582
583 ics->offset = XICS_IRQ_BASE;
584}
585
b45ff2d9 586static void ics_realize(DeviceState *dev, Error **errp)
c04d6cfa
AL
587{
588 ICSState *ics = ICS(dev);
589
b45ff2d9
AK
590 if (!ics->nr_irqs) {
591 error_setg(errp, "Number of interrupts needs to be greater 0");
592 return;
593 }
c04d6cfa
AL
594 ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
595 ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
596 ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
c04d6cfa
AL
597}
598
599static void ics_class_init(ObjectClass *klass, void *data)
600{
601 DeviceClass *dc = DEVICE_CLASS(klass);
d1b5682d 602 ICSStateClass *isc = ICS_CLASS(klass);
c04d6cfa 603
b45ff2d9 604 dc->realize = ics_realize;
c04d6cfa
AL
605 dc->vmsd = &vmstate_ics;
606 dc->reset = ics_reset;
d1b5682d 607 isc->post_load = ics_post_load;
c04d6cfa
AL
608}
609
456df19c 610static const TypeInfo ics_info = {
c04d6cfa
AL
611 .name = TYPE_ICS,
612 .parent = TYPE_DEVICE,
613 .instance_size = sizeof(ICSState),
614 .class_init = ics_class_init,
d1b5682d 615 .class_size = sizeof(ICSStateClass),
5a3d7b23 616 .instance_init = ics_initfn,
c04d6cfa
AL
617};
618
b5cec4c5
DG
619/*
620 * Exported functions
621 */
622
c04d6cfa 623qemu_irq xics_get_qirq(XICSState *icp, int irq)
b5cec4c5 624{
1ecbbab4 625 if (!ics_valid_irq(icp->ics, irq)) {
b5cec4c5
DG
626 return NULL;
627 }
628
a307d594
AK
629 return icp->ics->qirqs[irq - icp->ics->offset];
630}
631
c04d6cfa 632void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
a307d594 633{
1ecbbab4 634 assert(ics_valid_irq(icp->ics, irq));
d07fee7e 635
22a2611c 636 icp->ics->islsi[irq - icp->ics->offset] = lsi;
b5cec4c5
DG
637}
638
c04d6cfa
AL
639/*
640 * Guest interfaces
641 */
642
b13ce26d 643static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
644 target_ulong opcode, target_ulong *args)
645{
55e5c285 646 CPUState *cs = CPU(cpu);
b5cec4c5
DG
647 target_ulong cppr = args[0];
648
55e5c285 649 icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
b5cec4c5
DG
650 return H_SUCCESS;
651}
652
b13ce26d 653static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
654 target_ulong opcode, target_ulong *args)
655{
656 target_ulong server = args[0];
657 target_ulong mfrr = args[1];
658
659 if (server >= spapr->icp->nr_servers) {
660 return H_PARAMETER;
661 }
662
663 icp_set_mfrr(spapr->icp, server, mfrr);
664 return H_SUCCESS;
b5cec4c5
DG
665}
666
b13ce26d 667static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
668 target_ulong opcode, target_ulong *args)
669{
55e5c285
AF
670 CPUState *cs = CPU(cpu);
671 uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
b5cec4c5
DG
672
673 args[0] = xirr;
674 return H_SUCCESS;
675}
676
b13ce26d 677static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
b5cec4c5
DG
678 target_ulong opcode, target_ulong *args)
679{
55e5c285 680 CPUState *cs = CPU(cpu);
b5cec4c5
DG
681 target_ulong xirr = args[0];
682
55e5c285 683 icp_eoi(spapr->icp, cs->cpu_index, xirr);
b5cec4c5
DG
684 return H_SUCCESS;
685}
686
210b580b
AL
687static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
688 uint32_t token,
b5cec4c5
DG
689 uint32_t nargs, target_ulong args,
690 uint32_t nret, target_ulong rets)
691{
c04d6cfa 692 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
693 uint32_t nr, server, priority;
694
695 if ((nargs != 3) || (nret != 1)) {
696 rtas_st(rets, 0, -3);
697 return;
698 }
699
700 nr = rtas_ld(args, 0);
701 server = rtas_ld(args, 1);
702 priority = rtas_ld(args, 2);
703
704 if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
705 || (priority > 0xff)) {
706 rtas_st(rets, 0, -3);
707 return;
708 }
709
3fe719f4 710 ics_write_xive(ics, nr, server, priority, priority);
b5cec4c5
DG
711
712 rtas_st(rets, 0, 0); /* Success */
713}
714
210b580b
AL
715static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
716 uint32_t token,
b5cec4c5
DG
717 uint32_t nargs, target_ulong args,
718 uint32_t nret, target_ulong rets)
719{
c04d6cfa 720 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
721 uint32_t nr;
722
723 if ((nargs != 1) || (nret != 3)) {
724 rtas_st(rets, 0, -3);
725 return;
726 }
727
728 nr = rtas_ld(args, 0);
729
730 if (!ics_valid_irq(ics, nr)) {
731 rtas_st(rets, 0, -3);
732 return;
733 }
734
735 rtas_st(rets, 0, 0); /* Success */
736 rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
737 rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
738}
739
210b580b
AL
740static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
741 uint32_t token,
b5cec4c5
DG
742 uint32_t nargs, target_ulong args,
743 uint32_t nret, target_ulong rets)
744{
c04d6cfa 745 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
746 uint32_t nr;
747
748 if ((nargs != 1) || (nret != 1)) {
749 rtas_st(rets, 0, -3);
750 return;
751 }
752
753 nr = rtas_ld(args, 0);
754
755 if (!ics_valid_irq(ics, nr)) {
756 rtas_st(rets, 0, -3);
757 return;
758 }
759
3fe719f4
DG
760 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
761 ics->irqs[nr - ics->offset].priority);
b5cec4c5
DG
762
763 rtas_st(rets, 0, 0); /* Success */
764}
765
210b580b
AL
766static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
767 uint32_t token,
b5cec4c5
DG
768 uint32_t nargs, target_ulong args,
769 uint32_t nret, target_ulong rets)
770{
c04d6cfa 771 ICSState *ics = spapr->icp->ics;
b5cec4c5
DG
772 uint32_t nr;
773
774 if ((nargs != 1) || (nret != 1)) {
775 rtas_st(rets, 0, -3);
776 return;
777 }
778
779 nr = rtas_ld(args, 0);
780
781 if (!ics_valid_irq(ics, nr)) {
782 rtas_st(rets, 0, -3);
783 return;
784 }
785
3fe719f4
DG
786 ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
787 ics->irqs[nr - ics->offset].saved_priority,
788 ics->irqs[nr - ics->offset].saved_priority);
b5cec4c5
DG
789
790 rtas_st(rets, 0, 0); /* Success */
791}
792
c04d6cfa
AL
793/*
794 * XICS
795 */
796
5a3d7b23
AK
797static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp)
798{
799 icp->nr_irqs = icp->ics->nr_irqs = nr_irqs;
800}
801
802static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers,
803 Error **errp)
804{
805 int i;
806
807 icp->nr_servers = nr_servers;
808
809 icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
810 for (i = 0; i < icp->nr_servers; i++) {
811 char buffer[32];
812 object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
813 snprintf(buffer, sizeof(buffer), "icp[%d]", i);
814 object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]),
815 errp);
816 }
817}
818
c04d6cfa 819static void xics_realize(DeviceState *dev, Error **errp)
7b565160 820{
c04d6cfa 821 XICSState *icp = XICS(dev);
b45ff2d9 822 Error *error = NULL;
c04d6cfa 823 int i;
b5cec4c5 824
b45ff2d9
AK
825 if (!icp->nr_servers) {
826 error_setg(errp, "Number of servers needs to be greater 0");
827 return;
828 }
829
33a0e5d8
AK
830 /* Registration of global state belongs into realize */
831 spapr_rtas_register("ibm,set-xive", rtas_set_xive);
832 spapr_rtas_register("ibm,get-xive", rtas_get_xive);
833 spapr_rtas_register("ibm,int-off", rtas_int_off);
834 spapr_rtas_register("ibm,int-on", rtas_int_on);
835
836 spapr_register_hypercall(H_CPPR, h_cppr);
837 spapr_register_hypercall(H_IPI, h_ipi);
838 spapr_register_hypercall(H_XIRR, h_xirr);
839 spapr_register_hypercall(H_EOI, h_eoi);
840
b45ff2d9
AK
841 object_property_set_bool(OBJECT(icp->ics), true, "realized", &error);
842 if (error) {
843 error_propagate(errp, error);
844 return;
845 }
b5cec4c5 846
c04d6cfa 847 for (i = 0; i < icp->nr_servers; i++) {
b45ff2d9
AK
848 object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error);
849 if (error) {
850 error_propagate(errp, error);
851 return;
852 }
c04d6cfa
AL
853 }
854}
b5cec4c5 855
c04d6cfa
AL
856static void xics_initfn(Object *obj)
857{
858 XICSState *xics = XICS(obj);
859
860 xics->ics = ICS(object_new(TYPE_ICS));
861 object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
5a3d7b23 862 xics->ics->icp = xics;
c04d6cfa
AL
863}
864
c04d6cfa
AL
865static void xics_class_init(ObjectClass *oc, void *data)
866{
867 DeviceClass *dc = DEVICE_CLASS(oc);
5a3d7b23 868 XICSStateClass *xsc = XICS_CLASS(oc);
c04d6cfa
AL
869
870 dc->realize = xics_realize;
5a3d7b23
AK
871 xsc->set_nr_irqs = xics_set_nr_irqs;
872 xsc->set_nr_servers = xics_set_nr_servers;
c04d6cfa
AL
873}
874
875static const TypeInfo xics_info = {
876 .name = TYPE_XICS,
5a3d7b23 877 .parent = TYPE_XICS_COMMON,
c04d6cfa 878 .instance_size = sizeof(XICSState),
5a3d7b23 879 .class_size = sizeof(XICSStateClass),
c04d6cfa
AL
880 .class_init = xics_class_init,
881 .instance_init = xics_initfn,
882};
256b408a 883
c04d6cfa
AL
884static void xics_register_types(void)
885{
5a3d7b23 886 type_register_static(&xics_common_info);
c04d6cfa
AL
887 type_register_static(&xics_info);
888 type_register_static(&ics_info);
889 type_register_static(&icp_info);
b5cec4c5 890}
c04d6cfa
AL
891
892type_init(xics_register_types)
This page took 0.509946 seconds and 4 git commands to generate.