From patchwork Wed Oct 12 23:13:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Roth X-Patchwork-Id: 681494 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3svVQh5LkDz9ryn for ; Thu, 13 Oct 2016 10:27:56 +1100 (AEDT) Received: from localhost ([::1]:36390 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1buSwD-0006Ku-PA for incoming@patchwork.ozlabs.org; Wed, 12 Oct 2016 19:27:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35405) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1buSjS-0004dO-N2 for qemu-devel@nongnu.org; Wed, 12 Oct 2016 19:14:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1buSjP-0000Xh-5t for qemu-devel@nongnu.org; Wed, 12 Oct 2016 19:14:42 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:40965) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1buSjO-0000Wk-SE for qemu-devel@nongnu.org; Wed, 12 Oct 2016 19:14:39 -0400 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.17/8.16.0.17) with SMTP id u9CNDTZE104060 for ; Wed, 12 Oct 2016 19:14:38 -0400 Received: from e33.co.us.ibm.com (e33.co.us.ibm.com [32.97.110.151]) by mx0a-001b2d01.pphosted.com with ESMTP id 261qwsu8c5-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 12 Oct 2016 19:14:38 -0400 Received: from localhost by e33.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 12 Oct 2016 17:14:37 -0600 Received: from d03dlp02.boulder.ibm.com (9.17.202.178) by e33.co.us.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 12 Oct 2016 17:14:34 -0600 Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by d03dlp02.boulder.ibm.com (Postfix) with ESMTP id 47CF43E40041; Wed, 12 Oct 2016 17:14:34 -0600 (MDT) Received: from b03ledav002.gho.boulder.ibm.com (b03ledav002.gho.boulder.ibm.com [9.17.130.233]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u9CNEYtM16056594; Wed, 12 Oct 2016 16:14:34 -0700 Received: from b03ledav002.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2401C136043; Wed, 12 Oct 2016 17:14:34 -0600 (MDT) Received: from localhost (unknown [9.41.92.211]) by b03ledav002.gho.boulder.ibm.com (Postfix) with ESMTP id F302E136040; Wed, 12 Oct 2016 17:14:33 -0600 (MDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Wed, 12 Oct 2016 18:13:56 -0500 X-Mailer: git-send-email 1.9.1 In-Reply-To: <1476314039-9520-1-git-send-email-mdroth@linux.vnet.ibm.com> References: <1476314039-9520-1-git-send-email-mdroth@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16101223-0008-0000-0000-000005CCFC7D X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00005900; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000186; SDB=6.00767567; UDB=6.00367283; IPR=6.00543728; BA=6.00004805; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00012969; XFM=3.00000011; UTC=2016-10-12 23:14:36 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16101223-0009-0000-0000-00003C174690 Message-Id: <1476314039-9520-9-git-send-email-mdroth@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-10-12_13:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=3 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1609300000 definitions=main-1610120387 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH 08/11] spapr_events: add support for dedicated hotplug event source X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: nfont@linux.vnet.ibm.com, david@gibson.dropbear.id.au, qemu-ppc@nongnu.org, jallen@linux.vnet.ibm.com, bharata@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Hotplug events were previously delivered using an EPOW interrupt and were queued by linux guests into a circular buffer. For traditional EPOW events like shutdown/resets, this isn't an issue, but for hotplug events there are cases where this buffer can be exhausted, resulting in the loss of hotplug events, resets, etc. Newer-style hotplug event are delivered using a dedicated event source. We enable this in supported guests by adding standard an additional event source in the guest device-tree via /event-sources, and, if the guest advertises support for the newer-style hotplug events, using the corresponding interrupt to signal the available of hotplug/unplug events. Signed-off-by: Michael Roth --- hw/ppc/spapr.c | 10 ++-- hw/ppc/spapr_events.c | 148 ++++++++++++++++++++++++++++++++++++++----------- include/hw/ppc/spapr.h | 3 +- 3 files changed, 120 insertions(+), 41 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d80a6fa..2037222 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -275,8 +275,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, hwaddr initrd_size, hwaddr kernel_size, bool little_endian, - const char *kernel_cmdline, - uint32_t epow_irq) + const char *kernel_cmdline) { void *fdt; uint32_t start_prop = cpu_to_be32(initrd_base); @@ -437,7 +436,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, _FDT((fdt_end_node(fdt))); /* event-sources */ - spapr_events_fdt_skel(fdt, epow_irq); + spapr_events_fdt_skel(fdt); /* /hypervisor node */ if (kvm_enabled()) { @@ -1944,7 +1943,7 @@ static void ppc_spapr_init(MachineState *machine) } g_free(filename); - /* Set up EPOW events infrastructure */ + /* Set up RTAS event infrastructure */ spapr_events_init(spapr); /* Set up the RTC RTAS interfaces */ @@ -2076,8 +2075,7 @@ static void ppc_spapr_init(MachineState *machine) /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, kernel_size, kernel_le, - kernel_cmdline, - spapr->check_exception_irq); + kernel_cmdline); assert(spapr->fdt_skel != NULL); /* used by RTAS */ diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 4c7b6ae..f8bbec6 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -40,6 +40,7 @@ #include "hw/ppc/spapr_drc.h" #include "qemu/help_option.h" #include "qemu/bcd.h" +#include "hw/ppc/spapr_ovec.h" #include struct rtas_error_log { @@ -206,28 +207,104 @@ struct hp_log_full { struct rtas_event_log_v6_hp hp; } QEMU_PACKED; -#define EVENT_MASK_INTERNAL_ERRORS 0x80000000 -#define EVENT_MASK_EPOW 0x40000000 -#define EVENT_MASK_HOTPLUG 0x10000000 -#define EVENT_MASK_IO 0x08000000 +typedef enum EventClassIndex { + EVENT_CLASS_INTERNAL_ERRORS = 0, + EVENT_CLASS_EPOW = 1, + EVENT_CLASS_RESERVED = 2, + EVENT_CLASS_HOT_PLUG = 3, + EVENT_CLASS_IO = 4, + EVENT_CLASS_MAX +} EventClassIndex; + +#define EVENT_CLASS_MASK(index) (1 << (31 - index)) + +typedef struct EventSource { + const char *name; + int irq; + uint32_t mask; + bool enabled; +} EventSource; + +static EventSource event_source[EVENT_CLASS_MAX] = { + [EVENT_CLASS_INTERNAL_ERRORS] = { .name = "internal-errors", }, + [EVENT_CLASS_EPOW] = { .name = "epow-events", }, + [EVENT_CLASS_HOT_PLUG] = { .name = "hot-plug-events", }, + [EVENT_CLASS_IO] = { .name = "ibm,io-events", }, +}; + +static void rtas_event_source_register(EventClassIndex index, int irq) +{ + /* we only support 1 irq per event class at the moment */ + g_assert(!event_source[index].enabled); + event_source[index].irq = irq; + event_source[index].mask = EVENT_CLASS_MASK(index); + event_source[index].enabled = true; +} -void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq) +void spapr_events_fdt_skel(void *fdt) { - uint32_t irq_ranges[] = {cpu_to_be32(check_exception_irq), cpu_to_be32(1)}; - uint32_t interrupts[] = {cpu_to_be32(check_exception_irq), 0}; + uint32_t irq_ranges[EVENT_CLASS_MAX * 2]; + int i, count = 0; _FDT((fdt_begin_node(fdt, "event-sources"))); + for (i = 0, count = 0; i < EVENT_CLASS_MAX; i++) { + /* TODO: what does 0 entail? */ + uint32_t interrupts[] = { cpu_to_be32(event_source[i].irq), 0 }; + + if (!event_source[i].enabled) { + continue; + } + + _FDT((fdt_begin_node(fdt, event_source[i].name))); + _FDT((fdt_property(fdt, "interrupts", interrupts, sizeof(interrupts)))); + _FDT((fdt_end_node(fdt))); + + irq_ranges[count++] = interrupts[0]; + irq_ranges[count++] = cpu_to_be32(1); + } + + /* TODO: confirm the count is the last expected element */ + irq_ranges[count] = cpu_to_be32(count); + count++; + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); _FDT((fdt_property(fdt, "interrupt-ranges", - irq_ranges, sizeof(irq_ranges)))); + irq_ranges, count * sizeof(uint32_t)))); - _FDT((fdt_begin_node(fdt, "epow-events"))); - _FDT((fdt_property(fdt, "interrupts", interrupts, sizeof(interrupts)))); _FDT((fdt_end_node(fdt))); +} - _FDT((fdt_end_node(fdt))); +static const EventSource *rtas_event_log_to_source(int log_type) +{ + const EventSource *source; + + switch (log_type) { + case RTAS_LOG_TYPE_HOTPLUG: + source = &event_source[EVENT_CLASS_HOT_PLUG]; + if (event_source[EVENT_CLASS_HOT_PLUG].enabled) { + break; + } + /* fall back to epow for legacy hotplug interrupt source */ + case RTAS_LOG_TYPE_EPOW: + source = &event_source[EVENT_CLASS_EPOW]; + break; + default: + source = NULL; + } + + return source; +} + +static int rtas_event_log_to_irq(int log_type) +{ + const EventSource *source = rtas_event_log_to_source(log_type); + + g_assert(source); + g_assert(source->enabled); + + return source->irq; } static void rtas_event_log_queue(int log_type, void *data, bool exception) @@ -248,19 +325,14 @@ static sPAPREventLogEntry *rtas_event_log_dequeue(uint32_t event_mask, sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); sPAPREventLogEntry *entry = NULL; - /* we only queue EPOW events atm. */ - if ((event_mask & EVENT_MASK_EPOW) == 0) { - return NULL; - } - QTAILQ_FOREACH(entry, &spapr->pending_events, next) { + const EventSource *source = rtas_event_log_to_source(entry->log_type); + 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) { + if (source->mask & event_mask) { break; } } @@ -277,19 +349,14 @@ static bool rtas_event_log_contains(uint32_t event_mask, bool exception) sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); sPAPREventLogEntry *entry = NULL; - /* we only queue EPOW events atm. */ - if ((event_mask & EVENT_MASK_EPOW) == 0) { - return false; - } - QTAILQ_FOREACH(entry, &spapr->pending_events, next) { + const EventSource *source = rtas_event_log_to_source(entry->log_type); + 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) { + if (source->mask & event_mask) { return true; } } @@ -377,7 +444,8 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, + rtas_event_log_to_irq(RTAS_LOG_TYPE_EPOW))); } static void spapr_hotplug_set_signalled(uint32_t drc_index) @@ -459,7 +527,8 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, + rtas_event_log_to_irq(RTAS_LOG_TYPE_HOTPLUG))); } void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc) @@ -505,6 +574,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint64_t xinfo; sPAPREventLogEntry *event; struct rtas_error_log *hdr; + int i; if ((nargs < 6) || (nargs > 7) || nret != 1) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -541,8 +611,11 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, * do the latter here, since our code relies on edge-triggered * interrupts. */ - if (rtas_event_log_contains(mask, true)) { - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + for (i = 0; i < EVENT_CLASS_MAX; i++) { + if (rtas_event_log_contains(EVENT_CLASS_MASK(i), true)) { + g_assert(event_source[i].enabled); + qemu_irq_pulse(xics_get_qirq(spapr->xics, event_source[i].irq)); + } } return; @@ -594,8 +667,17 @@ out_no_events: void spapr_events_init(sPAPRMachineState *spapr) { QTAILQ_INIT(&spapr->pending_events); - spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false, - &error_fatal); + + rtas_event_source_register(EVENT_CLASS_EPOW, + xics_spapr_alloc(spapr->xics, 0, 0, false, + &error_fatal)); + + if (spapr->use_hotplug_event_source) { + rtas_event_source_register(EVENT_CLASS_HOT_PLUG, + xics_spapr_alloc(spapr->xics, 0, 0, false, + &error_fatal)); + } + spapr->epow_notifier.notify = spapr_powerdown_req; qemu_register_powerdown_notifier(&spapr->epow_notifier); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception", diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index d1a4a14..2295ac6 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -71,7 +71,6 @@ struct sPAPRMachineState { sPAPROptionVector *ov5_cas; bool cas_reboot; - uint32_t check_exception_irq; Notifier epow_notifier; QTAILQ_HEAD(, sPAPREventLogEntry) pending_events; bool use_hotplug_event_source; @@ -579,7 +578,7 @@ struct sPAPREventLogEntry { }; void spapr_events_init(sPAPRMachineState *sm); -void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); +void spapr_events_fdt_skel(void *fdt); int spapr_h_cas_compose_response(sPAPRMachineState *sm, target_ulong addr, target_ulong size, bool cpu_update,