qemu-devel
[Top][All Lists]
Advanced

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

Re: [RFC PATCH v2 2/2] s390x: Implement the USER_SIGP_BUSY capability


From: David Hildenbrand
Subject: Re: [RFC PATCH v2 2/2] s390x: Implement the USER_SIGP_BUSY capability
Date: Thu, 4 Nov 2021 09:23:29 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.2.0

On 02.11.21 21:11, Eric Farman wrote:
> With the USER_SIGP capability, the kernel will pass most (but not all)
> SIGP orders to userspace for processing. But that means that the kernel
> is unable to determine if/when the order has been completed by userspace,
> and could potentially return an incorrect answer (CC1 with status bits
> versus CC2 indicating BUSY) for one of the remaining in-kernel orders.
> 
> With a new USER_SIGP_BUSY capability, the kernel will automatically
> flag a vcpu as busy for a SIGP order, and block further orders directed
> to the same vcpu until userspace resets it to indicate the order has
> been fully processed.
> 
> Let's use the new capability in QEMU.
> 
> Signed-off-by: Eric Farman <farman@linux.ibm.com>

[...]

> +void kvm_s390_vcpu_reset_busy(S390CPU *cpu)


kvm_s390_vcpu_reset_sigp_busy ?

> +{
> +    CPUState *cs = CPU(cpu);
> +
> +    /* Don't care about the response from this */
> +    kvm_vcpu_ioctl(cs, KVM_S390_VCPU_RESET_SIGP_BUSY);
> +}
> +
>  bool kvm_arch_cpu_check_are_resettable(void)
>  {
>      return true;

[...]

>  static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
> @@ -338,12 +367,14 @@ static void sigp_sense_running(S390CPU *dst_cpu, 
> SigpInfo *si)
>      if (!tcg_enabled()) {
>          /* handled in KVM */
>          set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
> +        s390_cpu_reset_sigp_busy(dst_cpu);
>          return;
>      }
>  
>      /* sensing without locks is racy, but it's the same for real hw */
>      if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
>          set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
> +        s390_cpu_reset_sigp_busy(dst_cpu);
>          return;
>      }
>  
> @@ -353,6 +384,7 @@ static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo 
> *si)
>      } else {
>          si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
>      }
> +    s390_cpu_reset_sigp_busy(dst_cpu);
>  }


Can't we call s390_cpu_reset_sigp_busy() directly from handle_sigp_single_dst(),
after the handle_sigp_single_dst() call?

IIRC we could clear it in case cpu->env.sigp_order wasn't set. Otherwise,
we'll have to clear it once we clear cpu->env.sigp_order -- e.g., in 
do_stop_interrupt(), but
also during s390_cpu_reset().

We could have a helper function that sets cpu->env.sigp_order = 0 and clears 
the busy indication.




>  
>  static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t 
> order,
> @@ -420,6 +452,7 @@ static int handle_sigp_single_dst(S390CPU *cpu, S390CPU 
> *dst_cpu, uint8_t order,
>          break;
>      default:
>          set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
> +        s390_cpu_reset_sigp_busy(dst_cpu);
>      }
>  
>      return si.cc;
> @@ -444,6 +477,12 @@ int handle_sigp(CPUS390XState *env, uint8_t order, 
> uint64_t r1, uint64_t r3)
>      int ret;
>  

Maybe rather lookup the dst once:

if (order != SIGP_SET_ARCH) {
    /* all other sigp orders target a single vcpu */
    dst_cpu = s390_cpu_addr2state(env->regs[r3]);
}

if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
    if (dst_cpu) {
        s390_cpu_reset_sigp_busy(dst_cpu);
    }
    ret = SIGP_CC_BUSY;
    goto out;
}

switch (order) {
case SIGP_SET_ARCH:
    ret = sigp_set_architecture(cpu, param, status_reg);
    break;
default:
    ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg);
}


BUT, I wonder if this is fully correct.

Can't it happen that another CPU is currently processing an order for
that very same dst_cpu and you would clear SIGP busy of that cpu
prematurely?

>      if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
> +        if (order != SIGP_SET_ARCH) {
> +            dst_cpu = s390_cpu_addr2state(env->regs[r3]);
> +            if (dst_cpu) {
> +                s390_cpu_reset_sigp_busy(dst_cpu);
> +            }
> +        }
>          ret = SIGP_CC_BUSY;
>          goto out;
>      }
> @@ -487,6 +526,7 @@ void do_stop_interrupt(CPUS390XState *env)
>      }
>      env->sigp_order = 0;
>      env->pending_int &= ~INTERRUPT_STOP;
> +    s390_cpu_reset_sigp_busy(cpu);
>  }
>  
>  void s390_init_sigp(void)
> 


-- 
Thanks,

David / dhildenb




reply via email to

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