From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suraj Jitindar Singh Subject: [kvm-unit-tests PATCH V2 3/4] lib/powerpc: Add function to start secondary threads Date: Wed, 10 Aug 2016 11:59:36 +1000 Message-ID: <1470794377-14427-3-git-send-email-sjitindarsingh@gmail.com> References: <1470794377-14427-1-git-send-email-sjitindarsingh@gmail.com> Cc: sjitindarsingh@gmail.com, pbonzini@redhat.com, rkrcmar@redhat.com, kvm-ppc@vger.kernel.org, lvivier@redhat.com, thuth@redhat.com, drjones@redhat.com To: kvm@vger.kernel.org Return-path: Received: from mail-pf0-f195.google.com ([209.85.192.195]:33423 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932595AbcHJCPC (ORCPT ); Tue, 9 Aug 2016 22:15:02 -0400 In-Reply-To: <1470794377-14427-1-git-send-email-sjitindarsingh@gmail.com> Sender: kvm-owner@vger.kernel.org List-ID: Add the lib/powerpc/smp.c file and associated header files as a place to implement generic smp functionality for inclusion in tests. Add functions start_all_cpus(), start_cpu() and start_thread() to start all stopped threads of all cpus, all stopped threads of a single cpu or a single stopped thread of a guest at a given execution location, respectively. Signed-off-by: Suraj Jitindar Singh --- lib/powerpc/asm/smp.h | 15 +++++++ lib/powerpc/smp.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ppc64/asm/smp.h | 1 + powerpc/Makefile.common | 1 + 4 files changed, 132 insertions(+) create mode 100644 lib/powerpc/asm/smp.h create mode 100644 lib/powerpc/smp.c create mode 100644 lib/ppc64/asm/smp.h diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h new file mode 100644 index 0000000..a4f3e7f --- /dev/null +++ b/lib/powerpc/asm/smp.h @@ -0,0 +1,15 @@ +#ifndef _ASMPOWERPC_SMP_H_ +#define _ASMPOWERPC_SMP_H_ + +#include +#include + +typedef void (*secondary_entry_fn)(void); + +extern void halt(void); + +bool start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); +bool start_cpu(int cpu_node, secondary_entry_fn entry, uint32_t r3); +bool start_all_cpus(secondary_entry_fn entry, uint32_t r3); + +#endif /* _ASMPOWERPC_SMP_H_ */ diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c new file mode 100644 index 0000000..8968907 --- /dev/null +++ b/lib/powerpc/smp.c @@ -0,0 +1,115 @@ +/* + * Secondary cpu support + * + * Copyright 2016 Suraj Jitindar Singh, IBM. + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct secondary_entry_data { + secondary_entry_fn entry; + uint64_t r3; + bool init_failed; +}; + +/* + * Start stopped thread cpu_id at entry + * Returns: 1 on success or cpu not in stopped state + * 0 on failure to start stopped cpu + * + * Note: This function returns 1 on success in starting a stopped cpu or if the + * given cpu was not in the stopped state. Thus this can be called on a + * list of cpus and all the stopped ones will be started while false + * won't be returned if some cpus in that list were already running. Thus + * the user should check that cpus passed to this function are already in + * the stopped state if they want to guarantee that a return value of + * true corresponds to the given cpu now executing at entry. This + * function checks again however as calling cpu-start on a not stopped + * cpu results in undefined behaviour. + */ +bool start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3) +{ + int query_token, start_token, outputs[1], ret; + + query_token = rtas_token("query-cpu-stopped-state"); + start_token = rtas_token("start-cpu"); + assert(query_token != RTAS_UNKNOWN_SERVICE && + start_token != RTAS_UNKNOWN_SERVICE); + + ret = rtas_call(query_token, 1, 2, outputs, cpu_id); + if (ret) { + printf("query-cpu-stopped-state failed for cpu %d\n", cpu_id); + return false; + } + + if (!outputs[0]) { /* cpu in stopped state */ + ret = rtas_call(start_token, 3, 1, NULL, cpu_id, entry, r3); + if (ret) { + printf("failed to start cpu %d\n", cpu_id); + return false; + } + } + + return true; +} + +/* + * Start all stopped threads (vcpus) on cpu_node + * Returns: 1 on success + * 0 on failure + */ +bool start_cpu(int cpu_node, secondary_entry_fn entry, uint32_t r3) +{ + const struct fdt_property *prop; + int len, nr_cpu, cpu; + u32 *cpus; + bool ret = true; + + /* Get the id array of threads on this cpu_node */ + prop = fdt_get_property(dt_fdt(), cpu_node, + "ibm,ppc-interrupt-server#s", &len); + assert(prop); + + nr_cpu = len >> 2; /* Divide by 4 since 4 bytes per cpu */ + cpus = (u32 *)prop->data; /* Array of valid cpu numbers */ + + for (cpu = 0; cpu < nr_cpu && ret; cpu++) + ret = start_thread(fdt32_to_cpu(cpus[cpu]), entry, r3); + + return ret; +} + +static void start_each_secondary(int fdtnode, u32 regval __unused, void *info) +{ + struct secondary_entry_data *datap = info; + + datap->init_failed |= !start_cpu(fdtnode, datap->entry, datap->r3); +} + +/* + * Start all stopped cpus on the guest at entry with register 3 set to r3 + * Returns: 1 on success + * 0 on failure + */ +bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) +{ + struct secondary_entry_data data = { + entry, + r3, + false + }; + int ret; + + ret = dt_for_each_cpu_node(&start_each_secondary, (void *) &data); + + return !(ret || data.init_failed); +} diff --git a/lib/ppc64/asm/smp.h b/lib/ppc64/asm/smp.h new file mode 100644 index 0000000..67ced75 --- /dev/null +++ b/lib/ppc64/asm/smp.h @@ -0,0 +1 @@ +#include "../../powerpc/asm/smp.h" diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common index 404194b..677030a 100644 --- a/powerpc/Makefile.common +++ b/powerpc/Makefile.common @@ -37,6 +37,7 @@ cflatobjs += lib/powerpc/setup.o cflatobjs += lib/powerpc/rtas.o cflatobjs += lib/powerpc/processor.o cflatobjs += lib/powerpc/handlers.o +cflatobjs += lib/powerpc/smp.o FLATLIBS = $(libcflat) $(LIBFDT_archive) %.elf: CFLAGS += $(arch_CFLAGS) -- 2.5.5