Message ID | 1471331895-29887-3-git-send-email-sjitindarsingh@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Aug 16, 2016 at 05:18:13PM +1000, Suraj Jitindar Singh wrote: > 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 <sjitindarsingh@gmail.com> > --- > > Change Log: > > V2 -> V3: > - start_thread now returns int to reflect error, success or failure to > start thread > - start_cpu returns number of threads on cpu and number successfully > started > - start_all_cpus checks if number of threads started == total number of > threads - 1 > > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com> > --- > lib/powerpc/asm/smp.h | 22 ++++++++++ > lib/powerpc/smp.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ > lib/ppc64/asm/smp.h | 1 + > powerpc/Makefile.common | 1 + > 4 files changed, 130 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..21940b4 > --- /dev/null > +++ b/lib/powerpc/asm/smp.h > @@ -0,0 +1,22 @@ > +#ifndef _ASMPOWERPC_SMP_H_ > +#define _ASMPOWERPC_SMP_H_ > + > +#include <libcflat.h> > + > +extern int nr_threads; > + > +struct start_threads { > + int nr_threads; > + int nr_started; > +}; > + > +typedef void (*secondary_entry_fn)(void); > + > +extern void halt(void); > + > +extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); > +extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, > + uint32_t r3); > +extern 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..48c636e > --- /dev/null > +++ b/lib/powerpc/smp.c > @@ -0,0 +1,106 @@ > +/* > + * Secondary cpu support > + * > + * Copyright 2016 Suraj Jitindar Singh, IBM. > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > + > +#include <devicetree.h> > +#include <asm/setup.h> > +#include <asm/rtas.h> > +#include <asm/smp.h> > + > +int nr_threads; > + > +struct secondary_entry_data { > + secondary_entry_fn entry; > + uint64_t r3; > + int nr_started; > +}; > + > +/* > + * Start stopped thread cpu_id at entry > + * Returns: <0 on failure to start stopped cpu > + * 0 on success > + * >0 on cpu not in stopped state > + */ > +int 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) /* rtas query call failed */ > + printf("query-cpu-stopped-state failed for cpu %d\n", cpu_id); > + else if (!outputs[0]) { /* cpu in stopped state */ > + ret = rtas_call(start_token, 3, 1, NULL, cpu_id, entry, r3); > + if (ret) /* rtas start-cpu call failed */ > + printf("failed to start cpu %d\n", cpu_id); > + } else /* cpu not in stopped state */ > + ret = outputs[0]; > + > + return ret; > +} > + > +/* > + * Start all stopped threads (vcpus) on cpu_node > + * Returns: Number of stopped cpus which were successfully started > + */ > +struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, > + uint32_t r3) > +{ > + int len, cpu, nr_threads, nr_started = 0; > + const struct fdt_property *prop; > + u32 *cpus; The mixing of the terms cpus and threads in the function is confusing. Let's change the variables like this /cpus/threads/ /cpu/i/ > + > + /* 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_threads = len >> 2; /* Divide by 4 since 4 bytes per cpu */ /cpu/thread/ in comment > + cpus = (u32 *)prop->data; /* Array of valid cpu numbers */ /cpu/thread/ in comment > + > + for (cpu = 0; cpu < nr_threads; cpu++) { > + if (!start_thread(fdt32_to_cpu(cpus[cpu]), entry, r3)) > + nr_started++; > + } > + > + return (struct start_threads) {nr_threads, nr_started}; > +} > + > +static void start_each_secondary(int fdtnode, u32 regval __unused, void *info) > +{ > + struct secondary_entry_data *datap = info; > + struct start_threads ret = start_cpu(fdtnode, datap->entry, datap->r3); > + > + nr_threads += ret.nr_threads; > + datap->nr_started += ret.nr_started; > +} > + > +/* > + * Start all stopped cpus on the guest at entry with register 3 set to r3 > + * We expect that we come in with only one thread currently started > + * Returns: TRUE on success > + * FALSE on failure > + */ > +bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) > +{ > + struct secondary_entry_data data = { > + entry, > + r3, > + 0 > + }; nit: no need for all the white space, can just do = { entry, r3, 0 }; > + int ret; > + > + ret = dt_for_each_cpu_node(&start_each_secondary, &data); nit: no need for '&' on function pointer. > + assert(ret == 0); > + > + /* We expect that we come in with one thread already started */ > + return data.nr_started == (nr_threads - 1); nit: no need for the () You could also init data.nr_started to 1 above, and then avoid the -1 here, but whatever. > +} > 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 > My comments are just nits of varying degrees, so Reviewed-by: Andrew Jones <drjones@redhat.com> Thanks, drew -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 2016-08-16 at 14:27 +0200, Andrew Jones wrote: > On Tue, Aug 16, 2016 at 05:18:13PM +1000, Suraj Jitindar Singh wrote: > > > > 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 <sjitindarsingh@gmail.com> > > --- > > > > Change Log: > > > > V2 -> V3: > > - start_thread now returns int to reflect error, success or > > failure to > > start thread > > - start_cpu returns number of threads on cpu and number > > successfully > > started > > - start_all_cpus checks if number of threads started == total > > number of > > threads - 1 > > > > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com> > > --- > > lib/powerpc/asm/smp.h | 22 ++++++++++ > > lib/powerpc/smp.c | 106 > > ++++++++++++++++++++++++++++++++++++++++++++++++ > > lib/ppc64/asm/smp.h | 1 + > > powerpc/Makefile.common | 1 + > > 4 files changed, 130 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..21940b4 > > --- /dev/null > > +++ b/lib/powerpc/asm/smp.h > > @@ -0,0 +1,22 @@ > > +#ifndef _ASMPOWERPC_SMP_H_ > > +#define _ASMPOWERPC_SMP_H_ > > + > > +#include <libcflat.h> > > + > > +extern int nr_threads; > > + > > +struct start_threads { > > + int nr_threads; > > + int nr_started; > > +}; > > + > > +typedef void (*secondary_entry_fn)(void); > > + > > +extern void halt(void); > > + > > +extern int start_thread(int cpu_id, secondary_entry_fn entry, > > uint32_t r3); > > +extern struct start_threads start_cpu(int cpu_node, > > secondary_entry_fn entry, > > + uint32_t r3); > > +extern 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..48c636e > > --- /dev/null > > +++ b/lib/powerpc/smp.c > > @@ -0,0 +1,106 @@ > > +/* > > + * Secondary cpu support > > + * > > + * Copyright 2016 Suraj Jitindar Singh, IBM. > > + * > > + * This work is licensed under the terms of the GNU LGPL, version > > 2. > > + */ > > + > > +#include <devicetree.h> > > +#include <asm/setup.h> > > +#include <asm/rtas.h> > > +#include <asm/smp.h> > > + > > +int nr_threads; > > + > > +struct secondary_entry_data { > > + secondary_entry_fn entry; > > + uint64_t r3; > > + int nr_started; > > +}; > > + > > +/* > > + * Start stopped thread cpu_id at entry > > + * Returns: <0 on failure to start stopped cpu > > + * 0 on success > > + * >0 on cpu not in stopped state > > + */ > > +int 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) /* rtas query call failed */ > > + printf("query-cpu-stopped-state failed for cpu > > %d\n", cpu_id); > > + else if (!outputs[0]) { /* cpu in stopped state */ > > + ret = rtas_call(start_token, 3, 1, NULL, cpu_id, > > entry, r3); > > + if (ret) /* rtas start-cpu call failed */ > > + printf("failed to start cpu %d\n", > > cpu_id); > > + } else /* cpu not in stopped state */ > > + ret = outputs[0]; > > + > > + return ret; > > +} > > + > > +/* > > + * Start all stopped threads (vcpus) on cpu_node > > + * Returns: Number of stopped cpus which were successfully started > > + */ > > +struct start_threads start_cpu(int cpu_node, secondary_entry_fn > > entry, > > + uint32_t r3) > > +{ > > + int len, cpu, nr_threads, nr_started = 0; > > + const struct fdt_property *prop; > > + u32 *cpus; > The mixing of the terms cpus and threads in the function is > confusing. > Let's change the variables like this > > /cpus/threads/ > /cpu/i/ Sounds good > > > > > + > > + /* 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_threads = len >> 2; /* Divide by 4 since 4 bytes per > > cpu */ > /cpu/thread/ in comment ok > > > > > + cpus = (u32 *)prop->data; /* Array of valid cpu numbers */ > /cpu/thread/ in comment > > > > > + > > + for (cpu = 0; cpu < nr_threads; cpu++) { > > + if (!start_thread(fdt32_to_cpu(cpus[cpu]), entry, > > r3)) > > + nr_started++; > > + } > > + > > + return (struct start_threads) {nr_threads, nr_started}; > > +} > > + > > +static void start_each_secondary(int fdtnode, u32 regval __unused, > > void *info) > > +{ > > + struct secondary_entry_data *datap = info; > > + struct start_threads ret = start_cpu(fdtnode, datap- > > >entry, datap->r3); > > + > > + nr_threads += ret.nr_threads; > > + datap->nr_started += ret.nr_started; > > +} > > + > > +/* > > + * Start all stopped cpus on the guest at entry with register 3 > > set to r3 > > + * We expect that we come in with only one thread currently > > started > > + * Returns: TRUE on success > > + * FALSE on failure > > + */ > > +bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) > > +{ > > + struct secondary_entry_data data = { > > + entry, > > + r3, > > + 0 > > + }; > nit: no need for all the white space, can just do = { entry, r3, 0 }; Ok > > > > > + int ret; > > + > > + ret = dt_for_each_cpu_node(&start_each_secondary, &data); > nit: no need for '&' on function pointer. I like having it > > > > > + assert(ret == 0); > > + > > + /* We expect that we come in with one thread already > > started */ > > + return data.nr_started == (nr_threads - 1); > nit: no need for the () > > You could also init data.nr_started to 1 above, and then avoid > the -1 here, but whatever. But then nr_started wouldn't actually represent the number of threads that were started, it'd be ++ that. I'll keep the -1. > > > > > +} > > 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) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h new file mode 100644 index 0000000..21940b4 --- /dev/null +++ b/lib/powerpc/asm/smp.h @@ -0,0 +1,22 @@ +#ifndef _ASMPOWERPC_SMP_H_ +#define _ASMPOWERPC_SMP_H_ + +#include <libcflat.h> + +extern int nr_threads; + +struct start_threads { + int nr_threads; + int nr_started; +}; + +typedef void (*secondary_entry_fn)(void); + +extern void halt(void); + +extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); +extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, + uint32_t r3); +extern 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..48c636e --- /dev/null +++ b/lib/powerpc/smp.c @@ -0,0 +1,106 @@ +/* + * Secondary cpu support + * + * Copyright 2016 Suraj Jitindar Singh, IBM. + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ + +#include <devicetree.h> +#include <asm/setup.h> +#include <asm/rtas.h> +#include <asm/smp.h> + +int nr_threads; + +struct secondary_entry_data { + secondary_entry_fn entry; + uint64_t r3; + int nr_started; +}; + +/* + * Start stopped thread cpu_id at entry + * Returns: <0 on failure to start stopped cpu + * 0 on success + * >0 on cpu not in stopped state + */ +int 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) /* rtas query call failed */ + printf("query-cpu-stopped-state failed for cpu %d\n", cpu_id); + else if (!outputs[0]) { /* cpu in stopped state */ + ret = rtas_call(start_token, 3, 1, NULL, cpu_id, entry, r3); + if (ret) /* rtas start-cpu call failed */ + printf("failed to start cpu %d\n", cpu_id); + } else /* cpu not in stopped state */ + ret = outputs[0]; + + return ret; +} + +/* + * Start all stopped threads (vcpus) on cpu_node + * Returns: Number of stopped cpus which were successfully started + */ +struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, + uint32_t r3) +{ + int len, cpu, nr_threads, nr_started = 0; + const struct fdt_property *prop; + u32 *cpus; + + /* 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_threads = len >> 2; /* Divide by 4 since 4 bytes per cpu */ + cpus = (u32 *)prop->data; /* Array of valid cpu numbers */ + + for (cpu = 0; cpu < nr_threads; cpu++) { + if (!start_thread(fdt32_to_cpu(cpus[cpu]), entry, r3)) + nr_started++; + } + + return (struct start_threads) {nr_threads, nr_started}; +} + +static void start_each_secondary(int fdtnode, u32 regval __unused, void *info) +{ + struct secondary_entry_data *datap = info; + struct start_threads ret = start_cpu(fdtnode, datap->entry, datap->r3); + + nr_threads += ret.nr_threads; + datap->nr_started += ret.nr_started; +} + +/* + * Start all stopped cpus on the guest at entry with register 3 set to r3 + * We expect that we come in with only one thread currently started + * Returns: TRUE on success + * FALSE on failure + */ +bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) +{ + struct secondary_entry_data data = { + entry, + r3, + 0 + }; + int ret; + + ret = dt_for_each_cpu_node(&start_each_secondary, &data); + assert(ret == 0); + + /* We expect that we come in with one thread already started */ + return data.nr_started == (nr_threads - 1); +} 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)