qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-ppc] [QEMU-PPC] [RFC 1/3] hw/ppc/spapr_caps: Rework spapr_caps


From: Suraj Jitindar Singh
Subject: Re: [Qemu-ppc] [QEMU-PPC] [RFC 1/3] hw/ppc/spapr_caps: Rework spapr_caps to use uint8 internal representation
Date: Fri, 12 Jan 2018 13:19:25 +1100

On Wed, 2018-01-10 at 15:13 +1100, David Gibson wrote:
> On Tue, Jan 09, 2018 at 08:21:01PM +1100, Suraj Jitindar Singh wrote:
> > Currently spapr_caps are tied to boolean values (on or off). This
> > patch
> > reworks the caps so that they can have any value between 0 and 127,
> > inclusive. This allows more capabilities with various values to be
> > represented in the same way internally. Capabilities are numbered
> > in
> > ascending order. The internal representation of capability values
> > is an
> > array of uint8s in the sPAPRMachineState, indexed by capability
> > number.
> > Note: The MSB (0x80) of a capability is reserved to track whether
> > the
> >       capability was set from the command line.
> > 
> > Capabilities can have their own name, description, options, getter
> > and
> > setter functions, type and allow functions. They also each have
> > their own
> > section in the migration stream. Capabilities are only migrated if
> > they
> > were explictly set on the command line, with the assumption that
> > otherwise the default will match.
> > 
> > On migration we ensure that the capability value on the destination
> > is greater than or equal to the capability value from the source.
> > So
> > long at this remains the case then the migration is considered
> > compatible and allowed to continue.
> > 
> > This patch implements generic getter and setter functions for
> > boolean
> > capabilities. It also converts the existings cap-htm, cap-vsx and
> > cap-dfp capabilities to this new format.
> > ---
> >  hw/ppc/spapr.c         |  19 +--
> >  hw/ppc/spapr_caps.c    | 335 ++++++++++++++++++++++++++++---------
> > ------------
> >  include/hw/ppc/spapr.h |  41 +++---
> >  3 files changed, 222 insertions(+), 173 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index d1acfe8858..7fa45729ba 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -320,7 +320,7 @@ static void
> > spapr_populate_pa_features(sPAPRMachineState *spapr,
> >           */
> >          pa_features[3] |= 0x20;
> >      }
> > -    if (spapr_has_cap(spapr, SPAPR_CAP_HTM) && pa_size > 24) {
> > +    if (spapr_get_cap(spapr, SPAPR_CAP_HTM) && pa_size > 24) {
> 
> I'd prefer to see explicit >0 or !=0 to emphasise that the returned
> value is now an integer not a bool.

Sure

> 
> >          pa_features[24] |= 0x80;    /* Transactional memory
> > support */
> >      }
> >      if (legacy_guest && pa_size > 40) {
> > @@ -563,7 +563,7 @@ static void spapr_populate_cpu_dt(CPUState *cs,
> > void *fdt, int offset,
> >       *
> >       * Only CPUs for which we create core types in
> > spapr_cpu_core.c
> >       * are possible, and all of those have VMX */
> > -    if (spapr_has_cap(spapr, SPAPR_CAP_VSX)) {
> > +    if (spapr_get_cap(spapr, SPAPR_CAP_VSX)) {
> >          _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
> >      } else {
> >          _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
> > @@ -572,7 +572,7 @@ static void spapr_populate_cpu_dt(CPUState *cs,
> > void *fdt, int offset,
> >      /* Advertise DFP (Decimal Floating Point) if available
> >       *   0 / no property == no DFP
> >       *   1               == DFP available */
> > -    if (spapr_has_cap(spapr, SPAPR_CAP_DFP)) {
> > +    if (spapr_get_cap(spapr, SPAPR_CAP_DFP)) {
> >          _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
> >      }
> >  
> > @@ -1762,7 +1762,9 @@ static const VMStateDescription vmstate_spapr
> > = {
> >          &vmstate_spapr_ov5_cas,
> >          &vmstate_spapr_patb_entry,
> >          &vmstate_spapr_pending_events,
> > -        &vmstate_spapr_caps,
> > +        &vmstate_spapr_cap_htm,
> > +        &vmstate_spapr_cap_vsx,
> > +        &vmstate_spapr_cap_dfp,
> >          NULL
> >      }
> >  };
> > @@ -2323,8 +2325,6 @@ static void spapr_machine_init(MachineState
> > *machine)
> >      char *filename;
> >      Error *resize_hpt_err = NULL;
> >  
> > -    spapr_caps_validate(spapr, &error_fatal);
> > -
> >      msi_nonbroken = true;
> >  
> >      QLIST_INIT(&spapr->phbs);
> > @@ -3834,7 +3834,9 @@ static void
> > spapr_machine_class_init(ObjectClass *oc, void *data)
> >       */
> >      mc->numa_mem_align_shift = 28;
> >  
> > -    smc->default_caps = spapr_caps(SPAPR_CAP_VSX | SPAPR_CAP_DFP);
> > +    smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
> > +    smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
> > +    smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
> >      spapr_caps_add_properties(smc, &error_abort);
> >  }
> >  
> > @@ -3916,8 +3918,7 @@ static void
> > spapr_machine_2_11_class_options(MachineClass *mc)
> >      sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
> >  
> >      spapr_machine_2_12_class_options(mc);
> > -    smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX
> > -                                   | SPAPR_CAP_DFP);
> > +    smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
> >      SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11);
> >  }
> >  
> > diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> > index 9d070a306c..af40f2e469 100644
> > --- a/hw/ppc/spapr_caps.c
> > +++ b/hw/ppc/spapr_caps.c
> > @@ -35,33 +35,71 @@
> >  typedef struct sPAPRCapabilityInfo {
> >      const char *name;
> >      const char *description;
> > -    uint64_t flag;
> > +    const char *options;
> > +    int index;
> >  
> > +    /* Getter and Setter Function Pointers */
> > +    ObjectPropertyAccessor *get;
> > +    ObjectPropertyAccessor *set;
> > +    const char *type;
> >      /* Make sure the virtual hardware can support this capability
> > */
> > -    void (*allow)(sPAPRMachineState *spapr, Error **errp);
> > -
> > -    /* If possible, tell the virtual hardware not to allow the cap
> > to
> > -     * be used at all */
> > -    void (*disallow)(sPAPRMachineState *spapr, Error **errp);
> > +    void (*allow)(sPAPRMachineState *spapr, uint8_t val, Error
> > **errp);
> 
> I think we need a new name for this since it can both allow and
> disallow.  Maybe 'apply'?

Sure

> 
> >  } sPAPRCapabilityInfo;
> >  
> > -static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp)
> > +static void spapr_cap_get_bool(Object *obj, Visitor *v, const char
> > *name,
> > +                               void *opaque, Error **errp)
> > +{
> > +    sPAPRCapabilityInfo *cap = opaque;
> > +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > +    bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
> > +
> > +    visit_type_bool(v, name, &value, errp);
> > +}
> > +
> > +static void spapr_cap_set_bool(Object *obj, Visitor *v, const char
> > *name,
> > +                               void *opaque, Error **errp)
> >  {
> > +    sPAPRCapabilityInfo *cap = opaque;
> > +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > +    bool value;
> > +    Error *local_err = NULL;
> > +
> > +    visit_type_bool(v, name, &value, &local_err);
> > +    if (local_err) {
> > +        error_propagate(errp, local_err);
> > +        return;
> > +    }
> > +
> > +    spapr->cmd_line_caps.caps[cap->index] = (value ? SPAPR_CAP_ON
> > :
> > +                                                     SPAPR_CAP_OFF
> > ) |
> > +                                             SPAPR_CAP_CMD_LINE;
> > +}
> > +
> > +static void cap_htm_allow(sPAPRMachineState *spapr, uint8_t val,
> > Error **errp)
> > +{
> > +    if (!val) {
> > +        /* TODO: We don't support disabling htm yet */
> > +        return;
> > +    }
> 
> A downside of fusing allow and disallow is that we can't now apply
> the
> rule that failure to allow is an error but failure to disallow is
> only
> a warning in the common code.  Oh well.

Yep, well it's up to the apply function now to either allow it or cause
an error if it thinks it's fatal.

> 
> >      if (tcg_enabled()) {
> >          error_setg(errp,
> > -                   "No Transactional Memory support in TCG, try
> > cap-htm=off");
> > +                   "No Transactional Memory support in TCG, try
> > cap-htm=0");
> >      } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
> >          error_setg(errp,
> > -"KVM implementation does not support Transactional Memory, try
> > cap-htm=off"
> > +"KVM implementation does not support Transactional Memory, try
> > cap-htm=0"
> >              );
> >      }
> >  }
> >  
> > -static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp)
> > +static void cap_vsx_allow(sPAPRMachineState *spapr, uint8_t val,
> > Error **errp)
> >  {
> >      PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
> >      CPUPPCState *env = &cpu->env;
> >  
> > +    if (!val) {
> > +        /* TODO: We don't support disabling vsx yet */
> > +        return;
> > +    }
> >      /* Allowable CPUs in spapr_cpu_core.c should already have
> > gotten
> >       * rid of anything that doesn't do VMX */
> >      g_assert(env->insns_flags & PPC_ALTIVEC);
> > @@ -70,37 +108,51 @@ static void cap_vsx_allow(sPAPRMachineState
> > *spapr, Error **errp)
> >      }
> >  }
> >  
> > -static void cap_dfp_allow(sPAPRMachineState *spapr, Error **errp)
> > +static void cap_dfp_allow(sPAPRMachineState *spapr, uint8_t val,
> > Error **errp)
> >  {
> >      PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
> >      CPUPPCState *env = &cpu->env;
> >  
> > +    if (!val) {
> > +        /* TODO: We don't support disabling dfp yet */
> > +        return;
> > +    }
> >      if (!(env->insns_flags2 & PPC2_DFP)) {
> >          error_setg(errp, "DFP support not available, try cap-
> > dfp=off");
> >      }
> >  }
> >  
> > -static sPAPRCapabilityInfo capability_table[] = {
> > -    {
> > +
> > +sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
> > +    [SPAPR_CAP_HTM] = {
> >          .name = "htm",
> >          .description = "Allow Hardware Transactional Memory
> > (HTM)",
> > -        .flag = SPAPR_CAP_HTM,
> > +        .options = "",
> 
> It's not really clear to me what the options field is for.

So for string options it's for the allowed values which go in the
description.
See next patch :)

> 
> > +        .index = SPAPR_CAP_HTM,
> > +        .get = spapr_cap_get_bool,
> > +        .set = spapr_cap_set_bool,
> > +        .type = "bool",
> >          .allow = cap_htm_allow,
> > -        /* TODO: add cap_htm_disallow */
> >      },
> > -    {
> > +    [SPAPR_CAP_VSX] = {
> >          .name = "vsx",
> >          .description = "Allow Vector Scalar Extensions (VSX)",
> > -        .flag = SPAPR_CAP_VSX,
> > +        .options = "",
> > +        .index = SPAPR_CAP_VSX,
> > +        .get = spapr_cap_get_bool,
> > +        .set = spapr_cap_set_bool,
> > +        .type = "bool",
> >          .allow = cap_vsx_allow,
> > -        /* TODO: add cap_vsx_disallow */
> >      },
> > -    {
> > +    [SPAPR_CAP_DFP] = {
> >          .name = "dfp",
> >          .description = "Allow Decimal Floating Point (DFP)",
> > -        .flag = SPAPR_CAP_DFP,
> > +        .options = "",
> > +        .index = SPAPR_CAP_DFP,
> > +        .get = spapr_cap_get_bool,
> > +        .set = spapr_cap_set_bool,
> > +        .type = "bool",
> >          .allow = cap_dfp_allow,
> > -        /* TODO: add cap_dfp_disallow */
> >      },
> >  };
> >  
> > @@ -115,201 +167,192 @@ static sPAPRCapabilities
> > default_caps_with_cpu(sPAPRMachineState *spapr,
> >  
> >      if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
> >                            0, spapr->max_compat_pvr)) {
> > -        caps.mask &= ~SPAPR_CAP_HTM;
> > +        caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
> >      }
> >  
> >      if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
> >                            0, spapr->max_compat_pvr)) {
> > -        caps.mask &= ~SPAPR_CAP_VSX;
> > -        caps.mask &= ~SPAPR_CAP_DFP;
> > +        caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
> > +        caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
> >      }
> >  
> >      return caps;
> >  }
> >  
> > -static bool spapr_caps_needed(void *opaque)
> > -{
> > -    sPAPRMachineState *spapr = opaque;
> > -
> > -    return (spapr->forced_caps.mask != 0) || (spapr-
> > >forbidden_caps.mask != 0);
> > -}
> > -
> >  /* This has to be called from the top-level spapr post_load, not
> > the
> >   * caps specific one.  Otherwise it wouldn't be called when the
> > source
> >   * caps are all defaults, which could still conflict with
> > overridden
> >   * caps on the destination */
> >  int spapr_caps_post_migration(sPAPRMachineState *spapr)
> >  {
> > -    uint64_t allcaps = 0;
> >      int i;
> >      bool ok = true;
> >      sPAPRCapabilities dstcaps = spapr->effective_caps;
> >      sPAPRCapabilities srccaps;
> >  
> >      srccaps = default_caps_with_cpu(spapr, first_cpu);
> > -    srccaps.mask |= spapr->mig_forced_caps.mask;
> > -    srccaps.mask &= ~spapr->mig_forbidden_caps.mask;
> > +    for (i = 0; i < SPAPR_CAP_NUM; i++) {
> > +        if (spapr->mig_caps.caps[i] & SPAPR_CAP_CMD_LINE) {
> > +            srccaps.caps[i] = spapr->mig_caps.caps[i] &
> > ~SPAPR_CAP_CMD_LINE;
> > +        }
> > +    }
> >  
> > -    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
> > +    for (i = 0; i < SPAPR_CAP_NUM; i++) {
> >          sPAPRCapabilityInfo *info = &capability_table[i];
> >  
> > -        allcaps |= info->flag;
> > -
> > -        if ((srccaps.mask & info->flag) && !(dstcaps.mask & info-
> > >flag)) {
> > -            error_report("cap-%s=on in incoming stream, but off in
> > destination",
> > -                         info->name);
> > +        if (srccaps.caps[i] > dstcaps.caps[i]) {
> > +            error_report("cap-%s higher level (%d) in incoming
> > stream than on destination (%d)",
> > +                         info->name, srccaps.caps[i],
> > dstcaps.caps[i]);
> >              ok = false;
> >          }
> >  
> > -        if (!(srccaps.mask & info->flag) && (dstcaps.mask & info-
> > >flag)) {
> > -            warn_report("cap-%s=off in incoming stream, but on in
> > destination",
> > -                         info->name);
> > +        if (srccaps.caps[i] < dstcaps.caps[i]) {
> > +            warn_report("cap-%s lower level (%d) in incoming
> > stream than on destination (%d)",
> > +                         info->name, srccaps.caps[i],
> > dstcaps.caps[i]);
> >          }
> >      }
> >  
> > -    if (spapr->mig_forced_caps.mask & ~allcaps) {
> > -        error_report(
> > -            "Unknown capabilities 0x%"PRIx64" enabled in incoming
> > stream",
> > -            spapr->mig_forced_caps.mask & ~allcaps);
> > -        ok = false;
> > -    }
> > -    if (spapr->mig_forbidden_caps.mask & ~allcaps) {
> > -        warn_report(
> > -            "Unknown capabilities 0x%"PRIx64" disabled in incoming
> > stream",
> > -            spapr->mig_forbidden_caps.mask & ~allcaps);
> > -    }
> > -
> >      return ok ? 0 : -EINVAL;
> >  }
> >  
> > -static int spapr_caps_pre_save(void *opaque)
> > +static bool spapr_cap_htm_needed(void *opaque)
> >  {
> >      sPAPRMachineState *spapr = opaque;
> >  
> > -    spapr->mig_forced_caps = spapr->forced_caps;
> > -    spapr->mig_forbidden_caps = spapr->forbidden_caps;
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_HTM] &
> > SPAPR_CAP_CMD_LINE);
> > +}
> > +
> > +static int spapr_cap_htm_pre_save(void *opaque)
> 
> Having to have a separate needed, pre_save and pre_load for each cap
> will be a pain.  I hope we can find a way to do this in common.

As discussed on IRC

> 
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_HTM] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_HTM];
> >      return 0;
> >  }
> >  
> > -static int spapr_caps_pre_load(void *opaque)
> > +static int spapr_cap_htm_pre_load(void *opaque)
> >  {
> >      sPAPRMachineState *spapr = opaque;
> >  
> > -    spapr->mig_forced_caps = spapr_caps(0);
> > -    spapr->mig_forbidden_caps = spapr_caps(0);
> > +    spapr->mig_caps.caps[SPAPR_CAP_HTM] = 0;
> >      return 0;
> >  }
> >  
> > -const VMStateDescription vmstate_spapr_caps = {
> > -    .name = "spapr/caps",
> > +const VMStateDescription vmstate_spapr_cap_htm = {
> > +    .name = "spapr/cap_htm",
> 
> I'd suggest spapr/caps/htm - and a common vmstate_spapr_caps to hold
> the subsections for convenience rather than putting them straight
> under the master spapr one.

As discussed on IRC

> 
> >      .version_id = 1,
> >      .minimum_version_id = 1,
> > -    .needed = spapr_caps_needed,
> > -    .pre_save = spapr_caps_pre_save,
> > -    .pre_load = spapr_caps_pre_load,
> > +    .needed = spapr_cap_htm_needed,
> > +    .pre_save = spapr_cap_htm_pre_save,
> > +    .pre_load = spapr_cap_htm_pre_load,
> >      .fields = (VMStateField[]) {
> > -        VMSTATE_UINT64(mig_forced_caps.mask, sPAPRMachineState),
> > -        VMSTATE_UINT64(mig_forbidden_caps.mask,
> > sPAPRMachineState),
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_HTM],
> > sPAPRMachineState),
> >          VMSTATE_END_OF_LIST()
> >      },
> >  };
> >  
> > -void spapr_caps_reset(sPAPRMachineState *spapr)
> > +static bool spapr_cap_vsx_needed(void *opaque)
> >  {
> > -    Error *local_err = NULL;
> > -    sPAPRCapabilities caps;
> > -    int i;
> > +    sPAPRMachineState *spapr = opaque;
> >  
> > -    /* First compute the actual set of caps we're running with..
> > */
> > -    caps = default_caps_with_cpu(spapr, first_cpu);
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_VSX] &
> > SPAPR_CAP_CMD_LINE);
> > +}
> >  
> > -    /* Remove unnecessary forced/forbidden bits (this will help us
> > -     * with migration) */
> > -    spapr->forced_caps.mask &= ~caps.mask;
> > -    spapr->forbidden_caps.mask &= caps.mask;
> 
> I don't think you have an equivalent of this in the new code, which
> means that an explicitly set property could prevent migration, even
> if
> it actually has the default value.

As discussed on IRC

> 
> > +static int spapr_cap_vsx_pre_save(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_VSX] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_VSX];
> > +    return 0;
> > +}
> >  
> > -    caps.mask |= spapr->forced_caps.mask;
> > -    caps.mask &= ~spapr->forbidden_caps.mask;
> > +static int spapr_cap_vsx_pre_load(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> >  
> > -    spapr->effective_caps = caps;
> > +    spapr->mig_caps.caps[SPAPR_CAP_VSX] = 0;
> > +    return 0;
> > +}
> >  
> > -    /* .. then apply those caps to the virtual hardware */
> > +const VMStateDescription vmstate_spapr_cap_vsx = {
> > +    .name = "spapr/cap_vsx",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = spapr_cap_vsx_needed,
> > +    .pre_save = spapr_cap_vsx_pre_save,
> > +    .pre_load = spapr_cap_vsx_pre_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_VSX],
> > sPAPRMachineState),
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> >  
> > -    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
> > -        sPAPRCapabilityInfo *info = &capability_table[i];
> > +static bool spapr_cap_dfp_needed(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> >  
> > -        if (spapr->effective_caps.mask & info->flag) {
> > -            /* Failure to allow a cap is fatal - if the guest
> > doesn't
> > -             * have it, we'll be supplying an incorrect
> > environment */
> > -            if (info->allow) {
> > -                info->allow(spapr, &error_fatal);
> > -            }
> > -        } else {
> > -            /* Failure to enforce a cap is only a warning.  The
> > guest
> > -             * shouldn't be using it, since it's not advertised,
> > so it
> > -             * doesn't get to complain about weird behaviour if it
> > -             * goes ahead anyway */
> > -            if (info->disallow) {
> > -                info->disallow(spapr, &local_err);
> > -            }
> > -            if (local_err) {
> > -                warn_report_err(local_err);
> > -                local_err = NULL;
> > -            }
> > -        }
> > -    }
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_DFP] &
> > SPAPR_CAP_CMD_LINE);
> >  }
> >  
> > -static void spapr_cap_get(Object *obj, Visitor *v, const char
> > *name,
> > -                          void *opaque, Error **errp)
> > +static int spapr_cap_dfp_pre_save(void *opaque)
> >  {
> > -    sPAPRCapabilityInfo *cap = opaque;
> > -    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > -    bool value = spapr_has_cap(spapr, cap->flag);
> > -
> > -    /* TODO: Could this get called before effective_caps is
> > finalized
> > -     * in spapr_caps_reset()? */
> > +    sPAPRMachineState *spapr = opaque;
> >  
> > -    visit_type_bool(v, name, &value, errp);
> > +    spapr->mig_caps.caps[SPAPR_CAP_DFP] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_DFP];
> > +    return 0;
> >  }
> >  
> > -static void spapr_cap_set(Object *obj, Visitor *v, const char
> > *name,
> > -                          void *opaque, Error **errp)
> > +static int spapr_cap_dfp_pre_load(void *opaque)
> >  {
> > -    sPAPRCapabilityInfo *cap = opaque;
> > -    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > -    bool value;
> > -    Error *local_err = NULL;
> > -
> > -    visit_type_bool(v, name, &value, &local_err);
> > -    if (local_err) {
> > -        error_propagate(errp, local_err);
> > -        return;
> > -    }
> > +    sPAPRMachineState *spapr = opaque;
> >  
> > -    if (value) {
> > -        spapr->forced_caps.mask |= cap->flag;
> > -    } else {
> > -        spapr->forbidden_caps.mask |= cap->flag;
> > -    }
> > +    spapr->mig_caps.caps[SPAPR_CAP_DFP] = 0;
> > +    return 0;
> >  }
> >  
> > -void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp)
> > +const VMStateDescription vmstate_spapr_cap_dfp = {
> > +    .name = "spapr/cap_dfp",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = spapr_cap_dfp_needed,
> > +    .pre_save = spapr_cap_dfp_pre_save,
> > +    .pre_load = spapr_cap_dfp_pre_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_DFP],
> > sPAPRMachineState),
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> > +
> > +void spapr_caps_reset(sPAPRMachineState *spapr)
> >  {
> > -    uint64_t allcaps = 0;
> > +    sPAPRCapabilities caps;
> >      int i;
> >  
> > -    for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
> > -        g_assert((allcaps & capability_table[i].flag) == 0);
> > -        allcaps |= capability_table[i].flag;
> > +    /* First compute the actual set of caps we're running with..
> > */
> > +    caps = default_caps_with_cpu(spapr, first_cpu);
> > +
> > +    for (i = 0; i < SPAPR_CAP_NUM; i++) {
> > +        /* Check if set from command line and override default if
> > so */
> > +        if (spapr->cmd_line_caps.caps[i] & SPAPR_CAP_CMD_LINE) {
> > +            caps.caps[i] = spapr->cmd_line_caps.caps[i] &
> > ~SPAPR_CAP_CMD_LINE;
> > +        }
> >      }
> >  
> > -    g_assert((spapr->forced_caps.mask & ~allcaps) == 0);
> > -    g_assert((spapr->forbidden_caps.mask & ~allcaps) == 0);
> > +    spapr->effective_caps = caps;
> >  
> > -    if (spapr->forced_caps.mask & spapr->forbidden_caps.mask) {
> > -        error_setg(errp, "Some sPAPR capabilities set both on and
> > off");
> > -        return;
> > +    /* .. then apply those caps to the virtual hardware */
> > +
> > +    for (i = 0; i < SPAPR_CAP_NUM; i++) {
> > +        sPAPRCapabilityInfo *info = &capability_table[i];
> > +
> > +        /*
> > +         * If the allow function can't set the desired level and
> > think's it's
> 
> Nit, s/think's/thinks/

yep

> 
> > +         * fatal, it should cause that.
> > +         */
> > +        info->allow(spapr, spapr->effective_caps.caps[i],
> > &error_fatal);
> >      }
> >  }
> >  
> > @@ -322,17 +365,19 @@ void
> > spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
> >      for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
> >          sPAPRCapabilityInfo *cap = &capability_table[i];
> >          const char *name = g_strdup_printf("cap-%s", cap->name);
> > +        char *desc;
> >  
> > -        object_class_property_add(klass, name, "bool",
> > -                                  spapr_cap_get, spapr_cap_set,
> > NULL,
> > -                                  cap, &local_err);
> > +        object_class_property_add(klass, name, cap->type,
> > +                                  cap->get, cap->set,
> > +                                  NULL, cap, &local_err);
> >          if (local_err) {
> >              error_propagate(errp, local_err);
> >              return;
> >          }
> >  
> > -        object_class_property_set_description(klass, name, cap-
> > >description,
> > -                                              &local_err);
> > +        desc = g_strdup_printf("%s%s", cap->description, cap-
> > >options);
> > +        object_class_property_set_description(klass, name, desc,
> > &local_err);
> > +        g_free(desc);
> >          if (local_err) {
> >              error_propagate(errp, local_err);
> >              return;
> > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > index 26ac17e641..2804fbbf12 100644
> > --- a/include/hw/ppc/spapr.h
> > +++ b/include/hw/ppc/spapr.h
> > @@ -57,17 +57,26 @@ typedef enum {
> >  /* These bits go in the migration stream, so they can't be
> > reassigned */
> >  
> >  /* Hardware Transactional Memory */
> > -#define SPAPR_CAP_HTM               0x0000000000000001ULL
> > -
> > +#define SPAPR_CAP_HTM                   0x00
> >  /* Vector Scalar Extensions */
> > -#define SPAPR_CAP_VSX               0x0000000000000002ULL
> > -
> > +#define SPAPR_CAP_VSX                   0x01
> >  /* Decimal Floating Point */
> > -#define SPAPR_CAP_DFP               0x0000000000000004ULL
> > +#define SPAPR_CAP_DFP                   0x02
> > +/* Num Caps */
> > +#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
> > +
> > +/*
> > + * Capability Values
> > + * NOTE: All execpt the immediately following MUST be less than
> > 128 (0x80)
> > + */
> > +#define SPAPR_CAP_CMD_LINE              0x80
> > +/* Bool Caps */
> > +#define SPAPR_CAP_OFF                   0x00
> > +#define SPAPR_CAP_ON                    0x01
> >  
> >  typedef struct sPAPRCapabilities sPAPRCapabilities;
> >  struct sPAPRCapabilities {
> > -    uint64_t mask;
> > +    uint8_t caps[SPAPR_CAP_NUM];
> >  };
> >  
> >  /**
> > @@ -149,9 +158,8 @@ struct sPAPRMachineState {
> >  
> >      const char *icp_type;
> >  
> > -    sPAPRCapabilities forced_caps, forbidden_caps;
> > -    sPAPRCapabilities mig_forced_caps, mig_forbidden_caps;
> > -    sPAPRCapabilities effective_caps;
> > +    sPAPRCapabilities cmd_line_caps, effective_caps;
> > +    sPAPRCapabilities mig_caps;
> >  };
> >  
> >  #define H_SUCCESS         0
> > @@ -752,21 +760,16 @@ qemu_irq spapr_qirq(sPAPRMachineState *spapr,
> > int irq);
> >  /*
> >   * Handling of optional capabilities
> >   */
> > -extern const VMStateDescription vmstate_spapr_caps;
> > -
> > -static inline sPAPRCapabilities spapr_caps(uint64_t mask)
> > -{
> > -    sPAPRCapabilities caps = { mask };
> > -    return caps;
> > -}
> > +extern const VMStateDescription vmstate_spapr_cap_htm;
> > +extern const VMStateDescription vmstate_spapr_cap_vsx;
> > +extern const VMStateDescription vmstate_spapr_cap_dfp;
> >  
> > -static inline bool spapr_has_cap(sPAPRMachineState *spapr,
> > uint64_t cap)
> > +static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int
> > cap)
> >  {
> > -    return !!(spapr->effective_caps.mask & cap);
> > +    return spapr->effective_caps.caps[cap];
> >  }
> >  
> >  void spapr_caps_reset(sPAPRMachineState *spapr);
> > -void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp);
> >  void spapr_caps_add_properties(sPAPRMachineClass *smc, Error
> > **errp);
> >  int spapr_caps_post_migration(sPAPRMachineState *spapr);
> >  
> 
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]