diff mbox series

[QEMU-PPC,3/4] target/ppc: Implement large decrementer support for KVM

Message ID 20190226030531.9932-3-sjitindarsingh@gmail.com (mailing list archive)
State New, archived
Headers show
Series [QEMU-PPC,1/4] target/ppc/spapr: Add SPAPR_CAP_LARGE_DECREMENTER | expand

Commit Message

Suraj Jitindar Singh Feb. 26, 2019, 3:05 a.m. UTC
Implement support to allow KVM guests to take advantage of the large
decrementer introduced on POWER9 cpus.

To determine if the host can support the requested large decrementer
size, we check it matches that specified in the ibm,dec-bits device-tree
property. We also need to enable it in KVM by setting the LPCR_LD bit in
the LPCR. Note that to do this we need to try and set the bit, then read
it back to check the host allowed us to set it, if so we can use it but
if we were unable to set it the host cannot support it and we must not
use the large decrementer.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/ppc/spapr_caps.c  | 17 +++++++++++++++--
 target/ppc/kvm.c     | 39 +++++++++++++++++++++++++++++++++++++++
 target/ppc/kvm_ppc.h | 12 ++++++++++++
 3 files changed, 66 insertions(+), 2 deletions(-)

Comments

David Gibson Feb. 26, 2019, 3:55 a.m. UTC | #1
On Tue, Feb 26, 2019 at 02:05:30PM +1100, Suraj Jitindar Singh wrote:
> Implement support to allow KVM guests to take advantage of the large
> decrementer introduced on POWER9 cpus.
> 
> To determine if the host can support the requested large decrementer
> size, we check it matches that specified in the ibm,dec-bits device-tree
> property. We also need to enable it in KVM by setting the LPCR_LD bit in
> the LPCR. Note that to do this we need to try and set the bit, then read
> it back to check the host allowed us to set it, if so we can use it but
> if we were unable to set it the host cannot support it and we must not
> use the large decrementer.
> 
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

Although changes might be necessary to match it to things I've
suggested in the earlier patches in the series.

Is the KVM side support for this already merged?  If so, as of when?

> ---
>  hw/ppc/spapr_caps.c  | 17 +++++++++++++++--
>  target/ppc/kvm.c     | 39 +++++++++++++++++++++++++++++++++++++++
>  target/ppc/kvm_ppc.h | 12 ++++++++++++
>  3 files changed, 66 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> index 44542fdbb2..e07568fb94 100644
> --- a/hw/ppc/spapr_caps.c
> +++ b/hw/ppc/spapr_caps.c
> @@ -440,8 +440,16 @@ static void cap_large_decr_apply(sPAPRMachineState *spapr,
>                  pcc->hdecr_bits);
>              return;
>          }
> -    } else {
> -        error_setg(errp, "No large decrementer support, try cap-large-decr=0");
> +    } else if (kvm_enabled()) {
> +        int kvm_nr_bits = kvmppc_get_cap_large_decr();
> +
> +        if (!kvm_nr_bits) {
> +            error_setg(errp, "No large decrementer support, try cap-large-decr=0");
> +        } else if (val != kvm_nr_bits) {
> +            error_setg(errp,
> +                "Large decrementer size unsupported, try -cap-large-decr=%d",
> +                kvm_nr_bits);
> +        }
>      }
>  }
>  
> @@ -452,6 +460,11 @@ static void cap_large_decr_cpu_apply(sPAPRMachineState *spapr,
>      CPUPPCState *env = &cpu->env;
>      target_ulong lpcr = env->spr[SPR_LPCR];
>  
> +    if (kvm_enabled()) {
> +        if (kvmppc_enable_cap_large_decr(cpu, !!val))
> +            error_setg(errp, "No large decrementer support, try cap-large-decr=0");
> +    }
> +
>      if (val)
>          lpcr |= LPCR_LD;
>      else
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index d01852fe31..3f650c8fc4 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -91,6 +91,7 @@ static int cap_ppc_safe_cache;
>  static int cap_ppc_safe_bounds_check;
>  static int cap_ppc_safe_indirect_branch;
>  static int cap_ppc_nested_kvm_hv;
> +static int cap_large_decr;
>  
>  static uint32_t debug_inst_opcode;
>  
> @@ -124,6 +125,7 @@ static bool kvmppc_is_pr(KVMState *ks)
>  
>  static int kvm_ppc_register_host_cpu_type(MachineState *ms);
>  static void kvmppc_get_cpu_characteristics(KVMState *s);
> +static int kvmppc_get_dec_bits(void);
>  
>  int kvm_arch_init(MachineState *ms, KVMState *s)
>  {
> @@ -151,6 +153,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>      cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
>      kvmppc_get_cpu_characteristics(s);
>      cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
> +    cap_large_decr = kvmppc_get_dec_bits();
>      /*
>       * Note: setting it to false because there is not such capability
>       * in KVM at this moment.
> @@ -1927,6 +1930,15 @@ uint64_t kvmppc_get_clockfreq(void)
>      return kvmppc_read_int_cpu_dt("clock-frequency");
>  }
>  
> +static int kvmppc_get_dec_bits(void)
> +{
> +    int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
> +
> +    if (nr_bits > 0)
> +        return nr_bits;
> +    return 0;
> +}
> +
>  static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
>   {
>       PowerPCCPU *cpu = ppc_env_get_cpu(env);
> @@ -2442,6 +2454,33 @@ bool kvmppc_has_cap_spapr_vfio(void)
>      return cap_spapr_vfio;
>  }
>  
> +int kvmppc_get_cap_large_decr(void)
> +{
> +    return cap_large_decr;
> +}
> +
> +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
> +{
> +    CPUState *cs = CPU(cpu);
> +    uint64_t lpcr;
> +
> +    kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> +    /* Do we need to modify the LPCR? */
> +    if (!!(lpcr & LPCR_LD) != !!enable) {
> +        if (enable)
> +            lpcr |= LPCR_LD;
> +        else
> +            lpcr &= ~LPCR_LD;
> +        kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> +        kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> +
> +        if (!!(lpcr & LPCR_LD) != !!enable)
> +            return -1;
> +    }
> +
> +    return 0;
> +}
> +
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
>  {
>      uint32_t host_pvr = mfpvr();
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index bdfaa4e70a..a79835bd14 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -64,6 +64,8 @@ int kvmppc_get_cap_safe_bounds_check(void);
>  int kvmppc_get_cap_safe_indirect_branch(void);
>  bool kvmppc_has_cap_nested_kvm_hv(void);
>  int kvmppc_set_cap_nested_kvm_hv(int enable);
> +int kvmppc_get_cap_large_decr(void);
> +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
>  int kvmppc_enable_hwrng(void);
>  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> @@ -332,6 +334,16 @@ static inline int kvmppc_set_cap_nested_kvm_hv(int enable)
>      return -1;
>  }
>  
> +static inline int kvmppc_get_cap_large_decr(void)
> +{
> +    return 0;
> +}
> +
> +static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
> +{
> +    return -1;
> +}
> +
>  static inline int kvmppc_enable_hwrng(void)
>  {
>      return -1;
Suraj Jitindar Singh Feb. 26, 2019, 11:34 p.m. UTC | #2
On Tue, 2019-02-26 at 14:55 +1100, David Gibson wrote:
> On Tue, Feb 26, 2019 at 02:05:30PM +1100, Suraj Jitindar Singh wrote:
> > Implement support to allow KVM guests to take advantage of the
> > large
> > decrementer introduced on POWER9 cpus.
> > 
> > To determine if the host can support the requested large
> > decrementer
> > size, we check it matches that specified in the ibm,dec-bits
> > device-tree
> > property. We also need to enable it in KVM by setting the LPCR_LD
> > bit in
> > the LPCR. Note that to do this we need to try and set the bit, then
> > read
> > it back to check the host allowed us to set it, if so we can use it
> > but
> > if we were unable to set it the host cannot support it and we must
> > not
> > use the large decrementer.
> > 
> > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> > Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Although changes might be necessary to match it to things I've
> suggested in the earlier patches in the series.
> 
> Is the KVM side support for this already merged?  If so, as of when?

Yes, as of v4.13

> 
> > ---
> >  hw/ppc/spapr_caps.c  | 17 +++++++++++++++--
> >  target/ppc/kvm.c     | 39 +++++++++++++++++++++++++++++++++++++++
> >  target/ppc/kvm_ppc.h | 12 ++++++++++++
> >  3 files changed, 66 insertions(+), 2 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> > index 44542fdbb2..e07568fb94 100644
> > --- a/hw/ppc/spapr_caps.c
> > +++ b/hw/ppc/spapr_caps.c
> > @@ -440,8 +440,16 @@ static void
> > cap_large_decr_apply(sPAPRMachineState *spapr,
> >                  pcc->hdecr_bits);
> >              return;
> >          }
> > -    } else {
> > -        error_setg(errp, "No large decrementer support, try cap-
> > large-decr=0");
> > +    } else if (kvm_enabled()) {
> > +        int kvm_nr_bits = kvmppc_get_cap_large_decr();
> > +
> > +        if (!kvm_nr_bits) {
> > +            error_setg(errp, "No large decrementer support, try
> > cap-large-decr=0");
> > +        } else if (val != kvm_nr_bits) {
> > +            error_setg(errp,
> > +                "Large decrementer size unsupported, try -cap-
> > large-decr=%d",
> > +                kvm_nr_bits);
> > +        }
> >      }
> >  }
> >  
> > @@ -452,6 +460,11 @@ static void
> > cap_large_decr_cpu_apply(sPAPRMachineState *spapr,
> >      CPUPPCState *env = &cpu->env;
> >      target_ulong lpcr = env->spr[SPR_LPCR];
> >  
> > +    if (kvm_enabled()) {
> > +        if (kvmppc_enable_cap_large_decr(cpu, !!val))
> > +            error_setg(errp, "No large decrementer support, try
> > cap-large-decr=0");
> > +    }
> > +
> >      if (val)
> >          lpcr |= LPCR_LD;
> >      else
> > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > index d01852fe31..3f650c8fc4 100644
> > --- a/target/ppc/kvm.c
> > +++ b/target/ppc/kvm.c
> > @@ -91,6 +91,7 @@ static int cap_ppc_safe_cache;
> >  static int cap_ppc_safe_bounds_check;
> >  static int cap_ppc_safe_indirect_branch;
> >  static int cap_ppc_nested_kvm_hv;
> > +static int cap_large_decr;
> >  
> >  static uint32_t debug_inst_opcode;
> >  
> > @@ -124,6 +125,7 @@ static bool kvmppc_is_pr(KVMState *ks)
> >  
> >  static int kvm_ppc_register_host_cpu_type(MachineState *ms);
> >  static void kvmppc_get_cpu_characteristics(KVMState *s);
> > +static int kvmppc_get_dec_bits(void);
> >  
> >  int kvm_arch_init(MachineState *ms, KVMState *s)
> >  {
> > @@ -151,6 +153,7 @@ int kvm_arch_init(MachineState *ms, KVMState
> > *s)
> >      cap_resize_hpt = kvm_vm_check_extension(s,
> > KVM_CAP_SPAPR_RESIZE_HPT);
> >      kvmppc_get_cpu_characteristics(s);
> >      cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s,
> > KVM_CAP_PPC_NESTED_HV);
> > +    cap_large_decr = kvmppc_get_dec_bits();
> >      /*
> >       * Note: setting it to false because there is not such
> > capability
> >       * in KVM at this moment.
> > @@ -1927,6 +1930,15 @@ uint64_t kvmppc_get_clockfreq(void)
> >      return kvmppc_read_int_cpu_dt("clock-frequency");
> >  }
> >  
> > +static int kvmppc_get_dec_bits(void)
> > +{
> > +    int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
> > +
> > +    if (nr_bits > 0)
> > +        return nr_bits;
> > +    return 0;
> > +}
> > +
> >  static int kvmppc_get_pvinfo(CPUPPCState *env, struct
> > kvm_ppc_pvinfo *pvinfo)
> >   {
> >       PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > @@ -2442,6 +2454,33 @@ bool kvmppc_has_cap_spapr_vfio(void)
> >      return cap_spapr_vfio;
> >  }
> >  
> > +int kvmppc_get_cap_large_decr(void)
> > +{
> > +    return cap_large_decr;
> > +}
> > +
> > +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
> > +{
> > +    CPUState *cs = CPU(cpu);
> > +    uint64_t lpcr;
> > +
> > +    kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > +    /* Do we need to modify the LPCR? */
> > +    if (!!(lpcr & LPCR_LD) != !!enable) {
> > +        if (enable)
> > +            lpcr |= LPCR_LD;
> > +        else
> > +            lpcr &= ~LPCR_LD;
> > +        kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > +        kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > +
> > +        if (!!(lpcr & LPCR_LD) != !!enable)
> > +            return -1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
> >  {
> >      uint32_t host_pvr = mfpvr();
> > diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> > index bdfaa4e70a..a79835bd14 100644
> > --- a/target/ppc/kvm_ppc.h
> > +++ b/target/ppc/kvm_ppc.h
> > @@ -64,6 +64,8 @@ int kvmppc_get_cap_safe_bounds_check(void);
> >  int kvmppc_get_cap_safe_indirect_branch(void);
> >  bool kvmppc_has_cap_nested_kvm_hv(void);
> >  int kvmppc_set_cap_nested_kvm_hv(int enable);
> > +int kvmppc_get_cap_large_decr(void);
> > +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
> >  int kvmppc_enable_hwrng(void);
> >  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
> >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> > @@ -332,6 +334,16 @@ static inline int
> > kvmppc_set_cap_nested_kvm_hv(int enable)
> >      return -1;
> >  }
> >  
> > +static inline int kvmppc_get_cap_large_decr(void)
> > +{
> > +    return 0;
> > +}
> > +
> > +static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu,
> > int enable)
> > +{
> > +    return -1;
> > +}
> > +
> >  static inline int kvmppc_enable_hwrng(void)
> >  {
> >      return -1;
> 
>
David Gibson Feb. 26, 2019, 11:40 p.m. UTC | #3
On Wed, Feb 27, 2019 at 10:34:15AM +1100, Suraj Jitindar Singh wrote:
> On Tue, 2019-02-26 at 14:55 +1100, David Gibson wrote:
> > On Tue, Feb 26, 2019 at 02:05:30PM +1100, Suraj Jitindar Singh wrote:
> > > Implement support to allow KVM guests to take advantage of the
> > > large
> > > decrementer introduced on POWER9 cpus.
> > > 
> > > To determine if the host can support the requested large
> > > decrementer
> > > size, we check it matches that specified in the ibm,dec-bits
> > > device-tree
> > > property. We also need to enable it in KVM by setting the LPCR_LD
> > > bit in
> > > the LPCR. Note that to do this we need to try and set the bit, then
> > > read
> > > it back to check the host allowed us to set it, if so we can use it
> > > but
> > > if we were unable to set it the host cannot support it and we must
> > > not
> > > use the large decrementer.
> > > 
> > > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> > > Signed-off-by: Cédric Le Goater <clg@kaod.org>
> > 
> > Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> > 
> > Although changes might be necessary to match it to things I've
> > suggested in the earlier patches in the series.
> > 
> > Is the KVM side support for this already merged?  If so, as of when?
> 
> Yes, as of v4.13

Ah, so already in RHEL8.  Great!

> 
> > 
> > > ---
> > >  hw/ppc/spapr_caps.c  | 17 +++++++++++++++--
> > >  target/ppc/kvm.c     | 39 +++++++++++++++++++++++++++++++++++++++
> > >  target/ppc/kvm_ppc.h | 12 ++++++++++++
> > >  3 files changed, 66 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> > > index 44542fdbb2..e07568fb94 100644
> > > --- a/hw/ppc/spapr_caps.c
> > > +++ b/hw/ppc/spapr_caps.c
> > > @@ -440,8 +440,16 @@ static void
> > > cap_large_decr_apply(sPAPRMachineState *spapr,
> > >                  pcc->hdecr_bits);
> > >              return;
> > >          }
> > > -    } else {
> > > -        error_setg(errp, "No large decrementer support, try cap-
> > > large-decr=0");
> > > +    } else if (kvm_enabled()) {
> > > +        int kvm_nr_bits = kvmppc_get_cap_large_decr();
> > > +
> > > +        if (!kvm_nr_bits) {
> > > +            error_setg(errp, "No large decrementer support, try
> > > cap-large-decr=0");
> > > +        } else if (val != kvm_nr_bits) {
> > > +            error_setg(errp,
> > > +                "Large decrementer size unsupported, try -cap-
> > > large-decr=%d",
> > > +                kvm_nr_bits);
> > > +        }
> > >      }
> > >  }
> > >  
> > > @@ -452,6 +460,11 @@ static void
> > > cap_large_decr_cpu_apply(sPAPRMachineState *spapr,
> > >      CPUPPCState *env = &cpu->env;
> > >      target_ulong lpcr = env->spr[SPR_LPCR];
> > >  
> > > +    if (kvm_enabled()) {
> > > +        if (kvmppc_enable_cap_large_decr(cpu, !!val))
> > > +            error_setg(errp, "No large decrementer support, try
> > > cap-large-decr=0");
> > > +    }
> > > +
> > >      if (val)
> > >          lpcr |= LPCR_LD;
> > >      else
> > > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > > index d01852fe31..3f650c8fc4 100644
> > > --- a/target/ppc/kvm.c
> > > +++ b/target/ppc/kvm.c
> > > @@ -91,6 +91,7 @@ static int cap_ppc_safe_cache;
> > >  static int cap_ppc_safe_bounds_check;
> > >  static int cap_ppc_safe_indirect_branch;
> > >  static int cap_ppc_nested_kvm_hv;
> > > +static int cap_large_decr;
> > >  
> > >  static uint32_t debug_inst_opcode;
> > >  
> > > @@ -124,6 +125,7 @@ static bool kvmppc_is_pr(KVMState *ks)
> > >  
> > >  static int kvm_ppc_register_host_cpu_type(MachineState *ms);
> > >  static void kvmppc_get_cpu_characteristics(KVMState *s);
> > > +static int kvmppc_get_dec_bits(void);
> > >  
> > >  int kvm_arch_init(MachineState *ms, KVMState *s)
> > >  {
> > > @@ -151,6 +153,7 @@ int kvm_arch_init(MachineState *ms, KVMState
> > > *s)
> > >      cap_resize_hpt = kvm_vm_check_extension(s,
> > > KVM_CAP_SPAPR_RESIZE_HPT);
> > >      kvmppc_get_cpu_characteristics(s);
> > >      cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s,
> > > KVM_CAP_PPC_NESTED_HV);
> > > +    cap_large_decr = kvmppc_get_dec_bits();
> > >      /*
> > >       * Note: setting it to false because there is not such
> > > capability
> > >       * in KVM at this moment.
> > > @@ -1927,6 +1930,15 @@ uint64_t kvmppc_get_clockfreq(void)
> > >      return kvmppc_read_int_cpu_dt("clock-frequency");
> > >  }
> > >  
> > > +static int kvmppc_get_dec_bits(void)
> > > +{
> > > +    int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
> > > +
> > > +    if (nr_bits > 0)
> > > +        return nr_bits;
> > > +    return 0;
> > > +}
> > > +
> > >  static int kvmppc_get_pvinfo(CPUPPCState *env, struct
> > > kvm_ppc_pvinfo *pvinfo)
> > >   {
> > >       PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > > @@ -2442,6 +2454,33 @@ bool kvmppc_has_cap_spapr_vfio(void)
> > >      return cap_spapr_vfio;
> > >  }
> > >  
> > > +int kvmppc_get_cap_large_decr(void)
> > > +{
> > > +    return cap_large_decr;
> > > +}
> > > +
> > > +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
> > > +{
> > > +    CPUState *cs = CPU(cpu);
> > > +    uint64_t lpcr;
> > > +
> > > +    kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > > +    /* Do we need to modify the LPCR? */
> > > +    if (!!(lpcr & LPCR_LD) != !!enable) {
> > > +        if (enable)
> > > +            lpcr |= LPCR_LD;
> > > +        else
> > > +            lpcr &= ~LPCR_LD;
> > > +        kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > > +        kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
> > > +
> > > +        if (!!(lpcr & LPCR_LD) != !!enable)
> > > +            return -1;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
> > >  {
> > >      uint32_t host_pvr = mfpvr();
> > > diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> > > index bdfaa4e70a..a79835bd14 100644
> > > --- a/target/ppc/kvm_ppc.h
> > > +++ b/target/ppc/kvm_ppc.h
> > > @@ -64,6 +64,8 @@ int kvmppc_get_cap_safe_bounds_check(void);
> > >  int kvmppc_get_cap_safe_indirect_branch(void);
> > >  bool kvmppc_has_cap_nested_kvm_hv(void);
> > >  int kvmppc_set_cap_nested_kvm_hv(int enable);
> > > +int kvmppc_get_cap_large_decr(void);
> > > +int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
> > >  int kvmppc_enable_hwrng(void);
> > >  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
> > >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> > > @@ -332,6 +334,16 @@ static inline int
> > > kvmppc_set_cap_nested_kvm_hv(int enable)
> > >      return -1;
> > >  }
> > >  
> > > +static inline int kvmppc_get_cap_large_decr(void)
> > > +{
> > > +    return 0;
> > > +}
> > > +
> > > +static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu,
> > > int enable)
> > > +{
> > > +    return -1;
> > > +}
> > > +
> > >  static inline int kvmppc_enable_hwrng(void)
> > >  {
> > >      return -1;
> > 
> > 
>
diff mbox series

Patch

diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 44542fdbb2..e07568fb94 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -440,8 +440,16 @@  static void cap_large_decr_apply(sPAPRMachineState *spapr,
                 pcc->hdecr_bits);
             return;
         }
-    } else {
-        error_setg(errp, "No large decrementer support, try cap-large-decr=0");
+    } else if (kvm_enabled()) {
+        int kvm_nr_bits = kvmppc_get_cap_large_decr();
+
+        if (!kvm_nr_bits) {
+            error_setg(errp, "No large decrementer support, try cap-large-decr=0");
+        } else if (val != kvm_nr_bits) {
+            error_setg(errp,
+                "Large decrementer size unsupported, try -cap-large-decr=%d",
+                kvm_nr_bits);
+        }
     }
 }
 
@@ -452,6 +460,11 @@  static void cap_large_decr_cpu_apply(sPAPRMachineState *spapr,
     CPUPPCState *env = &cpu->env;
     target_ulong lpcr = env->spr[SPR_LPCR];
 
+    if (kvm_enabled()) {
+        if (kvmppc_enable_cap_large_decr(cpu, !!val))
+            error_setg(errp, "No large decrementer support, try cap-large-decr=0");
+    }
+
     if (val)
         lpcr |= LPCR_LD;
     else
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index d01852fe31..3f650c8fc4 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -91,6 +91,7 @@  static int cap_ppc_safe_cache;
 static int cap_ppc_safe_bounds_check;
 static int cap_ppc_safe_indirect_branch;
 static int cap_ppc_nested_kvm_hv;
+static int cap_large_decr;
 
 static uint32_t debug_inst_opcode;
 
@@ -124,6 +125,7 @@  static bool kvmppc_is_pr(KVMState *ks)
 
 static int kvm_ppc_register_host_cpu_type(MachineState *ms);
 static void kvmppc_get_cpu_characteristics(KVMState *s);
+static int kvmppc_get_dec_bits(void);
 
 int kvm_arch_init(MachineState *ms, KVMState *s)
 {
@@ -151,6 +153,7 @@  int kvm_arch_init(MachineState *ms, KVMState *s)
     cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
     kvmppc_get_cpu_characteristics(s);
     cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
+    cap_large_decr = kvmppc_get_dec_bits();
     /*
      * Note: setting it to false because there is not such capability
      * in KVM at this moment.
@@ -1927,6 +1930,15 @@  uint64_t kvmppc_get_clockfreq(void)
     return kvmppc_read_int_cpu_dt("clock-frequency");
 }
 
+static int kvmppc_get_dec_bits(void)
+{
+    int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
+
+    if (nr_bits > 0)
+        return nr_bits;
+    return 0;
+}
+
 static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
  {
      PowerPCCPU *cpu = ppc_env_get_cpu(env);
@@ -2442,6 +2454,33 @@  bool kvmppc_has_cap_spapr_vfio(void)
     return cap_spapr_vfio;
 }
 
+int kvmppc_get_cap_large_decr(void)
+{
+    return cap_large_decr;
+}
+
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+    CPUState *cs = CPU(cpu);
+    uint64_t lpcr;
+
+    kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+    /* Do we need to modify the LPCR? */
+    if (!!(lpcr & LPCR_LD) != !!enable) {
+        if (enable)
+            lpcr |= LPCR_LD;
+        else
+            lpcr &= ~LPCR_LD;
+        kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+        kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
+
+        if (!!(lpcr & LPCR_LD) != !!enable)
+            return -1;
+    }
+
+    return 0;
+}
+
 PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
 {
     uint32_t host_pvr = mfpvr();
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index bdfaa4e70a..a79835bd14 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -64,6 +64,8 @@  int kvmppc_get_cap_safe_bounds_check(void);
 int kvmppc_get_cap_safe_indirect_branch(void);
 bool kvmppc_has_cap_nested_kvm_hv(void);
 int kvmppc_set_cap_nested_kvm_hv(int enable);
+int kvmppc_get_cap_large_decr(void);
+int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable);
 int kvmppc_enable_hwrng(void);
 int kvmppc_put_books_sregs(PowerPCCPU *cpu);
 PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
@@ -332,6 +334,16 @@  static inline int kvmppc_set_cap_nested_kvm_hv(int enable)
     return -1;
 }
 
+static inline int kvmppc_get_cap_large_decr(void)
+{
+    return 0;
+}
+
+static inline int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
+{
+    return -1;
+}
+
 static inline int kvmppc_enable_hwrng(void)
 {
     return -1;