Re: [PATCH v3 07/17] KVM: PPC: Book3S HV: XIVE: add a global reset control

2019-03-17 Thread David Gibson
On Fri, Mar 15, 2019 at 01:05:59PM +0100, Cédric Le Goater wrote:
> This control is to be used by the H_INT_RESET hcall from QEMU. Its
> purpose is to clear all configuration of the sources and EQs. This is
> necessary in case of a kexec (for a kdump kernel for instance) to make
> sure that no remaining configuration is left from the previous boot
> setup so that the new kernel can start safely from a clean state.
> 
> The queue 7 is ignored when the XIVE device is configured to run in
> single escalation mode. Prio 7 is used by escalations.
> 
> The XIVE VP is kept enabled as the vCPU is still active and connected
> to the XIVE device.
> 
> Signed-off-by: Cédric Le Goater 

Reviewed-by: David Gibson 

> ---
> 
>  Changes since v2 :
> 
>  - fixed locking on source block
> 
>  arch/powerpc/include/uapi/asm/kvm.h|  1 +
>  arch/powerpc/kvm/book3s_xive_native.c  | 85 ++
>  Documentation/virtual/kvm/devices/xive.txt |  5 ++
>  3 files changed, 91 insertions(+)
> 
> diff --git a/arch/powerpc/include/uapi/asm/kvm.h 
> b/arch/powerpc/include/uapi/asm/kvm.h
> index 1cd728c87d7c..95e82ab57c03 100644
> --- a/arch/powerpc/include/uapi/asm/kvm.h
> +++ b/arch/powerpc/include/uapi/asm/kvm.h
> @@ -677,6 +677,7 @@ struct kvm_ppc_cpu_char {
>  
>  /* POWER9 XIVE Native Interrupt Controller */
>  #define KVM_DEV_XIVE_GRP_CTRL1
> +#define   KVM_DEV_XIVE_RESET 1
>  #define KVM_DEV_XIVE_GRP_SOURCE  2   /* 64-bit source 
> identifier */
>  #define KVM_DEV_XIVE_GRP_SOURCE_CONFIG   3   /* 64-bit source 
> identifier */
>  #define KVM_DEV_XIVE_GRP_EQ_CONFIG   4   /* 64-bit EQ identifier */
> diff --git a/arch/powerpc/kvm/book3s_xive_native.c 
> b/arch/powerpc/kvm/book3s_xive_native.c
> index 42e824658a30..3385c336fd89 100644
> --- a/arch/powerpc/kvm/book3s_xive_native.c
> +++ b/arch/powerpc/kvm/book3s_xive_native.c
> @@ -560,6 +560,83 @@ static int kvmppc_xive_native_get_queue_config(struct 
> kvmppc_xive *xive,
>   return 0;
>  }
>  
> +static void kvmppc_xive_reset_sources(struct kvmppc_xive_src_block *sb)
> +{
> + int i;
> +
> + for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
> + struct kvmppc_xive_irq_state *state = >irq_state[i];
> +
> + if (!state->valid)
> + continue;
> +
> + if (state->act_priority == MASKED)
> + continue;
> +
> + state->eisn = 0;
> + state->act_server = 0;
> + state->act_priority = MASKED;
> + xive_vm_esb_load(>ipi_data, XIVE_ESB_SET_PQ_01);
> + xive_native_configure_irq(state->ipi_number, 0, MASKED, 0);
> + if (state->pt_number) {
> + xive_vm_esb_load(state->pt_data, XIVE_ESB_SET_PQ_01);
> + xive_native_configure_irq(state->pt_number,
> +   0, MASKED, 0);
> + }
> + }
> +}
> +
> +static int kvmppc_xive_reset(struct kvmppc_xive *xive)
> +{
> + struct kvm *kvm = xive->kvm;
> + struct kvm_vcpu *vcpu;
> + unsigned int i;
> +
> + pr_devel("%s\n", __func__);
> +
> + mutex_lock(>lock);
> +
> + kvm_for_each_vcpu(i, vcpu, kvm) {
> + struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
> + unsigned int prio;
> +
> + if (!xc)
> + continue;
> +
> + kvmppc_xive_disable_vcpu_interrupts(vcpu);
> +
> + for (prio = 0; prio < KVMPPC_XIVE_Q_COUNT; prio++) {
> +
> + /* Single escalation, no queue 7 */
> + if (prio == 7 && xive->single_escalation)
> + break;
> +
> + if (xc->esc_virq[prio]) {
> + free_irq(xc->esc_virq[prio], vcpu);
> + irq_dispose_mapping(xc->esc_virq[prio]);
> + kfree(xc->esc_virq_names[prio]);
> + xc->esc_virq[prio] = 0;
> + }
> +
> + kvmppc_xive_native_cleanup_queue(vcpu, prio);
> + }
> + }
> +
> + for (i = 0; i <= xive->max_sbid; i++) {
> + struct kvmppc_xive_src_block *sb = xive->src_blocks[i];
> +
> + if (sb) {
> + arch_spin_lock(>lock);
> + kvmppc_xive_reset_sources(sb);
> + arch_spin_unlock(>lock);
> + }
> + }
> +
> + mutex_unlock(>lock);
> +
> + return 0;
> +}
> +
>  static int kvmppc_xive_native_set_attr(struct kvm_device *dev,
>  struct kvm_device_attr *attr)
>  {
> @@ -567,6 +644,10 @@ static int kvmppc_xive_native_set_attr(struct kvm_device 
> *dev,
>  
>   switch (attr->group) {
>   case KVM_DEV_XIVE_GRP_CTRL:
> + switch (attr->attr) {
> + case KVM_DEV_XIVE_RESET:
> + return kvmppc_xive_reset(xive);
> + 

[PATCH v3 07/17] KVM: PPC: Book3S HV: XIVE: add a global reset control

2019-03-15 Thread Cédric Le Goater
This control is to be used by the H_INT_RESET hcall from QEMU. Its
purpose is to clear all configuration of the sources and EQs. This is
necessary in case of a kexec (for a kdump kernel for instance) to make
sure that no remaining configuration is left from the previous boot
setup so that the new kernel can start safely from a clean state.

The queue 7 is ignored when the XIVE device is configured to run in
single escalation mode. Prio 7 is used by escalations.

The XIVE VP is kept enabled as the vCPU is still active and connected
to the XIVE device.

Signed-off-by: Cédric Le Goater 
---

 Changes since v2 :

 - fixed locking on source block

 arch/powerpc/include/uapi/asm/kvm.h|  1 +
 arch/powerpc/kvm/book3s_xive_native.c  | 85 ++
 Documentation/virtual/kvm/devices/xive.txt |  5 ++
 3 files changed, 91 insertions(+)

diff --git a/arch/powerpc/include/uapi/asm/kvm.h 
b/arch/powerpc/include/uapi/asm/kvm.h
index 1cd728c87d7c..95e82ab57c03 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -677,6 +677,7 @@ struct kvm_ppc_cpu_char {
 
 /* POWER9 XIVE Native Interrupt Controller */
 #define KVM_DEV_XIVE_GRP_CTRL  1
+#define   KVM_DEV_XIVE_RESET   1
 #define KVM_DEV_XIVE_GRP_SOURCE2   /* 64-bit source 
identifier */
 #define KVM_DEV_XIVE_GRP_SOURCE_CONFIG 3   /* 64-bit source identifier */
 #define KVM_DEV_XIVE_GRP_EQ_CONFIG 4   /* 64-bit EQ identifier */
diff --git a/arch/powerpc/kvm/book3s_xive_native.c 
b/arch/powerpc/kvm/book3s_xive_native.c
index 42e824658a30..3385c336fd89 100644
--- a/arch/powerpc/kvm/book3s_xive_native.c
+++ b/arch/powerpc/kvm/book3s_xive_native.c
@@ -560,6 +560,83 @@ static int kvmppc_xive_native_get_queue_config(struct 
kvmppc_xive *xive,
return 0;
 }
 
+static void kvmppc_xive_reset_sources(struct kvmppc_xive_src_block *sb)
+{
+   int i;
+
+   for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
+   struct kvmppc_xive_irq_state *state = >irq_state[i];
+
+   if (!state->valid)
+   continue;
+
+   if (state->act_priority == MASKED)
+   continue;
+
+   state->eisn = 0;
+   state->act_server = 0;
+   state->act_priority = MASKED;
+   xive_vm_esb_load(>ipi_data, XIVE_ESB_SET_PQ_01);
+   xive_native_configure_irq(state->ipi_number, 0, MASKED, 0);
+   if (state->pt_number) {
+   xive_vm_esb_load(state->pt_data, XIVE_ESB_SET_PQ_01);
+   xive_native_configure_irq(state->pt_number,
+ 0, MASKED, 0);
+   }
+   }
+}
+
+static int kvmppc_xive_reset(struct kvmppc_xive *xive)
+{
+   struct kvm *kvm = xive->kvm;
+   struct kvm_vcpu *vcpu;
+   unsigned int i;
+
+   pr_devel("%s\n", __func__);
+
+   mutex_lock(>lock);
+
+   kvm_for_each_vcpu(i, vcpu, kvm) {
+   struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+   unsigned int prio;
+
+   if (!xc)
+   continue;
+
+   kvmppc_xive_disable_vcpu_interrupts(vcpu);
+
+   for (prio = 0; prio < KVMPPC_XIVE_Q_COUNT; prio++) {
+
+   /* Single escalation, no queue 7 */
+   if (prio == 7 && xive->single_escalation)
+   break;
+
+   if (xc->esc_virq[prio]) {
+   free_irq(xc->esc_virq[prio], vcpu);
+   irq_dispose_mapping(xc->esc_virq[prio]);
+   kfree(xc->esc_virq_names[prio]);
+   xc->esc_virq[prio] = 0;
+   }
+
+   kvmppc_xive_native_cleanup_queue(vcpu, prio);
+   }
+   }
+
+   for (i = 0; i <= xive->max_sbid; i++) {
+   struct kvmppc_xive_src_block *sb = xive->src_blocks[i];
+
+   if (sb) {
+   arch_spin_lock(>lock);
+   kvmppc_xive_reset_sources(sb);
+   arch_spin_unlock(>lock);
+   }
+   }
+
+   mutex_unlock(>lock);
+
+   return 0;
+}
+
 static int kvmppc_xive_native_set_attr(struct kvm_device *dev,
   struct kvm_device_attr *attr)
 {
@@ -567,6 +644,10 @@ static int kvmppc_xive_native_set_attr(struct kvm_device 
*dev,
 
switch (attr->group) {
case KVM_DEV_XIVE_GRP_CTRL:
+   switch (attr->attr) {
+   case KVM_DEV_XIVE_RESET:
+   return kvmppc_xive_reset(xive);
+   }
break;
case KVM_DEV_XIVE_GRP_SOURCE:
return kvmppc_xive_native_set_source(xive, attr->attr,
@@ -599,6 +680,10 @@ static int kvmppc_xive_native_has_attr(struct kvm_device 
*dev,
 {
switch (attr->group) {