Blame SOURCES/kvm-hw-ppc-spapr_caps-Rework-spapr_caps-to-use-uint8-int.patch

4a2fec
From dde06ffd66bbc8aa9232dd2c0b849c074d9fcd06 Mon Sep 17 00:00:00 2001
4a2fec
From: David Gibson <dgibson@redhat.com>
4a2fec
Date: Fri, 19 Jan 2018 02:34:41 +0100
4a2fec
Subject: [PATCH 13/21] hw/ppc/spapr_caps: Rework spapr_caps to use uint8
4a2fec
 internal representation
4a2fec
4a2fec
RH-Author: David Gibson <dgibson@redhat.com>
4a2fec
Message-id: <20180119023442.28577-7-dgibson@redhat.com>
4a2fec
Patchwork-id: 78674
4a2fec
O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 6/7] hw/ppc/spapr_caps: Rework spapr_caps to use uint8 internal representation
4a2fec
Bugzilla: 1523414
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: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
4a2fec
4a2fec
Currently spapr_caps are tied to boolean values (on or off). This patch
4a2fec
reworks the caps so that they can have any uint8 value. This allows more
4a2fec
capabilities with various values to be represented in the same way
4a2fec
internally. Capabilities are numbered in ascending order. The internal
4a2fec
representation of capability values is an array of uint8s in the
4a2fec
sPAPRMachineState, indexed by capability number.
4a2fec
4a2fec
Capabilities can have their own name, description, options, getter and
4a2fec
setter functions, type and allow functions. They also each have their own
4a2fec
section in the migration stream. Capabilities are only migrated if they
4a2fec
were explictly set on the command line, with the assumption that
4a2fec
otherwise the default will match.
4a2fec
4a2fec
On migration we ensure that the capability value on the destination
4a2fec
is greater than or equal to the capability value from the source. So
4a2fec
long at this remains the case then the migration is considered
4a2fec
compatible and allowed to continue.
4a2fec
4a2fec
This patch implements generic getter and setter functions for boolean
4a2fec
capabilities. It also converts the existings cap-htm, cap-vsx and
4a2fec
cap-dfp capabilities to this new format.
4a2fec
4a2fec
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
4a2fec
(cherry picked from commit 4e5fe3688e23d61b45cc549ff1322aff8f50ef45)
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
4a2fec
Conflicts:
4a2fec
	hw/ppc/spapr.c
4a2fec
	include/hw/ppc/spapr.h
4a2fec
4a2fec
Some trivial contextual conflicts.  Also conflicts due to difference
4a2fec
between upstream and downstream machine type versions.  Converted to
4a2fec
apply to relevant downstream versions.
4a2fec
4a2fec
Again needed adjustment to the pre_save function because its return
4a2fec
type has been changed upstream, but not downstream.
4a2fec
4a2fec
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414
4a2fec
4a2fec
Signed-off-by: David Gibson <dgibson@redhat.com>
4a2fec
---
4a2fec
 hw/ppc/spapr.c         |  38 ++++--
4a2fec
 hw/ppc/spapr_caps.c    | 321 +++++++++++++++++++++++++------------------------
4a2fec
 include/hw/ppc/spapr.h |  45 +++----
4a2fec
 3 files changed, 218 insertions(+), 186 deletions(-)
4a2fec
4a2fec
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
4a2fec
index 41cb2fa..66227c3 100644
4a2fec
--- a/hw/ppc/spapr.c
4a2fec
+++ b/hw/ppc/spapr.c
4a2fec
@@ -320,7 +320,7 @@ static void spapr_populate_pa_features(sPAPRMachineState *spapr,
4a2fec
          */
4a2fec
         pa_features[3] |= 0x20;
4a2fec
     }
4a2fec
-    if (spapr_has_cap(spapr, SPAPR_CAP_HTM) && pa_size > 24) {
4a2fec
+    if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
4a2fec
         pa_features[24] |= 0x80;    /* Transactional memory support */
4a2fec
     }
4a2fec
     if (legacy_guest && pa_size > 40) {
4a2fec
@@ -566,7 +566,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
4a2fec
      *
4a2fec
      * Only CPUs for which we create core types in spapr_cpu_core.c
4a2fec
      * are possible, and all of those have VMX */
4a2fec
-    if (spapr_has_cap(spapr, SPAPR_CAP_VSX)) {
4a2fec
+    if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
4a2fec
         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
4a2fec
     } else {
4a2fec
         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
4a2fec
@@ -575,7 +575,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
4a2fec
     /* Advertise DFP (Decimal Floating Point) if available
4a2fec
      *   0 / no property == no DFP
4a2fec
      *   1               == DFP available */
4a2fec
-    if (spapr_has_cap(spapr, SPAPR_CAP_DFP)) {
4a2fec
+    if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
4a2fec
         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
4a2fec
     }
4a2fec
 
4a2fec
@@ -1544,6 +1544,18 @@ static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
+static int spapr_pre_load(void *opaque)
4a2fec
+{
4a2fec
+    int rc;
4a2fec
+
4a2fec
+    rc = spapr_caps_pre_load(opaque);
4a2fec
+    if (rc) {
4a2fec
+        return rc;
4a2fec
+    }
4a2fec
+
4a2fec
+    return 0;
4a2fec
+}
4a2fec
+
4a2fec
 static int spapr_post_load(void *opaque, int version_id)
4a2fec
 {
4a2fec
     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
4a2fec
@@ -1585,6 +1597,11 @@ static int spapr_post_load(void *opaque, int version_id)
4a2fec
     return err;
4a2fec
 }
4a2fec
 
4a2fec
+static void spapr_pre_save(void *opaque)
4a2fec
+{
4a2fec
+    spapr_caps_pre_save(opaque);
4a2fec
+}
4a2fec
+
4a2fec
 static bool version_before_3(void *opaque, int version_id)
4a2fec
 {
4a2fec
     return version_id < 3;
4a2fec
@@ -1705,7 +1722,9 @@ static const VMStateDescription vmstate_spapr = {
4a2fec
     .name = "spapr",
4a2fec
     .version_id = 3,
4a2fec
     .minimum_version_id = 1,
4a2fec
+    .pre_load = spapr_pre_load,
4a2fec
     .post_load = spapr_post_load,
4a2fec
+    .pre_save = spapr_pre_save,
4a2fec
     .fields = (VMStateField[]) {
4a2fec
         /* used to be @next_irq */
4a2fec
         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
4a2fec
@@ -1720,7 +1739,9 @@ static const VMStateDescription vmstate_spapr = {
4a2fec
         &vmstate_spapr_ov5_cas,
4a2fec
         &vmstate_spapr_patb_entry,
4a2fec
         &vmstate_spapr_pending_events,
4a2fec
-        &vmstate_spapr_caps,
4a2fec
+        &vmstate_spapr_cap_htm,
4a2fec
+        &vmstate_spapr_cap_vsx,
4a2fec
+        &vmstate_spapr_cap_dfp,
4a2fec
         NULL
4a2fec
     }
4a2fec
 };
4a2fec
@@ -2279,8 +2300,6 @@ static void ppc_spapr_init(MachineState *machine)
4a2fec
     char *filename;
4a2fec
     Error *resize_hpt_err = NULL;
4a2fec
 
4a2fec
-    spapr_caps_validate(spapr, &error_fatal);
4a2fec
-
4a2fec
     msi_nonbroken = true;
4a2fec
 
4a2fec
     QLIST_INIT(&spapr->phbs);
4a2fec
@@ -3650,7 +3669,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
4a2fec
     mc->numa_mem_align_shift = 28;
4a2fec
     smc->has_power9_support = true;
4a2fec
 
4a2fec
-    smc->default_caps = spapr_caps(SPAPR_CAP_VSX | SPAPR_CAP_DFP);
4a2fec
+    smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
4a2fec
+    smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
4a2fec
+    smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
4a2fec
     spapr_caps_add_properties(smc, &error_abort);
4a2fec
 }
4a2fec
 
4a2fec
@@ -4056,8 +4077,7 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc)
4a2fec
     smc->has_power9_support = false;
4a2fec
     smc->pre_2_10_has_unused_icps = true;
4a2fec
     smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
4a2fec
-    smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX
4a2fec
-                                   | SPAPR_CAP_DFP);
4a2fec
+    smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
4a2fec
 }
4a2fec
 
4a2fec
 DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false);
4a2fec
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
4a2fec
index 2b67ac2..f95a785 100644
4a2fec
--- a/hw/ppc/spapr_caps.c
4a2fec
+++ b/hw/ppc/spapr_caps.c
4a2fec
@@ -35,18 +35,51 @@
4a2fec
 typedef struct sPAPRCapabilityInfo {
4a2fec
     const char *name;
4a2fec
     const char *description;
4a2fec
-    uint64_t flag;
4a2fec
+    const char *options;                        /* valid capability values */
4a2fec
+    int index;
4a2fec
 
4a2fec
+    /* Getter and Setter Function Pointers */
4a2fec
+    ObjectPropertyAccessor *get;
4a2fec
+    ObjectPropertyAccessor *set;
4a2fec
+    const char *type;
4a2fec
     /* Make sure the virtual hardware can support this capability */
4a2fec
-    void (*allow)(sPAPRMachineState *spapr, Error **errp);
4a2fec
-
4a2fec
-    /* If possible, tell the virtual hardware not to allow the cap to
4a2fec
-     * be used at all */
4a2fec
-    void (*disallow)(sPAPRMachineState *spapr, Error **errp);
4a2fec
+    void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
4a2fec
 } sPAPRCapabilityInfo;
4a2fec
 
4a2fec
-static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp)
4a2fec
+static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
4a2fec
+                               void *opaque, Error **errp)
4a2fec
+{
4a2fec
+    sPAPRCapabilityInfo *cap = opaque;
4a2fec
+    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
4a2fec
+    bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
4a2fec
+
4a2fec
+    visit_type_bool(v, name, &value, errp);
4a2fec
+}
4a2fec
+
4a2fec
+static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
4a2fec
+                               void *opaque, Error **errp)
4a2fec
+{
4a2fec
+    sPAPRCapabilityInfo *cap = opaque;
4a2fec
+    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
4a2fec
+    bool value;
4a2fec
+    Error *local_err = NULL;
4a2fec
+
4a2fec
+    visit_type_bool(v, name, &value, &local_err);
4a2fec
+    if (local_err) {
4a2fec
+        error_propagate(errp, local_err);
4a2fec
+        return;
4a2fec
+    }
4a2fec
+
4a2fec
+    spapr->cmd_line_caps[cap->index] = true;
4a2fec
+    spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
4a2fec
+}
4a2fec
+
4a2fec
+static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
4a2fec
 {
4a2fec
+    if (!val) {
4a2fec
+        /* TODO: We don't support disabling htm yet */
4a2fec
+        return;
4a2fec
+    }
4a2fec
     if (tcg_enabled()) {
4a2fec
         error_setg(errp,
4a2fec
                    "No Transactional Memory support in TCG, try cap-htm=off");
4a2fec
@@ -57,11 +90,15 @@ static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
-static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp)
4a2fec
+static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
4a2fec
 {
4a2fec
     PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
4a2fec
     CPUPPCState *env = &cpu->env;
4a2fec
 
4a2fec
+    if (!val) {
4a2fec
+        /* TODO: We don't support disabling vsx yet */
4a2fec
+        return;
4a2fec
+    }
4a2fec
     /* Allowable CPUs in spapr_cpu_core.c should already have gotten
4a2fec
      * rid of anything that doesn't do VMX */
4a2fec
     g_assert(env->insns_flags & PPC_ALTIVEC);
4a2fec
@@ -70,37 +107,51 @@ static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
-static void cap_dfp_allow(sPAPRMachineState *spapr, Error **errp)
4a2fec
+static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
4a2fec
 {
4a2fec
     PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
4a2fec
     CPUPPCState *env = &cpu->env;
4a2fec
 
4a2fec
+    if (!val) {
4a2fec
+        /* TODO: We don't support disabling dfp yet */
4a2fec
+        return;
4a2fec
+    }
4a2fec
     if (!(env->insns_flags2 & PPC2_DFP)) {
4a2fec
         error_setg(errp, "DFP support not available, try cap-dfp=off");
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
-static sPAPRCapabilityInfo capability_table[] = {
4a2fec
-    {
4a2fec
+
4a2fec
+sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
4a2fec
+    [SPAPR_CAP_HTM] = {
4a2fec
         .name = "htm",
4a2fec
         .description = "Allow Hardware Transactional Memory (HTM)",
4a2fec
-        .flag = SPAPR_CAP_HTM,
4a2fec
-        .allow = cap_htm_allow,
4a2fec
-        /* TODO: add cap_htm_disallow */
4a2fec
+        .options = "",
4a2fec
+        .index = SPAPR_CAP_HTM,
4a2fec
+        .get = spapr_cap_get_bool,
4a2fec
+        .set = spapr_cap_set_bool,
4a2fec
+        .type = "bool",
4a2fec
+        .apply = cap_htm_apply,
4a2fec
     },
4a2fec
-    {
4a2fec
+    [SPAPR_CAP_VSX] = {
4a2fec
         .name = "vsx",
4a2fec
         .description = "Allow Vector Scalar Extensions (VSX)",
4a2fec
-        .flag = SPAPR_CAP_VSX,
4a2fec
-        .allow = cap_vsx_allow,
4a2fec
-        /* TODO: add cap_vsx_disallow */
4a2fec
+        .options = "",
4a2fec
+        .index = SPAPR_CAP_VSX,
4a2fec
+        .get = spapr_cap_get_bool,
4a2fec
+        .set = spapr_cap_set_bool,
4a2fec
+        .type = "bool",
4a2fec
+        .apply = cap_vsx_apply,
4a2fec
     },
4a2fec
-    {
4a2fec
+    [SPAPR_CAP_DFP] = {
4a2fec
         .name = "dfp",
4a2fec
         .description = "Allow Decimal Floating Point (DFP)",
4a2fec
-        .flag = SPAPR_CAP_DFP,
4a2fec
-        .allow = cap_dfp_allow,
4a2fec
-        /* TODO: add cap_dfp_disallow */
4a2fec
+        .options = "",
4a2fec
+        .index = SPAPR_CAP_DFP,
4a2fec
+        .get = spapr_cap_get_bool,
4a2fec
+        .set = spapr_cap_set_bool,
4a2fec
+        .type = "bool",
4a2fec
+        .apply = cap_dfp_apply,
4a2fec
     },
4a2fec
 };
4a2fec
 
4a2fec
@@ -115,23 +166,33 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
4a2fec
 
4a2fec
     if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
4a2fec
                           0, spapr->max_compat_pvr)) {
4a2fec
-        caps.mask &= ~SPAPR_CAP_HTM;
4a2fec
+        caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
4a2fec
     }
4a2fec
 
4a2fec
     if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
4a2fec
                           0, spapr->max_compat_pvr)) {
4a2fec
-        caps.mask &= ~SPAPR_CAP_VSX;
4a2fec
-        caps.mask &= ~SPAPR_CAP_DFP;
4a2fec
+        caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
4a2fec
+        caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
4a2fec
     }
4a2fec
 
4a2fec
     return caps;
4a2fec
 }
4a2fec
 
4a2fec
-static bool spapr_caps_needed(void *opaque)
4a2fec
+int spapr_caps_pre_load(void *opaque)
4a2fec
 {
4a2fec
     sPAPRMachineState *spapr = opaque;
4a2fec
 
4a2fec
-    return (spapr->forced_caps.mask != 0) || (spapr->forbidden_caps.mask != 0);
4a2fec
+    /* Set to default so we can tell if this came in with the migration */
4a2fec
+    spapr->mig = spapr->def;
4a2fec
+    return 0;
4a2fec
+}
4a2fec
+
4a2fec
+int spapr_caps_pre_save(void *opaque)
4a2fec
+{
4a2fec
+    sPAPRMachineState *spapr = opaque;
4a2fec
+
4a2fec
+    spapr->mig = spapr->eff;
4a2fec
+    return 0;
4a2fec
 }
4a2fec
 
4a2fec
 /* This has to be called from the top-level spapr post_load, not the
4a2fec
@@ -140,175 +201,121 @@ static bool spapr_caps_needed(void *opaque)
4a2fec
  * caps on the destination */
4a2fec
 int spapr_caps_post_migration(sPAPRMachineState *spapr)
4a2fec
 {
4a2fec
-    uint64_t allcaps = 0;
4a2fec
     int i;
4a2fec
     bool ok = true;
4a2fec
-    sPAPRCapabilities dstcaps = spapr->effective_caps;
4a2fec
+    sPAPRCapabilities dstcaps = spapr->eff;
4a2fec
     sPAPRCapabilities srccaps;
4a2fec
 
4a2fec
     srccaps = default_caps_with_cpu(spapr, first_cpu);
4a2fec
-    srccaps.mask |= spapr->mig_forced_caps.mask;
4a2fec
-    srccaps.mask &= ~spapr->mig_forbidden_caps.mask;
4a2fec
+    for (i = 0; i < SPAPR_CAP_NUM; i++) {
4a2fec
+        /* If not default value then assume came in with the migration */
4a2fec
+        if (spapr->mig.caps[i] != spapr->def.caps[i]) {
4a2fec
+            srccaps.caps[i] = spapr->mig.caps[i];
4a2fec
+        }
4a2fec
+    }
4a2fec
 
4a2fec
-    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
4a2fec
+    for (i = 0; i < SPAPR_CAP_NUM; i++) {
4a2fec
         sPAPRCapabilityInfo *info = &capability_table[i];
4a2fec
 
4a2fec
-        allcaps |= info->flag;
4a2fec
-
4a2fec
-        if ((srccaps.mask & info->flag) && !(dstcaps.mask & info->flag)) {
4a2fec
-            error_report("cap-%s=on in incoming stream, but off in destination",
4a2fec
-                         info->name);
4a2fec
+        if (srccaps.caps[i] > dstcaps.caps[i]) {
4a2fec
+            error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
4a2fec
+                         info->name, srccaps.caps[i], dstcaps.caps[i]);
4a2fec
             ok = false;
4a2fec
         }
4a2fec
 
4a2fec
-        if (!(srccaps.mask & info->flag) && (dstcaps.mask & info->flag)) {
4a2fec
-            warn_report("cap-%s=off in incoming stream, but on in destination",
4a2fec
-                         info->name);
4a2fec
+        if (srccaps.caps[i] < dstcaps.caps[i]) {
4a2fec
+            warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
4a2fec
+                         info->name, srccaps.caps[i], dstcaps.caps[i]);
4a2fec
         }
4a2fec
     }
4a2fec
 
4a2fec
-    if (spapr->mig_forced_caps.mask & ~allcaps) {
4a2fec
-        error_report(
4a2fec
-            "Unknown capabilities 0x%"PRIx64" enabled in incoming stream",
4a2fec
-            spapr->mig_forced_caps.mask & ~allcaps);
4a2fec
-        ok = false;
4a2fec
-    }
4a2fec
-    if (spapr->mig_forbidden_caps.mask & ~allcaps) {
4a2fec
-        warn_report(
4a2fec
-            "Unknown capabilities 0x%"PRIx64" disabled in incoming stream",
4a2fec
-            spapr->mig_forbidden_caps.mask & ~allcaps);
4a2fec
-    }
4a2fec
-
4a2fec
     return ok ? 0 : -EINVAL;
4a2fec
 }
4a2fec
 
4a2fec
-static void spapr_caps_pre_save(void *opaque)
4a2fec
+static bool spapr_cap_htm_needed(void *opaque)
4a2fec
 {
4a2fec
     sPAPRMachineState *spapr = opaque;
4a2fec
 
4a2fec
-    spapr->mig_forced_caps = spapr->forced_caps;
4a2fec
-    spapr->mig_forbidden_caps = spapr->forbidden_caps;
4a2fec
+    return spapr->cmd_line_caps[SPAPR_CAP_HTM] &&
4a2fec
+           (spapr->eff.caps[SPAPR_CAP_HTM] != spapr->def.caps[SPAPR_CAP_HTM]);
4a2fec
 }
4a2fec
 
4a2fec
-static int spapr_caps_pre_load(void *opaque)
4a2fec
+const VMStateDescription vmstate_spapr_cap_htm = {
4a2fec
+    .name = "spapr/cap/htm",
4a2fec
+    .version_id = 1,
4a2fec
+    .minimum_version_id = 1,
4a2fec
+    .needed = spapr_cap_htm_needed,
4a2fec
+    .fields = (VMStateField[]) {
4a2fec
+        VMSTATE_UINT8(mig.caps[SPAPR_CAP_HTM], sPAPRMachineState),
4a2fec
+        VMSTATE_END_OF_LIST()
4a2fec
+    },
4a2fec
+};
4a2fec
+
4a2fec
+static bool spapr_cap_vsx_needed(void *opaque)
4a2fec
 {
4a2fec
     sPAPRMachineState *spapr = opaque;
4a2fec
 
4a2fec
-    spapr->mig_forced_caps = spapr_caps(0);
4a2fec
-    spapr->mig_forbidden_caps = spapr_caps(0);
4a2fec
-    return 0;
4a2fec
+    return spapr->cmd_line_caps[SPAPR_CAP_VSX] &&
4a2fec
+           (spapr->eff.caps[SPAPR_CAP_VSX] != spapr->def.caps[SPAPR_CAP_VSX]);
4a2fec
 }
4a2fec
 
4a2fec
-const VMStateDescription vmstate_spapr_caps = {
4a2fec
-    .name = "spapr/caps",
4a2fec
+const VMStateDescription vmstate_spapr_cap_vsx = {
4a2fec
+    .name = "spapr/cap/vsx",
4a2fec
     .version_id = 1,
4a2fec
     .minimum_version_id = 1,
4a2fec
-    .needed = spapr_caps_needed,
4a2fec
-    .pre_save = spapr_caps_pre_save,
4a2fec
-    .pre_load = spapr_caps_pre_load,
4a2fec
+    .needed = spapr_cap_vsx_needed,
4a2fec
     .fields = (VMStateField[]) {
4a2fec
-        VMSTATE_UINT64(mig_forced_caps.mask, sPAPRMachineState),
4a2fec
-        VMSTATE_UINT64(mig_forbidden_caps.mask, sPAPRMachineState),
4a2fec
+        VMSTATE_UINT8(mig.caps[SPAPR_CAP_VSX], sPAPRMachineState),
4a2fec
         VMSTATE_END_OF_LIST()
4a2fec
     },
4a2fec
 };
4a2fec
 
4a2fec
-void spapr_caps_reset(sPAPRMachineState *spapr)
4a2fec
-{
4a2fec
-    Error *local_err = NULL;
4a2fec
-    sPAPRCapabilities caps;
4a2fec
-    int i;
4a2fec
-
4a2fec
-    /* First compute the actual set of caps we're running with.. */
4a2fec
-    caps = default_caps_with_cpu(spapr, first_cpu);
4a2fec
-
4a2fec
-    /* Remove unnecessary forced/forbidden bits (this will help us
4a2fec
-     * with migration) */
4a2fec
-    spapr->forced_caps.mask &= ~caps.mask;
4a2fec
-    spapr->forbidden_caps.mask &= caps.mask;
4a2fec
-
4a2fec
-    caps.mask |= spapr->forced_caps.mask;
4a2fec
-    caps.mask &= ~spapr->forbidden_caps.mask;
4a2fec
-
4a2fec
-    spapr->effective_caps = caps;
4a2fec
-
4a2fec
-    /* .. then apply those caps to the virtual hardware */
4a2fec
-
4a2fec
-    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
4a2fec
-        sPAPRCapabilityInfo *info = &capability_table[i];
4a2fec
-
4a2fec
-        if (spapr->effective_caps.mask & info->flag) {
4a2fec
-            /* Failure to allow a cap is fatal - if the guest doesn't
4a2fec
-             * have it, we'll be supplying an incorrect environment */
4a2fec
-            if (info->allow) {
4a2fec
-                info->allow(spapr, &error_fatal);
4a2fec
-            }
4a2fec
-        } else {
4a2fec
-            /* Failure to enforce a cap is only a warning.  The guest
4a2fec
-             * shouldn't be using it, since it's not advertised, so it
4a2fec
-             * doesn't get to complain about weird behaviour if it
4a2fec
-             * goes ahead anyway */
4a2fec
-            if (info->disallow) {
4a2fec
-                info->disallow(spapr, &local_err);
4a2fec
-            }
4a2fec
-            if (local_err) {
4a2fec
-                warn_report_err(local_err);
4a2fec
-                local_err = NULL;
4a2fec
-            }
4a2fec
-        }
4a2fec
-    }
4a2fec
-}
4a2fec
-
4a2fec
-static void spapr_cap_get(Object *obj, Visitor *v, const char *name,
4a2fec
-                          void *opaque, Error **errp)
4a2fec
+static bool spapr_cap_dfp_needed(void *opaque)
4a2fec
 {
4a2fec
-    sPAPRCapabilityInfo *cap = opaque;
4a2fec
-    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
4a2fec
-    bool value = spapr_has_cap(spapr, cap->flag);
4a2fec
-
4a2fec
-    /* TODO: Could this get called before effective_caps is finalized
4a2fec
-     * in spapr_caps_reset()? */
4a2fec
+    sPAPRMachineState *spapr = opaque;
4a2fec
 
4a2fec
-    visit_type_bool(v, name, &value, errp);
4a2fec
+    return spapr->cmd_line_caps[SPAPR_CAP_DFP] &&
4a2fec
+           (spapr->eff.caps[SPAPR_CAP_DFP] != spapr->def.caps[SPAPR_CAP_DFP]);
4a2fec
 }
4a2fec
 
4a2fec
-static void spapr_cap_set(Object *obj, Visitor *v, const char *name,
4a2fec
-                          void *opaque, Error **errp)
4a2fec
-{
4a2fec
-    sPAPRCapabilityInfo *cap = opaque;
4a2fec
-    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
4a2fec
-    bool value;
4a2fec
-    Error *local_err = NULL;
4a2fec
-
4a2fec
-    visit_type_bool(v, name, &value, &local_err);
4a2fec
-    if (local_err) {
4a2fec
-        error_propagate(errp, local_err);
4a2fec
-        return;
4a2fec
-    }
4a2fec
-
4a2fec
-    if (value) {
4a2fec
-        spapr->forced_caps.mask |= cap->flag;
4a2fec
-    } else {
4a2fec
-        spapr->forbidden_caps.mask |= cap->flag;
4a2fec
-    }
4a2fec
-}
4a2fec
+const VMStateDescription vmstate_spapr_cap_dfp = {
4a2fec
+    .name = "spapr/cap/dfp",
4a2fec
+    .version_id = 1,
4a2fec
+    .minimum_version_id = 1,
4a2fec
+    .needed = spapr_cap_dfp_needed,
4a2fec
+    .fields = (VMStateField[]) {
4a2fec
+        VMSTATE_UINT8(mig.caps[SPAPR_CAP_DFP], sPAPRMachineState),
4a2fec
+        VMSTATE_END_OF_LIST()
4a2fec
+    },
4a2fec
+};
4a2fec
 
4a2fec
-void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp)
4a2fec
+void spapr_caps_reset(sPAPRMachineState *spapr)
4a2fec
 {
4a2fec
-    uint64_t allcaps = 0;
4a2fec
+    sPAPRCapabilities default_caps;
4a2fec
     int i;
4a2fec
 
4a2fec
-    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
4a2fec
-        g_assert((allcaps & capability_table[i].flag) == 0);
4a2fec
-        allcaps |= capability_table[i].flag;
4a2fec
+    /* First compute the actual set of caps we're running with.. */
4a2fec
+    default_caps = default_caps_with_cpu(spapr, first_cpu);
4a2fec
+
4a2fec
+    for (i = 0; i < SPAPR_CAP_NUM; i++) {
4a2fec
+        /* Store the defaults */
4a2fec
+        spapr->def.caps[i] = default_caps.caps[i];
4a2fec
+        /* If not set on the command line then apply the default value */
4a2fec
+        if (!spapr->cmd_line_caps[i]) {
4a2fec
+            spapr->eff.caps[i] = default_caps.caps[i];
4a2fec
+        }
4a2fec
     }
4a2fec
 
4a2fec
-    g_assert((spapr->forced_caps.mask & ~allcaps) == 0);
4a2fec
-    g_assert((spapr->forbidden_caps.mask & ~allcaps) == 0);
4a2fec
+    /* .. then apply those caps to the virtual hardware */
4a2fec
+
4a2fec
+    for (i = 0; i < SPAPR_CAP_NUM; i++) {
4a2fec
+        sPAPRCapabilityInfo *info = &capability_table[i];
4a2fec
 
4a2fec
-    if (spapr->forced_caps.mask & spapr->forbidden_caps.mask) {
4a2fec
-        error_setg(errp, "Some sPAPR capabilities set both on and off");
4a2fec
-        return;
4a2fec
+        /*
4a2fec
+         * If the apply function can't set the desired level and thinks it's
4a2fec
+         * fatal, it should cause that.
4a2fec
+         */
4a2fec
+        info->apply(spapr, spapr->eff.caps[i], &error_fatal);
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
@@ -321,17 +328,19 @@ void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
4a2fec
     for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
4a2fec
         sPAPRCapabilityInfo *cap = &capability_table[i];
4a2fec
         const char *name = g_strdup_printf("cap-%s", cap->name);
4a2fec
+        char *desc;
4a2fec
 
4a2fec
-        object_class_property_add(klass, name, "bool",
4a2fec
-                                  spapr_cap_get, spapr_cap_set, NULL,
4a2fec
-                                  cap, &local_err);
4a2fec
+        object_class_property_add(klass, name, cap->type,
4a2fec
+                                  cap->get, cap->set,
4a2fec
+                                  NULL, cap, &local_err);
4a2fec
         if (local_err) {
4a2fec
             error_propagate(errp, local_err);
4a2fec
             return;
4a2fec
         }
4a2fec
 
4a2fec
-        object_class_property_set_description(klass, name, cap->description,
4a2fec
-                                              &local_err);
4a2fec
+        desc = g_strdup_printf("%s%s", cap->description, cap->options);
4a2fec
+        object_class_property_set_description(klass, name, desc, &local_err);
4a2fec
+        g_free(desc);
4a2fec
         if (local_err) {
4a2fec
             error_propagate(errp, local_err);
4a2fec
             return;
4a2fec
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
4a2fec
index df767c3..7156a70 100644
4a2fec
--- a/include/hw/ppc/spapr.h
4a2fec
+++ b/include/hw/ppc/spapr.h
4a2fec
@@ -54,20 +54,25 @@ typedef enum {
4a2fec
  * Capabilities
4a2fec
  */
4a2fec
 
4a2fec
-/* These bits go in the migration stream, so they can't be reassigned */
4a2fec
-
4a2fec
 /* Hardware Transactional Memory */
4a2fec
-#define SPAPR_CAP_HTM               0x0000000000000001ULL
4a2fec
-
4a2fec
+#define SPAPR_CAP_HTM                   0x00
4a2fec
 /* Vector Scalar Extensions */
4a2fec
-#define SPAPR_CAP_VSX               0x0000000000000002ULL
4a2fec
-
4a2fec
+#define SPAPR_CAP_VSX                   0x01
4a2fec
 /* Decimal Floating Point */
4a2fec
-#define SPAPR_CAP_DFP               0x0000000000000004ULL
4a2fec
+#define SPAPR_CAP_DFP                   0x02
4a2fec
+/* Num Caps */
4a2fec
+#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
4a2fec
+
4a2fec
+/*
4a2fec
+ * Capability Values
4a2fec
+ */
4a2fec
+/* Bool Caps */
4a2fec
+#define SPAPR_CAP_OFF                   0x00
4a2fec
+#define SPAPR_CAP_ON                    0x01
4a2fec
 
4a2fec
 typedef struct sPAPRCapabilities sPAPRCapabilities;
4a2fec
 struct sPAPRCapabilities {
4a2fec
-    uint64_t mask;
4a2fec
+    uint8_t caps[SPAPR_CAP_NUM];
4a2fec
 };
4a2fec
 
4a2fec
 /**
4a2fec
@@ -151,9 +156,8 @@ struct sPAPRMachineState {
4a2fec
 
4a2fec
     const char *icp_type;
4a2fec
 
4a2fec
-    sPAPRCapabilities forced_caps, forbidden_caps;
4a2fec
-    sPAPRCapabilities mig_forced_caps, mig_forbidden_caps;
4a2fec
-    sPAPRCapabilities effective_caps;
4a2fec
+    bool cmd_line_caps[SPAPR_CAP_NUM];
4a2fec
+    sPAPRCapabilities def, eff, mig;
4a2fec
 };
4a2fec
 
4a2fec
 #define H_SUCCESS         0
4a2fec
@@ -732,24 +736,23 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
4a2fec
 
4a2fec
 #define HTAB_SIZE(spapr)        (1ULL << ((spapr)->htab_shift))
4a2fec
 
4a2fec
+
4a2fec
+int spapr_caps_pre_load(void *opaque);
4a2fec
+int spapr_caps_pre_save(void *opaque);
4a2fec
+
4a2fec
 /*
4a2fec
  * Handling of optional capabilities
4a2fec
  */
4a2fec
-extern const VMStateDescription vmstate_spapr_caps;
4a2fec
-
4a2fec
-static inline sPAPRCapabilities spapr_caps(uint64_t mask)
4a2fec
-{
4a2fec
-    sPAPRCapabilities caps = { mask };
4a2fec
-    return caps;
4a2fec
-}
4a2fec
+extern const VMStateDescription vmstate_spapr_cap_htm;
4a2fec
+extern const VMStateDescription vmstate_spapr_cap_vsx;
4a2fec
+extern const VMStateDescription vmstate_spapr_cap_dfp;
4a2fec
 
4a2fec
-static inline bool spapr_has_cap(sPAPRMachineState *spapr, uint64_t cap)
4a2fec
+static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
4a2fec
 {
4a2fec
-    return !!(spapr->effective_caps.mask & cap);
4a2fec
+    return spapr->eff.caps[cap];
4a2fec
 }
4a2fec
 
4a2fec
 void spapr_caps_reset(sPAPRMachineState *spapr);
4a2fec
-void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp);
4a2fec
 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp);
4a2fec
 int spapr_caps_post_migration(sPAPRMachineState *spapr);
4a2fec
 
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec