Blame SOURCES/kvm-hw-ppc-CAS-reset-on-early-device-hotplug.patch

4a2fec
From b6e63f25b4569d9e7c48862f3363b7002feec76f Mon Sep 17 00:00:00 2001
4a2fec
From: David Gibson <dgibson@redhat.com>
4a2fec
Date: Wed, 4 Oct 2017 05:40:13 +0200
4a2fec
Subject: [PATCH 06/34] hw/ppc: CAS reset on early device hotplug
4a2fec
4a2fec
RH-Author: David Gibson <dgibson@redhat.com>
4a2fec
Message-id: <20171004054014.14159-4-dgibson@redhat.com>
4a2fec
Patchwork-id: 76801
4a2fec
O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 3/4] hw/ppc: CAS reset on early device hotplug
4a2fec
Bugzilla: 1448344
4a2fec
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
4a2fec
RH-Acked-by: Thomas Huth <thuth@redhat.com>
4a2fec
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
4a2fec
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
4a2fec
4a2fec
This patch is a follow up on the discussions made in patch
4a2fec
"hw/ppc: disable hotplug before CAS is completed" that can be
4a2fec
found at [1].
4a2fec
4a2fec
At this moment, we do not support CPU/memory hotplug in early
4a2fec
boot stages, before CAS. When a hotplug occurs, the event is logged
4a2fec
in an internal RTAS event log queue and an IRQ pulse is fired. In
4a2fec
regular conditions, the guest handles the interrupt by executing
4a2fec
check_exception, fetching the generated hotplug event and enabling
4a2fec
the device for use.
4a2fec
4a2fec
In early boot, this IRQ isn't caught (SLOF does not handle hotplug
4a2fec
events), leaving the event in the rtas event log queue. If the guest
4a2fec
executes check_exception due to another hotplug event, the re-assertion
4a2fec
of the IRQ ends up de-queuing the first hotplug event as well. In short,
4a2fec
a device hotplugged before CAS is considered coldplugged by SLOF.
4a2fec
This leads to device misbehavior and, in some cases, guest kernel
4a2fec
Ooops when trying to unplug the device.
4a2fec
4a2fec
A proper fix would be to turn every device hotplugged before CAS
4a2fec
as a colplugged device. This is not trivial to do with the current
4a2fec
code base though - the FDT is written in the guest memory at
4a2fec
ppc_spapr_reset and can't be retrieved without adding extra state
4a2fec
(fdt_size for example) that will need to managed and migrated. Adding
4a2fec
the hotplugged DT in the middle of CAS negotiation via the updated DT
4a2fec
tree works with CPU devs, but panics the guest kernel at boot. Additional
4a2fec
analysis would be necessary for LMBs and PCI devices. There are
4a2fec
questions to be made in QEMU/SLOF/kernel level about how we can make
4a2fec
this change in a sustainable way.
4a2fec
4a2fec
With Linux guests, a fix would be the kernel executing check_exception
4a2fec
at boot time, de-queueing the events that happened in early boot and
4a2fec
processing them. However, even if/when the newer kernels start
4a2fec
fetching these events at boot time, we need to take care of older
4a2fec
kernels that won't be doing that.
4a2fec
4a2fec
This patch works around the situation by issuing a CAS reset if a hotplugged
4a2fec
device is detected during CAS:
4a2fec
4a2fec
- the DRC conditions that warrant a CAS reset is the same as those that
4a2fec
triggers a DRC migration - the DRC must have a device attached and
4a2fec
the DRC state is not equal to its ready_state. With that in mind, this
4a2fec
patch makes use of 'spapr_drc_needed' to determine if a CAS reset
4a2fec
is needed.
4a2fec
4a2fec
- In the middle of CAS negotiations, the function
4a2fec
'spapr_hotplugged_dev_before_cas' goes through all the DRCs to see
4a2fec
if there are any DRC that requires a reset, using spapr_drc_needed. If
4a2fec
that happens, returns '1' in 'spapr_h_cas_compose_response' which will set
4a2fec
spapr->cas_reboot to true, causing the machine to reboot.
4a2fec
4a2fec
No changes are made for coldplug devices.
4a2fec
4a2fec
[1] http://lists.nongnu.org/archive/html/qemu-devel/2017-08/msg02855.html
4a2fec
4a2fec
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
4a2fec
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
4a2fec
(cherry picked from commit 10f12e6450407b18b4d5a6b50d3852dcfd7fff75)
4a2fec
4a2fec
Signed-off-by: David Gibson <dgibson@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 hw/ppc/spapr.c             | 26 +++++++++++++++++++++++++-
4a2fec
 hw/ppc/spapr_drc.c         |  2 +-
4a2fec
 include/hw/ppc/spapr_drc.h |  1 +
4a2fec
 3 files changed, 27 insertions(+), 2 deletions(-)
4a2fec
4a2fec
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
4a2fec
index a419aa7..d3db051 100644
4a2fec
--- a/hw/ppc/spapr.c
4a2fec
+++ b/hw/ppc/spapr.c
4a2fec
@@ -790,6 +790,26 @@ out:
4a2fec
     return ret;
4a2fec
 }
4a2fec
 
4a2fec
+static bool spapr_hotplugged_dev_before_cas(void)
4a2fec
+{
4a2fec
+    Object *drc_container, *obj;
4a2fec
+    ObjectProperty *prop;
4a2fec
+    ObjectPropertyIterator iter;
4a2fec
+
4a2fec
+    drc_container = container_get(object_get_root(), "/dr-connector");
4a2fec
+    object_property_iter_init(&iter, drc_container);
4a2fec
+    while ((prop = object_property_iter_next(&iter))) {
4a2fec
+        if (!strstart(prop->type, "link<", NULL)) {
4a2fec
+            continue;
4a2fec
+        }
4a2fec
+        obj = object_property_get_link(drc_container, prop->name, NULL);
4a2fec
+        if (spapr_drc_needed(obj)) {
4a2fec
+            return true;
4a2fec
+        }
4a2fec
+    }
4a2fec
+    return false;
4a2fec
+}
4a2fec
+
4a2fec
 int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
4a2fec
                                  target_ulong addr, target_ulong size,
4a2fec
                                  sPAPROptionVector *ov5_updates)
4a2fec
@@ -797,9 +817,13 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
4a2fec
     void *fdt, *fdt_skel;
4a2fec
     sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
4a2fec
 
4a2fec
+    if (spapr_hotplugged_dev_before_cas()) {
4a2fec
+        return 1;
4a2fec
+    }
4a2fec
+
4a2fec
     size -= sizeof(hdr);
4a2fec
 
4a2fec
-    /* Create sceleton */
4a2fec
+    /* Create skeleton */
4a2fec
     fdt_skel = g_malloc0(size);
4a2fec
     _FDT((fdt_create(fdt_skel, size)));
4a2fec
     _FDT((fdt_begin_node(fdt_skel, "")));
4a2fec
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
4a2fec
index 031ba7c..85c999d 100644
4a2fec
--- a/hw/ppc/spapr_drc.c
4a2fec
+++ b/hw/ppc/spapr_drc.c
4a2fec
@@ -460,7 +460,7 @@ static void drc_reset(void *opaque)
4a2fec
     spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque));
4a2fec
 }
4a2fec
 
4a2fec
-static bool spapr_drc_needed(void *opaque)
4a2fec
+bool spapr_drc_needed(void *opaque)
4a2fec
 {
4a2fec
     sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
4a2fec
     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
4a2fec
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
4a2fec
index a7958d0..f8d9f5b 100644
4a2fec
--- a/include/hw/ppc/spapr_drc.h
4a2fec
+++ b/include/hw/ppc/spapr_drc.h
4a2fec
@@ -257,6 +257,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
4a2fec
 void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
4a2fec
                       int fdt_start_offset, Error **errp);
4a2fec
 void spapr_drc_detach(sPAPRDRConnector *drc);
4a2fec
+bool spapr_drc_needed(void *opaque);
4a2fec
 
4a2fec
 static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc)
4a2fec
 {
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec