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

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