From patchwork Fri May 22 02:23:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1295832 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=QyXfXXib; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49Sr2j21fwz9sSw for ; Fri, 22 May 2020 12:26:21 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id AE57981E95; Fri, 22 May 2020 04:24:50 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="QyXfXXib"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D589581E5D; Fri, 22 May 2020 04:24:20 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-il1-x142.google.com (mail-il1-x142.google.com [IPv6:2607:f8b0:4864:20::142]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E0BBA81E5E for ; Fri, 22 May 2020 04:24:10 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-il1-x142.google.com with SMTP id c20so9311702ilk.6 for ; Thu, 21 May 2020 19:24:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RBC1Nrlreeg2//9LFRxP9FA1VAsNH8oRcrvnjxV5a2I=; b=QyXfXXibmRsGie+wKI7cF6rmsWkMe4JSY3UuhSV0ngatweFwQKBnjju/2oc1UI5p3+ yMyNt0omC/QT8JLpjIaz8VDQMMJR0t8Aq4YmGtrODGGueRpVLnq+NBYLYsCq4o6BLpYL hbRgPz7VSmkNVofuU96ju0zNjx7zy/q62V7Ng= 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:in-reply-to :references:mime-version:content-transfer-encoding; bh=RBC1Nrlreeg2//9LFRxP9FA1VAsNH8oRcrvnjxV5a2I=; b=hBo/Y6EjSsScRWkOBrZOixEAQyUtjgX4rwyX9taKV11+1zVIbic6ghNPEWWrv+UgqO /78rktxm1sSCRzPeTVb+D11peoshHeXEcUwXdiIS6oIWsysJ0ozREbA/g7tlciqkKVV3 xpfjqFI3wyknhTa9y5UjWxoo4xub+nDY05mYfdZWyDdOSVPmFKaaHKuusMkuXv+zMB3I egOiArMWt4DQfZ3wlzGq3ZQIqzOK/XZIcIrVRMUccp/cdVjKzNIgtiIijRNv/VB7C/K8 7cKPJuLPy1zbJFAkq2lGCgUkjYP8afa4ACWu/qUDlTqr46+Y43olbeQZLb0NmKjoeGo9 ChOQ== X-Gm-Message-State: AOAM531m3QusbDKG/3KLHH9xI+B1RPw9QJHwuXK2NVXjLML5y3kowfiN zGrYfaz4uim8O5MYCFzkUh/zbP5lxYOguA== X-Google-Smtp-Source: ABdhPJzXcmwhQBAne5mR+SN5o8yQENFs3TEuCMpQPZknDQwfN642wRkT2lEY0Djlasmenxk2IdbMkQ== X-Received: by 2002:a92:c952:: with SMTP id i18mr11897533ilq.100.1590114249569; Thu, 21 May 2020 19:24:09 -0700 (PDT) Received: from localhost.localdomain (c-73-14-175-90.hsd1.co.comcast.net. [73.14.175.90]) by smtp.gmail.com with ESMTPSA id t10sm3757098ilq.62.2020.05.21.19.24.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 May 2020 19:24:09 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Bin Meng , Andy Shevchenko , Wolfgang Wallner , Simon Glass Subject: [PATCH 10/22] x86: mp: Support APs waiting for instructions Date: Thu, 21 May 2020 20:23:14 -0600 Message-Id: <20200521202309.10.I5cdb6d2b53a528eaebda2227b8cdfe26c4c73ceb@changeid> X-Mailer: git-send-email 2.27.0.rc0.183.gde8f92d652-goog In-Reply-To: <20200522022326.238388-1-sjg@chromium.org> References: <20200522022326.238388-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.30rc1 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.2 at phobos.denx.de X-Virus-Status: Clean At present the APs (non-boot CPUs) are inited once and then parked ready for the OS to use them. However in some cases we want to send new requests through, such as to change MTRRs and keep them consistent across CPUs. Change the last state of the flight plan to go into a wait loop, accepting instructions from the main CPU. Signed-off-by: Simon Glass --- arch/x86/cpu/mp_init.c | 99 ++++++++++++++++++++++++++++++++++++--- arch/x86/include/asm/mp.h | 11 +++++ 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ccb68b8b89b..c424f283807 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -43,14 +43,36 @@ struct mp_flight_plan { struct mp_flight_record *records; }; -static struct mp_flight_plan mp_info; - struct cpu_map { struct udevice *dev; int apic_id; int err_code; }; +struct mp_callback { + /** + * func() - Function to call on the AP + * + * @arg: Argument to pass + */ + void (*func)(void *arg); + void *arg; + int logical_cpu_number; +}; + +static struct mp_flight_plan mp_info; + +/* + * ap_callbacks - Callback mailbox array + * + * Array of callback, one entry for each available CPU, indexed by the CPU + * number, which is dev->req_seq. The entry for the main CPU is never used. + * When this is NULL, there is no pending work for the CPU to run. When + * non-NULL it points to the mp_callback structure. This is shared between all + * CPUs, so should only be written by the main CPU. + */ +static struct mp_callback **ap_callbacks; + static inline void barrier_wait(atomic_t *b) { while (atomic_read(b) == 0) @@ -147,11 +169,9 @@ static void ap_init(unsigned int cpu_index) debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id, dev ? dev->name : "(apic_id not found)"); - /* Walk the flight plan */ + /* Walk the flight plan, which never returns */ ap_do_flight_plan(dev); - - /* Park the AP */ - debug("parking\n"); + debug("Unexpected return\n"); done: stop_this_cpu(); } @@ -442,6 +462,68 @@ static int get_bsp(struct udevice **devp, int *cpu_countp) return dev->req_seq; } +static struct mp_callback *read_callback(struct mp_callback **slot) +{ + struct mp_callback *ret; + + asm volatile ("mov %1, %0\n" + : "=r" (ret) + : "m" (*slot) + : "memory" + ); + return ret; +} + +static void store_callback(struct mp_callback **slot, struct mp_callback *val) +{ + asm volatile ("mov %1, %0\n" + : "=m" (*slot) + : "r" (val) + : "memory" + ); +} + +/** + * ap_wait_for_instruction() - Wait for and process requests from the main CPU + * + * This is called by APs (here, everything other than the main boot CPU) to + * await instructions. They arrive in the form of a function call and argument, + * which is then called. This uses a simple mailbox with atomic read/set + * + * @cpu: CPU that is waiting + * @unused: Optional argument provided by struct mp_flight_record, not used here + * @return Does not return + */ +static int ap_wait_for_instruction(struct udevice *cpu, void *unused) +{ + struct mp_callback lcb; + struct mp_callback **per_cpu_slot; + + per_cpu_slot = &ap_callbacks[cpu->req_seq]; + + while (1) { + struct mp_callback *cb = read_callback(per_cpu_slot); + + if (!cb) { + asm ("pause"); + continue; + } + + /* Copy to local variable before using the value */ + memcpy(&lcb, cb, sizeof(lcb)); + mfence(); + if (lcb.logical_cpu_number == MP_SELECT_ALL || + lcb.logical_cpu_number == MP_SELECT_APS || + cpu->req_seq == lcb.logical_cpu_number) + lcb.func(lcb.arg); + + /* Indicate we are finished */ + store_callback(per_cpu_slot, NULL); + } + + return 0; +} + static int mp_init_cpu(struct udevice *cpu, void *unused) { struct cpu_platdata *plat = dev_get_parent_platdata(cpu); @@ -454,6 +536,7 @@ static int mp_init_cpu(struct udevice *cpu, void *unused) static struct mp_flight_record mp_steps[] = { MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), + MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL, NULL, NULL), }; int mp_init(void) @@ -491,6 +574,10 @@ int mp_init(void) if (ret) log_warning("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); + ap_callbacks = calloc(num_cpus, sizeof(struct mp_callback *)); + if (!ap_callbacks) + return -ENOMEM; + /* Copy needed parameters so that APs have a reference to the plan */ mp_info.num_records = ARRAY_SIZE(mp_steps); mp_info.records = mp_steps; diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 94af819ad9a..41b1575f4be 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -11,6 +11,17 @@ #include #include +enum { + /* Indicates that the function should run on all CPUs */ + MP_SELECT_ALL = -1, + + /* Run on boot CPUs */ + MP_SELECT_BSP = -2, + + /* Run on non-boot CPUs */ + MP_SELECT_APS = -3, +}; + typedef int (*mp_callback_t)(struct udevice *cpu, void *arg); /*