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@xxxxxxxxx> Signed-off-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx> --- powerpc/include/kvm/kvm-cpu-arch.h | 2 ++ powerpc/kvm.c | 2 +- powerpc/spapr.h | 15 +++++++-- powerpc/spapr_hcall.c | 66 ++++++++++++++++++++++++++++++++++++++ 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 f2bfbb5..a69e0cc 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 d147e0c..2dbd0fe 100644 --- a/powerpc/kvm.c +++ b/powerpc/kvm.c @@ -286,7 +286,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 8b294d1..f851f4a 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 ff1d63a..25bec82 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, ®)) + 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, ®)) + 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); -- 2.5.5 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html