Blame SOURCES/kvm-spapr_rtas-add-ibm-configure-connector-RTAS-interfac.patch

8be556
From fbfb411fd95ec7653edbc9e15a9ce5315c744c1a Mon Sep 17 00:00:00 2001
8be556
From: Laurent Vivier <lvivier@redhat.com>
8be556
Date: Thu, 25 Jun 2015 13:44:33 +0200
8be556
Subject: [PATCH 094/217] spapr_rtas: add ibm, configure-connector RTAS
8be556
 interface
8be556
8be556
Message-id: <1435239881-28541-7-git-send-email-lvivier@redhat.com>
8be556
Patchwork-id: 66486
8be556
O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH 06/14] spapr_rtas: add ibm, configure-connector RTAS interface
8be556
Bugzilla: 1172478
8be556
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
8be556
RH-Acked-by: Thomas Huth <thuth@redhat.com>
8be556
RH-Acked-by: David Gibson <dgibson@redhat.com>
8be556
8be556
From: Michael Roth <mdroth@linux.vnet.ibm.com>
8be556
8be556
This interface is used to fetch an OF device-tree nodes that describes a
8be556
newly-attached device to guest. It is called multiple times to walk the
8be556
device-tree node and fetch individual properties into a 'workarea'/buffer
8be556
provided by the guest.
8be556
8be556
The device-tree is generated by QEMU and passed to an sPAPRDRConnector during
8be556
the initial hotplug operation, and the state of these RTAS calls is tracked by
8be556
the sPAPRDRConnector. When the last of these properties is successfully
8be556
fetched, we report as special return value to the guest and transition
8be556
the device to a 'configured' state on the QEMU/DRC side.
8be556
8be556
See docs/specs/ppc-spapr-hotplug.txt for a complete description of
8be556
this interface.
8be556
8be556
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
8be556
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
8be556
Signed-off-by: Alexander Graf <agraf@suse.de>
8be556
(cherry picked from commit 46503c2bc047bfe8c26440e17298fcbc59d7bbbe)
8be556
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
8be556
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
8be556
---
8be556
 hw/ppc/spapr.c         |   4 ++
8be556
 hw/ppc/spapr_rtas.c    | 180 +++++++++++++++++++++++++++++++++++++++++++++++++
8be556
 include/hw/ppc/spapr.h |  14 ++++
8be556
 3 files changed, 198 insertions(+)
8be556
8be556
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
8be556
index 3fe98ff..8b21a71 100644
8be556
--- a/hw/ppc/spapr.c
8be556
+++ b/hw/ppc/spapr.c
8be556
@@ -1663,6 +1663,10 @@ static void ppc_spapr_init(MachineState *machine)
8be556
                                             kernel_cmdline, spapr->epow_irq);
8be556
     assert(spapr->fdt_skel != NULL);
8be556
 
8be556
+    /* used by RTAS */
8be556
+    QTAILQ_INIT(&spapr->ccs_list);
8be556
+    qemu_register_reset(spapr_ccs_reset_hook, spapr);
8be556
+
8be556
     qemu_register_boot_set(spapr_boot_set, spapr);
8be556
 }
8be556
 
8be556
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
8be556
index f80beb2..fa28d43 100644
8be556
--- a/hw/ppc/spapr_rtas.c
8be556
+++ b/hw/ppc/spapr_rtas.c
8be556
@@ -47,6 +47,43 @@
8be556
     do { } while (0)
8be556
 #endif
8be556
 
8be556
+static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPREnvironment *spapr,
8be556
+                                                    uint32_t drc_index)
8be556
+{
8be556
+    sPAPRConfigureConnectorState *ccs = NULL;
8be556
+
8be556
+    QTAILQ_FOREACH(ccs, &spapr->ccs_list, next) {
8be556
+        if (ccs->drc_index == drc_index) {
8be556
+            break;
8be556
+        }
8be556
+    }
8be556
+
8be556
+    return ccs;
8be556
+}
8be556
+
8be556
+static void spapr_ccs_add(sPAPREnvironment *spapr,
8be556
+                          sPAPRConfigureConnectorState *ccs)
8be556
+{
8be556
+    g_assert(!spapr_ccs_find(spapr, ccs->drc_index));
8be556
+    QTAILQ_INSERT_HEAD(&spapr->ccs_list, ccs, next);
8be556
+}
8be556
+
8be556
+static void spapr_ccs_remove(sPAPREnvironment *spapr,
8be556
+                             sPAPRConfigureConnectorState *ccs)
8be556
+{
8be556
+    QTAILQ_REMOVE(&spapr->ccs_list, ccs, next);
8be556
+    g_free(ccs);
8be556
+}
8be556
+
8be556
+void spapr_ccs_reset_hook(void *opaque)
8be556
+{
8be556
+    sPAPREnvironment *spapr = opaque;
8be556
+    sPAPRConfigureConnectorState *ccs, *ccs_tmp;
8be556
+
8be556
+    QTAILQ_FOREACH_SAFE(ccs, &spapr->ccs_list, next, ccs_tmp) {
8be556
+        spapr_ccs_remove(spapr, ccs);
8be556
+    }
8be556
+}
8be556
 
8be556
 static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr,
8be556
                                    uint32_t token, uint32_t nargs,
8be556
@@ -355,6 +392,19 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPREnvironment *spapr,
8be556
 
8be556
     switch (sensor_type) {
8be556
     case RTAS_SENSOR_TYPE_ISOLATION_STATE:
8be556
+        /* if the guest is configuring a device attached to this
8be556
+         * DRC, we should reset the configuration state at this
8be556
+         * point since it may no longer be reliable (guest released
8be556
+         * device and needs to start over, or unplug occurred so
8be556
+         * the FDT is no longer valid)
8be556
+         */
8be556
+        if (sensor_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
8be556
+            sPAPRConfigureConnectorState *ccs = spapr_ccs_find(spapr,
8be556
+                                                               sensor_index);
8be556
+            if (ccs) {
8be556
+                spapr_ccs_remove(spapr, ccs);
8be556
+            }
8be556
+        }
8be556
         drck->set_isolation_state(drc, sensor_state);
8be556
         break;
8be556
     case RTAS_SENSOR_TYPE_DR:
8be556
@@ -418,6 +468,134 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPREnvironment *spapr,
8be556
     rtas_st(rets, 1, entity_sense);
8be556
 }
8be556
 
8be556
+/* configure-connector work area offsets, int32_t units for field
8be556
+ * indexes, bytes for field offset/len values.
8be556
+ *
8be556
+ * as documented by PAPR+ v2.7, 13.5.3.5
8be556
+ */
8be556
+#define CC_IDX_NODE_NAME_OFFSET 2
8be556
+#define CC_IDX_PROP_NAME_OFFSET 2
8be556
+#define CC_IDX_PROP_LEN 3
8be556
+#define CC_IDX_PROP_DATA_OFFSET 4
8be556
+#define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
8be556
+#define CC_WA_LEN 4096
8be556
+
8be556
+static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
8be556
+                                         sPAPREnvironment *spapr,
8be556
+                                         uint32_t token, uint32_t nargs,
8be556
+                                         target_ulong args, uint32_t nret,
8be556
+                                         target_ulong rets)
8be556
+{
8be556
+    uint64_t wa_addr;
8be556
+    uint64_t wa_offset;
8be556
+    uint32_t drc_index;
8be556
+    sPAPRDRConnector *drc;
8be556
+    sPAPRDRConnectorClass *drck;
8be556
+    sPAPRConfigureConnectorState *ccs;
8be556
+    sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
8be556
+    int rc;
8be556
+    const void *fdt;
8be556
+
8be556
+    if (nargs != 2 || nret != 1) {
8be556
+        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
8be556
+        return;
8be556
+    }
8be556
+
8be556
+    wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
8be556
+
8be556
+    drc_index = rtas_ld(wa_addr, 0);
8be556
+    drc = spapr_dr_connector_by_index(drc_index);
8be556
+    if (!drc) {
8be556
+        DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n",
8be556
+                drc_index);
8be556
+        rc = RTAS_OUT_PARAM_ERROR;
8be556
+        goto out;
8be556
+    }
8be556
+
8be556
+    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
8be556
+    fdt = drck->get_fdt(drc, NULL);
8be556
+
8be556
+    ccs = spapr_ccs_find(spapr, drc_index);
8be556
+    if (!ccs) {
8be556
+        ccs = g_new0(sPAPRConfigureConnectorState, 1);
8be556
+        (void)drck->get_fdt(drc, &ccs->fdt_offset);
8be556
+        ccs->drc_index = drc_index;
8be556
+        spapr_ccs_add(spapr, ccs);
8be556
+    }
8be556
+
8be556
+    do {
8be556
+        uint32_t tag;
8be556
+        const char *name;
8be556
+        const struct fdt_property *prop;
8be556
+        int fdt_offset_next, prop_len;
8be556
+
8be556
+        tag = fdt_next_tag(fdt, ccs->fdt_offset, &fdt_offset_next);
8be556
+
8be556
+        switch (tag) {
8be556
+        case FDT_BEGIN_NODE:
8be556
+            ccs->fdt_depth++;
8be556
+            name = fdt_get_name(fdt, ccs->fdt_offset, NULL);
8be556
+
8be556
+            /* provide the name of the next OF node */
8be556
+            wa_offset = CC_VAL_DATA_OFFSET;
8be556
+            rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
8be556
+            rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
8be556
+                                  (uint8_t *)name, strlen(name) + 1);
8be556
+            resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
8be556
+            break;
8be556
+        case FDT_END_NODE:
8be556
+            ccs->fdt_depth--;
8be556
+            if (ccs->fdt_depth == 0) {
8be556
+                /* done sending the device tree, don't need to track
8be556
+                 * the state anymore
8be556
+                 */
8be556
+                drck->set_configured(drc);
8be556
+                spapr_ccs_remove(spapr, ccs);
8be556
+                ccs = NULL;
8be556
+                resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
8be556
+            } else {
8be556
+                resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
8be556
+            }
8be556
+            break;
8be556
+        case FDT_PROP:
8be556
+            prop = fdt_get_property_by_offset(fdt, ccs->fdt_offset,
8be556
+                                              &prop_len);
8be556
+            name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
8be556
+
8be556
+            /* provide the name of the next OF property */
8be556
+            wa_offset = CC_VAL_DATA_OFFSET;
8be556
+            rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
8be556
+            rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
8be556
+                                  (uint8_t *)name, strlen(name) + 1);
8be556
+
8be556
+            /* provide the length and value of the OF property. data gets
8be556
+             * placed immediately after NULL terminator of the OF property's
8be556
+             * name string
8be556
+             */
8be556
+            wa_offset += strlen(name) + 1,
8be556
+            rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
8be556
+            rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
8be556
+            rtas_st_buffer_direct(wa_addr + wa_offset, CC_WA_LEN - wa_offset,
8be556
+                                  (uint8_t *)((struct fdt_property *)prop)->data,
8be556
+                                  prop_len);
8be556
+            resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
8be556
+            break;
8be556
+        case FDT_END:
8be556
+            resp = SPAPR_DR_CC_RESPONSE_ERROR;
8be556
+        default:
8be556
+            /* keep seeking for an actionable tag */
8be556
+            break;
8be556
+        }
8be556
+        if (ccs) {
8be556
+            ccs->fdt_offset = fdt_offset_next;
8be556
+        }
8be556
+    } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
8be556
+
8be556
+    rc = resp;
8be556
+out:
8be556
+    rtas_st(rets, 0, rc);
8be556
+}
8be556
+
8be556
 static struct rtas_call {
8be556
     const char *name;
8be556
     spapr_rtas_fn fn;
8be556
@@ -551,6 +729,8 @@ static void core_rtas_register_types(void)
8be556
                         rtas_set_indicator);
8be556
     spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
8be556
                         rtas_get_sensor_state);
8be556
+    spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
8be556
+                        rtas_ibm_configure_connector);
8be556
 }
8be556
 
8be556
 type_init(core_rtas_register_types)
8be556
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
8be556
index 919eec6..673fd89 100644
8be556
--- a/include/hw/ppc/spapr.h
8be556
+++ b/include/hw/ppc/spapr.h
8be556
@@ -7,6 +7,7 @@
8be556
 struct VIOsPAPRBus;
8be556
 struct sPAPRPHBState;
8be556
 struct sPAPRNVRAM;
8be556
+typedef struct sPAPRConfigureConnectorState sPAPRConfigureConnectorState;
8be556
 
8be556
 #define HPTE64_V_HPTE_DIRTY     0x0000000000000040ULL
8be556
 
8be556
@@ -39,6 +40,9 @@ typedef struct sPAPREnvironment {
8be556
     bool htab_first_pass;
8be556
     int htab_fd;
8be556
     bool htab_fd_stale;
8be556
+
8be556
+    /* RTAS state */
8be556
+    QTAILQ_HEAD(, sPAPRConfigureConnectorState) ccs_list;
8be556
 } sPAPREnvironment;
8be556
 
8be556
 #define H_SUCCESS         0
8be556
@@ -539,6 +543,16 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
8be556
                       sPAPRTCETable *tcet);
8be556
 void spapr_pci_switch_vga(bool big_endian);
8be556
 
8be556
+/* rtas-configure-connector state */
8be556
+struct sPAPRConfigureConnectorState {
8be556
+    uint32_t drc_index;
8be556
+    int fdt_offset;
8be556
+    int fdt_depth;
8be556
+    QTAILQ_ENTRY(sPAPRConfigureConnectorState) next;
8be556
+};
8be556
+
8be556
+void spapr_ccs_reset_hook(void *opaque);
8be556
+
8be556
 #define TYPE_SPAPR_RTC "spapr-rtc"
8be556
 
8be556
 void spapr_rtc_read(DeviceState *dev, struct tm *tm, uint32_t *ns);
8be556
-- 
8be556
1.8.3.1
8be556