X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/8d1dc5d188b84a2b2aeb9bd39fddb3d2c67be60c..f62f210943f8290bc0a060f4090046841815a046:/hw/intc/openpic.c diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 17136c9333..9dd285b923 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -33,6 +33,7 @@ * 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" @@ -40,8 +41,11 @@ #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 @@ -51,8 +55,10 @@ static const int debug_openpic = 1; 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) @@ -192,6 +198,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 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, @@ -199,11 +206,14 @@ typedef enum IRQType { 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; @@ -239,6 +249,37 @@ typedef struct IRQSource { #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; @@ -287,14 +328,9 @@ typedef struct OpenPICState { 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; @@ -311,11 +347,6 @@ static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) 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; @@ -534,55 +565,6 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) } } -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; @@ -838,37 +820,98 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) 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; @@ -887,27 +930,28 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) 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; } @@ -1066,7 +1110,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, 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; } @@ -1181,7 +1225,10 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) 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 */ @@ -1205,7 +1252,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 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; } @@ -1340,130 +1387,59 @@ static const MemoryRegionOps openpic_summary_ops_be = { }, }; -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; - } - - qemu_get_sbe32s(f, &q->next); - qemu_get_sbe32s(f, &q->priority); -} - -static int openpic_load(QEMUFile* f, void *opaque, int version_id) -{ - OpenPICState *opp = (OpenPICState *)opaque; - unsigned int i, nb_cpus; + 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; - if (version_id != 1) { - return -EINVAL; - } + case IRQ_TYPE_FSLINT: + opp->src[i].ivpr |= IVPR_POLARITY_MASK; + break; - 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); + case IRQ_TYPE_FSLSPECIAL: + break; + } - qemu_get_be32s(f, &nb_cpus); - if (opp->nb_cpus != nb_cpus) { - return -EINVAL; + write_IRQreg_idr(opp, i, opp->idr_reset); } - assert(nb_cpus > 0 && nb_cpus <= MAX_CPU); - + /* 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 { @@ -1495,7 +1471,7 @@ static void fsl_common_init(OpenPICState *opp) opp->irq_msi = 224; - msi_supported = true; + msi_nonbroken = true; for (i = 0; i < opp->fsl->max_ext; i++) { opp->src[i].level = false; } @@ -1511,6 +1487,15 @@ static void fsl_common_init(OpenPICState *opp) 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) @@ -1529,6 +1514,110 @@ 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); @@ -1573,9 +1662,9 @@ static void openpic_realize(DeviceState *dev, Error **errp) }; if (opp->nb_cpus > MAX_CPU) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus, - (uint64_t)0, (uint64_t)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; } @@ -1631,14 +1720,16 @@ static void openpic_realize(DeviceState *dev, Error **errp) } 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); @@ -1657,6 +1748,8 @@ static void openpic_class_init(ObjectClass *oc, void *data) 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 = {