Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp496085pxb; Thu, 21 Jan 2021 12:06:31 -0800 (PST) X-Google-Smtp-Source: ABdhPJz/FIbd+0x2NWobkqf3DbQ423isTB1/ZMepOs9EK2xEJf6OL5XUYzzTaCxxAQXd+3m2WkU1 X-Received: by 2002:a17:906:4d19:: with SMTP id r25mr756497eju.148.1611259591039; Thu, 21 Jan 2021 12:06:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611259591; cv=none; d=google.com; s=arc-20160816; b=NDEPN0xiW2VUMsktbt07P2dwoiffHhQpCVWR/YRAHaLcfDaVzZh/X7XU86EdL9ZEMU yVVgoZv97P42tj2ko2U/p2Iq1gGHeshL8Jrnh7rL7h7YG2BwOpB+IOWB2bbd7N3AXj25 33cWnzUw5PllgHVpjTtXjBSL8TQ0ZIKXa2WD0ftOmkIuuChI+UeI1d/jbIXCDHUL0i6O nu6awPg33kn7W0TmFW49Nh7R2bF0ya4hQj6J5Ue2I+ca7K6XuUoOBG/+R/83JEfrM3/4 qlX2I2vNYZE/BXyxwBiO9Cink0OJXL6tUkl3vnzkr4YLvw8amQdTjhC6qfR7om5VcmtE Cxeg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=LfHiI0g+23eIMuog6udJcNrMXTyASbXeGSbiAk6THh8=; b=OdPN9H3EsZtm+AxPUF4aKa1x4xYTL36CvNxCNCsHoxUJMjKj3mypG//0VudAkrYizf wCnTApXbQuyF4amwGzWaHGY2puqgdn0CVMdvS2i6GCE4TIlkVG66guf0JGVJ4kLpu3YW BtamzOzbs3nmpQXCpL8yF5t9EirPb9IHZyQ+GfVd645KhptvGuWi51cLJKnWcopRRKpQ G4hN075MsqeL0vzv/GhmhtR3HbYmbeCNrCQcb2118PN94z1hrg71UVe5X00Lmtn6rkTF 5Gz4vBmaJ26JXqC3HON1Mm2xF830Ck0qiSuphBl7CV7S5Kl6jRebPM5KArtwrHSKF1Uw hwUQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=ha374Qsa; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id j15si2623229edv.474.2021.01.21.12.06.07; Thu, 21 Jan 2021 12:06:31 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=ha374Qsa; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726519AbhAUUCY (ORCPT + 99 others); Thu, 21 Jan 2021 15:02:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39450 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726689AbhAUUAy (ORCPT ); Thu, 21 Jan 2021 15:00:54 -0500 Received: from casper.infradead.org (casper.infradead.org [IPv6:2001:8b0:10b:1236::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CFD3CC06174A for ; Thu, 21 Jan 2021 12:00:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=LfHiI0g+23eIMuog6udJcNrMXTyASbXeGSbiAk6THh8=; b=ha374QsaNijUYdbYHPh9Fm2H1W t10Fx30xIcOCxAZ7w7o0txNGVVsbjbWqq5BfYOX1HnwCUNhSEh0eZPVC8x8Z04X78tlYcuGky2xTa 6lhz0MsNEArqFyrCpW1oFXs+AnismeFfalstnpnOTYRMMx4Ua4Kn9YdH37QSYZqyiz0I418wXdRi2 gDd+Ne1HIMk8A6EBOfFqNXnInTgVKhmL8hfE1XT/qieP80t4HAdG341ZuqApItJzYY5n/x65pPHUO CtJzf7uLTL1EPvQb1fdqIDDa4suUkpxsbp0CuENKJFKhRFlQxUpIPaFIlL0iySO29rplpf72jq065 bZ1PIwWQ==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.94 #2 (Red Hat Linux)) id 1l2g6w-00HSm0-7I; Thu, 21 Jan 2021 19:59:22 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.94 #2 (Red Hat Linux)) id 1l2g6v-000BCe-Qq; Thu, 21 Jan 2021 19:59:17 +0000 From: David Woodhouse To: Thomas Gleixner Cc: Andy Lutomirski , shenkai , "Schander, Johanna Amelie" , LKML , Ingo Molnar , Borislav Petkov , X86 ML , "H . Peter Anvin" , hewenliang4@huawei.com, hushiyuan@huawei.com, luolongjun@huawei.com, hejingxian@huawei.com Subject: [PATCH] x86/apic/x2apic: Fix parallel handling of cluster_mask Date: Thu, 21 Jan 2021 19:59:17 +0000 Message-Id: <20210121195917.43021-1-dwmw2@infradead.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <877do65og8.fsf@nanos.tec.linutronix.de> References: <877do65og8.fsf@nanos.tec.linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: David Woodhouse For each CPU being brought up, the alloc_clustermask() function allocates a new struct cluster_mask just in case it's needed. Then the target CPU actually runs, and in init_x2apic_ldr() it either uses a cluster_mask from a previous CPU in the same cluster, or consumes the "spare" one and sets the global pointer to NULL. That isn't going to parallelise stunningly well. Ditch the global variable, let alloc_clustermask() install the struct *directly* in the per_cpu data for the CPU being brought up. As an optimisation, actually make it do so for *all* present CPUs in the same cluster, which means only one iteration over for_each_present_cpu() instead of doing so repeatedly, once for each CPU. This was a harmless "bug" while CPU bringup wasn't actually happening in parallel. It's about to become less harmless... Fixes: 023a611748fd5 ("x86/apic/x2apic: Simplify cluster management") Signed-off-by: David Woodhouse --- arch/x86/kernel/apic/x2apic_cluster.c | 82 ++++++++++++++++----------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index b0889c48a2ac..ee5a9a438780 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -18,7 +18,6 @@ struct cluster_mask { static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); static DEFINE_PER_CPU(cpumask_var_t, ipi_mask); static DEFINE_PER_CPU(struct cluster_mask *, cluster_masks); -static struct cluster_mask *cluster_hotplug_mask; static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { @@ -98,54 +97,71 @@ static u32 x2apic_calc_apicid(unsigned int cpu) static void init_x2apic_ldr(void) { struct cluster_mask *cmsk = this_cpu_read(cluster_masks); - u32 cluster, apicid = apic_read(APIC_LDR); - unsigned int cpu; - this_cpu_write(x86_cpu_to_logical_apicid, apicid); + BUG_ON(!cmsk); - if (cmsk) - goto update; - - cluster = apicid >> 16; - for_each_online_cpu(cpu) { - cmsk = per_cpu(cluster_masks, cpu); - /* Matching cluster found. Link and update it. */ - if (cmsk && cmsk->clusterid == cluster) - goto update; - } - cmsk = cluster_hotplug_mask; - cmsk->clusterid = cluster; - cluster_hotplug_mask = NULL; -update: - this_cpu_write(cluster_masks, cmsk); cpumask_set_cpu(smp_processor_id(), &cmsk->mask); } -static int alloc_clustermask(unsigned int cpu, int node) +static int alloc_clustermask(unsigned int cpu, u32 cluster, int node) { + struct cluster_mask *cmsk = NULL; + unsigned int cpu_i; + u32 apicid; + if (per_cpu(cluster_masks, cpu)) return 0; - /* - * If a hotplug spare mask exists, check whether it's on the right - * node. If not, free it and allocate a new one. + + /* For the hotplug case, don't always allocate a new one */ + for_each_present_cpu(cpu_i) { + apicid = apic->cpu_present_to_apicid(cpu_i); + if (apicid != BAD_APICID && apicid >> 4 == cluster) { + cmsk = per_cpu(cluster_masks, cpu_i); + if (cmsk) + break; + } + } + if (!cmsk) { + cmsk = kzalloc_node(sizeof(*cmsk), GFP_KERNEL, node); + } + if (!cmsk) + return -ENOMEM; + + cmsk->node = node; + cmsk->clusterid = cluster; + + per_cpu(cluster_masks, cpu) = cmsk; + + /* + * As an optimisation during boot, set the cluster_mask for *all* + * present CPUs at once, to prevent *each* of them having to iterate + * over the others to find the existing cluster_mask. */ - if (cluster_hotplug_mask) { - if (cluster_hotplug_mask->node == node) - return 0; - kfree(cluster_hotplug_mask); + if (system_state < SYSTEM_RUNNING) { + for_each_present_cpu(cpu) { + u32 apicid = apic->cpu_present_to_apicid(cpu); + if (apicid != BAD_APICID && apicid >> 4 == cluster) { + struct cluster_mask **cpu_cmsk = &per_cpu(cluster_masks, cpu); + if (*cpu_cmsk) + BUG_ON(*cpu_cmsk != cmsk); + else + *cpu_cmsk = cmsk; + } + } } - cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask), - GFP_KERNEL, node); - if (!cluster_hotplug_mask) - return -ENOMEM; - cluster_hotplug_mask->node = node; return 0; } static int x2apic_prepare_cpu(unsigned int cpu) { - if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0) + u32 phys_apicid = apic->cpu_present_to_apicid(cpu); + u32 cluster = phys_apicid >> 4; + u32 logical_apicid = (cluster << 16) | (1 << (phys_apicid & 0xf)); + + per_cpu(x86_cpu_to_logical_apicid, cpu) = logical_apicid; + + if (alloc_clustermask(cpu, cluster, cpu_to_node(cpu)) < 0) return -ENOMEM; if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL)) return -ENOMEM; -- 2.29.2