Re: [PATCH v6 7/7] ACPI/NUMA: Print CXL Early Discovery Table (CEDT)

From: Jonathan Cameron
Date: Tue Apr 30 2024 - 12:22:57 EST


On Tue, 30 Apr 2024 11:22:00 +0200
Robert Richter <rrichter@xxxxxxx> wrote:

> The CEDT contains similar entries as the SRAT. For diagnostic reasons
> print the CEDT same style as the SRAT.
>
> Signed-off-by: Robert Richter <rrichter@xxxxxxx>
I'm fairly sure the interleave ways conversion is wrong.
Otherwise all trivial stuff.

Jonathan

> ---
> drivers/acpi/numa/srat.c | 111 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 111 insertions(+)
>
> diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c
> index 34ecf2dc912f..fa21d4d5fccf 100644
> --- a/drivers/acpi/numa/srat.c
> +++ b/drivers/acpi/numa/srat.c
> @@ -320,6 +320,114 @@ acpi_parse_memory_affinity(union acpi_subtable_headers *header,
> return 0;
> }
>
> +static int __init
> +__acpi_table_print_cedt_entry(union acpi_subtable_headers *__header,
> + void *arg, const unsigned long table_end)
> +{
> + struct acpi_cedt_header *header = (struct acpi_cedt_header *)__header;
> +
> + switch (header->type) {
> + case ACPI_CEDT_TYPE_CHBS:
> + {
> + struct acpi_cedt_chbs *p =
> + (struct acpi_cedt_chbs *)header;
> +
> + if (header->length < sizeof(struct acpi_cedt_chbs)) {
> + pr_warn("CEDT: unsupported CHBS entry: size %d\n",
> + header->length);
> + break;

Might as well return.

> + }
> +
> + pr_debug("CEDT: CHBS (0x%llx length 0x%llx uid %lu) %s (%d)\n",
> + (unsigned long long)p->base,
> + (unsigned long long)p->length,

The printk docs https://docs.kernel.org/core-api/printk-formats.html
suggest you shouldn't need the casts though I appreciate other functions in here
are doing this.

> + (unsigned long)p->uid,
> + (p->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) ?
> + "cxl11" :
> + (p->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20) ?
> + "cxl20" :
> + "unsupported version",

That seems harsh. Like all ACPI tables, these should be backwards compatible.
So not so much unsupported as "newer version". Breakage happens, but it is rare
and for the rest of the kernel I don' think we check this.

Also can we switch to the 3.1 spec terms. RCH etc. Though the term for 2.0+ in the
table definition for CHBS is the nasty:
"Host Bridge that is associated with one or more CXL root ports."

> + p->cxl_version);
> + }
> + break;

Trivial but I love early returns as they tend to avoid lots of scrolling to see where
the break goes and it is unlikely there will ever be anything to do after this.

> + case ACPI_CEDT_TYPE_CFMWS:
> + {
> + struct acpi_cedt_cfmws *p =
> + (struct acpi_cedt_cfmws *)header;
> + int eiw_to_ways[] = {1, 2, 4, 8, 16, 3, 6, 12};
> + int targets = -1;
> +
> + if (header->length < sizeof(struct acpi_cedt_cfmws)) {
> + pr_warn("CEDT: unsupported CFMWS entry: size %d\n",
> + header->length);
> + break;

Might as well return.

> + }
> +
> + if (p->interleave_ways < ARRAY_SIZE(eiw_to_ways))
> + targets = eiw_to_ways[p->interleave_ways];

That looks wrong for 3, 6, 12 as index is 0x8, 0x9, 0xA not 5 6 7
Don't we have a function to decode this somewhere than can be reused?

> + if (header->length < struct_size(
> + p, interleave_targets, targets))
> + targets = -1;
> +
> + pr_debug("CEDT: CFMWS (0x%llx length 0x%llx) with %d target%s",
> + (unsigned long long)p->base_hpa,
> + (unsigned long long)p->window_size,
> + targets, targets > 1 ? "s" : "");
> + for (int i = 0; i < targets; i++)
> + pr_cont("%s%lu", i ? ", " : " (",
> + (unsigned long)p->interleave_targets[i]);
> + pr_cont("%s%s%s%s%s%s\n",
> + targets > 0 ? ")" : "",
> + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2) ?
> + " type2" : "",
> + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3) ?
> + " type3" : "",
> + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE) ?
> + " volatile" : "",
> + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM) ?
> + " pmem" : "",
> + (p->restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED) ?
> + " fixed" : "");
> + }
> + break;
return

> + case ACPI_CEDT_TYPE_CXIMS:
> + {
> + struct acpi_cedt_cxims *p =
> + (struct acpi_cedt_cxims *)header;
> +
> + if (header->length < sizeof(struct acpi_cedt_cxims)) {
> + pr_warn("CEDT: unsupported CXIMS entry: size %d\n",
> + header->length);
> + break;
return
> + }
> +
> + pr_debug("CEDT: CXIMS (hbig %u nr_xormaps %u)\n",
> + (unsigned int)p->hbig,
> + (unsigned int)p->nr_xormaps);
> + }
> + break;
return
> + default:
> + pr_warn("CEDT: Found unsupported entry (type = 0x%x)\n",
> + header->type);
> + break;
return
> + }
> +
> + return 0;
> +}
> +
> +static void __init acpi_table_print_cedt_entry(enum acpi_cedt_type id)
> +{
> + acpi_table_parse_cedt(id, __acpi_table_print_cedt_entry, NULL);
> +}
> +
> +static void __init acpi_table_print_cedt(void)
> +{
> + /* Print only implemented CEDT types */
> + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CHBS);
> + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CFMWS);
> + acpi_table_print_cedt_entry(ACPI_CEDT_TYPE_CXIMS);
> +}
> +
> static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
> void *arg, const unsigned long table_end)
> {
> @@ -518,6 +626,9 @@ int __init acpi_numa_init(void)
> /* SLIT: System Locality Information Table */
> acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
>
> + /* CEDT: CXL Early Discovery Table */
> + acpi_table_print_cedt();
> +
> /*
> * CXL Fixed Memory Window Structures (CFMWS) must be parsed
> * after the SRAT. Create NUMA Nodes for CXL memory ranges that