From patchwork Tue Jul 3 09:25:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 938557 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41Kf1G0FKbz9s3q for ; Tue, 3 Jul 2018 19:28:02 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ypqd0iIV"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 41Kf1F5FTWzF1PF for ; Tue, 3 Jul 2018 19:28:01 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ypqd0iIV"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400e:c00::244; helo=mail-pf0-x244.google.com; envelope-from=npiggin@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ypqd0iIV"; dkim-atps=neutral Received: from mail-pf0-x244.google.com (mail-pf0-x244.google.com [IPv6:2607:f8b0:400e:c00::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 41Kdyg388qzF1RW for ; Tue, 3 Jul 2018 19:25:47 +1000 (AEST) Received: by mail-pf0-x244.google.com with SMTP id e10-v6so729907pfn.1 for ; Tue, 03 Jul 2018 02:25:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=FtStkTON3OD91nrFVnwpo3N2OONRiMG3g//U8m6pC9M=; b=Ypqd0iIVeLsWdSm/sdynBEl5fT7w95brZjg1iMumVW1XBy4ldLxg7S6h9kUFhR2jZ3 6S/A/ysmJ1TMOVpJMbThvaBImF9Lvy5/Lj5s8t0cxkSMSth7NPl6o/Sf+VTuWzNliyTC 6iNm04TZ/HIfOR2UDxvQZtJWherkQtyRxBZj6sCMIkAOONS1qbAmy3aaqjGkS4JfaIx2 yg20PtfcRx93IfZASJ2c12KI96sXwS5CE8uFRkF6xVj+gs6NDG+agXQQF117tx8BEiYU 3qRwcqTr144DN3PlJ8DWQ0EDv5+GQrXWbvRGc3P6eodK+UTardXzy1P1d5gIwH8Df2ME Lx2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=FtStkTON3OD91nrFVnwpo3N2OONRiMG3g//U8m6pC9M=; b=n20TkJafv1rCu7Kz1BJG3omVG7x/gUmVMrWAr2AjqQ1k4lUk4w4EXO+79DyJf0VnFk 83JovZkCrzgNimEXKqGp/bzjavHNNTHSckVU/ZZNc9RSNc1Mi9ApFZrinmCZHObwv0a4 EM2oQTwcd0DI7OJKGbS90RLC7fbTRAvpiPqGo3WIpfV21se/1wp6vCn//4OcC5/OXEth DhuwL64yCYT4ZGJ7PnJwqLHPPSBI+GZECTXX7Ex8KIbQN9UCgBAtIsYo0tfnmb67qEKp TH9k7UJeiTPrQc/+99T3v8Dn2XH+1DNN27uo4rbYDKOMz0zc/1Mp9fuAr41heN0eGxVz Z7Yw== X-Gm-Message-State: APt69E12VMRrFZWxhRe7oOOdO9MhOZHubkcNRhvf7VS+pU1tQfLPToxK ta8Zz/dHdKvE+CfDtZTqlv/ZuQ== X-Google-Smtp-Source: ADUXVKLiNpZ4t507N72xhUUTfkwGeZrtfBygsVjDXiwTx/5GZiXWQI5GbV4llbwZyeljQ/ZqT3w0dg== X-Received: by 2002:a65:42c3:: with SMTP id l3-v6mr23756480pgp.398.1530609944972; Tue, 03 Jul 2018 02:25:44 -0700 (PDT) Received: from roar.ozlabs.ibm.com. ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id l11-v6sm1436809pgp.56.2018.07.03.02.25.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Jul 2018 02:25:44 -0700 (PDT) From: Nicholas Piggin To: skiboot@lists.ozlabs.org Date: Tue, 3 Jul 2018 19:25:36 +1000 Message-Id: <20180703092536.28358-1-npiggin@gmail.com> X-Mailer: git-send-email 2.17.0 Subject: [Skiboot] [PATCH] cpu: add cpu_queue_job_on_node() X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" 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 --- 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(-) 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 #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 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 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 #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 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 +#include +#include #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 #include 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 #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 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 #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 #include 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 #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 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 #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 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 #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 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 #include #include +#include #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 #include #include +#include #include @@ -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);