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