From patchwork Mon Mar 21 07:17:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Education Directorate X-Patchwork-Id: 8629781 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D7125C0553 for ; Mon, 21 Mar 2016 07:18:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9FB1F20274 for ; Mon, 21 Mar 2016 07:18:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 02CBE2027D for ; Mon, 21 Mar 2016 07:18:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752114AbcCUHSQ (ORCPT ); Mon, 21 Mar 2016 03:18:16 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:36485 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752569AbcCUHSL (ORCPT ); Mon, 21 Mar 2016 03:18:11 -0400 Received: by mail-pf0-f195.google.com with SMTP id q129so29205618pfb.3 for ; Mon, 21 Mar 2016 00:18:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=a0vNqhhD7qu1lkzdHbFtBsRvLigUKWzxUqf+zqD1Ruc=; b=TdDpoVsFV5r+laFZwM4gUfkzdJkDuz4S3ovmlRzUSXA/v6aEn9CL/3gqvTMbsQ9raj OCvpSg8Q79xc/ITSDUsRl4BFiByZGQ2nTE+7iSPIMZfASFHYveaoRcDj8EpOQBn3s7Ct wvyukuqxsdsGCWjG9BjmQfleNRwPd8D/gu8yBi+fWR70iAUcKMYKiLqOwVpR/7qj+m5F +L6t7waCjIOwoHu1CFSCHvYxDr5TK3Kfj2bSJSVVacGdYW6MINuJb7gPyW5JIyk0U+Vl 9473/3vNcOja3RO6UulaGhLJKzgcoPNMi7huOPmtN6qy6EI8itEG1mg3wYxx+H3OsQqG FLkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=a0vNqhhD7qu1lkzdHbFtBsRvLigUKWzxUqf+zqD1Ruc=; b=QlmA/tEIohaRA0P3zJbRklK0FDDelCV0Qe3q3f0xmE6aeO6ThL96YVfVh0IWv+0IyL xNr1Uqnd2AqQ6R/BmAfgiC+ksFMGW32tD5ayqBj0+shBxEw32w6Nybjgej1/n29zZNRx h2ql1VSPfsuQTESDjebXxEwY0V/N+W57AVoJLc6EBvA6gaqO3O/969UUpe5bP9jW2YzL AZsht/1694OZmCTVZrNPD2iSI0iJAo116xfGhx1iHlosffsV636hW2AFlpfQyfwEElw3 x4g2Lod2rW33WX3EgMk8I5ONG7v4bGtf8FnZayGZGpkkbQtRZE3dWsiw0eUBF5KD8ZYI J/tQ== X-Gm-Message-State: AD7BkJJ5PC0zuqUILeQu3DaYkMvPzF06gN9iYcqrI65H40zeFC/ckT0LTRSd4q2EwPzt+g== X-Received: by 10.66.90.136 with SMTP id bw8mr43094149pab.52.1458544691042; Mon, 21 Mar 2016 00:18:11 -0700 (PDT) Received: from cotter.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id w27sm9004191pfa.67.2016.03.21.00.18.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Mar 2016 00:18:10 -0700 (PDT) Received: by cotter.ozlabs.ibm.com (Postfix, from userid 1000) id 54E69C01EB; Mon, 21 Mar 2016 18:18:06 +1100 (AEDT) From: Balbir Singh To: will.deacon@arm.com, kvm@vger.kernel.org Cc: penberg@kernel.org, mpe@ellerman.id.au, mikey@neuling.org, aik@ozlabs.ru, Balbir Singh Subject: [PATCH 2/4] Implement H_SET_MODE for ppc64le Date: Mon, 21 Mar 2016 18:17:28 +1100 Message-Id: <1458544650-31416-3-git-send-email-bsingharora@gmail.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1458544650-31416-1-git-send-email-bsingharora@gmail.com> References: <1458544650-31416-1-git-send-email-bsingharora@gmail.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Basic infrastructure for queuing a task to a specifici CPU and the use of that in setting ILE (Little Endian Interrupt Handling) on power via h_set_mode hypercall Signed-off-by: Balbir Singh --- include/kvm/kvm-cpu.h | 7 +++ include/kvm/kvm.h | 1 + kvm-cpu.c | 50 +++++++++++++++++ powerpc/include/kvm/kvm-cpu-arch.h | 2 + powerpc/kvm.c | 2 +- powerpc/spapr.h | 15 ++++- powerpc/spapr_hcall.c | 111 +++++++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 3 deletions(-) diff --git a/include/kvm/kvm-cpu.h b/include/kvm/kvm-cpu.h index aa0cb54..5009681 100644 --- a/include/kvm/kvm-cpu.h +++ b/include/kvm/kvm-cpu.h @@ -4,6 +4,11 @@ #include "kvm/kvm-cpu-arch.h" #include +struct kvm_cpu_task { + void (*task)(void *data); + void *data; +}; + int kvm_cpu__init(struct kvm *kvm); int kvm_cpu__exit(struct kvm *kvm); struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id); @@ -23,5 +28,7 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu); void kvm_cpu__show_registers(struct kvm_cpu *vcpu); void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu); void kvm_cpu__arch_nmi(struct kvm_cpu *cpu); +int kvm_cpu__queue_task(struct kvm_cpu *cpu, void (*task)(void *data), + void *data); #endif /* KVM__KVM_CPU_H */ diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index 37155db..731abee 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -15,6 +15,7 @@ #define SIGKVMEXIT (SIGRTMIN + 0) #define SIGKVMPAUSE (SIGRTMIN + 1) +#define SIGKVMTASK (SIGRTMIN + 2) #define KVM_PID_FILE_PATH "/.lkvm/" #define HOME_DIR getenv("HOME") diff --git a/kvm-cpu.c b/kvm-cpu.c index ad4441b..438414f 100644 --- a/kvm-cpu.c +++ b/kvm-cpu.c @@ -83,10 +83,59 @@ void kvm_cpu__reboot(struct kvm *kvm) } } +static void kvm_cpu__run_task(int sig, siginfo_t * info, void *context) +{ + union sigval val; + struct kvm_cpu_task *task_ptr; + + if (!info) { + pr_warning("signal queued without info\n"); + return; + } + + val = info->si_value; + task_ptr = val.sival_ptr; + if (!task_ptr) { + pr_warning("Task queued without data\n"); + return; + } + + if (!task_ptr->task || !task_ptr->data) { + pr_warning("Failed to get task information\n"); + return; + } + + task_ptr->task(task_ptr->data); + free(task_ptr); +} + +int kvm_cpu__queue_task(struct kvm_cpu *cpu, void (*task)(void *data), + void *data) +{ + struct kvm_cpu_task *task_ptr = NULL; + union sigval val; + + task_ptr = malloc(sizeof(struct kvm_cpu_task)); + if (!task_ptr) + return -ENOMEM; + + task_ptr->task = task; + task_ptr->data = data; + val.sival_ptr = task_ptr; + + pthread_sigqueue(cpu->thread, SIGKVMTASK, val); + return 0; +} + int kvm_cpu__start(struct kvm_cpu *cpu) { sigset_t sigset; + struct sigaction action = { + .sa_sigaction = kvm_cpu__run_task, + .sa_flags = SA_SIGINFO, + }; + sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); @@ -94,6 +143,7 @@ int kvm_cpu__start(struct kvm_cpu *cpu) signal(SIGKVMEXIT, kvm_cpu_signal_handler); signal(SIGKVMPAUSE, kvm_cpu_signal_handler); + sigaction(SIGKVMTASK, &action, NULL); kvm_cpu__reset_vcpu(cpu); diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h index 01eafdf..033b702 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..682fad5 100644 --- a/powerpc/spapr_hcall.c +++ b/powerpc/spapr_hcall.c @@ -18,6 +18,9 @@ #include #include +#include + +static int task_event; static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - @@ -74,6 +77,113 @@ 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 int get_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr) +{ + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_LPCR_64, + .addr = (__u64)lpcr + }; + + return ioctl(vcpu->vcpu_fd, KVM_GET_ONE_REG, ®); +} + +static int set_cpu_lpcr(struct kvm_cpu *vcpu, target_ulong *lpcr) +{ + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_LPCR_64, + .addr = (__u64)lpcr + }; + + return ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, ®); +} + +static void set_lpcr_cpu(void *data) +{ + struct lpcr_data *fn_data = (struct lpcr_data *)data; + int ret; + target_ulong lpcr; + u64 task_done = 1; + + if (!fn_data || !fn_data->cpu) + return; + + ret = get_cpu_lpcr(fn_data->cpu, &lpcr); + if (ret < 0) + return; + + if (fn_data->mode == H_SET_MODE_ENDIAN_BIG) + lpcr &= ~LPCR_ILE; + else + lpcr |= LPCR_ILE; + + ret = set_cpu_lpcr(fn_data->cpu, &lpcr); + if (ret < 0) + return; + + free(data); + if (write(task_event, &task_done, sizeof(task_done)) < 0) + pr_warning("Failed to notify of lpcr task done\n"); +} + +#define for_each_vcpu(cpu, kvm, i) \ + for ((i) = 0, (cpu) = (kvm)->cpus[i]; (i) < (kvm)->nrcpus; (i)++, (cpu) = (kvm)->cpus[i]) + +static target_ulong h_set_mode(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args) +{ + int ret = H_SUCCESS; + struct kvm *kvm = vcpu->kvm; + struct kvm_cpu *cpu; + int i; + + switch (args[1]) { + case H_SET_MODE_RESOURCE_LE: { + u64 total_done = 0; + u64 task_read; + + task_event = eventfd(0, 0); + if (task_event < 0) { + pr_warning("Failed to create task_event"); + break; + } + for_each_vcpu(cpu, kvm, i) { + struct lpcr_data *data; + + data = malloc(sizeof(struct lpcr_data)); + if (!data) { + ret = H_P2; + break; + } + data->cpu = cpu; + data->mode = args[0]; + + kvm_cpu__queue_task(cpu, set_lpcr_cpu, data); + } + + while ((int)total_done < kvm->nrcpus) { + int err; + err = read(task_event, &task_read, sizeof(task_read)); + if (err < 0) { + ret = H_P2; + break; + } + total_done += task_read; + } + close(task_event); + break; + } + default: + ret = H_FUNCTION; + break; + } + return (ret < 0) ? H_P2 : H_SUCCESS; +} + + void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) { spapr_hcall_fn *slot; @@ -128,6 +238,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);