aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBalbir Singh <bsingharora@gmail.com>2016-04-03 20:38:00 +1000
committerWill Deacon <will.deacon@arm.com>2016-04-11 11:59:57 +0100
commit015785d4efcc6fde5f6d1c79e4adced42283efb2 (patch)
tree6f31fa707b7fc01beca168fcefc582da6c6b1a09
parente300a5eef43ed25dc415b47d67cdf8d8987a9bf8 (diff)
downloadkvmtool-015785d4efcc6fde5f6d1c79e4adced42283efb2.tar.gz
Implement H_SET_MODE for ppc64le
Use the infrastructure for queuing a task to a specific vCPU and sett ILE (Little Endian Interrupt Handling) on power via h_set_mode hypercall Signed-off-by: Balbir Singh <bsingharora@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--powerpc/include/kvm/kvm-cpu-arch.h2
-rw-r--r--powerpc/kvm.c2
-rw-r--r--powerpc/spapr.h15
-rw-r--r--powerpc/spapr_hcall.c66
4 files changed, 82 insertions, 3 deletions
diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h
index f2bfbb5b..a69e0cc3 100644
--- a/powerpc/include/kvm/kvm-cpu-arch.h
+++ b/powerpc/include/kvm/kvm-cpu-arch.h
@@ -38,6 +38,8 @@
#define POWER7_EXT_IRQ 0
+#define LPCR_ILE (1 << (63-38))
+
struct kvm;
struct kvm_cpu {
diff --git a/powerpc/kvm.c b/powerpc/kvm.c
index d061c981..f9314802 100644
--- a/powerpc/kvm.c
+++ b/powerpc/kvm.c
@@ -291,7 +291,7 @@ static int setup_fdt(struct kvm *kvm)
uint32_t int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
char hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
"hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
- "hcall-splpar\0hcall-bulk";
+ "hcall-splpar\0hcall-bulk\0hcall-set-mode";
int i, j;
char cpu_name[30];
u8 staging_fdt[FDT_MAX_SIZE];
diff --git a/powerpc/spapr.h b/powerpc/spapr.h
index 8b294d17..f851f4ab 100644
--- a/powerpc/spapr.h
+++ b/powerpc/spapr.h
@@ -27,7 +27,7 @@ typedef uintptr_t target_phys_addr_t;
#define H_HARDWARE -1 /* Hardware error */
#define H_FUNCTION -2 /* Function not supported */
#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */
-
+#define H_P2 -55
#define H_SET_DABR 0x28
#define H_LOGICAL_CI_LOAD 0x3c
#define H_LOGICAL_CI_STORE 0x40
@@ -41,7 +41,18 @@ typedef uintptr_t target_phys_addr_t;
#define H_EOI 0x64
#define H_IPI 0x6c
#define H_XIRR 0x74
-#define MAX_HCALL_OPCODE H_XIRR
+#define H_SET_MODE 0x31C
+#define MAX_HCALL_OPCODE H_SET_MODE
+
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_CIABR 1
+#define H_SET_MODE_RESOURCE_SET_DAWR 2
+#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3
+#define H_SET_MODE_RESOURCE_LE 4
+
+/* Flags for H_SET_MODE_RESOURCE_LE */
+#define H_SET_MODE_ENDIAN_BIG 0
+#define H_SET_MODE_ENDIAN_LITTLE 1
/*
* The hcalls above are standardized in PAPR and implemented by pHyp
diff --git a/powerpc/spapr_hcall.c b/powerpc/spapr_hcall.c
index ff1d63ac..25bec829 100644
--- a/powerpc/spapr_hcall.c
+++ b/powerpc/spapr_hcall.c
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <assert.h>
+#include <sys/eventfd.h>
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX -
@@ -74,6 +75,70 @@ static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, ta
return H_SUCCESS;
}
+struct lpcr_data {
+ struct kvm_cpu *cpu;
+ int mode;
+};
+
+static void get_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
+{
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_LPCR_64,
+ .addr = (__u64)lpcr
+ };
+
+ if (ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, &reg))
+ die("Couldn't read vcpu reg?!");
+}
+
+static void set_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr)
+{
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_LPCR_64,
+ .addr = (__u64)lpcr
+ };
+
+ if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg))
+ die("Couldn't write vcpu reg?!");
+}
+
+static void set_endian_task(struct kvm_cpu *vcpu, void *data)
+{
+ target_ulong mflags = (target_ulong)data;
+ target_ulong lpcr;
+
+ get_cpu_lpcr(vcpu, &lpcr);
+
+ if (mflags == H_SET_MODE_ENDIAN_BIG)
+ lpcr &= ~LPCR_ILE;
+ else
+ lpcr |= LPCR_ILE;
+
+ set_cpu_lpcr(vcpu, &lpcr);
+}
+
+static target_ulong h_set_mode(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+ int ret;
+
+ switch (args[1]) {
+ case H_SET_MODE_RESOURCE_LE: {
+ struct kvm_cpu_task task;
+ task.func = set_endian_task;
+ task.data = (void *)args[0];
+ kvm_cpu__run_on_all_cpus(vcpu->kvm, &task);
+ ret = H_SUCCESS;
+ break;
+ }
+ default:
+ ret = H_FUNCTION;
+ break;
+ }
+
+ return ret;
+}
+
+
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
{
spapr_hcall_fn *slot;
@@ -128,6 +193,7 @@ void hypercall_init(void)
spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+ spapr_register_hypercall(H_SET_MODE, h_set_mode);
/* KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);