aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_drc.c
diff options
context:
space:
mode:
authorGreg Kurz <groug@kaod.org>2019-02-19 18:17:38 +0100
committerDavid Gibson <david@gibson.dropbear.id.au>2019-02-26 09:21:25 +1100
commitd9c95c71aca38e3221ae38672494721650c99edc (patch)
treeb3dadf2c2fc8187785272255e5ff2bf93ac35787 /hw/ppc/spapr_drc.c
parent539c6e735871aae54d9a61520efdfc02dc506d9b (diff)
downloadqemu-d9c95c71aca38e3221ae38672494721650c99edc.zip
qemu-d9c95c71aca38e3221ae38672494721650c99edc.tar.gz
qemu-d9c95c71aca38e3221ae38672494721650c99edc.tar.bz2
spapr_drc: Allow FDT fragment to be added later
The current logic is to provide the FDT fragment when attaching a device to a DRC. This works perfectly fine for our current hotplug support, but soon we will add support for PHB hotplug which has some constraints, that CPU, PCI and LMB devices don't seem to have. The first constraint is that the "ibm,dma-window" property of the PHB node requires the IOMMU to be configured, ie, spapr_tce_table_enable() has been called, which happens during PHB reset. It is okay in the case of hotplug since the device is reset before the hotplug handler is called. On the contrary with coldplug, the hotplug handler is called first and device is only reset during the initial system reset. Trying to create the FDT fragment on the hotplug path in this case, would result in somthing like this: ibm,dma-window = < 0x80000000 0x00 0x00 0x00 0x00 >; This will cause linux in the guest to panic, by simply removing and re-adding the PHB using the drmgr command: page = alloc_pages_node(nid, GFP_KERNEL, get_order(sz)); if (!page) panic("iommu_init_table: Can't allocate %ld bytes\n", sz); The second and maybe more problematic constraint is that the "interrupt-map" property needs to reference the interrupt controller node using the very same phandle that SLOF has already exposed to the guest. QEMU requires SLOF to call the private KVMPPC_H_UPDATE_DT hcall at some point to know about this phandle. With the latest QEMU and SLOF, this happens when SLOF gets quiesced. This means that if the PHB gets hotplugged after CAS but before SLOF quiesce, then we're sure that the phandle is not known when the hotplug handler is called. The FDT is only needed when the guest first invokes RTAS to configure the connector actually, long after SLOF quiesce. Let's postpone the creation of FDT fragments for PHBs to rtas_ibm_configure_connector(). Since we only need this for PHBs, introduce a new method in the base DRC class for that. DRC subtypes will be converted to use it in subsequent patches. Allow spapr_drc_attach() to be passed a NULL fdt argument if the method is available. When all DRC subtypes have been converted, the fdt argument will eventually disappear. Signed-off-by: Greg Kurz <groug@kaod.org> Message-Id: <155059665823.1466090.18358845122627355537.stgit@bahia.lab.toulouse-stg.fr.ibm.com> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/ppc/spapr_drc.c')
-rw-r--r--hw/ppc/spapr_drc.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 2edb7d1..66b965a 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -22,6 +22,7 @@
#include "qemu/error-report.h"
#include "hw/ppc/spapr.h" /* for RTAS return codes */
#include "hw/pci-host/spapr.h" /* spapr_phb_remove_pci_device_cb callback */
+#include "sysemu/device_tree.h"
#include "trace.h"
#define DRC_CONTAINER_PATH "/dr-connector"
@@ -376,6 +377,8 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
int fdt_start_offset, Error **errp)
{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
trace_spapr_drc_attach(spapr_drc_index(drc));
if (drc->dev) {
@@ -384,11 +387,14 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
}
g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE)
|| (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON));
- g_assert(fdt);
+ g_assert(fdt || drck->dt_populate);
drc->dev = d;
- drc->fdt = fdt;
- drc->fdt_start_offset = fdt_start_offset;
+
+ if (fdt) {
+ drc->fdt = fdt;
+ drc->fdt_start_offset = fdt_start_offset;
+ }
object_property_add_link(OBJECT(drc), "device",
object_get_typename(OBJECT(drc->dev)),
@@ -1102,10 +1108,30 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
goto out;
}
- g_assert(drc->fdt);
-
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ g_assert(drc->fdt || drck->dt_populate);
+
+ if (!drc->fdt) {
+ Error *local_err = NULL;
+ void *fdt;
+ int fdt_size;
+
+ fdt = create_device_tree(&fdt_size);
+
+ if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset,
+ &local_err)) {
+ g_free(fdt);
+ error_free(local_err);
+ rc = SPAPR_DR_CC_RESPONSE_ERROR;
+ goto out;
+ }
+
+ drc->fdt = fdt;
+ drc->ccs_offset = drc->fdt_start_offset;
+ drc->ccs_depth = 0;
+ }
+
do {
uint32_t tag;
const char *name;