* Serial interrupts, as implemented in Raven chipset are not supported yet.
*
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/ppc/mac.h"
#include "hw/pci/pci.h"
#include "hw/ppc/ppc_e500.h"
#include "hw/sysbus.h"
#include "hw/pci/msi.h"
+#include "qapi/error.h"
#include "qemu/bitops.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
//#define DEBUG_OPENPIC
static const int debug_openpic = 0;
#endif
+static int get_current_cpu(void);
#define DPRINTF(fmt, ...) do { \
if (debug_openpic) { \
+ printf("Core%d: ", get_current_cpu()); \
printf(fmt , ## __VA_ARGS__); \
} \
} while (0)
int idx);
static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx);
+static void openpic_reset(DeviceState *d);
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
} IRQType;
+/* Round up to the nearest 64 IRQs so that the queue length
+ * won't change when moving between 32 and 64 bit hosts.
+ */
+#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
+
typedef struct IRQQueue {
- /* Round up to the nearest 64 IRQs so that the queue length
- * won't change when moving between 32 and 64 bit hosts.
- */
- unsigned long queue[BITS_TO_LONGS((OPENPIC_MAX_IRQ + 63) & ~63)];
+ unsigned long *queue;
+ int32_t queue_size; /* Only used for VMSTATE_BITMAP */
int next;
int priority;
} IRQQueue;
#define IDR_EP 0x80000000 /* external pin */
#define IDR_CI 0x40000000 /* critical interrupt */
+/* Convert between openpic clock ticks and nanosecs. In the hardware the clock
+ frequency is driven by board inputs to the PIC which the PIC would then
+ divide by 4 or 8. For now hard code to 25MZ.
+*/
+#define OPENPIC_TIMER_FREQ_MHZ 25
+#define OPENPIC_TIMER_NS_PER_TICK (1000 / OPENPIC_TIMER_FREQ_MHZ)
+static inline uint64_t ns_to_ticks(uint64_t ns)
+{
+ return ns / OPENPIC_TIMER_NS_PER_TICK;
+}
+static inline uint64_t ticks_to_ns(uint64_t ticks)
+{
+ return ticks * OPENPIC_TIMER_NS_PER_TICK;
+}
+
+typedef struct OpenPICTimer {
+ uint32_t tccr; /* Global timer current count register */
+ uint32_t tbcr; /* Global timer base count register */
+ int n_IRQ;
+ bool qemu_timer_active; /* Is the qemu_timer is running? */
+ struct QEMUTimer *qemu_timer;
+ struct OpenPICState *opp; /* Device timer is part of. */
+ /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
+ current_count written or read, only defined if qemu_timer_active. */
+ uint64_t origin_time;
+} OpenPICTimer;
+
+typedef struct OpenPICMSI {
+ uint32_t msir; /* Shared Message Signaled Interrupt Register */
+} OpenPICMSI;
+
typedef struct IRQDest {
int32_t ctpr; /* CPU current task priority */
IRQQueue raised;
IRQDest dst[MAX_CPU];
uint32_t nb_cpus;
/* Timer registers */
- struct {
- uint32_t tccr; /* Global timer current count register */
- uint32_t tbcr; /* Global timer base count register */
- } timers[OPENPIC_MAX_TMR];
+ OpenPICTimer timers[OPENPIC_MAX_TMR];
/* Shared MSI registers */
- struct {
- uint32_t msir; /* Shared Message Signaled Interrupt Register */
- } msi[MAX_MSI];
+ OpenPICMSI msi[MAX_MSI];
uint32_t max_irq;
uint32_t irq_ipi0;
uint32_t irq_tim0;
clear_bit(n_IRQ, q->queue);
}
-static inline int IRQ_testbit(IRQQueue *q, int n_IRQ)
-{
- return test_bit(n_IRQ, q->queue);
-}
-
static void IRQ_check(OpenPICState *opp, IRQQueue *q)
{
int irq = -1;
}
}
-static void openpic_reset(DeviceState *d)
-{
- OpenPICState *opp = OPENPIC(d);
- int i;
-
- opp->gcr = GCR_RESET;
- /* Initialise controller registers */
- opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
- ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
- (opp->vid << FRR_VID_SHIFT);
-
- opp->pir = 0;
- opp->spve = -1 & opp->vector_mask;
- opp->tfrr = opp->tfrr_reset;
- /* Initialise IRQ sources */
- for (i = 0; i < opp->max_irq; i++) {
- opp->src[i].ivpr = opp->ivpr_reset;
- opp->src[i].idr = opp->idr_reset;
-
- switch (opp->src[i].type) {
- case IRQ_TYPE_NORMAL:
- opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
- break;
-
- case IRQ_TYPE_FSLINT:
- opp->src[i].ivpr |= IVPR_POLARITY_MASK;
- break;
-
- case IRQ_TYPE_FSLSPECIAL:
- break;
- }
- }
- /* Initialise IRQ destinations */
- for (i = 0; i < MAX_CPU; i++) {
- opp->dst[i].ctpr = 15;
- memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
- opp->dst[i].raised.next = -1;
- memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
- opp->dst[i].servicing.next = -1;
- }
- /* Initialise timers */
- for (i = 0; i < OPENPIC_MAX_TMR; i++) {
- opp->timers[i].tccr = 0;
- opp->timers[i].tbcr = TBCR_CI;
- }
- /* Go out of RESET state */
- opp->gcr = 0;
-}
-
static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
{
return opp->src[n_IRQ].idr;
return retval;
}
+static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled);
+
+static void qemu_timer_cb(void *opaque)
+{
+ OpenPICTimer *tmr = opaque;
+ OpenPICState *opp = tmr->opp;
+ uint32_t n_IRQ = tmr->n_IRQ;
+ uint32_t val = tmr->tbcr & ~TBCR_CI;
+ uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggle. */
+
+ DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ);
+ /* Reload current count from base count and setup timer. */
+ tmr->tccr = val | tog;
+ openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
+ /* Raise the interrupt. */
+ opp->src[n_IRQ].destmask = read_IRQreg_idr(opp, n_IRQ);
+ openpic_set_irq(opp, n_IRQ, 1);
+ openpic_set_irq(opp, n_IRQ, 0);
+}
+
+/* If enabled is true, arranges for an interrupt to be raised val clocks into
+ the future, if enabled is false cancels the timer. */
+static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled)
+{
+ uint64_t ns = ticks_to_ns(val & ~TCCR_TOG);
+ /* A count of zero causes a timer to be set to expire immediately. This
+ effectively stops the simulation since the timer is constantly expiring
+ which prevents guest code execution, so we don't honor that
+ configuration. On real hardware, this situation would generate an
+ interrupt on every clock cycle if the interrupt was unmasked. */
+ if ((ns == 0) || !enabled) {
+ tmr->qemu_timer_active = false;
+ tmr->tccr = tmr->tccr & TCCR_TOG;
+ timer_del(tmr->qemu_timer); /* set timer to never expire. */
+ } else {
+ tmr->qemu_timer_active = true;
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ tmr->origin_time = now;
+ timer_mod(tmr->qemu_timer, now + ns); /* set timer expiration. */
+ }
+}
+
+/* Returns the currrent tccr value, i.e., timer value (in clocks) with
+ appropriate TOG. */
+static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr)
+{
+ uint64_t retval;
+ if (!tmr->qemu_timer_active) {
+ retval = tmr->tccr;
+ } else {
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint64_t used = now - tmr->origin_time; /* nsecs */
+ uint32_t used_ticks = (uint32_t)ns_to_ticks(used);
+ uint32_t count = (tmr->tccr & ~TCCR_TOG) - used_ticks;
+ retval = (uint32_t)((tmr->tccr & TCCR_TOG) | (count & ~TCCR_TOG));
+ }
+ return retval;
+}
+
static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned len)
+ unsigned len)
{
OpenPICState *opp = opaque;
int idx;
- addr += 0x10f0;
-
DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
- __func__, addr, val);
+ __func__, (addr + 0x10f0), val);
if (addr & 0xF) {
return;
}
- if (addr == 0x10f0) {
+ if (addr == 0) {
/* TFRR */
opp->tfrr = val;
return;
}
-
+ addr -= 0x10; /* correct for TFRR */
idx = (addr >> 6) & 0x3;
- addr = addr & 0x30;
switch (addr & 0x30) {
case 0x00: /* TCCR */
break;
case 0x10: /* TBCR */
- if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
- (val & TBCR_CI) == 0 &&
- (opp->timers[idx].tbcr & TBCR_CI) != 0) {
- opp->timers[idx].tccr &= ~TCCR_TOG;
+ /* Did the enable status change? */
+ if ((opp->timers[idx].tbcr & TBCR_CI) != (val & TBCR_CI)) {
+ /* Did "Count Inhibit" transition from 1 to 0? */
+ if ((val & TBCR_CI) == 0) {
+ opp->timers[idx].tccr = val & ~TCCR_TOG;
+ }
+ openpic_tmr_set_tmr(&opp->timers[idx],
+ (val & ~TBCR_CI),
+ /*enabled=*/((val & TBCR_CI) == 0));
}
opp->timers[idx].tbcr = val;
break;
uint32_t retval = -1;
int idx;
- DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+ DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0);
if (addr & 0xF) {
goto out;
}
- idx = (addr >> 6) & 0x3;
- if (addr == 0x0) {
+ if (addr == 0) {
/* TFRR */
retval = opp->tfrr;
goto out;
}
+ addr -= 0x10; /* correct for TFRR */
+ idx = (addr >> 6) & 0x3;
switch (addr & 0x30) {
case 0x00: /* TCCR */
- retval = opp->timers[idx].tccr;
+ retval = openpic_tmr_get_timer(&opp->timers[idx]);
break;
case 0x10: /* TBCR */
retval = opp->timers[idx].tbcr;
break;
- case 0x20: /* TIPV */
+ case 0x20: /* TVPR */
retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
break;
- case 0x30: /* TIDE (TIDR) */
+ case 0x30: /* TDR */
retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
break;
}
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
addr, val);
- if (idx < 0) {
+ if (idx < 0 || idx >= opp->nb_cpus) {
return;
}
IRQ_resetbit(&dst->raised, irq);
}
- if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) {
+ /* Timers and IPIs support multicast. */
+ if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
+ ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
+ DPRINTF("irq is IPI or TMR\n");
src->destmask &= ~(1 << cpu);
if (src->destmask && !src->level) {
/* trigger on CPUs that didn't know about it yet */
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
retval = 0xFFFFFFFF;
- if (idx < 0) {
+ if (idx < 0 || idx >= opp->nb_cpus) {
return retval;
}
},
};
-static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
- /* Always put the lower half of a 64-bit long first, in case we
- * restore on a 32-bit host. The least significant bits correspond
- * to lower IRQ numbers in the bitmap.
- */
- qemu_put_be32(f, (uint32_t)q->queue[i]);
-#if LONG_MAX > 0x7FFFFFFF
- qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
-#endif
- }
-
- qemu_put_sbe32s(f, &q->next);
- qemu_put_sbe32s(f, &q->priority);
-}
-
-static void openpic_save(QEMUFile* f, void *opaque)
+static void openpic_reset(DeviceState *d)
{
- OpenPICState *opp = (OpenPICState *)opaque;
- unsigned int i;
-
- qemu_put_be32s(f, &opp->gcr);
- qemu_put_be32s(f, &opp->vir);
- qemu_put_be32s(f, &opp->pir);
- qemu_put_be32s(f, &opp->spve);
- qemu_put_be32s(f, &opp->tfrr);
-
- qemu_put_be32s(f, &opp->nb_cpus);
-
- for (i = 0; i < opp->nb_cpus; i++) {
- qemu_put_sbe32s(f, &opp->dst[i].ctpr);
- openpic_save_IRQ_queue(f, &opp->dst[i].raised);
- openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
- qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
- sizeof(opp->dst[i].outputs_active));
- }
+ OpenPICState *opp = OPENPIC(d);
+ int i;
- for (i = 0; i < OPENPIC_MAX_TMR; i++) {
- qemu_put_be32s(f, &opp->timers[i].tccr);
- qemu_put_be32s(f, &opp->timers[i].tbcr);
- }
+ opp->gcr = GCR_RESET;
+ /* Initialise controller registers */
+ opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
+ ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
+ (opp->vid << FRR_VID_SHIFT);
+ opp->pir = 0;
+ opp->spve = -1 & opp->vector_mask;
+ opp->tfrr = opp->tfrr_reset;
+ /* Initialise IRQ sources */
for (i = 0; i < opp->max_irq; i++) {
- qemu_put_be32s(f, &opp->src[i].ivpr);
- qemu_put_be32s(f, &opp->src[i].idr);
- qemu_get_be32s(f, &opp->src[i].destmask);
- qemu_put_sbe32s(f, &opp->src[i].last_cpu);
- qemu_put_sbe32s(f, &opp->src[i].pending);
- }
-}
-
-static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
- unsigned long val;
-
- val = qemu_get_be32(f);
-#if LONG_MAX > 0x7FFFFFFF
- val <<= 32;
- val |= qemu_get_be32(f);
-#endif
-
- q->queue[i] = val;
- }
+ opp->src[i].ivpr = opp->ivpr_reset;
+ switch (opp->src[i].type) {
+ case IRQ_TYPE_NORMAL:
+ opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
+ break;
- qemu_get_sbe32s(f, &q->next);
- qemu_get_sbe32s(f, &q->priority);
-}
+ case IRQ_TYPE_FSLINT:
+ opp->src[i].ivpr |= IVPR_POLARITY_MASK;
+ break;
-static int openpic_load(QEMUFile* f, void *opaque, int version_id)
-{
- OpenPICState *opp = (OpenPICState *)opaque;
- unsigned int i;
+ case IRQ_TYPE_FSLSPECIAL:
+ break;
+ }
- if (version_id != 1) {
- return -EINVAL;
+ write_IRQreg_idr(opp, i, opp->idr_reset);
}
-
- qemu_get_be32s(f, &opp->gcr);
- qemu_get_be32s(f, &opp->vir);
- qemu_get_be32s(f, &opp->pir);
- qemu_get_be32s(f, &opp->spve);
- qemu_get_be32s(f, &opp->tfrr);
-
- qemu_get_be32s(f, &opp->nb_cpus);
-
+ /* Initialise IRQ destinations */
for (i = 0; i < opp->nb_cpus; i++) {
- qemu_get_sbe32s(f, &opp->dst[i].ctpr);
- openpic_load_IRQ_queue(f, &opp->dst[i].raised);
- openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
- qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
- sizeof(opp->dst[i].outputs_active));
+ opp->dst[i].ctpr = 15;
+ opp->dst[i].raised.next = -1;
+ opp->dst[i].raised.priority = 0;
+ bitmap_clear(opp->dst[i].raised.queue, 0, IRQQUEUE_SIZE_BITS);
+ opp->dst[i].servicing.next = -1;
+ opp->dst[i].servicing.priority = 0;
+ bitmap_clear(opp->dst[i].servicing.queue, 0, IRQQUEUE_SIZE_BITS);
}
-
+ /* Initialise timers */
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
- qemu_get_be32s(f, &opp->timers[i].tccr);
- qemu_get_be32s(f, &opp->timers[i].tbcr);
- }
-
- for (i = 0; i < opp->max_irq; i++) {
- uint32_t val;
-
- val = qemu_get_be32(f);
- write_IRQreg_idr(opp, i, val);
- val = qemu_get_be32(f);
- write_IRQreg_ivpr(opp, i, val);
-
- qemu_get_be32s(f, &opp->src[i].ivpr);
- qemu_get_be32s(f, &opp->src[i].idr);
- qemu_get_be32s(f, &opp->src[i].destmask);
- qemu_get_sbe32s(f, &opp->src[i].last_cpu);
- qemu_get_sbe32s(f, &opp->src[i].pending);
+ opp->timers[i].tccr = 0;
+ opp->timers[i].tbcr = TBCR_CI;
+ if (opp->timers[i].qemu_timer_active) {
+ timer_del(opp->timers[i].qemu_timer); /* Inhibit timer */
+ opp->timers[i].qemu_timer_active = false;
+ }
}
-
- return 0;
+ /* Go out of RESET state */
+ opp->gcr = 0;
}
typedef struct MemReg {
opp->irq_msi = 224;
- msi_supported = true;
+ msi_nonbroken = true;
for (i = 0; i < opp->fsl->max_ext; i++) {
opp->src[i].level = false;
}
opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
opp->src[i].level = false;
}
+
+ for (i = 0; i < OPENPIC_MAX_TMR; i++) {
+ opp->timers[i].n_IRQ = opp->irq_tim0 + i;
+ opp->timers[i].qemu_timer_active = false;
+ opp->timers[i].qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ &qemu_timer_cb,
+ &opp->timers[i]);
+ opp->timers[i].opp = opp;
+ }
}
static void map_list(OpenPICState *opp, const MemReg *list, int *count)
}
}
+static const VMStateDescription vmstate_openpic_irq_queue = {
+ .name = "openpic_irq_queue",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BITMAP(queue, IRQQueue, 0, queue_size),
+ VMSTATE_INT32(next, IRQQueue),
+ VMSTATE_INT32(priority, IRQQueue),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_openpic_irqdest = {
+ .name = "openpic_irqdest",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(ctpr, IRQDest),
+ VMSTATE_STRUCT(raised, IRQDest, 0, vmstate_openpic_irq_queue,
+ IRQQueue),
+ VMSTATE_STRUCT(servicing, IRQDest, 0, vmstate_openpic_irq_queue,
+ IRQQueue),
+ VMSTATE_UINT32_ARRAY(outputs_active, IRQDest, OPENPIC_OUTPUT_NB),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_openpic_irqsource = {
+ .name = "openpic_irqsource",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ivpr, IRQSource),
+ VMSTATE_UINT32(idr, IRQSource),
+ VMSTATE_UINT32(destmask, IRQSource),
+ VMSTATE_INT32(last_cpu, IRQSource),
+ VMSTATE_INT32(pending, IRQSource),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_openpic_timer = {
+ .name = "openpic_timer",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tccr, OpenPICTimer),
+ VMSTATE_UINT32(tbcr, OpenPICTimer),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_openpic_msi = {
+ .name = "openpic_msi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(msir, OpenPICMSI),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int openpic_post_load(void *opaque, int version_id)
+{
+ OpenPICState *opp = (OpenPICState *)opaque;
+ int i;
+
+ /* Update internal ivpr and idr variables */
+ for (i = 0; i < opp->max_irq; i++) {
+ write_IRQreg_idr(opp, i, opp->src[i].idr);
+ write_IRQreg_ivpr(opp, i, opp->src[i].ivpr);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_openpic = {
+ .name = "openpic",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .post_load = openpic_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(gcr, OpenPICState),
+ VMSTATE_UINT32(vir, OpenPICState),
+ VMSTATE_UINT32(pir, OpenPICState),
+ VMSTATE_UINT32(spve, OpenPICState),
+ VMSTATE_UINT32(tfrr, OpenPICState),
+ VMSTATE_UINT32(max_irq, OpenPICState),
+ VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0,
+ vmstate_openpic_irqsource, IRQSource),
+ VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState, NULL),
+ VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0,
+ vmstate_openpic_irqdest, IRQDest),
+ VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0,
+ vmstate_openpic_timer, OpenPICTimer),
+ VMSTATE_STRUCT_ARRAY(msi, OpenPICState, MAX_MSI, 0,
+ vmstate_openpic_msi, OpenPICMSI),
+ VMSTATE_UINT32(irq_ipi0, OpenPICState),
+ VMSTATE_UINT32(irq_tim0, OpenPICState),
+ VMSTATE_UINT32(irq_msi, OpenPICState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void openpic_init(Object *obj)
{
OpenPICState *opp = OPENPIC(obj);
{NULL}
};
+ if (opp->nb_cpus > MAX_CPU) {
+ error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+ TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
+ (uint64_t)0, (uint64_t)MAX_CPU);
+ return;
+ }
+
switch (opp->model) {
case OPENPIC_MODEL_FSL_MPIC_20:
default:
}
for (i = 0; i < opp->nb_cpus; i++) {
- opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
+ opp->dst[i].irqs = g_new0(qemu_irq, OPENPIC_OUTPUT_NB);
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
sysbus_init_irq(d, &opp->dst[i].irqs[j]);
}
- }
- register_savevm(dev, "openpic", 0, 2,
- openpic_save, openpic_load, opp);
+ opp->dst[i].raised.queue_size = IRQQUEUE_SIZE_BITS;
+ opp->dst[i].raised.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
+ opp->dst[i].servicing.queue_size = IRQQUEUE_SIZE_BITS;
+ opp->dst[i].servicing.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
+ }
sysbus_init_mmio(d, &opp->mem);
qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq);
dc->realize = openpic_realize;
dc->props = openpic_properties;
dc->reset = openpic_reset;
+ dc->vmsd = &vmstate_openpic;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo openpic_info = {