Re: [PATCH v3 1/7] ACPI/PPTT: Add Processor Properties Topology Table parsing

From: Jeremy Linton
Date: Fri Oct 13 2017 - 15:58:39 EST


Hi,

On 10/13/2017 09:23 AM, tn wrote:
Hi Jeremy,

On 12.10.2017 21:48, Jeremy Linton wrote:
ACPI 6.2 adds a new table, which describes how processing units
are related to each other in tree like fashion. Caches are
also sprinkled throughout the tree and describe the properties
of the caches in relation to other caches and processing units.

Add the code to parse the cache hierarchy and report the total
number of levels of cache for a given core using
acpi_find_last_cache_level() as well as fill out the individual
cores cache information with cache_setup_acpi() once the
cpu_cacheinfo structure has been populated by the arch specific
code.

Further, report peers in the topology using setup_acpi_cpu_topology()
to report a unique ID for each processing unit at a given level
in the tree. These unique id's can then be used to match related
processing units which exist as threads, COD (clusters
on die), within a given package, etc.

Signed-off-by: Jeremy Linton <jeremy.linton@xxxxxxx>
---
 drivers/acpi/pptt.c | 485 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 485 insertions(+)
 create mode 100644 drivers/acpi/pptt.c

diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
new file mode 100644
index 000000000000..c86715fed4a7
--- /dev/null
+++ b/drivers/acpi/pptt.c
@@ -0,1 +1,485 @@
+/*
+ * Copyright (C) 2017, ARM
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * This file implements parsing of Processor Properties Topology Table (PPTT)
+ * which is optionally used to describe the processor and cache topology.
+ * Due to the relative pointers used throughout the table, this doesn't
+ * leverage the existing subtable parsing in the kernel.
+ */
+#define pr_fmt(fmt) "ACPI PPTT: " fmt
+
+#include <linux/acpi.h>
+#include <linux/cacheinfo.h>
+#include <acpi/processor.h>
+
+/*
+ * Given the PPTT table, find and verify that the subtable entry
+ * is located within the table
+ */
+static struct acpi_subtable_header *fetch_pptt_subtable(
+ÂÂÂ struct acpi_table_header *table_hdr, u32 pptt_ref)
+{
+ÂÂÂ struct acpi_subtable_header *entry;
+
+ÂÂÂ /* there isn't a subtable at reference 0 */
+ÂÂÂ if (!pptt_ref)
+ÂÂÂÂÂÂÂ return NULL;
+
+ÂÂÂ if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length)
+ÂÂÂÂÂÂÂ return NULL;
+
+ÂÂÂ entry = (struct acpi_subtable_header *)((u8 *)table_hdr + pptt_ref);

You can use ACPI_ADD_PTR() here.

Hmmm, that is a useful macro.



+
+ÂÂÂ if (pptt_ref + entry->length > table_hdr->length)
+ÂÂÂÂÂÂÂ return NULL;
+
+ÂÂÂ return entry;
+}
+
+static struct acpi_pptt_processor *fetch_pptt_node(
+ÂÂÂ struct acpi_table_header *table_hdr, u32 pptt_ref)
+{
+ÂÂÂ return (struct acpi_pptt_processor *)fetch_pptt_subtable(table_hdr, pptt_ref);
+}
+
+static struct acpi_pptt_cache *fetch_pptt_cache(
+ÂÂÂ struct acpi_table_header *table_hdr, u32 pptt_ref)
+{
+ÂÂÂ return (struct acpi_pptt_cache *)fetch_pptt_subtable(table_hdr, pptt_ref);
+}
+
+static struct acpi_subtable_header *acpi_get_pptt_resource(
+ÂÂÂ struct acpi_table_header *table_hdr,
+ÂÂÂ struct acpi_pptt_processor *node, int resource)
+{
+ÂÂÂ u32 ref;
+
+ÂÂÂ if (resource >= node->number_of_priv_resources)
+ÂÂÂÂÂÂÂ return NULL;
+
+ÂÂÂ ref = *(u32 *)((u8 *)node + sizeof(struct acpi_pptt_processor) +
+ÂÂÂÂÂÂÂÂÂÂÂÂÂ sizeof(u32) * resource);

ACPI_ADD_PTR()

+
+ÂÂÂ return fetch_pptt_subtable(table_hdr, ref);
+}
+
+/*
+ * given a pptt resource, verify that it is a cache node, then walk
+ * down each level of caches, counting how many levels are found
+ * as well as checking the cache type (icache, dcache, unified). If a
+ * level & type match, then we set found, and continue the search.
+ * Once the entire cache branch has been walked return its max
+ * depth.
+ */
+static int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int local_level,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_subtable_header *res,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_pptt_cache **found,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int level, int type)
+{
+ÂÂÂ struct acpi_pptt_cache *cache;
+
+ÂÂÂ if (res->type != ACPI_PPTT_TYPE_CACHE)
+ÂÂÂÂÂÂÂ return 0;
+
+ÂÂÂ cache = (struct acpi_pptt_cache *) res;
+ÂÂÂ while (cache) {
+ÂÂÂÂÂÂÂ local_level++;
+
+ÂÂÂÂÂÂÂ if ((local_level == level) &&
+ÂÂÂÂÂÂÂÂÂÂÂ (cache->flags & ACPI_PPTT_CACHE_TYPE_VALID) &&
+ÂÂÂÂÂÂÂÂÂÂÂ ((cache->attributes & ACPI_PPTT_MASK_CACHE_TYPE) == type)) {
+ÂÂÂÂÂÂÂÂÂÂÂ if (*found != NULL)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ pr_err("Found duplicate cache level/type unable to determine uniqueness\n");
+
+ÂÂÂÂÂÂÂÂÂÂÂ pr_debug("Found cache @ level %d\n", level);
+ÂÂÂÂÂÂÂÂÂÂÂ *found = cache;
+ÂÂÂÂÂÂÂÂÂÂÂ /*
+ÂÂÂÂÂÂÂÂÂÂÂÂ * continue looking at this node's resource list
+ÂÂÂÂÂÂÂÂÂÂÂÂ * to verify that we don't find a duplicate
+ÂÂÂÂÂÂÂÂÂÂÂÂ * cache node.
+ÂÂÂÂÂÂÂÂÂÂÂÂ */
+ÂÂÂÂÂÂÂ }
+ÂÂÂÂÂÂÂ cache = fetch_pptt_cache(table_hdr, cache->next_level_of_cache);
+ÂÂÂ }
+ÂÂÂ return local_level;
+}
+
+/*
+ * Given a CPU node look for cache levels that exist at this level, and then
+ * for each cache node, count how many levels exist below (logically above) it.
+ * If a level and type are specified, and we find that level/type, abort
+ * processing and return the acpi_pptt_cache structure.
+ */
+static struct acpi_pptt_cache *acpi_find_cache_level(
+ÂÂÂ struct acpi_table_header *table_hdr,
+ÂÂÂ struct acpi_pptt_processor *cpu_node,
+ÂÂÂ int *starting_level, int level, int type)
+{
+ÂÂÂ struct acpi_subtable_header *res;
+ÂÂÂ int number_of_levels = *starting_level;
+ÂÂÂ int resource = 0;
+ÂÂÂ struct acpi_pptt_cache *ret = NULL;
+ÂÂÂ int local_level;
+
+ÂÂÂ /* walk down from the processor node */
+ÂÂÂ while ((res = acpi_get_pptt_resource(table_hdr, cpu_node, resource))) {
+ÂÂÂÂÂÂÂ resource++;
+
+ÂÂÂÂÂÂÂ local_level = acpi_pptt_walk_cache(table_hdr, *starting_level,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ res, &ret, level, type);
+ÂÂÂÂÂÂÂ /*
+ÂÂÂÂÂÂÂÂ * we are looking for the max depth. Since its potentially
+ÂÂÂÂÂÂÂÂ * possible for a given node to have resources with differing
+ÂÂÂÂÂÂÂÂ * depths verify that the depth we have found is the largest.
+ÂÂÂÂÂÂÂÂ */
+ÂÂÂÂÂÂÂ if (number_of_levels < local_level)
+ÂÂÂÂÂÂÂÂÂÂÂ number_of_levels = local_level;
+ÂÂÂ }
+ÂÂÂ if (number_of_levels > *starting_level)
+ÂÂÂÂÂÂÂ *starting_level = number_of_levels;
+
+ÂÂÂ return ret;
+}
+
+/*
+ * given a processor node containing a processing unit, walk into it and count
+ * how many levels exist solely for it, and then walk up each level until we hit
+ * the root node (ignore the package level because it may be possible to have
+ * caches that exist across packages). Count the number of cache levels that
+ * exist at each level on the way up.
+ */
+static int acpi_process_node(struct acpi_table_header *table_hdr,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_pptt_processor *cpu_node)
+{
+ÂÂÂ int total_levels = 0;
+
+ÂÂÂ do {
+ÂÂÂÂÂÂÂ acpi_find_cache_level(table_hdr, cpu_node, &total_levels, 0, 0);
+ÂÂÂÂÂÂÂ cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
+ÂÂÂ } while (cpu_node);
+
+ÂÂÂ return total_levels;
+}
+
+/* determine if the given node is a leaf node */
+static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_pptt_processor *node)
+{
+ÂÂÂ struct acpi_subtable_header *entry;
+ÂÂÂ unsigned long table_end;
+ÂÂÂ u32 node_entry;
+ÂÂÂ struct acpi_pptt_processor *cpu_node;
+
+ÂÂÂ table_end = (unsigned long)table_hdr + table_hdr->length;
+ÂÂÂ node_entry = (u32)((u8 *)node - (u8 *)table_hdr);
+ÂÂÂ entry = (struct acpi_subtable_header *)((u8 *)table_hdr +
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sizeof(struct acpi_table_pptt));

ACPI_ADD_PTR()

+
+ÂÂÂ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < table_end) {
+ÂÂÂÂÂÂÂ cpu_node = (struct acpi_pptt_processor *)entry;
+ÂÂÂÂÂÂÂ if ((entry->type == ACPI_PPTT_TYPE_PROCESSOR) &&
+ÂÂÂÂÂÂÂÂÂÂÂ (cpu_node->parent == node_entry))
+ÂÂÂÂÂÂÂÂÂÂÂ return 0;
+ÂÂÂÂÂÂÂ entry = (struct acpi_subtable_header *)((u8 *)entry + entry->length);
+ÂÂÂ }
+ÂÂÂ return 1;
+}
+
+/*
+ * Find the subtable entry describing the provided processor
+ */
+static struct acpi_pptt_processor *acpi_find_processor_node(
+ÂÂÂ struct acpi_table_header *table_hdr,
+ÂÂÂ u32 acpi_cpu_id)
+{
+ÂÂÂ struct acpi_subtable_header *entry;
+ÂÂÂ unsigned long table_end;
+ÂÂÂ struct acpi_pptt_processor *cpu_node;
+
+ÂÂÂ table_end = (unsigned long)table_hdr + table_hdr->length;
+ÂÂÂ entry = (struct acpi_subtable_header *)((u8 *)table_hdr +
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sizeof(struct acpi_table_pptt));

ACPI_ADD_PTR()

+
+ÂÂÂ /* find the processor structure associated with this cpuid */
+ÂÂÂ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < table_end) {
+ÂÂÂÂÂÂÂ cpu_node = (struct acpi_pptt_processor *)entry;
+
+ÂÂÂÂÂÂÂ if ((entry->type == ACPI_PPTT_TYPE_PROCESSOR) &&
+ÂÂÂÂÂÂÂÂÂÂÂ acpi_pptt_leaf_node(table_hdr, cpu_node)) {
+ÂÂÂÂÂÂÂÂÂÂÂ pr_debug("checking phy_cpu_id %d against acpi id %d\n",
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ acpi_cpu_id, cpu_node->acpi_processor_id);
+ÂÂÂÂÂÂÂÂÂÂÂ if (acpi_cpu_id == cpu_node->acpi_processor_id) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ /* found the correct entry */
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ pr_debug("match found!\n");
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return (struct acpi_pptt_processor *)entry;
+ÂÂÂÂÂÂÂÂÂÂÂ }
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂÂÂÂÂ if (entry->length == 0) {
+ÂÂÂÂÂÂÂÂÂÂÂ pr_err("Invalid zero length subtable\n");
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ }

For a better table content validation, this could be done at the beginning of the loop, like that:

if (WARN_TAINT(entry->length == 0, TAINT_FIRMWARE_WORKAROUND,
ÂÂÂÂÂÂ "Invalid zero length subtable, bad PPTT table!\n"))
ÂÂÂÂÂÂÂÂÂÂÂ break;


+ÂÂÂÂÂÂÂ entry = (struct acpi_subtable_header *)
+ÂÂÂÂÂÂÂÂÂÂÂ ((u8 *)entry + entry->length);

ACPI_ADD_PTR()

+ÂÂÂ }
+
+ÂÂÂ return NULL;
+}
+
+/*
+ * Given a acpi_pptt_processor node, walk up until we identify the
+ * package that the node is associated with or we run out of levels
+ * to request.
+ */
+static struct acpi_pptt_processor *acpi_find_processor_package_id(
+ÂÂÂ struct acpi_table_header *table_hdr,
+ÂÂÂ struct acpi_pptt_processor *cpu,
+ÂÂÂ int level)
+{
+ÂÂÂ struct acpi_pptt_processor *prev_node;
+
+ÂÂÂ while (cpu && level && !(cpu->flags & ACPI_PPTT_PHYSICAL_PACKAGE)) {
+ÂÂÂÂÂÂÂ pr_debug("level %d\n", level);
+ÂÂÂÂÂÂÂ prev_node = fetch_pptt_node(table_hdr, cpu->parent);
+ÂÂÂÂÂÂÂ if (prev_node == NULL)
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ cpu = prev_node;
+ÂÂÂÂÂÂÂ level--;
+ÂÂÂ }
+ÂÂÂ return cpu;
+}
+
+static int acpi_parse_pptt(struct acpi_table_header *table_hdr, u32 acpi_cpu_id)
+{
+ÂÂÂ int number_of_levels = 0;
+ÂÂÂ struct acpi_pptt_processor *cpu;
+
+ÂÂÂ cpu = acpi_find_processor_node(table_hdr, acpi_cpu_id);
+ÂÂÂ if (cpu)
+ÂÂÂÂÂÂÂ number_of_levels = acpi_process_node(table_hdr, cpu);
+
+ÂÂÂ return number_of_levels;
+}
+

Based on ACPI spec 6.2:

+#define ACPI_6_2_CACHE_TYPE_DATAÂÂÂÂÂÂÂÂÂÂÂÂÂ (0x0)
+#define ACPI_6_2_CACHE_TYPE_INSTRÂÂÂÂÂÂÂÂÂÂÂÂÂ (1<<2)
+#define ACPI_6_2_CACHE_TYPE_UNIFIEDÂÂÂÂÂÂÂÂÂÂÂÂÂ (1<<3)

Bits:3:2: Cache type:
0x0 Data
0x1 Instruction
0x2 or 0x3 Indicate a unified cache

Originally I was trying to do something more clever than the switch (given the less than optimal bit definitions), but the result wasn't as clear as the switch, so I just plugged that in but forgot about the 3rd case.


+#define ACPI_6_2_CACHE_POLICY_WBÂÂÂÂÂÂÂÂÂÂÂÂÂ (0x0)
+#define ACPI_6_2_CACHE_POLICY_WTÂÂÂÂÂÂÂÂÂÂÂÂÂ (1<<4)
+#define ACPI_6_2_CACHE_READ_ALLOCATEÂÂÂÂÂÂÂÂÂÂÂÂÂ (0x0)
+#define ACPI_6_2_CACHE_WRITE_ALLOCATEÂÂÂÂÂÂÂÂÂÂÂÂÂ (0x01)
+#define ACPI_6_2_CACHE_RW_ALLOCATEÂÂÂÂÂÂÂÂÂÂÂÂÂ (0x02)

Bits 1:0: Allocation type
0x0 - Read allocate
0x1 - Write allocate
0x2 or 0x03 indicate Read and Write allocate

BTW, why these are not part of ACPICA code (actbl1.h header) and have ACPI_PPTT prefixes?

Well I guess they probably should be the only question is how one goes about defining the duplicates..

AKA:

#define ACPI_PPTT_CACHE_RW_ALLOCATE (0x02)
#define ACPI_PPTT_CACHE_RW_ALLOCATE_ALT (0x03)


+
+static u8 acpi_cache_type(enum cache_type type)
+{
+ÂÂÂ switch (type) {
+ÂÂÂ case CACHE_TYPE_DATA:
+ÂÂÂÂÂÂÂ pr_debug("Looking for data cache\n");
+ÂÂÂÂÂÂÂ return ACPI_6_2_CACHE_TYPE_DATA;
+ÂÂÂ case CACHE_TYPE_INST:
+ÂÂÂÂÂÂÂ pr_debug("Looking for instruction cache\n");
+ÂÂÂÂÂÂÂ return ACPI_6_2_CACHE_TYPE_INSTR;
+ÂÂÂ default:
+ÂÂÂÂÂÂÂ pr_debug("Unknown cache type, assume unified\n");
+ÂÂÂ case CACHE_TYPE_UNIFIED:
+ÂÂÂÂÂÂÂ pr_debug("Looking for unified cache\n");
+ÂÂÂÂÂÂÂ return ACPI_6_2_CACHE_TYPE_UNIFIED;
+ÂÂÂ }
+}
+
+/* find the ACPI node describing the cache type/level for the given CPU */
+static struct acpi_pptt_cache *acpi_find_cache_node(
+ÂÂÂ struct acpi_table_header *table_hdr, u32 acpi_cpu_id,
+ÂÂÂ enum cache_type type, unsigned int level,
+ÂÂÂ struct acpi_pptt_processor **node)
+{
+ÂÂÂ int total_levels = 0;
+ÂÂÂ struct acpi_pptt_cache *found = NULL;
+ÂÂÂ struct acpi_pptt_processor *cpu_node;
+ÂÂÂ u8 acpi_type = acpi_cache_type(type);
+
+ÂÂÂ pr_debug("Looking for CPU %d's level %d cache type %d\n",
+ÂÂÂÂÂÂÂÂ acpi_cpu_id, level, acpi_type);
+
+ÂÂÂ cpu_node = acpi_find_processor_node(table_hdr, acpi_cpu_id);
+ÂÂÂ if (!cpu_node)
+ÂÂÂÂÂÂÂ return NULL;
+
+ÂÂÂ do {
+ÂÂÂÂÂÂÂ found = acpi_find_cache_level(table_hdr, cpu_node, &total_levels, level, acpi_type);

Please align line to 80 characters at maximum.

ok,


+ÂÂÂÂÂÂÂ *node = cpu_node;
+ÂÂÂÂÂÂÂ cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
+ÂÂÂ } while ((cpu_node) && (!found));
+
+ÂÂÂ return found;
+}
+
+int acpi_find_last_cache_level(unsigned int cpu)
+{
+ÂÂÂ u32 acpi_cpu_id;
+ÂÂÂ struct acpi_table_header *table;
+ÂÂÂ int number_of_levels = 0;
+ÂÂÂ acpi_status status;
+
+ÂÂÂ pr_debug("Cache Setup find last level cpu=%d\n", cpu);
+
+ÂÂÂ acpi_cpu_id = acpi_cpu_get_madt_gicc(cpu)->uid;
+ÂÂÂ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ÂÂÂ if (ACPI_FAILURE(status)) {
+ÂÂÂÂÂÂÂ pr_err_once("No PPTT table found, cache topology may be inaccurate\n");
+ÂÂÂ } else {
+ÂÂÂÂÂÂÂ number_of_levels = acpi_parse_pptt(table, acpi_cpu_id);
+ÂÂÂÂÂÂÂ acpi_put_table(table);
+ÂÂÂ }
+ÂÂÂ pr_debug("Cache Setup find last level level=%d\n", number_of_levels);
+
+ÂÂÂ return number_of_levels;
+}
+
+/*
+ * The ACPI spec implies that the fields in the cache structures are used to
+ * extend and correct the information probed from the hardware. In the case
+ * of arm64 the CCSIDR probing has been removed because it might be incorrect.
+ */
+static void update_cache_properties(struct cacheinfo *this_leaf,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_pptt_cache *found_cache,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct acpi_pptt_processor *cpu_node)
+{
+ÂÂÂ if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID)
+ÂÂÂÂÂÂÂ this_leaf->size = found_cache->size;
+ÂÂÂ if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID)
+ÂÂÂÂÂÂÂ this_leaf->coherency_line_size = found_cache->line_size;
+ÂÂÂ if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID)
+ÂÂÂÂÂÂÂ this_leaf->number_of_sets = found_cache->number_of_sets;
+ÂÂÂ if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID)
+ÂÂÂÂÂÂÂ this_leaf->ways_of_associativity = found_cache->associativity;
+ÂÂÂ if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID)
+ÂÂÂÂÂÂÂ switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) {
+ÂÂÂÂÂÂÂ case ACPI_6_2_CACHE_POLICY_WT:
+ÂÂÂÂÂÂÂÂÂÂÂ this_leaf->attributes = CACHE_WRITE_THROUGH;
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ case ACPI_6_2_CACHE_POLICY_WB:
+ÂÂÂÂÂÂÂÂÂÂÂ this_leaf->attributes = CACHE_WRITE_BACK;
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ default:
+ÂÂÂÂÂÂÂÂÂÂÂ pr_err("Unknown ACPI cache policy %d\n",
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY);
+ÂÂÂÂÂÂÂ }

The 'default' case can never happen, please remove dead code.

Ok,


+ÂÂÂ if (found_cache->flags & ACPI_PPTT_ALLOCATION_TYPE_VALID)
+ÂÂÂÂÂÂÂ switch (found_cache->attributes & ACPI_PPTT_MASK_ALLOCATION_TYPE) {
+ÂÂÂÂÂÂÂ case ACPI_6_2_CACHE_READ_ALLOCATE:
+ÂÂÂÂÂÂÂÂÂÂÂ this_leaf->attributes |= CACHE_READ_ALLOCATE;
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ case ACPI_6_2_CACHE_WRITE_ALLOCATE:
+ÂÂÂÂÂÂÂÂÂÂÂ this_leaf->attributes |= CACHE_WRITE_ALLOCATE;
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ case ACPI_6_2_CACHE_RW_ALLOCATE:
+ÂÂÂÂÂÂÂÂÂÂÂ this_leaf->attributes |=
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ CACHE_READ_ALLOCATE|CACHE_WRITE_ALLOCATE;
+ÂÂÂÂÂÂÂÂÂÂÂ break;
+ÂÂÂÂÂÂÂ default:
+ÂÂÂÂÂÂÂÂÂÂÂ pr_err("Unknown ACPI cache allocation policy %d\n",
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ found_cache->attributes & ACPI_PPTT_MASK_ALLOCATION_TYPE);
+ÂÂÂÂÂÂÂ }

Same here if you fix bits definitions.

Sure,


+}
+
+static void cache_setup_acpi_cpu(struct acpi_table_header *table,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int cpu)
+{
+ÂÂÂ struct acpi_pptt_cache *found_cache;
+ÂÂÂ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ÂÂÂ u32 acpi_cpu_id = acpi_cpu_get_madt_gicc(cpu)->uid;
+ÂÂÂ struct cacheinfo *this_leaf;
+ÂÂÂ unsigned int index = 0;
+ÂÂÂ struct acpi_pptt_processor *cpu_node = NULL;
+
+ÂÂÂ while (index < get_cpu_cacheinfo(cpu)->num_leaves) {
+ÂÂÂÂÂÂÂ this_leaf = this_cpu_ci->info_list + index;
+ÂÂÂÂÂÂÂ found_cache = acpi_find_cache_node(table, acpi_cpu_id,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ this_leaf->type,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ this_leaf->level,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &cpu_node);
+ÂÂÂÂÂÂÂ pr_debug("found = %p %p\n", found_cache, cpu_node);
+ÂÂÂÂÂÂÂ if (found_cache)
+ÂÂÂÂÂÂÂÂÂÂÂ update_cache_properties(this_leaf,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ found_cache,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ cpu_node);
+
+ÂÂÂÂÂÂÂ index++;
+ÂÂÂ }
+}
+
+static int topology_setup_acpi_cpu(struct acpi_table_header *table,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int cpu, int level)
+{
+ÂÂÂ struct acpi_pptt_processor *cpu_node;
+ÂÂÂ u32 acpi_cpu_id = acpi_cpu_get_madt_gicc(cpu)->uid;
+
+ÂÂÂ cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+ÂÂÂ if (cpu_node) {
+ÂÂÂÂÂÂÂ cpu_node = acpi_find_processor_package_id(table, cpu_node, level);
+ÂÂÂÂÂÂÂ /* Only the first level has a guaranteed id */
+ÂÂÂÂÂÂÂ if (level == 0)
+ÂÂÂÂÂÂÂÂÂÂÂ return cpu_node->acpi_processor_id;
+ÂÂÂÂÂÂÂ return (int)((u8 *)cpu_node - (u8 *)table);
+ÂÂÂ }
+ÂÂÂ pr_err_once("PPTT table found, but unable to locate core for %d\n",
+ÂÂÂÂÂÂÂÂÂÂÂ cpu);
+ÂÂÂ return -ENOENT;
+}
+
+/*
+ * simply assign a ACPI cache entry to each known CPU cache entry
+ * determining which entries are shared is done later.
+ */
+int cache_setup_acpi(unsigned int cpu)
+{
+ÂÂÂ struct acpi_table_header *table;
+ÂÂÂ acpi_status status;
+
+ÂÂÂ pr_debug("Cache Setup ACPI cpu %d\n", cpu);
+
+ÂÂÂ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ÂÂÂ if (ACPI_FAILURE(status)) {
+ÂÂÂÂÂÂÂ pr_err_once("No PPTT table found, cache topology may be inaccurate\n");
+ÂÂÂÂÂÂÂ return -ENOENT;
+ÂÂÂ }
+
+ÂÂÂ cache_setup_acpi_cpu(table, cpu);
+ÂÂÂ acpi_put_table(table);
+
+ÂÂÂ return status;
+}
+
+/*
+ * Determine a topology unique ID for each thread/core/cluster/socket/etc.
+ * This ID can then be used to group peers.
+ */
+int setup_acpi_cpu_topology(unsigned int cpu, int level)
+{
+ÂÂÂ struct acpi_table_header *table;
+ÂÂÂ acpi_status status;
+ÂÂÂ int retval;
+
+ÂÂÂ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ÂÂÂ if (ACPI_FAILURE(status)) {
+ÂÂÂÂÂÂÂ pr_err_once("No PPTT table found, cpu topology may be inaccurate\n");
+ÂÂÂÂÂÂÂ return -ENOENT;
+ÂÂÂ }
+ÂÂÂ retval = topology_setup_acpi_cpu(table, cpu, level);
+ÂÂÂ pr_debug("Topology Setup ACPI cpu %d, level %d ret = %d\n",
+ÂÂÂÂÂÂÂÂ cpu, level, retval);
+ÂÂÂ acpi_put_table(table);
+
+ÂÂÂ return retval;
+}


Thanks,
Tomasz


Thanks for taking the time to look at this.