]> git.proxmox.com Git - mirror_qemu.git/blame - hw/intc/xics.c
ppc/xics: move ics-simple post_load under the machine
[mirror_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
0d75590d 28#include "qemu/osdep.h"
da34e65c 29#include "qapi/error.h"
4771d756
PB
30#include "qemu-common.h"
31#include "cpu.h"
83c9f4ca 32#include "hw/hw.h"
500efa23 33#include "trace.h"
5d87e4b7 34#include "qemu/timer.h"
0d09e41a 35#include "hw/ppc/xics.h"
9ccff2a4 36#include "qemu/error-report.h"
5a3d7b23 37#include "qapi/visitor.h"
b1fc72f0
BH
38#include "monitor/monitor.h"
39#include "hw/intc/intc.h"
b5cec4c5 40
9c7027ba 41int xics_get_cpu_index_by_dt_id(int cpu_dt_id)
0f20ba62
AK
42{
43 PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
44
45 if (cpu) {
46 return cpu->parent_obj.cpu_index;
47 }
48
49 return -1;
50}
51
b4f27d71 52void xics_cpu_destroy(XICSFabric *xi, PowerPCCPU *cpu)
4a4b344c
BR
53{
54 CPUState *cs = CPU(cpu);
b4f27d71 55 ICPState *ss = xics_icp_get(xi, cs->cpu_index);
4a4b344c 56
b4f27d71 57 assert(ss);
4a4b344c
BR
58 assert(cs == ss->cs);
59
60 ss->output = NULL;
61 ss->cs = NULL;
62}
63
b4f27d71 64void xics_cpu_setup(XICSFabric *xi, PowerPCCPU *cpu)
8ffe04ed
AK
65{
66 CPUState *cs = CPU(cpu);
67 CPUPPCState *env = &cpu->env;
b4f27d71 68 ICPState *ss = xics_icp_get(xi, cs->cpu_index);
f0232434 69 ICPStateClass *icpc;
8ffe04ed 70
b4f27d71 71 assert(ss);
8ffe04ed 72
4a4b344c
BR
73 ss->cs = cs;
74
f0232434
CLG
75 icpc = ICP_GET_CLASS(ss);
76 if (icpc->cpu_setup) {
77 icpc->cpu_setup(ss, cpu);
5eb92ccc
AK
78 }
79
8ffe04ed
AK
80 switch (PPC_INPUT(env)) {
81 case PPC_FLAGS_INPUT_POWER7:
82 ss->output = env->irq_inputs[POWER7_INPUT_INT];
83 break;
84
85 case PPC_FLAGS_INPUT_970:
86 ss->output = env->irq_inputs[PPC970_INPUT_INT];
87 break;
88
89 default:
9ccff2a4
AK
90 error_report("XICS interrupt controller does not support this CPU "
91 "bus model");
8ffe04ed
AK
92 abort();
93 }
94}
95
b9038e78
CLG
96static void icp_pic_print_info(InterruptStatsProvider *obj,
97 Monitor *mon)
b1fc72f0 98{
b9038e78
CLG
99 ICPState *icp = ICP(obj);
100 int cpu_index = icp->cs ? icp->cs->cpu_index : -1;
101
102 if (!icp->output) {
103 return;
104 }
105 monitor_printf(mon, "CPU %d XIRR=%08x (%p) PP=%02x MFRR=%02x\n",
106 cpu_index, icp->xirr, icp->xirr_owner,
107 icp->pending_priority, icp->mfrr);
108}
109
110static void ics_simple_pic_print_info(InterruptStatsProvider *obj,
111 Monitor *mon)
112{
113 ICSState *ics = ICS_SIMPLE(obj);
b1fc72f0
BH
114 uint32_t i;
115
b9038e78
CLG
116 monitor_printf(mon, "ICS %4x..%4x %p\n",
117 ics->offset, ics->offset + ics->nr_irqs - 1, ics);
b1fc72f0 118
b9038e78
CLG
119 if (!ics->irqs) {
120 return;
b1fc72f0
BH
121 }
122
b9038e78
CLG
123 for (i = 0; i < ics->nr_irqs; i++) {
124 ICSIRQState *irq = ics->irqs + i;
b1fc72f0 125
b9038e78 126 if (!(irq->flags & XICS_FLAGS_IRQ_MASK)) {
b1fc72f0
BH
127 continue;
128 }
b9038e78
CLG
129 monitor_printf(mon, " %4x %s %02x %02x\n",
130 ics->offset + i,
131 (irq->flags & XICS_FLAGS_IRQ_LSI) ?
132 "LSI" : "MSI",
133 irq->priority, irq->status);
b1fc72f0
BH
134 }
135}
136
b5cec4c5
DG
137/*
138 * ICP: Presentation layer
139 */
140
b5cec4c5
DG
141#define XISR_MASK 0x00ffffff
142#define CPPR_MASK 0xff000000
143
144#define XISR(ss) (((ss)->xirr) & XISR_MASK)
145#define CPPR(ss) (((ss)->xirr) >> 24)
146
d4d7a59a
BH
147static void ics_reject(ICSState *ics, uint32_t nr)
148{
149 ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
150
151 if (k->reject) {
152 k->reject(ics, nr);
153 }
154}
155
7844e12b 156void ics_resend(ICSState *ics)
d4d7a59a
BH
157{
158 ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
159
160 if (k->resend) {
161 k->resend(ics);
162 }
163}
164
165static void ics_eoi(ICSState *ics, int nr)
166{
167 ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
168
169 if (k->eoi) {
170 k->eoi(ics, nr);
171 }
172}
b5cec4c5 173
cc706a53 174static void icp_check_ipi(ICPState *ss)
b5cec4c5 175{
b5cec4c5
DG
176 if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
177 return;
178 }
179
cc706a53 180 trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr);
500efa23 181
cc706a53
BH
182 if (XISR(ss) && ss->xirr_owner) {
183 ics_reject(ss->xirr_owner, XISR(ss));
b5cec4c5
DG
184 }
185
186 ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
187 ss->pending_priority = ss->mfrr;
cc706a53 188 ss->xirr_owner = NULL;
b5cec4c5
DG
189 qemu_irq_raise(ss->output);
190}
191
b2fc59aa 192void icp_resend(ICPState *ss)
b5cec4c5 193{
2cd908d0
CLG
194 XICSFabric *xi = ss->xics;
195 XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
b5cec4c5
DG
196
197 if (ss->mfrr < CPPR(ss)) {
cc706a53
BH
198 icp_check_ipi(ss);
199 }
2cd908d0
CLG
200
201 xic->ics_resend(xi);
b5cec4c5
DG
202}
203
e3403258 204void icp_set_cppr(ICPState *ss, uint8_t cppr)
b5cec4c5 205{
b5cec4c5
DG
206 uint8_t old_cppr;
207 uint32_t old_xisr;
208
209 old_cppr = CPPR(ss);
210 ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
211
212 if (cppr < old_cppr) {
213 if (XISR(ss) && (cppr <= ss->pending_priority)) {
214 old_xisr = XISR(ss);
215 ss->xirr &= ~XISR_MASK; /* Clear XISR */
e03c902c 216 ss->pending_priority = 0xff;
b5cec4c5 217 qemu_irq_lower(ss->output);
cc706a53
BH
218 if (ss->xirr_owner) {
219 ics_reject(ss->xirr_owner, old_xisr);
220 ss->xirr_owner = NULL;
221 }
b5cec4c5
DG
222 }
223 } else {
224 if (!XISR(ss)) {
e3403258 225 icp_resend(ss);
b5cec4c5
DG
226 }
227 }
228}
229
e3403258 230void icp_set_mfrr(ICPState *ss, uint8_t mfrr)
b5cec4c5 231{
b5cec4c5
DG
232 ss->mfrr = mfrr;
233 if (mfrr < CPPR(ss)) {
cc706a53 234 icp_check_ipi(ss);
b5cec4c5
DG
235 }
236}
237
9c7027ba 238uint32_t icp_accept(ICPState *ss)
b5cec4c5 239{
500efa23 240 uint32_t xirr = ss->xirr;
b5cec4c5
DG
241
242 qemu_irq_lower(ss->output);
b5cec4c5 243 ss->xirr = ss->pending_priority << 24;
e03c902c 244 ss->pending_priority = 0xff;
cc706a53 245 ss->xirr_owner = NULL;
500efa23
DG
246
247 trace_xics_icp_accept(xirr, ss->xirr);
248
b5cec4c5
DG
249 return xirr;
250}
251
1cbd2220
BH
252uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)
253{
254 if (mfrr) {
255 *mfrr = ss->mfrr;
256 }
257 return ss->xirr;
258}
259
e3403258 260void icp_eoi(ICPState *ss, uint32_t xirr)
b5cec4c5 261{
2cd908d0
CLG
262 XICSFabric *xi = ss->xics;
263 XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
cc706a53
BH
264 ICSState *ics;
265 uint32_t irq;
b5cec4c5 266
b5cec4c5
DG
267 /* Send EOI -> ICS */
268 ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
e3403258 269 trace_xics_icp_eoi(ss->cs->cpu_index, xirr, ss->xirr);
cc706a53 270 irq = xirr & XISR_MASK;
2cd908d0
CLG
271
272 ics = xic->ics_get(xi, irq);
273 if (ics) {
274 ics_eoi(ics, irq);
cc706a53 275 }
b5cec4c5 276 if (!XISR(ss)) {
e3403258 277 icp_resend(ss);
b5cec4c5
DG
278 }
279}
280
cc706a53 281static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority)
b5cec4c5 282{
b4f27d71 283 ICPState *ss = xics_icp_get(ics->xics, server);
b5cec4c5 284
500efa23
DG
285 trace_xics_icp_irq(server, nr, priority);
286
b5cec4c5
DG
287 if ((priority >= CPPR(ss))
288 || (XISR(ss) && (ss->pending_priority <= priority))) {
cc706a53 289 ics_reject(ics, nr);
b5cec4c5 290 } else {
cc706a53
BH
291 if (XISR(ss) && ss->xirr_owner) {
292 ics_reject(ss->xirr_owner, XISR(ss));
293 ss->xirr_owner = NULL;
b5cec4c5
DG
294 }
295 ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
cc706a53 296 ss->xirr_owner = ics;
b5cec4c5 297 ss->pending_priority = priority;
500efa23 298 trace_xics_icp_raise(ss->xirr, ss->pending_priority);
b5cec4c5
DG
299 qemu_irq_raise(ss->output);
300 }
301}
302
d1b5682d
AK
303static void icp_dispatch_pre_save(void *opaque)
304{
305 ICPState *ss = opaque;
306 ICPStateClass *info = ICP_GET_CLASS(ss);
307
308 if (info->pre_save) {
309 info->pre_save(ss);
310 }
311}
312
313static int icp_dispatch_post_load(void *opaque, int version_id)
314{
315 ICPState *ss = opaque;
316 ICPStateClass *info = ICP_GET_CLASS(ss);
317
318 if (info->post_load) {
319 return info->post_load(ss, version_id);
320 }
321
322 return 0;
323}
324
c04d6cfa
AL
325static const VMStateDescription vmstate_icp_server = {
326 .name = "icp/server",
327 .version_id = 1,
328 .minimum_version_id = 1,
d1b5682d
AK
329 .pre_save = icp_dispatch_pre_save,
330 .post_load = icp_dispatch_post_load,
3aff6c2f 331 .fields = (VMStateField[]) {
c04d6cfa
AL
332 /* Sanity check */
333 VMSTATE_UINT32(xirr, ICPState),
334 VMSTATE_UINT8(pending_priority, ICPState),
335 VMSTATE_UINT8(mfrr, ICPState),
336 VMSTATE_END_OF_LIST()
337 },
b5cec4c5
DG
338};
339
c04d6cfa
AL
340static void icp_reset(DeviceState *dev)
341{
342 ICPState *icp = ICP(dev);
343
344 icp->xirr = 0;
345 icp->pending_priority = 0xff;
346 icp->mfrr = 0xff;
347
348 /* Make all outputs are deasserted */
349 qemu_set_irq(icp->output, 0);
350}
351
817bb6a4
CLG
352static void icp_realize(DeviceState *dev, Error **errp)
353{
354 ICPState *icp = ICP(dev);
355 Object *obj;
356 Error *err = NULL;
357
358 obj = object_property_get_link(OBJECT(dev), "xics", &err);
359 if (!obj) {
360 error_setg(errp, "%s: required link 'xics' not found: %s",
361 __func__, error_get_pretty(err));
362 return;
363 }
364
2cd908d0 365 icp->xics = XICS_FABRIC(obj);
817bb6a4
CLG
366}
367
368
c04d6cfa
AL
369static void icp_class_init(ObjectClass *klass, void *data)
370{
371 DeviceClass *dc = DEVICE_CLASS(klass);
b9038e78 372 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
c04d6cfa
AL
373
374 dc->reset = icp_reset;
375 dc->vmsd = &vmstate_icp_server;
817bb6a4 376 dc->realize = icp_realize;
b9038e78 377 ic->print_info = icp_pic_print_info;
c04d6cfa
AL
378}
379
456df19c 380static const TypeInfo icp_info = {
c04d6cfa
AL
381 .name = TYPE_ICP,
382 .parent = TYPE_DEVICE,
383 .instance_size = sizeof(ICPState),
384 .class_init = icp_class_init,
d1b5682d 385 .class_size = sizeof(ICPStateClass),
b9038e78
CLG
386 .interfaces = (InterfaceInfo[]) {
387 { TYPE_INTERRUPT_STATS_PROVIDER },
388 { }
389 },
b5cec4c5
DG
390};
391
c04d6cfa
AL
392/*
393 * ICS: Source layer
394 */
d4d7a59a 395static void ics_simple_resend_msi(ICSState *ics, int srcno)
d07fee7e 396{
c04d6cfa 397 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e
DG
398
399 /* FIXME: filter by server#? */
98ca8c02
DG
400 if (irq->status & XICS_STATUS_REJECTED) {
401 irq->status &= ~XICS_STATUS_REJECTED;
d07fee7e 402 if (irq->priority != 0xff) {
cc706a53 403 icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
d07fee7e
DG
404 }
405 }
406}
407
d4d7a59a 408static void ics_simple_resend_lsi(ICSState *ics, int srcno)
d07fee7e 409{
c04d6cfa 410 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 411
98ca8c02
DG
412 if ((irq->priority != 0xff)
413 && (irq->status & XICS_STATUS_ASSERTED)
414 && !(irq->status & XICS_STATUS_SENT)) {
415 irq->status |= XICS_STATUS_SENT;
cc706a53 416 icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
d07fee7e
DG
417 }
418}
419
d4d7a59a 420static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
b5cec4c5 421{
c04d6cfa 422 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 423
d4d7a59a 424 trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset);
500efa23 425
b5cec4c5
DG
426 if (val) {
427 if (irq->priority == 0xff) {
98ca8c02 428 irq->status |= XICS_STATUS_MASKED_PENDING;
500efa23 429 trace_xics_masked_pending();
b5cec4c5 430 } else {
cc706a53 431 icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
432 }
433 }
434}
435
d4d7a59a 436static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val)
b5cec4c5 437{
c04d6cfa 438 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5 439
d4d7a59a 440 trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset);
98ca8c02
DG
441 if (val) {
442 irq->status |= XICS_STATUS_ASSERTED;
443 } else {
444 irq->status &= ~XICS_STATUS_ASSERTED;
445 }
d4d7a59a 446 ics_simple_resend_lsi(ics, srcno);
b5cec4c5
DG
447}
448
d4d7a59a 449static void ics_simple_set_irq(void *opaque, int srcno, int val)
b5cec4c5 450{
c04d6cfa 451 ICSState *ics = (ICSState *)opaque;
b5cec4c5 452
4af88944 453 if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
d4d7a59a 454 ics_simple_set_irq_lsi(ics, srcno, val);
d07fee7e 455 } else {
d4d7a59a 456 ics_simple_set_irq_msi(ics, srcno, val);
d07fee7e
DG
457 }
458}
b5cec4c5 459
d4d7a59a 460static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
d07fee7e 461{
c04d6cfa 462 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 463
98ca8c02
DG
464 if (!(irq->status & XICS_STATUS_MASKED_PENDING)
465 || (irq->priority == 0xff)) {
d07fee7e 466 return;
b5cec4c5 467 }
d07fee7e 468
98ca8c02 469 irq->status &= ~XICS_STATUS_MASKED_PENDING;
cc706a53 470 icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
b5cec4c5
DG
471}
472
d4d7a59a 473static void ics_simple_write_xive_lsi(ICSState *ics, int srcno)
b5cec4c5 474{
d4d7a59a 475 ics_simple_resend_lsi(ics, srcno);
d07fee7e
DG
476}
477
d4d7a59a
BH
478void ics_simple_write_xive(ICSState *ics, int srcno, int server,
479 uint8_t priority, uint8_t saved_priority)
d07fee7e 480{
c04d6cfa 481 ICSIRQState *irq = ics->irqs + srcno;
b5cec4c5
DG
482
483 irq->server = server;
484 irq->priority = priority;
3fe719f4 485 irq->saved_priority = saved_priority;
b5cec4c5 486
d4d7a59a
BH
487 trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server,
488 priority);
500efa23 489
4af88944 490 if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
d4d7a59a 491 ics_simple_write_xive_lsi(ics, srcno);
d07fee7e 492 } else {
d4d7a59a 493 ics_simple_write_xive_msi(ics, srcno);
b5cec4c5 494 }
b5cec4c5
DG
495}
496
d4d7a59a 497static void ics_simple_reject(ICSState *ics, uint32_t nr)
b5cec4c5 498{
c04d6cfa 499 ICSIRQState *irq = ics->irqs + nr - ics->offset;
d07fee7e 500
d4d7a59a 501 trace_xics_ics_simple_reject(nr, nr - ics->offset);
056b9775
ND
502 if (irq->flags & XICS_FLAGS_IRQ_MSI) {
503 irq->status |= XICS_STATUS_REJECTED;
504 } else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
505 irq->status &= ~XICS_STATUS_SENT;
506 }
b5cec4c5
DG
507}
508
d4d7a59a 509static void ics_simple_resend(ICSState *ics)
b5cec4c5 510{
d07fee7e
DG
511 int i;
512
513 for (i = 0; i < ics->nr_irqs; i++) {
d07fee7e 514 /* FIXME: filter by server#? */
4af88944 515 if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
d4d7a59a 516 ics_simple_resend_lsi(ics, i);
d07fee7e 517 } else {
d4d7a59a 518 ics_simple_resend_msi(ics, i);
d07fee7e
DG
519 }
520 }
b5cec4c5
DG
521}
522
d4d7a59a 523static void ics_simple_eoi(ICSState *ics, uint32_t nr)
b5cec4c5 524{
d07fee7e 525 int srcno = nr - ics->offset;
c04d6cfa 526 ICSIRQState *irq = ics->irqs + srcno;
d07fee7e 527
d4d7a59a 528 trace_xics_ics_simple_eoi(nr);
500efa23 529
4af88944 530 if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
98ca8c02 531 irq->status &= ~XICS_STATUS_SENT;
d07fee7e 532 }
b5cec4c5
DG
533}
534
d4d7a59a 535static void ics_simple_reset(DeviceState *dev)
c04d6cfa 536{
d4d7a59a 537 ICSState *ics = ICS_SIMPLE(dev);
c04d6cfa 538 int i;
a7e519a8
AK
539 uint8_t flags[ics->nr_irqs];
540
541 for (i = 0; i < ics->nr_irqs; i++) {
542 flags[i] = ics->irqs[i].flags;
543 }
c04d6cfa
AL
544
545 memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
a7e519a8 546
c04d6cfa
AL
547 for (i = 0; i < ics->nr_irqs; i++) {
548 ics->irqs[i].priority = 0xff;
549 ics->irqs[i].saved_priority = 0xff;
a7e519a8 550 ics->irqs[i].flags = flags[i];
c04d6cfa
AL
551 }
552}
553
d4d7a59a 554static void ics_simple_dispatch_pre_save(void *opaque)
d1b5682d
AK
555{
556 ICSState *ics = opaque;
d4d7a59a 557 ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
d1b5682d
AK
558
559 if (info->pre_save) {
560 info->pre_save(ics);
561 }
562}
563
d4d7a59a 564static int ics_simple_dispatch_post_load(void *opaque, int version_id)
d1b5682d
AK
565{
566 ICSState *ics = opaque;
d4d7a59a 567 ICSStateClass *info = ICS_BASE_GET_CLASS(ics);
d1b5682d
AK
568
569 if (info->post_load) {
570 return info->post_load(ics, version_id);
571 }
572
573 return 0;
574}
575
d4d7a59a 576static const VMStateDescription vmstate_ics_simple_irq = {
c04d6cfa 577 .name = "ics/irq",
4af88944 578 .version_id = 2,
c04d6cfa 579 .minimum_version_id = 1,
3aff6c2f 580 .fields = (VMStateField[]) {
c04d6cfa
AL
581 VMSTATE_UINT32(server, ICSIRQState),
582 VMSTATE_UINT8(priority, ICSIRQState),
583 VMSTATE_UINT8(saved_priority, ICSIRQState),
584 VMSTATE_UINT8(status, ICSIRQState),
4af88944 585 VMSTATE_UINT8(flags, ICSIRQState),
c04d6cfa
AL
586 VMSTATE_END_OF_LIST()
587 },
588};
589
d4d7a59a 590static const VMStateDescription vmstate_ics_simple = {
c04d6cfa
AL
591 .name = "ics",
592 .version_id = 1,
593 .minimum_version_id = 1,
d4d7a59a
BH
594 .pre_save = ics_simple_dispatch_pre_save,
595 .post_load = ics_simple_dispatch_post_load,
3aff6c2f 596 .fields = (VMStateField[]) {
c04d6cfa
AL
597 /* Sanity check */
598 VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
599
600 VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
d4d7a59a
BH
601 vmstate_ics_simple_irq,
602 ICSIRQState),
c04d6cfa
AL
603 VMSTATE_END_OF_LIST()
604 },
605};
606
d4d7a59a 607static void ics_simple_initfn(Object *obj)
5a3d7b23 608{
d4d7a59a 609 ICSState *ics = ICS_SIMPLE(obj);
5a3d7b23
AK
610
611 ics->offset = XICS_IRQ_BASE;
612}
613
d4d7a59a 614static void ics_simple_realize(DeviceState *dev, Error **errp)
c04d6cfa 615{
d4d7a59a 616 ICSState *ics = ICS_SIMPLE(dev);
c04d6cfa 617
b45ff2d9
AK
618 if (!ics->nr_irqs) {
619 error_setg(errp, "Number of interrupts needs to be greater 0");
620 return;
621 }
c04d6cfa 622 ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
d4d7a59a 623 ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
c04d6cfa
AL
624}
625
4e4169f7
CLG
626static Property ics_simple_properties[] = {
627 DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
628 DEFINE_PROP_END_OF_LIST(),
629};
630
d4d7a59a 631static void ics_simple_class_init(ObjectClass *klass, void *data)
c04d6cfa
AL
632{
633 DeviceClass *dc = DEVICE_CLASS(klass);
d4d7a59a 634 ICSStateClass *isc = ICS_BASE_CLASS(klass);
b9038e78 635 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
c04d6cfa 636
4e4169f7
CLG
637 isc->realize = ics_simple_realize;
638 dc->props = ics_simple_properties;
d4d7a59a
BH
639 dc->vmsd = &vmstate_ics_simple;
640 dc->reset = ics_simple_reset;
d4d7a59a
BH
641 isc->reject = ics_simple_reject;
642 isc->resend = ics_simple_resend;
643 isc->eoi = ics_simple_eoi;
b9038e78 644 ic->print_info = ics_simple_pic_print_info;
c04d6cfa
AL
645}
646
d4d7a59a
BH
647static const TypeInfo ics_simple_info = {
648 .name = TYPE_ICS_SIMPLE,
649 .parent = TYPE_ICS_BASE,
650 .instance_size = sizeof(ICSState),
651 .class_init = ics_simple_class_init,
652 .class_size = sizeof(ICSStateClass),
653 .instance_init = ics_simple_initfn,
b9038e78
CLG
654 .interfaces = (InterfaceInfo[]) {
655 { TYPE_INTERRUPT_STATS_PROVIDER },
656 { }
657 },
d4d7a59a
BH
658};
659
4e4169f7
CLG
660static void ics_base_realize(DeviceState *dev, Error **errp)
661{
662 ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
663 ICSState *ics = ICS_BASE(dev);
664 Object *obj;
665 Error *err = NULL;
666
667 obj = object_property_get_link(OBJECT(dev), "xics", &err);
668 if (!obj) {
669 error_setg(errp, "%s: required link 'xics' not found: %s",
670 __func__, error_get_pretty(err));
671 return;
672 }
b4f27d71 673 ics->xics = XICS_FABRIC(obj);
4e4169f7
CLG
674
675
676 if (icsc->realize) {
677 icsc->realize(dev, errp);
678 }
679}
680
681static void ics_base_class_init(ObjectClass *klass, void *data)
682{
683 DeviceClass *dc = DEVICE_CLASS(klass);
684
685 dc->realize = ics_base_realize;
686}
687
d4d7a59a
BH
688static const TypeInfo ics_base_info = {
689 .name = TYPE_ICS_BASE,
c04d6cfa 690 .parent = TYPE_DEVICE,
d4d7a59a 691 .abstract = true,
c04d6cfa 692 .instance_size = sizeof(ICSState),
4e4169f7 693 .class_init = ics_base_class_init,
d1b5682d 694 .class_size = sizeof(ICSStateClass),
c04d6cfa
AL
695};
696
51b18005
CLG
697static const TypeInfo xics_fabric_info = {
698 .name = TYPE_XICS_FABRIC,
699 .parent = TYPE_INTERFACE,
700 .class_size = sizeof(XICSFabricClass),
701};
702
b5cec4c5
DG
703/*
704 * Exported functions
705 */
f7759e43 706qemu_irq xics_get_qirq(XICSFabric *xi, int irq)
b5cec4c5 707{
f7759e43
CLG
708 XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
709 ICSState *ics = xic->ics_get(xi, irq);
641c3493 710
cc706a53 711 if (ics) {
641c3493 712 return ics->qirqs[irq - ics->offset];
b5cec4c5
DG
713 }
714
641c3493 715 return NULL;
a307d594
AK
716}
717
b4f27d71
CLG
718ICPState *xics_icp_get(XICSFabric *xi, int server)
719{
720 XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi);
721
722 return xic->icp_get(xi, server);
723}
724
9c7027ba 725void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
4af88944
AK
726{
727 assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK));
728
729 ics->irqs[srcno].flags |=
730 lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
731}
732
c04d6cfa
AL
733static void xics_register_types(void)
734{
d4d7a59a
BH
735 type_register_static(&ics_simple_info);
736 type_register_static(&ics_base_info);
c04d6cfa 737 type_register_static(&icp_info);
51b18005 738 type_register_static(&xics_fabric_info);
b5cec4c5 739}
c04d6cfa
AL
740
741type_init(xics_register_types)