mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Zhang, Rui" <rui.zhang@intel.com>
To: "tglx@linutronix.de" <tglx@linutronix.de>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Cc: "Gross, Jurgen" <jgross@suse.com>,
	"mikelley@microsoft.com" <mikelley@microsoft.com>,
	"arjan@linux.intel.com" <arjan@linux.intel.com>,
	"x86@kernel.org" <x86@kernel.org>,
	"thomas.lendacky@amd.com" <thomas.lendacky@amd.com>,
	"ray.huang@amd.com" <ray.huang@amd.com>,
	"andrew.cooper3@citrix.com" <andrew.cooper3@citrix.com>,
	"Sivanich, Dimitri" <dimitri.sivanich@hpe.com>,
	"wei.liu@kernel.org" <wei.liu@kernel.org>
Subject: Re: [patch V3 27/40] x86/cpu: Provide a sane leaf 0xb/0x1f parser
Date: Sat, 12 Aug 2023 08:21:55 +0000	[thread overview]
Message-ID: <8e5bbbc91ff9f74244efe916a4113999abc52213.camel@intel.com> (raw)
In-Reply-To: <20230802101934.258937135@linutronix.de>

Hi, Thomas,

On Wed, 2023-08-02 at 12:21 +0200, Thomas Gleixner wrote:
> detect_extended_topology() along with it's early() variant is a
> classic
> example for duct tape engineering:
> 
>   - It evaluates an array of subleafs with a boatload of local
> variables
>     for the relevant topology levels instead of using an array to
> save the
>     enumerated information and propagate it to the right level
> 
>   - It has no boundary checks for subleafs
> 
>   - It prevents updating the die_id with a crude workaround instead
> of
>     checking for leaf 0xb which does not provide die information.
> 
>   - It's broken vs. the number of dies evaluation as it uses:
> 
>       num_processors[DIE_LEVEL] / num_processors[CORE_LEVEL]
> 
>     which "works" only correctly if there is none of the intermediate
>     topology levels (MODULE/TILE) enumerated.
> 
> There is zero value in trying to "fix" that code as the only proper
> fix is
> to rewrite it from scratch.
> 
> Implement a sane parser with proper code documentation, which will be
> used
> for the consolidated topology evaluation in the next step.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V2: Fixed up the comment alignment for registers - Peterz
> ---
>  arch/x86/kernel/cpu/Makefile       |    2 
>  arch/x86/kernel/cpu/topology.h     |   12 +++
>  arch/x86/kernel/cpu/topology_ext.c |  136
> +++++++++++++++++++++++++++++++++++++
>  3 files changed, 149 insertions(+), 1 deletion(-)
> 
> --- a/arch/x86/kernel/cpu/Makefile
> +++ b/arch/x86/kernel/cpu/Makefile
> @@ -18,7 +18,7 @@ KMSAN_SANITIZE_common.o := n
>  KCSAN_SANITIZE_common.o := n
>  
>  obj-y                  := cacheinfo.o scattered.o
> -obj-y                  += topology_common.o topology.o
> +obj-y                  += topology_common.o topology_ext.o
> topology.o
>  obj-y                  += common.o
>  obj-y                  += rdrand.o
>  obj-y                  += match.o
> --- a/arch/x86/kernel/cpu/topology.h
> +++ b/arch/x86/kernel/cpu/topology.h
> @@ -16,6 +16,7 @@ void cpu_init_topology(struct cpuinfo_x8
>  void cpu_parse_topology(struct cpuinfo_x86 *c);
>  void topology_set_dom(struct topo_scan *tscan, enum
> x86_topology_domains dom,
>                       unsigned int shift, unsigned int ncpus);
> +bool cpu_parse_topology_ext(struct topo_scan *tscan);
>  
>  static inline u32 topo_shift_apicid(u32 apicid, enum
> x86_topology_domains dom)
>  {
> @@ -31,4 +32,15 @@ static inline u32 topo_relative_domain_i
>         return apicid & (x86_topo_system.dom_size[dom] - 1);
>  }
>  
> +/*
> + * Update a domain level after the fact without propagating. Used to
> fixup
> + * broken CPUID enumerations.
> + */
> +static inline void topology_update_dom(struct topo_scan *tscan, enum
> x86_topology_domains dom,
> +                                      unsigned int shift, unsigned
> int ncpus)
> +{
> +       tscan->dom_shifts[dom] = shift;
> +       tscan->dom_ncpus[dom] = ncpus;
> +}
> +
>  #endif /* ARCH_X86_TOPOLOGY_H */
> --- /dev/null
> +++ b/arch/x86/kernel/cpu/topology_ext.c
> @@ -0,0 +1,136 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/cpu.h>
> +
> +#include <asm/apic.h>
> +#include <asm/memtype.h>
> +#include <asm/processor.h>
> +
> +#include "cpu.h"
> +
> +enum topo_types {
> +       INVALID_TYPE    = 0,
> +       SMT_TYPE        = 1,
> +       CORE_TYPE       = 2,
> +       MODULE_TYPE     = 3,
> +       TILE_TYPE       = 4,
> +       DIE_TYPE        = 5,
> +       DIEGRP_TYPE     = 6,
> +       MAX_TYPE        = 7,
> +};
> +
> +/*
> + * Use a lookup table for the case that there are future types > 6
> which
> + * describe an intermediate domain level which does not exist today.
> + *
> + * A table will also be handy to parse the new AMD 0x80000026 leaf
> which
> + * has defined different domain types, but otherwise uses the same
> layout
> + * with some of the reserved bits used for new information.
> + */
> +static const unsigned int topo_domain_map[MAX_TYPE] = {
> +       [SMT_TYPE]      = TOPO_SMT_DOMAIN,
> +       [CORE_TYPE]     = TOPO_CORE_DOMAIN,
> +       [MODULE_TYPE]   = TOPO_MODULE_DOMAIN,
> +       [TILE_TYPE]     = TOPO_TILE_DOMAIN,
> +       [DIE_TYPE]      = TOPO_DIE_DOMAIN,
> +       [DIEGRP_TYPE]   = TOPO_PKG_DOMAIN,

May I know why DIEGRP_TYPE is mapped to TOPO_PKG_DOMAIN?

> +};
> +
> +static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf,
> u32 subleaf)
> +{
> +       unsigned int dom, maxtype = leaf == 0xb ? CORE_TYPE + 1 :
> MAX_TYPE;
> +       struct {
> +               // eax
> +               u32     x2apic_shift    :  5, // Number of bits to
> shift APIC ID right
> +                                             // for the topology ID
> at the next level
> +                       __rsvd0         : 27; // Reserved
> +               // ebx
> +               u32     num_processors  : 16, // Number of processors
> at current level
> +                       __rsvd1         : 16; // Reserved
> +               // ecx
> +               u32     level           :  8, // Current topology
> level. Same as sub leaf number
> +                       type            :  8, // Level type. If 0,
> invalid
> +                       __rsvd2         : 16; // Reserved
> +               // edx
> +               u32     x2apic_id       : 32; // X2APIC ID of the
> current logical processor
> +       } sl;
> +
> +       cpuid_subleaf(leaf, subleaf, &sl);
> +
> +       if (!sl.num_processors || sl.type == INVALID_TYPE)
> +               return false;
> +
> +       if (sl.type >= maxtype) {

It is still legal to have sparse type value in the future, and then
this check will break.
IMO, it is better to use a function to convert type to domain, and
check for unknown domain here, say, something like

diff --git a/arch/x86/kernel/cpu/topology_ext.c
b/arch/x86/kernel/cpu/topology_ext.c
index 5ddc5d24435e..7720a7bc7478 100644
--- a/arch/x86/kernel/cpu/topology_ext.c
+++ b/arch/x86/kernel/cpu/topology_ext.c
@@ -26,14 +26,27 @@ enum topo_types {
  * has defined different domain types, but otherwise uses the same
layout
  * with some of the reserved bits used for new information.
  */
-static const unsigned int topo_domain_map[MAX_TYPE] = {
-	[SMT_TYPE]	= TOPO_SMT_DOMAIN,
-	[CORE_TYPE]	= TOPO_CORE_DOMAIN,
-	[MODULE_TYPE]	= TOPO_MODULE_DOMAIN,
-	[TILE_TYPE]	= TOPO_TILE_DOMAIN,
-	[DIE_TYPE]	= TOPO_DIE_DOMAIN,
-	[DIEGRP_TYPE]	= TOPO_PKG_DOMAIN,
-};
+
+static enum x86_topology_domains topo_type_to_domain(int type)
+{
+	switch (type) {
+	case SMT_TYPE:
+		return TOPO_SMT_DOMAIN;
+	case CORE_TYPE:
+		return TOPO_CORE_DOMAIN;
+	case MODULE_TYPE:
+		return TOPO_MODULE_DOMAIN;
+	case TILE_TYPE:
+		return TOPO_TILE_DOMAIN;
+	case DIE_TYPE:
+		return TOPO_DIE_DOMAIN;
+	case DIEGRP_TYPE:
+		return TOPO_PKG_DOMAIN;
+	default:
+		return TOPO_MAX_DOMAIN;
+	}
+
+}
 
 static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf, u32
subleaf)
 {
@@ -59,7 +72,8 @@ static inline bool topo_subleaf(struct topo_scan
*tscan, u32 leaf, u32 subleaf)
 	if (!sl.num_processors || sl.type == INVALID_TYPE)
 		return false;
 
-	if (sl.type >= maxtype) {
+	dom = topo_type_to_domain(sl.type);
+	if (dom == TOPO_MAX_DOMAIN) {
 		/*
 		 * As the subleafs are ordered in domain level order,
this
 		 * could be recovered in theory by propagating the
@@ -84,7 +98,6 @@ static inline bool topo_subleaf(struct topo_scan
*tscan, u32 leaf, u32 subleaf)
 		return true;
 	}
 
-	dom = topo_domain_map[sl.type];
 	if (!dom) {
 		tscan->c->topo.initial_apicid = sl.x2apic_id;
 	} else if (tscan->c->topo.initial_apicid != sl.x2apic_id) {

> +               /*
> +                * As the subleafs are ordered in domain level order,
> this
> +                * could be recovered in theory by propagating the
> +                * information at the last parsed level.
> +                *
> +                * But if the infinite wisdom of hardware folks
> decides to
> +                * create a new domain type between CORE and MODULE
> or DIE
> +                * and DIEGRP, then that would overwrite the CORE or
> DIE
> +                * information.

Sorry that I'm confused here.

Say, we have CORE, FOO, MODULE, then the subleave of FOO must be higher
than CORE but lower than MODULE.
so we parse CORE first and propagates the info to FOO/MODULE, and then
parse FOO and propagate to MODULE, and parse MODULE in the end.
How could we overwrite the info of a lower level?

> +                *
> +                * It really would have been too obvious to make the
> domain
> +                * type space sparse and leave a few reserved types
> between
> +                * the points which might change instead of forcing
> +                * software to either create a monstrosity of
> workarounds
> +                * or just being up the creek without a paddle.

Agreed.
with sparse type space, we know the relationship between different
types, without knowing what the type really means.

> +                *
> +                * Refuse to implement monstrosity, emit an error and try
> +                * to survive.
> +                */
> +               pr_err_once("Topology: leaf 0x%x:%d Unknown domain type %u\n",
> +                           leaf, subleaf, sl.type);
> +               return true;

Don't want to be TLDR, I can think of a couple cases that breaks Linux
in different ways if we ignore the cpu topology info of an unknown
level.

So I just want to understand the strategy here, does this mean that
we're not looking for a future proof solution, and instead we are
planning to take future updates (patch enum topo_types/enum
x86_topology_domains/topo_domain_map) whenever a new level is invented?


TBH, I'm still thinking of a future proof proposal here.
currently, Linux only cares about pkg_id/core_id/die_id, and the
relationship between these three levels.
1. for package id: pkg_id_low = FOO.x2apic_shift (FOO is the highest
enumerated level, no matter its type is known or not)
2. for core_id: as SMT level is always enumerated, core_id_low =
SMT.x2apic_shift, core_id_high = pkg_id_low - 1;
3. for die_id: Make Linux Die *OPTIONAL*.
   when DIE is enumerated via CPUID.1F, die_id_low = FOO.x2apic_shift
(FOO is the next enumerated lower level of DIE, no matter its type is
known or not), die_id_high = pkg_id_low - 1;
   when DIE is not enumerated via CPUID.1F, then Linux die does not
exist, adjust the die related topology information, say, die_id = -1,
topology_max_dies_per_package = 0, etc, and don't expose die sysfs I/F.

With this, we can guarantee that all the available topology information
are always valid, even when running on future platforms.

what do you think?

thanks,
rui

  reply	other threads:[~2023-08-12  8:22 UTC|newest]

Thread overview: 88+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-02 10:20 [patch V3 00/40] x86/cpu: Rework the topology evaluation Thomas Gleixner
2023-08-02 10:20 ` [patch V3 01/40] cpu/SMT: Make SMT control more robust against enumeration failures Thomas Gleixner
2023-08-04 17:50   ` Borislav Petkov
2023-08-04 20:01     ` Thomas Gleixner
2023-08-02 10:21 ` [patch V3 02/40] x86/apic: Fake primary thread mask for XEN/PV Thomas Gleixner
2023-08-04 18:12   ` Borislav Petkov
2023-08-04 20:02     ` Thomas Gleixner
2023-08-02 10:21 ` [patch V3 03/40] x86/cpu: Encapsulate topology information in cpuinfo_x86 Thomas Gleixner
2023-08-02 10:21 ` [patch V3 04/40] x86/cpu: Move phys_proc_id into topology info Thomas Gleixner
2023-08-02 10:21 ` [patch V3 05/40] x86/cpu: Move cpu_die_id " Thomas Gleixner
2023-08-09 14:32   ` Zhang, Rui
2023-08-09 15:14     ` Thomas Gleixner
2023-08-02 10:21 ` [patch V3 06/40] scsi: lpfc: Use topology_core_id() Thomas Gleixner
2023-08-02 10:21 ` [patch V3 07/40] hwmon: (fam15h_power) " Thomas Gleixner
2023-08-02 10:21 ` [patch V3 08/40] x86/cpu: Move cpu_core_id into topology info Thomas Gleixner
2023-08-02 10:21 ` [patch V3 09/40] x86/cpu: Move cu_id " Thomas Gleixner
2023-08-02 10:21 ` [patch V3 10/40] x86/cpu: Remove pointless evaluation of x86_coreid_bits Thomas Gleixner
2023-08-02 10:21 ` [patch V3 11/40] x86/cpu: Move logical package and die IDs into topology info Thomas Gleixner
2023-08-02 10:21 ` [patch V3 12/40] x86/cpu: Move cpu_l[l2]c_id " Thomas Gleixner
2023-08-02 10:21 ` [patch V3 13/40] x86/apic: Use BAD_APICID consistently Thomas Gleixner
2023-08-02 10:21 ` [patch V3 14/40] x86/apic: Use u32 for APIC IDs in global data Thomas Gleixner
2023-08-02 10:21 ` [patch V3 15/40] x86/apic: Use u32 for check_apicid_used() Thomas Gleixner
2023-08-02 10:21 ` [patch V3 16/40] x86/apic: Use u32 for cpu_present_to_apicid() Thomas Gleixner
2023-08-02 10:21 ` [patch V3 17/40] x86/apic: Use u32 for phys_pkg_id() Thomas Gleixner
2023-08-02 10:21 ` [patch V3 18/40] x86/apic: Use u32 for [gs]et_apic_id() Thomas Gleixner
2023-08-02 10:21 ` [patch V3 19/40] x86/apic: Use u32 for wakeup_secondary_cpu[_64]() Thomas Gleixner
2023-08-10  7:58   ` Qiuxu Zhuo
2023-08-02 10:21 ` [patch V3 20/40] x86/cpu/topology: Cure the abuse of cpuinfo for persisting logical ids Thomas Gleixner
2023-08-02 10:21 ` [patch V3 21/40] x86/cpu: Provide debug interface Thomas Gleixner
2023-08-02 10:21 ` [patch V3 22/40] x86/cpu: Provide cpuid_read() et al Thomas Gleixner
2023-08-02 10:21 ` [patch V3 23/40] x86/cpu: Provide cpu_init/parse_topology() Thomas Gleixner
2023-08-04  8:14   ` K Prateek Nayak
2023-08-04  8:28     ` Thomas Gleixner
2023-08-04  8:34       ` K Prateek Nayak
2023-08-12  6:41   ` Zhang, Rui
2023-08-12  8:00     ` Zhang, Rui
2023-08-14  6:26       ` Thomas Gleixner
2023-08-14  7:11         ` Zhang, Rui
2023-08-13 13:30     ` Zhang, Rui
2023-08-13 14:36       ` Thomas Gleixner
2023-08-14  6:20         ` Thomas Gleixner
2023-08-14  6:42           ` Zhang, Rui
2023-08-02 10:21 ` [patch V3 24/40] x86/cpu: Add legacy topology parser Thomas Gleixner
2023-08-02 10:21 ` [patch V3 25/40] x86/cpu: Use common topology code for Centaur and Zhaoxin Thomas Gleixner
2023-08-02 10:21 ` [patch V3 26/40] x86/cpu: Move __max_die_per_package to common.c Thomas Gleixner
2023-08-02 10:21 ` [patch V3 27/40] x86/cpu: Provide a sane leaf 0xb/0x1f parser Thomas Gleixner
2023-08-12  8:21   ` Zhang, Rui [this message]
2023-08-12 20:04     ` Thomas Gleixner
2023-08-13 15:04       ` Thomas Gleixner
2023-08-14  8:25         ` Zhang, Rui
2023-08-14 12:26           ` Thomas Gleixner
2023-08-14 14:48             ` Brown, Len
2023-08-14 16:13               ` Thomas Gleixner
2023-08-15 19:30                 ` Brown, Len
2023-08-17  9:09                   ` Thomas Gleixner
2023-08-18  5:01                     ` Brown, Len
2023-08-21 10:27                       ` Thomas Gleixner
2023-08-30  2:46                         ` Brown, Len
2023-08-30 12:39                           ` Thomas Gleixner
2023-09-01  3:09                             ` Brown, Len
2023-09-01  7:45                               ` Thomas Gleixner
2023-08-14 15:28             ` Zhang, Rui
2023-08-14 17:12               ` Thomas Gleixner
2023-08-02 10:21 ` [patch V3 28/40] x86/cpu: Use common topology code for Intel Thomas Gleixner
2023-08-02 10:21 ` [patch V3 29/40] x86/cpu/amd: Provide a separate accessor for Node ID Thomas Gleixner
2023-08-02 10:21 ` [patch V3 30/40] x86/cpu: Provide an AMD/HYGON specific topology parser Thomas Gleixner
2023-08-02 19:28   ` Michael Kelley (LINUX)
2023-08-02 19:46     ` Thomas Gleixner
2023-08-02 19:51   ` [patch V3a " Thomas Gleixner
2023-08-11 12:58     ` Pu Wen
2023-08-11 17:11       ` Thomas Gleixner
2023-08-12  3:58         ` Pu Wen
2023-10-13  9:38           ` [tip: x86/core] x86/cpu/hygon: Fix the CPU topology evaluation for real tip-bot2 for Pu Wen
2023-08-02 10:21 ` [patch V3 31/40] x86/smpboot: Teach it about topo.amd_node_id Thomas Gleixner
2023-08-02 10:21 ` [patch V3 32/40] x86/cpu: Use common topology code for AMD Thomas Gleixner
2023-08-02 10:21 ` [patch V3 33/40] x86/cpu: Use common topology code for HYGON Thomas Gleixner
2023-08-11 13:00   ` Pu Wen
2023-08-11 17:11     ` Thomas Gleixner
2023-08-02 10:21 ` [patch V3 34/40] x86/mm/numa: Use core domain size on AMD Thomas Gleixner
2023-08-02 10:21 ` [patch V3 35/40] x86/cpu: Make topology_amd_node_id() use the actual node info Thomas Gleixner
2023-08-02 10:21 ` [patch V3 36/40] x86/cpu: Remove topology.c Thomas Gleixner
2023-08-02 10:21 ` [patch V3 37/40] x86/cpu: Remove x86_coreid_bits Thomas Gleixner
2023-08-02 10:21 ` [patch V3 38/40] x86/apic: Remove unused phys_pkg_id() callback Thomas Gleixner
2023-08-02 10:21 ` [patch V3 39/40] x86/xen/smp_pv: Remove cpudata fiddling Thomas Gleixner
2023-08-02 10:22 ` [patch V3 40/40] x86/apic/uv: Remove the private leaf 0xb parser Thomas Gleixner
2023-08-02 11:56 ` [patch V3 00/40] x86/cpu: Rework the topology evaluation Juergen Gross
2023-08-03  0:07 ` Sohil Mehta
2023-08-03  3:44 ` Michael Kelley (LINUX)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8e5bbbc91ff9f74244efe916a4113999abc52213.camel@intel.com \
    --to=rui.zhang@intel.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=arjan@linux.intel.com \
    --cc=dimitri.sivanich@hpe.com \
    --cc=jgross@suse.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mikelley@microsoft.com \
    --cc=ray.huang@amd.com \
    --cc=tglx@linutronix.de \
    --cc=thomas.lendacky@amd.com \
    --cc=wei.liu@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome