Skip to content

Commit

Permalink
spapr_events: event-scan RTAS interface
Browse files Browse the repository at this point in the history
We don't actually rely on this interface to surface hotplug events, and
instead rely on the similar-but-interrupt-driven check-exception RTAS
interface used for EPOW events. However, the existence of this interface
is needed to ensure guest kernels initialize the event-reporting
interfaces which will in turn be used by userspace tools to handle these
events, so we implement this interface here.

Since events surfaced by this call are mutually exclusive to those
surfaced via check-exception, we also update the RTAS event queue code
to accept a boolean to mark/filter for events accordingly.

Events of this sort are not currently generated by QEMU, but the interface
has been tested by surfacing hotplug events via event-scan in place
of check-exception.

Signed-off-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
  • Loading branch information
Tyrel Datwyler authored and agraf committed Jun 3, 2015
1 parent 31fe14d commit 79853e1
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
2 changes: 2 additions & 0 deletions hw/ppc/spapr.c
Expand Up @@ -533,6 +533,8 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
refpoints, sizeof(refpoints))));

_FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
_FDT((fdt_property_cell(fdt, "rtas-event-scan-rate",
RTAS_EVENT_SCAN_RATE)));

/*
* According to PAPR, rtas ibm,os-term does not guarantee a return
Expand Down
65 changes: 58 additions & 7 deletions hw/ppc/spapr_events.c
Expand Up @@ -236,17 +236,19 @@ void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq)
_FDT((fdt_end_node(fdt)));
}

static void rtas_event_log_queue(int log_type, void *data)
static void rtas_event_log_queue(int log_type, void *data, bool exception)
{
sPAPREventLogEntry *entry = g_new(sPAPREventLogEntry, 1);

g_assert(data);
entry->log_type = log_type;
entry->exception = exception;
entry->data = data;
QTAILQ_INSERT_TAIL(&spapr->pending_events, entry, next);
}

static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask)
static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask,
bool exception)
{
sPAPREventLogEntry *entry = NULL;

Expand All @@ -256,6 +258,10 @@ static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask)
}

QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
if (entry->exception != exception) {
continue;
}

/* EPOW and hotplug events are surfaced in the same manner */
if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
Expand All @@ -270,7 +276,7 @@ static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask)
return entry;
}

static bool rtas_event_log_contains(uint32_t event_mask)
static bool rtas_event_log_contains(uint32_t event_mask, bool exception)
{
sPAPREventLogEntry *entry = NULL;

Expand All @@ -280,6 +286,10 @@ static bool rtas_event_log_contains(uint32_t event_mask)
}

QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
if (entry->exception != exception) {
continue;
}

/* EPOW and hotplug events are surfaced in the same manner */
if (entry->log_type == RTAS_LOG_TYPE_EPOW ||
entry->log_type == RTAS_LOG_TYPE_HOTPLUG) {
Expand Down Expand Up @@ -367,7 +377,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(RTAS_LOG_TYPE_EPOW, new_epow, true);

qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
}
Expand Down Expand Up @@ -428,7 +438,7 @@ static void spapr_hotplug_req_event(sPAPRDRConnector *drc, uint8_t hp_action)
return;
}

rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp);
rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);

qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
}
Expand Down Expand Up @@ -466,7 +476,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
xinfo |= (uint64_t)rtas_ld(args, 6) << 32;
}

event = rtas_event_log_dequeue(mask);
event = rtas_event_log_dequeue(mask, true);
if (!event) {
goto out_no_events;
}
Expand All @@ -488,7 +498,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
* do the latter here, since our code relies on edge-triggered
* interrupts.
*/
if (rtas_event_log_contains(mask)) {
if (rtas_event_log_contains(mask, true)) {
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
}

Expand All @@ -498,6 +508,46 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
}

static void event_scan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
uint32_t mask, buf, len, event_len;
sPAPREventLogEntry *event;
struct rtas_error_log *hdr;

if (nargs != 4 || nret != 1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}

mask = rtas_ld(args, 0);
buf = rtas_ld(args, 2);
len = rtas_ld(args, 3);

event = rtas_event_log_dequeue(mask, false);
if (!event) {
goto out_no_events;
}

hdr = event->data;
event_len = be32_to_cpu(hdr->extended_length) + sizeof(*hdr);

if (event_len < len) {
len = event_len;
}

cpu_physical_memory_write(buf, event->data, len);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
g_free(event->data);
g_free(event);
return;

out_no_events:
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
}

void spapr_events_init(sPAPREnvironment *spapr)
{
QTAILQ_INIT(&spapr->pending_events);
Expand All @@ -506,4 +556,5 @@ void spapr_events_init(sPAPREnvironment *spapr)
qemu_register_powerdown_notifier(&spapr->epow_notifier);
spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
check_exception);
spapr_rtas_register(RTAS_EVENT_SCAN, "event-scan", event_scan);
}
3 changes: 3 additions & 0 deletions include/hw/ppc/spapr.h
Expand Up @@ -514,6 +514,8 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,

#define RTAS_ERROR_LOG_MAX 2048

#define RTAS_EVENT_SCAN_RATE 1

typedef struct sPAPRTCETable sPAPRTCETable;

#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table"
Expand All @@ -539,6 +541,7 @@ sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn);

struct sPAPREventLogEntry {
int log_type;
bool exception;
void *data;
QTAILQ_ENTRY(sPAPREventLogEntry) next;
};
Expand Down

0 comments on commit 79853e1

Please sign in to comment.