[PATCH 7/9] KVM: PPC: Book3S HV: Add support for real mode ICP in XICS emulation

2013-02-14 Thread Paul Mackerras
From: Benjamin Herrenschmidt b...@kernel.crashing.org

This adds an implementation of the XICS hypercalls in real mode for HV
KVM, which allows us to avoid exiting the guest MMU context on all
threads for a variety of operations such as fetching a pending
interrupt, EOI of messages, IPIs, etc.

Signed-off-by: Benjamin Herrenschmidt b...@kernel.crashing.org
Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/kvm/Makefile   |1 +
 arch/powerpc/kvm/book3s_hv_rm_xics.c|  402 +++
 arch/powerpc/kvm/book3s_hv_rmhandlers.S |   10 +-
 arch/powerpc/kvm/book3s_xics.c  |   64 -
 arch/powerpc/kvm/book3s_xics.h  |   16 ++
 5 files changed, 475 insertions(+), 18 deletions(-)
 create mode 100644 arch/powerpc/kvm/book3s_hv_rm_xics.c

diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index e2eb04c..895e880 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -77,6 +77,7 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
book3s_hv_rm_mmu.o \
book3s_64_vio_hv.o \
book3s_hv_ras.o \
+   book3s_hv_rm_xics.o \
book3s_hv_builtin.o
 
 kvm-book3s_64-module-objs := \
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c 
b/arch/powerpc/kvm/book3s_hv_rm_xics.c
new file mode 100644
index 000..3605e0c
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2012 Michael Ellerman, IBM Corporation.
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include linux/kernel.h
+#include linux/kvm_host.h
+#include linux/err.h
+
+#include asm/kvm_book3s.h
+#include asm/kvm_ppc.h
+#include asm/hvcall.h
+#include asm/xics.h
+#include asm/debug.h
+#include asm/synch.h
+#include asm/ppc-opcode.h
+
+#include book3s_xics.h
+
+#define DEBUG_PASSUP
+
+static inline void rm_writeb(unsigned long paddr, u8 val)
+{
+   __asm__ __volatile__(sync; stbcix %0,0,%1
+   : : r (val), r (paddr) : memory);
+}
+
+static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu, struct kvm_vcpu 
*this_vcpu)
+{
+   struct kvmppc_icp *this_icp = this_vcpu-arch.icp;
+   unsigned long xics_phys;
+   int cpu;
+
+   /* Mark the target VCPU as having an interrupt pending */
+   vcpu-stat.queue_intr++;
+   set_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, vcpu-arch.pending_exceptions);
+
+   /* Kick self ? Just set MER and return */
+   if (vcpu == this_vcpu) {
+   mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_MER);
+   return;
+   }
+
+   /* Check if the core is loaded, if not, too hard */
+   cpu = vcpu-cpu;
+   if (cpu  0 || cpu = nr_cpu_ids) {
+   this_icp-rm_action |= XICS_RM_KICK_VCPU;
+   this_icp-rm_kick_target = vcpu;
+   return;
+   }
+   /* In SMT cpu will always point to thread 0, we adjust it */
+   cpu += vcpu-arch.ptid;
+
+   /* Not too hard, then poke the target */
+   xics_phys = paca[cpu].kvm_hstate.xics_phys;
+   rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY);
+}
+
+static void icp_rm_clr_vcpu_irq(struct kvm_vcpu *vcpu)
+{
+   /* Note: Only called on self ! */
+   clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 
vcpu-arch.pending_exceptions);
+   mtspr(SPRN_LPCR, mfspr(SPRN_LPCR)  ~LPCR_MER);
+}
+
+static inline bool icp_rm_try_update(struct kvmppc_icp *icp,
+union kvmppc_icp_state old,
+union kvmppc_icp_state new)
+{
+   struct kvm_vcpu *this_vcpu = local_paca-kvm_hstate.kvm_vcpu;
+   bool success;
+
+   /* Calculate new output value */
+   new.out_ee = (new.xisr  (new.pending_pri  new.cppr));
+
+   /* Attempt atomic update */
+   success = cmpxchg64(icp-state.raw, old.raw, new.raw) == old.raw;
+   if (!success)
+   goto bail;
+
+   /*
+* Check for output state update
+*
+* Note that this is racy since another processor could be updating
+* the state already. This is why we never clear the interrupt output
+* here, we only ever set it. The clear only happens prior to doing
+* an update and only by the processor itself. Currently we do it
+* in Accept (H_XIRR) and Up_Cppr (H_XPPR).
+*
+* We also do not try to figure out whether the EE state has changed,
+* we unconditionally set it if the new state calls for it. The reason
+* for that is that we opportunistically remove the pending interrupt
+* flag when raising CPPR, so we need to set it back here if an
+* interrupt is still pending.
+*/
+   if (new.out_ee)
+   icp_rm_set_vcpu_irq(icp-vcpu, this_vcpu);
+
+   /* Expose the state 

[PATCH 7/9] KVM: PPC: Book3S HV: Add support for real mode ICP in XICS emulation

2013-02-14 Thread Paul Mackerras
From: Benjamin Herrenschmidt b...@kernel.crashing.org

This adds an implementation of the XICS hypercalls in real mode for HV
KVM, which allows us to avoid exiting the guest MMU context on all
threads for a variety of operations such as fetching a pending
interrupt, EOI of messages, IPIs, etc.

Signed-off-by: Benjamin Herrenschmidt b...@kernel.crashing.org
Signed-off-by: Paul Mackerras pau...@samba.org
---
 arch/powerpc/kvm/Makefile   |1 +
 arch/powerpc/kvm/book3s_hv_rm_xics.c|  402 +++
 arch/powerpc/kvm/book3s_hv_rmhandlers.S |   10 +-
 arch/powerpc/kvm/book3s_xics.c  |   64 -
 arch/powerpc/kvm/book3s_xics.h  |   16 ++
 5 files changed, 475 insertions(+), 18 deletions(-)
 create mode 100644 arch/powerpc/kvm/book3s_hv_rm_xics.c

diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index e2eb04c..895e880 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -77,6 +77,7 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
book3s_hv_rm_mmu.o \
book3s_64_vio_hv.o \
book3s_hv_ras.o \
+   book3s_hv_rm_xics.o \
book3s_hv_builtin.o
 
 kvm-book3s_64-module-objs := \
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c 
b/arch/powerpc/kvm/book3s_hv_rm_xics.c
new file mode 100644
index 000..3605e0c
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2012 Michael Ellerman, IBM Corporation.
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include linux/kernel.h
+#include linux/kvm_host.h
+#include linux/err.h
+
+#include asm/kvm_book3s.h
+#include asm/kvm_ppc.h
+#include asm/hvcall.h
+#include asm/xics.h
+#include asm/debug.h
+#include asm/synch.h
+#include asm/ppc-opcode.h
+
+#include book3s_xics.h
+
+#define DEBUG_PASSUP
+
+static inline void rm_writeb(unsigned long paddr, u8 val)
+{
+   __asm__ __volatile__(sync; stbcix %0,0,%1
+   : : r (val), r (paddr) : memory);
+}
+
+static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu, struct kvm_vcpu 
*this_vcpu)
+{
+   struct kvmppc_icp *this_icp = this_vcpu-arch.icp;
+   unsigned long xics_phys;
+   int cpu;
+
+   /* Mark the target VCPU as having an interrupt pending */
+   vcpu-stat.queue_intr++;
+   set_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, vcpu-arch.pending_exceptions);
+
+   /* Kick self ? Just set MER and return */
+   if (vcpu == this_vcpu) {
+   mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_MER);
+   return;
+   }
+
+   /* Check if the core is loaded, if not, too hard */
+   cpu = vcpu-cpu;
+   if (cpu  0 || cpu = nr_cpu_ids) {
+   this_icp-rm_action |= XICS_RM_KICK_VCPU;
+   this_icp-rm_kick_target = vcpu;
+   return;
+   }
+   /* In SMT cpu will always point to thread 0, we adjust it */
+   cpu += vcpu-arch.ptid;
+
+   /* Not too hard, then poke the target */
+   xics_phys = paca[cpu].kvm_hstate.xics_phys;
+   rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY);
+}
+
+static void icp_rm_clr_vcpu_irq(struct kvm_vcpu *vcpu)
+{
+   /* Note: Only called on self ! */
+   clear_bit(BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 
vcpu-arch.pending_exceptions);
+   mtspr(SPRN_LPCR, mfspr(SPRN_LPCR)  ~LPCR_MER);
+}
+
+static inline bool icp_rm_try_update(struct kvmppc_icp *icp,
+union kvmppc_icp_state old,
+union kvmppc_icp_state new)
+{
+   struct kvm_vcpu *this_vcpu = local_paca-kvm_hstate.kvm_vcpu;
+   bool success;
+
+   /* Calculate new output value */
+   new.out_ee = (new.xisr  (new.pending_pri  new.cppr));
+
+   /* Attempt atomic update */
+   success = cmpxchg64(icp-state.raw, old.raw, new.raw) == old.raw;
+   if (!success)
+   goto bail;
+
+   /*
+* Check for output state update
+*
+* Note that this is racy since another processor could be updating
+* the state already. This is why we never clear the interrupt output
+* here, we only ever set it. The clear only happens prior to doing
+* an update and only by the processor itself. Currently we do it
+* in Accept (H_XIRR) and Up_Cppr (H_XPPR).
+*
+* We also do not try to figure out whether the EE state has changed,
+* we unconditionally set it if the new state calls for it. The reason
+* for that is that we opportunistically remove the pending interrupt
+* flag when raising CPPR, so we need to set it back here if an
+* interrupt is still pending.
+*/
+   if (new.out_ee)
+   icp_rm_set_vcpu_irq(icp-vcpu, this_vcpu);
+
+   /* Expose the state