cpu: add cpu_queue_job_on_node()

Message ID 20180703092536.28358-1-npiggin@gmail.com
State Superseded
Headers show
Series
  • cpu: add cpu_queue_job_on_node()
Related show

Commit Message

Nicholas Piggin July 3, 2018, 9:25 a.m.
Add a job scheduling API which will run the job on the requested
chip_id (or return failure).

Includes test harness fixes from Stewart.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
I tested this on a 2 node POWER9 system with both sockets populated
with memory and it seems to work with Stewart's parallel clearing
patch.

Changes since RFC:
- changelog
- Stewart's test harness fixes
- fix for the fallback/error case paths

 core/cpu.c                                    | 84 +++++++++++++++----
 core/test/run-malloc-speed.c                  |  7 +-
 core/test/run-malloc.c                        |  7 +-
 core/test/run-mem_range_is_reserved.c         |  8 +-
 core/test/run-mem_region.c                    | 10 +--
 core/test/run-mem_region_init.c               |  8 +-
 core/test/run-mem_region_next.c               |  8 +-
 core/test/run-mem_region_release_unused.c     |  8 +-
 .../run-mem_region_release_unused_noalloc.c   |  8 +-
 core/test/run-mem_region_reservations.c       |  8 +-
 core/test/stubs.c                             | 44 ++++++++++
 hdata/test/hdata_to_dt.c                      |  9 ++
 hdata/test/stubs.c                            | 47 +++++++++++
 include/cpu.h                                 |  4 +
 14 files changed, 190 insertions(+), 70 deletions(-)

Patch

diff --git a/core/cpu.c b/core/cpu.c
index 2f30c582..5880527e 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -106,7 +106,11 @@  static void cpu_wake(struct cpu_thread *cpu)
 	}
 }
 
-static struct cpu_thread *cpu_find_job_target(void)
+/*
+ * If chip_id is >= 0, schedule the job on that node.
+ * Otherwise schedule the job anywhere.
+ */
+static struct cpu_thread *cpu_find_job_target(int32_t chip_id)
 {
 	struct cpu_thread *cpu, *best, *me = this_cpu();
 	uint32_t best_count;
@@ -124,6 +128,8 @@  static struct cpu_thread *cpu_find_job_target(void)
 	/* First we scan all available primary threads
 	 */
 	for_each_available_cpu(cpu) {
+		if (chip_id >= 0 && cpu->chip_id != chip_id)
+			continue;
 		if (cpu == me || !cpu_is_thread0(cpu) || cpu->job_has_no_return)
 			continue;
 		if (cpu->job_count)
@@ -143,6 +149,8 @@  static struct cpu_thread *cpu_find_job_target(void)
 	best = NULL;
 	best_count = -1u;
 	for_each_available_cpu(cpu) {
+		if (chip_id >= 0 && cpu->chip_id != chip_id)
+			continue;
 		if (cpu == me || cpu->job_has_no_return)
 			continue;
 		if (!best || cpu->job_count < best_count) {
@@ -167,6 +175,26 @@  static struct cpu_thread *cpu_find_job_target(void)
 	return NULL;
 }
 
+/* job_lock is held, returns with it released */
+static void queue_job_on_cpu(struct cpu_thread *cpu, struct cpu_job *job)
+{
+	/* That's bad, the job will never run */
+	if (cpu->job_has_no_return) {
+		prlog(PR_WARNING, "WARNING ! Job %s scheduled on CPU 0x%x"
+		      " which has a no-return job on its queue !\n",
+		      job->name, cpu->pir);
+		backtrace();
+	}
+	list_add_tail(&cpu->job_queue, &job->link);
+	if (job->no_return)
+		cpu->job_has_no_return = true;
+	else
+		cpu->job_count++;
+	if (pm_enabled)
+		cpu_wake(cpu);
+	unlock(&cpu->job_lock);
+}
+
 struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
 				const char *name,
 				void (*func)(void *data), void *data,
@@ -196,7 +224,7 @@  struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
 
 	/* Pick a candidate. Returns with target queue locked */
 	if (cpu == NULL)
-		cpu = cpu_find_job_target();
+		cpu = cpu_find_job_target(-1);
 	else if (cpu != this_cpu())
 		lock(&cpu->job_lock);
 	else
@@ -209,21 +237,45 @@  struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
 		return job;
 	}
 
-	/* That's bad, the job will never run */
-	if (cpu->job_has_no_return) {
-		prlog(PR_WARNING, "WARNING ! Job %s scheduled on CPU 0x%x"
-		      " which has a no-return job on its queue !\n",
-		      job->name, cpu->pir);
-		backtrace();
+	queue_job_on_cpu(cpu, job);
+
+	return job;
+}
+
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				const char *name,
+				void (*func)(void *data), void *data)
+{
+	struct cpu_thread *cpu;
+	struct cpu_job *job;
+
+	job = zalloc(sizeof(struct cpu_job));
+	if (!job)
+		return NULL;
+	job->func = func;
+	job->data = data;
+	job->name = name;
+	job->complete = false;
+	job->no_return = false;
+
+	/* Pick a candidate. Returns with target queue locked */
+	cpu = cpu_find_job_target(chip_id);
+
+	/* Can't be scheduled... */
+	if (cpu == NULL) {
+		cpu = this_cpu();
+		if (cpu->chip_id == chip_id) {
+			/* Run it now if we're the right node. */
+			func(data);
+			job->complete = true;
+			return job;
+		}
+		/* Otherwise fail. */
+		free(job);
+		return NULL;
 	}
-	list_add_tail(&cpu->job_queue, &job->link);
-	if (no_return)
-		cpu->job_has_no_return = true;
-	else
-		cpu->job_count++;
-	if (pm_enabled)
-		cpu_wake(cpu);
-	unlock(&cpu->job_lock);
+
+	queue_job_on_cpu(cpu, job);
 
 	return job;
 }
diff --git a/core/test/run-malloc-speed.c b/core/test/run-malloc-speed.c
index d842bd64..8ecef3a0 100644
--- a/core/test/run-malloc-speed.c
+++ b/core/test/run-malloc-speed.c
@@ -17,12 +17,7 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-malloc.c b/core/test/run-malloc.c
index 2feaacb9..0204e77d 100644
--- a/core/test/run-malloc.c
+++ b/core/test/run-malloc.c
@@ -18,12 +18,7 @@ 
 
 #define BITS_PER_LONG (sizeof(long) * 8)
 
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-mem_range_is_reserved.c b/core/test/run-mem_range_is_reserved.c
index 37f7db3f..f44f1c2d 100644
--- a/core/test/run-mem_range_is_reserved.c
+++ b/core/test/run-mem_range_is_reserved.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-mem_region.c b/core/test/run-mem_region.c
index f2506d65..1fd20937 100644
--- a/core/test/run-mem_region.c
+++ b/core/test/run-mem_region.c
@@ -15,14 +15,12 @@ 
  */
 
 #include <config.h>
+#include <stdbool.h>
+#include <stdint.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/core/test/run-mem_region_init.c b/core/test/run-mem_region_init.c
index f1028da3..f70d70f8 100644
--- a/core/test/run-mem_region_init.c
+++ b/core/test/run-mem_region_init.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-mem_region_next.c b/core/test/run-mem_region_next.c
index 72d02a98..fec5df8f 100644
--- a/core/test/run-mem_region_next.c
+++ b/core/test/run-mem_region_next.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/core/test/run-mem_region_release_unused.c b/core/test/run-mem_region_release_unused.c
index fdd273a7..4fe62ca5 100644
--- a/core/test/run-mem_region_release_unused.c
+++ b/core/test/run-mem_region_release_unused.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-mem_region_release_unused_noalloc.c b/core/test/run-mem_region_release_unused_noalloc.c
index 6ae79591..fe571350 100644
--- a/core/test/run-mem_region_release_unused_noalloc.c
+++ b/core/test/run-mem_region_release_unused_noalloc.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/run-mem_region_reservations.c b/core/test/run-mem_region_reservations.c
index ae885829..b0e48474 100644
--- a/core/test/run-mem_region_reservations.c
+++ b/core/test/run-mem_region_reservations.c
@@ -17,12 +17,8 @@ 
 #include <config.h>
 
 #define BITS_PER_LONG (sizeof(long) * 8)
-/* Don't include this, it's PPC-specific */
-#define __CPU_H
-static unsigned int cpu_max_pir = 1;
-struct cpu_thread {
-	unsigned int			chip_id;
-};
+
+#include "dummy-cpu.h"
 
 #include <stdlib.h>
 
diff --git a/core/test/stubs.c b/core/test/stubs.c
index 39ff18d8..939e3dc7 100644
--- a/core/test/stubs.c
+++ b/core/test/stubs.c
@@ -16,6 +16,7 @@ 
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <stdint.h>
 
 #include "../../ccan/list/list.c"
 
@@ -41,6 +42,49 @@  static void stub_function(void)
 	abort();
 }
 
+struct cpu_thread;
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+				const char *name,
+				void (*func)(void *data), void *data,
+				bool no_return);
+void cpu_wait_job(struct cpu_job *job, bool free_it);
+void cpu_process_local_jobs(void);
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				       const char *name,
+				       void (*func)(void *data), void *data);
+
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				       const char *name,
+				       void (*func)(void *data), void *data)
+{
+	(void)chip_id;
+	return __cpu_queue_job(NULL, name, func, data, false);
+}
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+				const char *name,
+				void (*func)(void *data), void *data,
+				bool no_return)
+{
+	(void)cpu;
+	(void)name;
+	(func)(data);
+	(void)no_return;
+	return NULL;
+}
+
+void cpu_wait_job(struct cpu_job *job, bool free_it)
+{
+	(void)job;
+	(void)free_it;
+	return;
+}
+
+void cpu_process_local_jobs(void)
+{
+}
+
 #define STUB(fnname) \
 	void fnname(void) __attribute__((weak, alias ("stub_function")))
 
diff --git a/hdata/test/hdata_to_dt.c b/hdata/test/hdata_to_dt.c
index 8c61b4f6..bd11fb0b 100644
--- a/hdata/test/hdata_to_dt.c
+++ b/hdata/test/hdata_to_dt.c
@@ -83,6 +83,15 @@  struct cpu_thread {
 	uint32_t			pir;
 	uint32_t			chip_id;
 };
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+				const char *name,
+				void (*func)(void *data), void *data,
+				bool no_return);
+void cpu_wait_job(struct cpu_job *job, bool free_it);
+void cpu_process_local_jobs(void);
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				       const char *name,
+				       void (*func)(void *data), void *data);
 
 struct cpu_thread __boot_cpu, *boot_cpu = &__boot_cpu;
 static unsigned long fake_pvr = PVR_P7;
diff --git a/hdata/test/stubs.c b/hdata/test/stubs.c
index 59225705..f7b1da10 100644
--- a/hdata/test/stubs.c
+++ b/hdata/test/stubs.c
@@ -18,6 +18,7 @@ 
 #include <stdarg.h>
 #include <string.h>
 #include <malloc.h>
+#include <stdint.h>
 
 #include <compiler.h>
 
@@ -84,6 +85,52 @@  void *__zalloc(size_t bytes, const char *location)
 	return p;
 }
 
+struct cpu_thread;
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+				const char *name,
+				void (*func)(void *data), void *data,
+				bool no_return);
+
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				      const char *name,
+				      void (*func)(void *data), void *data);
+
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				       const char *name,
+				       void (*func)(void *data), void *data)
+{
+	(void)chip_id;
+	return __cpu_queue_job(NULL, name, func, data, false);
+}
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+				const char *name,
+				void (*func)(void *data), void *data,
+				bool no_return)
+{
+	(void)cpu;
+	(void)name;
+	(func)(data);
+	(void)no_return;
+	return NULL;
+}
+
+void cpu_wait_job(struct cpu_job *job, bool free_it);
+
+void cpu_wait_job(struct cpu_job *job, bool free_it)
+{
+	(void)job;
+	(void)free_it;
+	return;
+}
+
+void cpu_process_local_jobs(void);
+
+void cpu_process_local_jobs(void)
+{
+}
+
 /* Add any stub functions required for linking here. */
 static void stub_function(void)
 {
diff --git a/include/cpu.h b/include/cpu.h
index 2ca59b96..ae318572 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -280,6 +280,10 @@  static inline struct cpu_job *cpu_queue_job(struct cpu_thread *cpu,
 	return __cpu_queue_job(cpu, name, func, data, false);
 }
 
+extern struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+				       const char *name,
+				       void (*func)(void *data), void *data);
+
 
 /* Poll job status, returns true if completed */
 extern bool cpu_poll_job(struct cpu_job *job);