diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 16638ce80cb738037cc6820b558c33a4269f5816..b451d856b8f20c39ca20b20d76007edcbaf5b2af 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1517,6 +1517,37 @@ static bool version_before_3(void *opaque, int version_id) return version_id < 3; } +static bool spapr_pending_events_needed(void *opaque) +{ + sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; + return !QTAILQ_EMPTY(&spapr->pending_events); +} + +static const VMStateDescription vmstate_spapr_event_entry = { + .name = "spapr_event_log_entry", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(header.summary, sPAPREventLogEntry), + VMSTATE_UINT32(header.extended_length, sPAPREventLogEntry), + VMSTATE_VBUFFER_ALLOC_UINT32(extended_log, sPAPREventLogEntry, 0, + NULL, header.extended_length), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pending_events = { + .name = "spapr_pending_events", + .version_id = 1, + .minimum_version_id = 1, + .needed = spapr_pending_events_needed, + .fields = (VMStateField[]) { + VMSTATE_QTAILQ_V(pending_events, sPAPRMachineState, 1, + vmstate_spapr_event_entry, sPAPREventLogEntry, next), + VMSTATE_END_OF_LIST() + }, +}; + static bool spapr_ov5_cas_needed(void *opaque) { sPAPRMachineState *spapr = opaque; @@ -1615,6 +1646,7 @@ static const VMStateDescription vmstate_spapr = { .subsections = (const VMStateDescription*[]) { &vmstate_spapr_ov5_cas, &vmstate_spapr_patb_entry, + &vmstate_spapr_pending_events, NULL } }; diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 587a3dacb250b6931a6da632ae71bf4542727181..ce41e74665dc09ac27d7eab5dae948ca847cd57f 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -42,8 +42,7 @@ #include "hw/ppc/spapr_ovec.h" #include -struct rtas_error_log { - uint32_t summary; +/* Macros related to rtas_error_log struct defined in spapr.h */ #define RTAS_LOG_VERSION_MASK 0xff000000 #define RTAS_LOG_VERSION_6 0x06000000 #define RTAS_LOG_SEVERITY_MASK 0x00e00000 @@ -85,8 +84,6 @@ struct rtas_error_log { #define RTAS_LOG_TYPE_ECC_CORR 0x0000000a #define RTAS_LOG_TYPE_EPOW 0x00000040 #define RTAS_LOG_TYPE_HOTPLUG 0x000000e5 - uint32_t extended_length; -} QEMU_PACKED; struct rtas_event_log_v6 { uint8_t b0; @@ -166,8 +163,7 @@ struct rtas_event_log_v6_epow { uint64_t reason_code; } QEMU_PACKED; -struct epow_log_full { - struct rtas_error_log hdr; +struct epow_extended_log { struct rtas_event_log_v6 v6hdr; struct rtas_event_log_v6_maina maina; struct rtas_event_log_v6_mainb mainb; @@ -205,8 +201,7 @@ struct rtas_event_log_v6_hp { union drc_identifier drc_id; } QEMU_PACKED; -struct hp_log_full { - struct rtas_error_log hdr; +struct hp_extended_log { struct rtas_event_log_v6 v6hdr; struct rtas_event_log_v6_maina maina; struct rtas_event_log_v6_mainb mainb; @@ -341,25 +336,26 @@ static int rtas_event_log_to_irq(sPAPRMachineState *spapr, int log_type) return source->irq; } -static void rtas_event_log_queue(int log_type, void *data) +static uint32_t spapr_event_log_entry_type(sPAPREventLogEntry *entry) { - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1); + return entry->header.summary & RTAS_LOG_TYPE_MASK; +} - g_assert(data); - entry->log_type = log_type; - entry->data = data; +static void rtas_event_log_queue(sPAPRMachineState *spapr, + sPAPREventLogEntry *entry) +{ QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next); } -static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask) +static sPAPREventLogEntry *rtas_event_log_dequeue(sPAPRMachineState *spapr, + uint32_t event_mask) { - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); sPAPREventLogEntry *entry = NULL; QTAILQ_FOREACH(entry, &spapr->pending_events, next) { const sPAPREventSource *source = - rtas_event_log_to_source(spapr, entry->log_type); + rtas_event_log_to_source(spapr, + spapr_event_log_entry_type(entry)); if (source->mask & event_mask) { break; @@ -380,7 +376,8 @@ static bool rtas_event_log_contains(uint32_t event_mask) QTAILQ_FOREACH(entry, &spapr->pending_events, next) { const sPAPREventSource *source = - rtas_event_log_to_source(spapr, entry->log_type); + rtas_event_log_to_source(spapr, + spapr_event_log_entry_type(entry)); if (source->mask & event_mask) { return true; @@ -428,27 +425,30 @@ static void spapr_init_maina(struct rtas_event_log_v6_maina *maina, static void spapr_powerdown_req(Notifier *n, void *opaque) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + sPAPREventLogEntry *entry; struct rtas_error_log *hdr; struct rtas_event_log_v6 *v6hdr; struct rtas_event_log_v6_maina *maina; struct rtas_event_log_v6_mainb *mainb; struct rtas_event_log_v6_epow *epow; - struct epow_log_full *new_epow; + struct epow_extended_log *new_epow; + entry = g_new(sPAPREventLogEntry, 1); new_epow = g_malloc0(sizeof(*new_epow)); - hdr = &new_epow->hdr; + entry->extended_log = new_epow; + + hdr = &entry->header; v6hdr = &new_epow->v6hdr; maina = &new_epow->maina; mainb = &new_epow->mainb; epow = &new_epow->epow; - hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 - | RTAS_LOG_SEVERITY_EVENT - | RTAS_LOG_DISPOSITION_NOT_RECOVERED - | RTAS_LOG_OPTIONAL_PART_PRESENT - | RTAS_LOG_TYPE_EPOW); - hdr->extended_length = cpu_to_be32(sizeof(*new_epow) - - sizeof(new_epow->hdr)); + hdr->summary = RTAS_LOG_VERSION_6 + | RTAS_LOG_SEVERITY_EVENT + | RTAS_LOG_DISPOSITION_NOT_RECOVERED + | RTAS_LOG_OPTIONAL_PART_PRESENT + | RTAS_LOG_TYPE_EPOW; + hdr->extended_length = sizeof(*new_epow); spapr_init_v6hdr(v6hdr); spapr_init_maina(maina, 3 /* Main-A, Main-B and EPOW */); @@ -468,7 +468,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL; epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC; - rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow); + rtas_event_log_queue(spapr, entry); qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), rtas_event_log_to_irq(spapr, @@ -480,28 +480,31 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, union drc_identifier *drc_id) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - struct hp_log_full *new_hp; + sPAPREventLogEntry *entry; + struct hp_extended_log *new_hp; struct rtas_error_log *hdr; struct rtas_event_log_v6 *v6hdr; struct rtas_event_log_v6_maina *maina; struct rtas_event_log_v6_mainb *mainb; struct rtas_event_log_v6_hp *hp; - new_hp = g_malloc0(sizeof(struct hp_log_full)); - hdr = &new_hp->hdr; + entry = g_new(sPAPREventLogEntry, 1); + new_hp = g_malloc0(sizeof(struct hp_extended_log)); + entry->extended_log = new_hp; + + hdr = &entry->header; v6hdr = &new_hp->v6hdr; maina = &new_hp->maina; mainb = &new_hp->mainb; hp = &new_hp->hp; - hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 - | RTAS_LOG_SEVERITY_EVENT - | RTAS_LOG_DISPOSITION_NOT_RECOVERED - | RTAS_LOG_OPTIONAL_PART_PRESENT - | RTAS_LOG_INITIATOR_HOTPLUG - | RTAS_LOG_TYPE_HOTPLUG); - hdr->extended_length = cpu_to_be32(sizeof(*new_hp) - - sizeof(new_hp->hdr)); + hdr->summary = RTAS_LOG_VERSION_6 + | RTAS_LOG_SEVERITY_EVENT + | RTAS_LOG_DISPOSITION_NOT_RECOVERED + | RTAS_LOG_OPTIONAL_PART_PRESENT + | RTAS_LOG_INITIATOR_HOTPLUG + | RTAS_LOG_TYPE_HOTPLUG; + hdr->extended_length = sizeof(*new_hp); spapr_init_v6hdr(v6hdr); spapr_init_maina(maina, 3 /* Main-A, Main-B, HP */); @@ -551,7 +554,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, cpu_to_be32(drc_id->count_indexed.index); } - rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp); + rtas_event_log_queue(spapr, entry); qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), rtas_event_log_to_irq(spapr, @@ -625,10 +628,10 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong args, uint32_t nret, target_ulong rets) { + CPUState *cs = CPU(cpu); uint32_t mask, buf, len, event_len; uint64_t xinfo; sPAPREventLogEntry *event; - struct rtas_error_log *hdr; int i; if ((nargs < 6) || (nargs > 7) || nret != 1) { @@ -644,21 +647,25 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, xinfo |= (uint64_t)rtas_ld(args, 6) << 32; } - event = rtas_event_log_dequeue(mask); + event = rtas_event_log_dequeue(spapr, mask); if (!event) { goto out_no_events; } - hdr = event->data; - event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr); + event_len = event->header.extended_length + sizeof(event->header); if (event_len < len) { len = event_len; } - cpu_physical_memory_write(buf, event->data, len); + stl_be_phys(cs->as, buf, event->header.summary); + stl_be_phys(cs->as, buf + sizeof(event->header.summary), + event->header.extended_length); + cpu_physical_memory_write(buf + sizeof(event->header), + event->extended_log, + event->header.extended_length); rtas_st(rets, 0, RTAS_OUT_SUCCESS); - g_free(event->data); + g_free(event->extended_log); g_free(event); /* according to PAPR+, the IRQ must be left asserted, or re-asserted, if diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 5f708eec23817eeda03206b721d432be03a076a0..2718b90db768581d0db20432d717b1c3866eab2b 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -606,9 +606,14 @@ struct sPAPRTCETable { sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn); +struct rtas_error_log { + uint32_t summary; + uint32_t extended_length; +} QEMU_PACKED; + struct sPAPREventLogEntry { - int log_type; - void *data; + struct rtas_error_log header; + void *extended_log; QTAILQ_ENTRY(sPAPREventLogEntry) next; };