2018-04-26 00:27:31

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 00/13] Support PPTT for ARM64

ACPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
used to describe the processor and cache topology. Ideally it is
used to extend/override information provided by the hardware, but
right now ARM64 is entirely dependent on firmware provided tables.

This patch parses the table for the cache topology and CPU topology.
When we enable ACPI/PPTT for arm64 we map the package_id to the
PPTT node flagged as the physical package by the firmware.
This results in topologies that match what the remainder of the
system expects. Finally, we update the scheduler MC domain so that
it generally reflects the LLC unless the LLC is too large for the
NUMA domain (or package).

For example on juno:
[root@mammon-juno-rh topology]# lstopo-no-graphics
Package L#0
L2 L#0 (1024KB)
L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
L2 L#1 (2048KB)
L1d L#4 (32KB) + L1i L#4 (48KB) + Core L#4 + PU L#4 (P#4)
L1d L#5 (32KB) + L1i L#5 (48KB) + Core L#5 + PU L#5 (P#5)
HostBridge L#0
PCIBridge
PCIBridge
PCIBridge
PCI 1095:3132
Block(Disk) L#0 "sda"
PCIBridge
PCI 1002:68f9
GPU L#1 "renderD128"
GPU L#2 "card0"
GPU L#3 "controlD64"
PCIBridge
PCI 11ab:4380
Net L#4 "enp8s0"

Git tree at:
http://linux-arm.org/git?p=linux-jlinton.git
branch: pptt_v8

v7->v8:
Modify the logic used to select the MC domain (the change
shouldn't modify the sched domains on any existing machines
compared to v7, only how they are built)
Reduce the severity of some parsing messages.
Fix s390 link problem.
Further checks to deal with broken PPTT tables.
Various style tweaks, SPDX license addition, etc.

v6->v7:
Add additional patch to use the last cache level within the NUMA
or socket as the MC domain. This assures the MC domain is
equal or smaller than the DIE.

Various formatting/etc review comments.

Rebase to 4.16rc2

v5->v6:
Add additional patches which re-factor how the initial DT code sets
up the cacheinfo structure so that its not as dependent on the
of_node stored in that tree. Once that is done we rename it
for use with the ACPI code.

Additionally there were a fair number of minor name/location/etc
tweaks scattered about made in response to review comments.

v4->v5:
Update the cache type from NOCACHE to UNIFIED when all the cache
attributes we update are valid. This fixes a problem where caches
which are entirely created by the PPTT don't show up in lstopo.

Give the PPTT its own firmware_node in the cache structure instead of
sharing it with the of_node.

Move some pieces around between patches.

(see previous cover letters for futher changes)

Jeremy Linton (13):
drivers: base: cacheinfo: move cache_setup_of_node()
drivers: base: cacheinfo: setup DT cache properties early
cacheinfo: rename of_node to fw_token
arm64/acpi: Create arch specific cpu to acpi id helper
ACPI/PPTT: Add Processor Properties Topology Table parsing
ACPI: Enable PPTT support on ARM64
drivers: base cacheinfo: Add support for ACPI based firmware tables
arm64: Add support for ACPI based firmware tables
ACPI/PPTT: Add topology parsing code
arm64: topology: rename cluster_id
arm64: topology: enable ACPI/PPTT based CPU topology
ACPI: Add PPTT to injectable table list
arm64: topology: divorce MC scheduling domain from core_siblings

arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/acpi.h | 4 +
arch/arm64/include/asm/topology.h | 6 +-
arch/arm64/kernel/cacheinfo.c | 15 +-
arch/arm64/kernel/topology.c | 103 +++++-
arch/riscv/kernel/cacheinfo.c | 1 -
drivers/acpi/Kconfig | 3 +
drivers/acpi/Makefile | 1 +
drivers/acpi/pptt.c | 678 ++++++++++++++++++++++++++++++++++++++
drivers/acpi/tables.c | 2 +-
drivers/base/cacheinfo.c | 157 ++++-----
include/linux/acpi.h | 4 +
include/linux/cacheinfo.h | 18 +-
13 files changed, 886 insertions(+), 107 deletions(-)
create mode 100644 drivers/acpi/pptt.c

--
2.13.6



2018-04-26 00:27:53

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 03/13] cacheinfo: rename of_node to fw_token

Rename and change the type of of_node to indicate
it is a generic pointer which is generally only used
for comparison purposes. In a later patch we will put
an ACPI/PPTT token pointer in fw_token so that
the code which builds the shared cpu masks can be reused.

Signed-off-by: Jeremy Linton <[email protected]>
Acked-by: Sudeep Holla <[email protected]>
---
drivers/base/cacheinfo.c | 16 +++++++++-------
include/linux/cacheinfo.h | 8 +++-----
2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index a872523e8951..597aacb233fc 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -35,7 +35,7 @@ struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu)
static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
struct cacheinfo *sib_leaf)
{
- return sib_leaf->of_node == this_leaf->of_node;
+ return sib_leaf->fw_token == this_leaf->fw_token;
}

/* OF properties to query for a given cache type */
@@ -167,9 +167,10 @@ static int cache_setup_of_node(unsigned int cpu)
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
unsigned int index = 0;

- /* skip if of_node is already populated */
- if (this_cpu_ci->info_list->of_node)
+ /* skip if fw_token is already populated */
+ if (this_cpu_ci->info_list->fw_token) {
return 0;
+ }

if (!cpu_dev) {
pr_err("No cpu device for CPU %d\n", cpu);
@@ -190,7 +191,7 @@ static int cache_setup_of_node(unsigned int cpu)
if (!np)
break;
cache_of_set_props(this_leaf, np);
- this_leaf->of_node = np;
+ this_leaf->fw_token = np;
index++;
}

@@ -278,7 +279,7 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
}
- of_node_put(this_leaf->of_node);
+ of_node_put(this_leaf->fw_token);
}
}

@@ -323,8 +324,9 @@ static int detect_cache_attributes(unsigned int cpu)
if (ret)
goto free_ci;
/*
- * For systems using DT for cache hierarchy, of_node and shared_cpu_map
- * will be set up here only if they are not populated already
+ * For systems using DT for cache hierarchy, fw_token
+ * and shared_cpu_map will be set up here only if they are
+ * not populated already
*/
ret = cache_shared_cpu_map_setup(cpu);
if (ret) {
diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h
index 3d9805297cda..0c6f658054d2 100644
--- a/include/linux/cacheinfo.h
+++ b/include/linux/cacheinfo.h
@@ -34,9 +34,8 @@ enum cache_type {
* @shared_cpu_map: logical cpumask representing all the cpus sharing
* this cache node
* @attributes: bitfield representing various cache attributes
- * @of_node: if devicetree is used, this represents either the cpu node in
- * case there's no explicit cache node or the cache node itself in the
- * device tree
+ * @fw_token: Unique value used to determine if different cacheinfo
+ * structures represent a single hardware cache instance.
* @disable_sysfs: indicates whether this node is visible to the user via
* sysfs or not
* @priv: pointer to any private data structure specific to particular
@@ -65,8 +64,7 @@ struct cacheinfo {
#define CACHE_ALLOCATE_POLICY_MASK \
(CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE)
#define CACHE_ID BIT(4)
-
- struct device_node *of_node;
+ void *fw_token;
bool disable_sysfs;
void *priv;
};
--
2.13.6


2018-04-26 00:28:08

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

Now that we have an accurate view of the physical topology
we need to represent it correctly to the scheduler. Generally MC
should equal the LLC in the system, but there are a number of
special cases that need to be dealt with.

In the case of NUMA in socket, we need to assure that the sched
domain we build for the MC layer isn't larger than the DIE above it.
Similarly for LLC's that might exist in cross socket interconnect or
directory hardware we need to assure that MC is shrunk to the socket
or NUMA node.

This patch builds a sibling mask for the LLC, and then picks the
smallest of LLC, socket siblings, or NUMA node siblings, which
gives us the behavior described above. This is ever so slightly
different than the similar alternative where we look for a cache
layer less than or equal to the socket/NUMA siblings.

The logic to pick the MC layer affects all arm64 machines, but
only changes the behavior for DT/MPIDR systems if the NUMA domain
is smaller than the core siblings (generally set to the cluster).
Potentially this fixes a possible bug in DT systems, but really
it only affects ACPI systems where the core siblings is correctly
set to the socket siblings. Thus all currently available ACPI
systems should have MC equal to LLC, including the NUMA in socket
machines where the LLC is partitioned between the NUMA nodes.

Signed-off-by: Jeremy Linton <[email protected]>
---
arch/arm64/include/asm/topology.h | 2 ++
arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index 6b10459e6905..df48212f767b 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -8,8 +8,10 @@ struct cpu_topology {
int thread_id;
int core_id;
int package_id;
+ int llc_id;
cpumask_t thread_sibling;
cpumask_t core_sibling;
+ cpumask_t llc_siblings;
};

extern struct cpu_topology cpu_topology[NR_CPUS];
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index bd1aae438a31..20b4341dc527 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -13,6 +13,7 @@

#include <linux/acpi.h>
#include <linux/arch_topology.h>
+#include <linux/cacheinfo.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);

const struct cpumask *cpu_coregroup_mask(int cpu)
{
- return &cpu_topology[cpu].core_sibling;
+ const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
+
+ /* Find the smaller of NUMA, core or LLC siblings */
+ if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
+ /* not numa in package, lets use the package siblings */
+ core_mask = &cpu_topology[cpu].core_sibling;
+ }
+ if (cpu_topology[cpu].llc_id != -1) {
+ if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
+ core_mask = &cpu_topology[cpu].llc_siblings;
+ }
+
+ return core_mask;
}

static void update_siblings_masks(unsigned int cpuid)
@@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
for_each_possible_cpu(cpu) {
cpu_topo = &cpu_topology[cpu];

+ if (cpuid_topo->llc_id == cpu_topo->llc_id)
+ cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
+
if (cpuid_topo->package_id != cpu_topo->package_id)
continue;

@@ -291,6 +307,10 @@ static void __init reset_cpu_topology(void)
cpu_topo->core_id = 0;
cpu_topo->package_id = -1;

+ cpu_topo->llc_id = -1;
+ cpumask_clear(&cpu_topo->llc_siblings);
+ cpumask_set_cpu(cpu, &cpu_topo->llc_siblings);
+
cpumask_clear(&cpu_topo->core_sibling);
cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
cpumask_clear(&cpu_topo->thread_sibling);
@@ -311,6 +331,8 @@ static int __init parse_acpi_topology(void)
is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;

for_each_possible_cpu(cpu) {
+ int i;
+
topology_id = find_acpi_cpu_topology(cpu, 0);
if (topology_id < 0)
return topology_id;
@@ -325,6 +347,14 @@ static int __init parse_acpi_topology(void)
}
topology_id = find_acpi_cpu_topology_package(cpu);
cpu_topology[cpu].package_id = topology_id;
+
+ i = acpi_find_last_cache_level(cpu);
+
+ if (i > 0) {
+ topology_id = find_acpi_cpu_cache_topology(cpu, i);
+ if (topology_id > 0)
+ cpu_topology[cpu].llc_id = topology_id;
+ }
}

return 0;
--
2.13.6


2018-04-26 00:28:35

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 10/13] arm64: topology: rename cluster_id

Lets match the name of the arm64 topology field
to the kernel macro that uses it.

Signed-off-by: Jeremy Linton <[email protected]>
---
arch/arm64/include/asm/topology.h | 4 ++--
arch/arm64/kernel/topology.c | 26 +++++++++++++-------------
2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index c4f2d50491eb..6b10459e6905 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -7,14 +7,14 @@
struct cpu_topology {
int thread_id;
int core_id;
- int cluster_id;
+ int package_id;
cpumask_t thread_sibling;
cpumask_t core_sibling;
};

extern struct cpu_topology cpu_topology[NR_CPUS];

-#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_id)
+#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 21868530018e..dc18b1e53194 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -47,7 +47,7 @@ static int __init get_cpu_for_node(struct device_node *node)
return cpu;
}

-static int __init parse_core(struct device_node *core, int cluster_id,
+static int __init parse_core(struct device_node *core, int package_id,
int core_id)
{
char name[10];
@@ -63,7 +63,7 @@ static int __init parse_core(struct device_node *core, int cluster_id,
leaf = false;
cpu = get_cpu_for_node(t);
if (cpu >= 0) {
- cpu_topology[cpu].cluster_id = cluster_id;
+ cpu_topology[cpu].package_id = package_id;
cpu_topology[cpu].core_id = core_id;
cpu_topology[cpu].thread_id = i;
} else {
@@ -85,7 +85,7 @@ static int __init parse_core(struct device_node *core, int cluster_id,
return -EINVAL;
}

- cpu_topology[cpu].cluster_id = cluster_id;
+ cpu_topology[cpu].package_id = package_id;
cpu_topology[cpu].core_id = core_id;
} else if (leaf) {
pr_err("%pOF: Can't get CPU for leaf core\n", core);
@@ -101,7 +101,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
bool leaf = true;
bool has_cores = false;
struct device_node *c;
- static int cluster_id __initdata;
+ static int package_id __initdata;
int core_id = 0;
int i, ret;

@@ -140,7 +140,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
}

if (leaf) {
- ret = parse_core(c, cluster_id, core_id++);
+ ret = parse_core(c, package_id, core_id++);
} else {
pr_err("%pOF: Non-leaf cluster with core %s\n",
cluster, name);
@@ -158,7 +158,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
pr_warn("%pOF: empty cluster\n", cluster);

if (leaf)
- cluster_id++;
+ package_id++;

return 0;
}
@@ -194,7 +194,7 @@ static int __init parse_dt_topology(void)
* only mark cores described in the DT as possible.
*/
for_each_possible_cpu(cpu)
- if (cpu_topology[cpu].cluster_id == -1)
+ if (cpu_topology[cpu].package_id == -1)
ret = -EINVAL;

out_map:
@@ -224,7 +224,7 @@ static void update_siblings_masks(unsigned int cpuid)
for_each_possible_cpu(cpu) {
cpu_topo = &cpu_topology[cpu];

- if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
+ if (cpuid_topo->package_id != cpu_topo->package_id)
continue;

cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
@@ -245,7 +245,7 @@ void store_cpu_topology(unsigned int cpuid)
struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
u64 mpidr;

- if (cpuid_topo->cluster_id != -1)
+ if (cpuid_topo->package_id != -1)
goto topology_populated;

mpidr = read_cpuid_mpidr();
@@ -259,19 +259,19 @@ void store_cpu_topology(unsigned int cpuid)
/* Multiprocessor system : Multi-threads per core */
cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
+ cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
} else {
/* Multiprocessor system : Single-thread per core */
cpuid_topo->thread_id = -1;
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
+ cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
}

pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
- cpuid, cpuid_topo->cluster_id, cpuid_topo->core_id,
+ cpuid, cpuid_topo->package_id, cpuid_topo->core_id,
cpuid_topo->thread_id, mpidr);

topology_populated:
@@ -287,7 +287,7 @@ static void __init reset_cpu_topology(void)

cpu_topo->thread_id = -1;
cpu_topo->core_id = 0;
- cpu_topo->cluster_id = -1;
+ cpu_topo->package_id = -1;

cpumask_clear(&cpu_topo->core_sibling);
cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
--
2.13.6


2018-04-26 00:28:57

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology

Propagate the topology information from the PPTT tree to the
cpu_topology array. We can get the thread id and core_id by assuming
certain levels of the PPTT tree correspond to those concepts.
The package_id is flagged in the tree and can be found by calling
find_acpi_cpu_topology_package() which terminates
its search when it finds an ACPI node flagged as the physical
package. If the tree doesn't contain enough levels to represent
all of the requested levels then the root node will be returned
for all subsequent levels.

Signed-off-by: Jeremy Linton <[email protected]>
---
arch/arm64/kernel/topology.c | 45 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index dc18b1e53194..bd1aae438a31 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -11,6 +11,7 @@
* for more details.
*/

+#include <linux/acpi.h>
#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
@@ -22,6 +23,7 @@
#include <linux/sched.h>
#include <linux/sched/topology.h>
#include <linux/slab.h>
+#include <linux/smp.h>
#include <linux/string.h>

#include <asm/cpu.h>
@@ -296,6 +298,45 @@ static void __init reset_cpu_topology(void)
}
}

+#ifdef CONFIG_ACPI
+/*
+ * Propagate the topology information of the processor_topology_node tree to the
+ * cpu_topology array.
+ */
+static int __init parse_acpi_topology(void)
+{
+ bool is_threaded;
+ int cpu, topology_id;
+
+ is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
+
+ for_each_possible_cpu(cpu) {
+ topology_id = find_acpi_cpu_topology(cpu, 0);
+ if (topology_id < 0)
+ return topology_id;
+
+ if (is_threaded) {
+ cpu_topology[cpu].thread_id = topology_id;
+ topology_id = find_acpi_cpu_topology(cpu, 1);
+ cpu_topology[cpu].core_id = topology_id;
+ } else {
+ cpu_topology[cpu].thread_id = -1;
+ cpu_topology[cpu].core_id = topology_id;
+ }
+ topology_id = find_acpi_cpu_topology_package(cpu);
+ cpu_topology[cpu].package_id = topology_id;
+ }
+
+ return 0;
+}
+
+#else
+static inline int __init parse_acpi_topology(void)
+{
+ return -EINVAL;
+}
+#endif
+
void __init init_cpu_topology(void)
{
reset_cpu_topology();
@@ -304,6 +345,8 @@ void __init init_cpu_topology(void)
* Discard anything that was parsed if we hit an error so we
* don't use partial information.
*/
- if (of_have_populated_dt() && parse_dt_topology())
+ if ((!acpi_disabled) && parse_acpi_topology())
+ reset_cpu_topology();
+ else if (of_have_populated_dt() && parse_dt_topology())
reset_cpu_topology();
}
--
2.13.6


2018-04-26 00:29:01

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 09/13] ACPI/PPTT: Add topology parsing code

The PPTT can be used to determine the groupings of CPU's at
given levels in the system. Lets add a few routines to the PPTT
parsing code to return a unique id for each unique level in the
processor hierarchy. This can then be matched to build
thread/core/cluster/die/package/etc mappings for each processing
element in the system.

Signed-off-by: Jeremy Linton <[email protected]>
---
drivers/acpi/pptt.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 4 ++
2 files changed, 164 insertions(+)

diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index cced71ef851a..0fc4b2654665 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -453,6 +453,86 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table,
}
}

+/* Passing level values greater than this will result in search termination */
+#define PPTT_ABORT_PACKAGE 0xFF
+
+/**
+ * acpi_find_processor_package_id() - Locate the processor structure for a cpu
+ *
+ * Given an 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 or the search is terminated with a flag match
+ * The level parameter also serves to limit possible loops within the tree.
+ *
+ * Return: acpi_pptt_processor* describing the passed core or NULL
+ */
+static struct acpi_pptt_processor *acpi_find_processor_package_id(struct acpi_table_header *table_hdr,
+ struct acpi_pptt_processor *cpu,
+ int level, int flag)
+{
+ struct acpi_pptt_processor *prev_node;
+
+ while (cpu && level) {
+ if (cpu->flags & flag)
+ break;
+ 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;
+}
+
+/**
+ * topology_get_acpi_cpu_tag() - Find a unique topology value for a feature
+ *
+ * Get a unique value given a cpu, and a topology level, that can be
+ * matched to determine which cpus share common topological features
+ * at that level.
+ *
+ * Return: Unique value, or -ENOENT if unable to locate cpu
+ */
+static int topology_get_acpi_cpu_tag(struct acpi_table_header *table,
+ unsigned int cpu, int level, int flag)
+{
+ struct acpi_pptt_processor *cpu_node;
+ u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+
+ cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+ if (cpu_node) {
+ cpu_node = acpi_find_processor_package_id(table, cpu_node,
+ level, flag);
+ /* Only the first level has a guaranteed id */
+ if (level == 0)
+ return cpu_node->acpi_processor_id;
+ return ACPI_PTR_DIFF(cpu_node, table);
+ }
+ pr_warn_once("PPTT table found, but unable to locate core %d (%d)\n",
+ cpu, acpi_cpu_id);
+ return -ENOENT;
+}
+
+static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag)
+{
+ struct acpi_table_header *table;
+ acpi_status status;
+ int retval;
+
+ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ if (ACPI_FAILURE(status)) {
+ pr_warn_once("No PPTT table found, cpu topology may be inaccurate\n");
+ return -ENOENT;
+ }
+ retval = topology_get_acpi_cpu_tag(table, cpu, level, flag);
+ pr_debug("Topology Setup ACPI cpu %d, level %d ret = %d\n",
+ cpu, level, retval);
+ acpi_put_table(table);
+
+ return retval;
+}
+
/**
* acpi_find_last_cache_level() - Determines the number of cache levels for a PE
* @cpu: Kernel logical cpu number
@@ -516,3 +596,83 @@ int cache_setup_acpi(unsigned int cpu)

return status;
}
+
+/**
+ * find_acpi_cpu_topology() - Determine a unique topology value for a given cpu
+ * @cpu: Kernel logical cpu number
+ * @level: The topological level for which we would like a unique ID
+ *
+ * Determine a topology unique ID for each thread/core/cluster/mc_grouping
+ * /socket/etc. This ID can then be used to group peers, which will have
+ * matching ids.
+ *
+ * The search terminates when either the requested level is found or
+ * we reach a root node. Levels beyond the termination point will return the
+ * same unique ID. The unique id for level 0 is the acpi processor id. All
+ * other levels beyond this use a generated value to uniquely identify
+ * a topological feature.
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found.
+ * Otherwise returns a value which represents a unique topological feature.
+ */
+int find_acpi_cpu_topology(unsigned int cpu, int level)
+{
+ return find_acpi_cpu_topology_tag(cpu, level, 0);
+}
+
+/**
+ * find_acpi_cpu_cache_topology() - Determine a unique cache topology value
+ * @cpu: Kernel logical cpu number
+ * @level: The cache level for which we would like a unique ID
+ *
+ * Determine a unique ID for each unified cache in the system
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found.
+ * Otherwise returns a value which represents a unique topological feature.
+ */
+int find_acpi_cpu_cache_topology(unsigned int cpu, int level)
+{
+ struct acpi_table_header *table;
+ struct acpi_pptt_cache *found_cache;
+ acpi_status status;
+ u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+ struct acpi_pptt_processor *cpu_node = NULL;
+ int ret = -1;
+
+ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ if (ACPI_FAILURE(status)) {
+ pr_warn_once("No PPTT table found, topology may be inaccurate\n");
+ return -ENOENT;
+ }
+
+ found_cache = acpi_find_cache_node(table, acpi_cpu_id,
+ CACHE_TYPE_UNIFIED,
+ level,
+ &cpu_node);
+ if (found_cache)
+ ret = ACPI_PTR_DIFF(cpu_node, table);
+
+ acpi_put_table(table);
+
+ return ret;
+}
+
+
+/**
+ * find_acpi_cpu_topology_package() - Determine a unique cpu package value
+ * @cpu: Kernel logical cpu number
+ *
+ * Determine a topology unique package ID for the given cpu.
+ * This ID can then be used to group peers, which will have matching ids.
+ *
+ * The search terminates when either a level is found with the PHYSICAL_PACKAGE
+ * flag set or we reach a root node.
+ *
+ * Return: -ENOENT if the PPTT doesn't exist, or the cpu cannot be found.
+ * Otherwise returns a value which represents the package for this cpu.
+ */
+int find_acpi_cpu_topology_package(unsigned int cpu)
+{
+ return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE,
+ ACPI_PPTT_PHYSICAL_PACKAGE);
+}
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 15bfb15c2fa5..032e12a2fdc2 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1297,4 +1297,8 @@ static inline int lpit_read_residency_count_address(u64 *address)
}
#endif

+int find_acpi_cpu_topology(unsigned int cpu, int level);
+int find_acpi_cpu_topology_package(unsigned int cpu);
+int find_acpi_cpu_cache_topology(unsigned int cpu, int level);
+
#endif /*_LINUX_ACPI_H*/
--
2.13.6


2018-04-26 00:29:15

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 12/13] ACPI: Add PPTT to injectable table list

Add ACPI_SIG_PPTT to the table so initrd's can override the
system topology.

Signed-off-by: Geoffrey Blake <[email protected]>
Signed-off-by: Jeremy Linton <[email protected]>
---
drivers/acpi/tables.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 849c4fb19b03..30d93bf7c6a2 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -457,7 +457,7 @@ static const char * const table_sigs[] = {
ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT,
- ACPI_SIG_NFIT, ACPI_SIG_HMAT, NULL };
+ ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, NULL };

#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)

--
2.13.6


2018-04-26 00:29:34

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 07/13] drivers: base cacheinfo: Add support for ACPI based firmware tables

Call ACPI cache parsing routines from base cacheinfo code if ACPI
is enable. Also stub out cache_setup_acpi() so that individual
architectures can enable ACPI topology parsing.

Signed-off-by: Jeremy Linton <[email protected]>
---
drivers/base/cacheinfo.c | 14 ++++++++++----
include/linux/cacheinfo.h | 10 ++++++++++
2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 597aacb233fc..2880e2ab01f5 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -206,7 +206,7 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
struct cacheinfo *sib_leaf)
{
/*
- * For non-DT systems, assume unique level 1 cache, system-wide
+ * For non-DT/ACPI systems, assume unique level 1 caches, system-wide
* shared caches for all other levels. This will be used only if
* arch specific code has not populated shared_cpu_map
*/
@@ -214,6 +214,11 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
}
#endif

+int __weak cache_setup_acpi(unsigned int cpu)
+{
+ return -ENOTSUPP;
+}
+
static int cache_shared_cpu_map_setup(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
@@ -227,8 +232,8 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
if (of_have_populated_dt())
ret = cache_setup_of_node(cpu);
else if (!acpi_disabled)
- /* No cache property/hierarchy support yet in ACPI */
- ret = -ENOTSUPP;
+ ret = cache_setup_acpi(cpu);
+
if (ret)
return ret;

@@ -279,7 +284,8 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
}
- of_node_put(this_leaf->fw_token);
+ if (of_have_populated_dt())
+ of_node_put(this_leaf->fw_token);
}
}

diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h
index 0c6f658054d2..70ef44669fa3 100644
--- a/include/linux/cacheinfo.h
+++ b/include/linux/cacheinfo.h
@@ -97,6 +97,16 @@ int func(unsigned int cpu) \
struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu);
int init_cache_level(unsigned int cpu);
int populate_cache_leaves(unsigned int cpu);
+int cache_setup_acpi(unsigned int cpu);
+#ifndef CONFIG_ACPI
+static inline int acpi_find_last_cache_level(unsigned int cpu)
+{
+ /* ACPI kernels should be built with PPTT support */
+ return 0;
+}
+#else
+int acpi_find_last_cache_level(unsigned int cpu);
+#endif

const struct attribute_group *cache_get_priv_group(struct cacheinfo *this_leaf);

--
2.13.6


2018-04-26 00:29:49

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 08/13] arm64: Add support for ACPI based firmware tables

The /sys cache entries should support ACPI/PPTT generated cache
topology information. Lets detect ACPI systems and call
an arch specific cache_setup_acpi() routine to update the hardware
probed cache topology.

For arm64, if ACPI is enabled, determine the max number of cache
levels and populate them using the PPTT table if one is available.

Signed-off-by: Jeremy Linton <[email protected]>
Reviewed-by: Sudeep Holla <[email protected]>
---
arch/arm64/kernel/cacheinfo.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c
index 380f2e2fbed5..0bf0a835122f 100644
--- a/arch/arm64/kernel/cacheinfo.c
+++ b/arch/arm64/kernel/cacheinfo.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

+#include <linux/acpi.h>
#include <linux/cacheinfo.h>
#include <linux/of.h>

@@ -46,7 +47,7 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,

static int __init_cache_level(unsigned int cpu)
{
- unsigned int ctype, level, leaves, of_level;
+ unsigned int ctype, level, leaves, fw_level;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);

for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
@@ -59,15 +60,19 @@ static int __init_cache_level(unsigned int cpu)
leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
}

- of_level = of_find_last_cache_level(cpu);
- if (level < of_level) {
+ if (acpi_disabled)
+ fw_level = of_find_last_cache_level(cpu);
+ else
+ fw_level = acpi_find_last_cache_level(cpu);
+
+ if (level < fw_level) {
/*
* some external caches not specified in CLIDR_EL1
* the information may be available in the device tree
* only unified external caches are considered here
*/
- leaves += (of_level - level);
- level = of_level;
+ leaves += (fw_level - level);
+ level = fw_level;
}

this_cpu_ci->num_levels = level;
--
2.13.6


2018-04-26 00:30:33

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 02/13] drivers: base: cacheinfo: setup DT cache properties early

The original intent in cacheinfo was that an architecture
specific populate_cache_leaves() would probe the hardware
and then cache_shared_cpu_map_setup() and
cache_override_properties() would provide firmware help to
extend/expand upon what was probed. Arm64 was really
the only architecture that was working this way, and
with the removal of most of the hardware probing logic it
became clear that it was possible to simplify the logic a bit.

This patch combines the walk of the DT nodes with the
code updating the cache size/line_size and nr_sets.
cache_override_properties() (which was DT specific) is
then removed. The result is that cacheinfo.of_node is
no longer used as a temporary place to hold DT references
for future calls that update cache properties. That change
helps to clarify its one remaining use (matching
cacheinfo nodes that represent shared caches) which
will be used by the ACPI/PPTT code in the following patches.

Signed-off-by: Jeremy Linton <[email protected]>
Acked-by: Sudeep Holla <[email protected]>
---
arch/riscv/kernel/cacheinfo.c | 1 -
drivers/base/cacheinfo.c | 65 +++++++++++++++++++------------------------
2 files changed, 29 insertions(+), 37 deletions(-)

diff --git a/arch/riscv/kernel/cacheinfo.c b/arch/riscv/kernel/cacheinfo.c
index 10ed2749e246..0bc86e5f8f3f 100644
--- a/arch/riscv/kernel/cacheinfo.c
+++ b/arch/riscv/kernel/cacheinfo.c
@@ -20,7 +20,6 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
struct device_node *node,
enum cache_type type, unsigned int level)
{
- this_leaf->of_node = node;
this_leaf->level = level;
this_leaf->type = type;
/* not a sector cache */
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 09ccef7ddc99..a872523e8951 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -71,7 +71,7 @@ static inline int get_cacheinfo_idx(enum cache_type type)
return type;
}

-static void cache_size(struct cacheinfo *this_leaf)
+static void cache_size(struct cacheinfo *this_leaf, struct device_node *np)
{
const char *propname;
const __be32 *cache_size;
@@ -80,13 +80,14 @@ static void cache_size(struct cacheinfo *this_leaf)
ct_idx = get_cacheinfo_idx(this_leaf->type);
propname = cache_type_info[ct_idx].size_prop;

- cache_size = of_get_property(this_leaf->of_node, propname, NULL);
+ cache_size = of_get_property(np, propname, NULL);
if (cache_size)
this_leaf->size = of_read_number(cache_size, 1);
}

/* not cache_line_size() because that's a macro in include/linux/cache.h */
-static void cache_get_line_size(struct cacheinfo *this_leaf)
+static void cache_get_line_size(struct cacheinfo *this_leaf,
+ struct device_node *np)
{
const __be32 *line_size;
int i, lim, ct_idx;
@@ -98,7 +99,7 @@ static void cache_get_line_size(struct cacheinfo *this_leaf)
const char *propname;

propname = cache_type_info[ct_idx].line_size_props[i];
- line_size = of_get_property(this_leaf->of_node, propname, NULL);
+ line_size = of_get_property(np, propname, NULL);
if (line_size)
break;
}
@@ -107,7 +108,7 @@ static void cache_get_line_size(struct cacheinfo *this_leaf)
this_leaf->coherency_line_size = of_read_number(line_size, 1);
}

-static void cache_nr_sets(struct cacheinfo *this_leaf)
+static void cache_nr_sets(struct cacheinfo *this_leaf, struct device_node *np)
{
const char *propname;
const __be32 *nr_sets;
@@ -116,7 +117,7 @@ static void cache_nr_sets(struct cacheinfo *this_leaf)
ct_idx = get_cacheinfo_idx(this_leaf->type);
propname = cache_type_info[ct_idx].nr_sets_prop;

- nr_sets = of_get_property(this_leaf->of_node, propname, NULL);
+ nr_sets = of_get_property(np, propname, NULL);
if (nr_sets)
this_leaf->number_of_sets = of_read_number(nr_sets, 1);
}
@@ -135,32 +136,27 @@ static void cache_associativity(struct cacheinfo *this_leaf)
this_leaf->ways_of_associativity = (size / nr_sets) / line_size;
}

-static bool cache_node_is_unified(struct cacheinfo *this_leaf)
+static bool cache_node_is_unified(struct cacheinfo *this_leaf,
+ struct device_node *np)
{
- return of_property_read_bool(this_leaf->of_node, "cache-unified");
+ return of_property_read_bool(np, "cache-unified");
}

-static void cache_of_override_properties(unsigned int cpu)
+static void cache_of_set_props(struct cacheinfo *this_leaf,
+ struct device_node *np)
{
- int index;
- struct cacheinfo *this_leaf;
- struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
-
- for (index = 0; index < cache_leaves(cpu); index++) {
- this_leaf = this_cpu_ci->info_list + index;
- /*
- * init_cache_level must setup the cache level correctly
- * overriding the architecturally specified levels, so
- * if type is NONE at this stage, it should be unified
- */
- if (this_leaf->type == CACHE_TYPE_NOCACHE &&
- cache_node_is_unified(this_leaf))
- this_leaf->type = CACHE_TYPE_UNIFIED;
- cache_size(this_leaf);
- cache_get_line_size(this_leaf);
- cache_nr_sets(this_leaf);
- cache_associativity(this_leaf);
- }
+ /*
+ * init_cache_level must setup the cache level correctly
+ * overriding the architecturally specified levels, so
+ * if type is NONE at this stage, it should be unified
+ */
+ if (this_leaf->type == CACHE_TYPE_NOCACHE &&
+ cache_node_is_unified(this_leaf, np))
+ this_leaf->type = CACHE_TYPE_UNIFIED;
+ cache_size(this_leaf, np);
+ cache_get_line_size(this_leaf, np);
+ cache_nr_sets(this_leaf, np);
+ cache_associativity(this_leaf);
}

static int cache_setup_of_node(unsigned int cpu)
@@ -193,6 +189,7 @@ static int cache_setup_of_node(unsigned int cpu)
np = of_node_get(np);/* cpu node itself */
if (!np)
break;
+ cache_of_set_props(this_leaf, np);
this_leaf->of_node = np;
index++;
}
@@ -203,7 +200,6 @@ static int cache_setup_of_node(unsigned int cpu)
return 0;
}
#else
-static void cache_of_override_properties(unsigned int cpu) { }
static inline int cache_setup_of_node(unsigned int cpu) { return 0; }
static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
struct cacheinfo *sib_leaf)
@@ -286,12 +282,6 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
}
}

-static void cache_override_properties(unsigned int cpu)
-{
- if (of_have_populated_dt())
- return cache_of_override_properties(cpu);
-}
-
static void free_cache_attributes(unsigned int cpu)
{
if (!per_cpu_cacheinfo(cpu))
@@ -325,6 +315,10 @@ static int detect_cache_attributes(unsigned int cpu)
if (per_cpu_cacheinfo(cpu) == NULL)
return -ENOMEM;

+ /*
+ * populate_cache_leaves() may completely setup the cache leaves and
+ * shared_cpu_map or it may leave it partially setup.
+ */
ret = populate_cache_leaves(cpu);
if (ret)
goto free_ci;
@@ -338,7 +332,6 @@ static int detect_cache_attributes(unsigned int cpu)
goto free_ci;
}

- cache_override_properties(cpu);
return 0;

free_ci:
--
2.13.6


2018-04-26 00:30:46

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 05/13] ACPI/PPTT: Add Processor Properties Topology Table parsing

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.

An additional patch later in the set adds the ability to report
peers in the topology using find_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, within a given
package, etc.

Signed-off-by: Jeremy Linton <[email protected]>
Acked-by: Sudeep Holla <[email protected]>
---
drivers/acpi/pptt.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 518 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..cced71ef851a
--- /dev/null
+++ b/drivers/acpi/pptt.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pptt.c - parsing of Processor Properties Topology Table
+ *
+ * Copyright (C) 2018, ARM
+ *
+ * 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.
+ *
+ * The PPTT structure is an inverted tree, with each node potentially
+ * holding one or two inverted tree data structures describing
+ * the caches available at that level. Each cache structure optionally
+ * contains properties describing the cache at a given level which can be
+ * used to override hardware probed values.
+ */
+#define pr_fmt(fmt) "ACPI PPTT: " fmt
+
+#include <linux/acpi.h>
+#include <linux/cacheinfo.h>
+#include <acpi/processor.h>
+
+/**
+ * fetch_pptt_subtable() - Find/Verify that the PPTT ref is a valid subtable
+ *
+ * Given the PPTT table, find and verify that the subtable entry
+ * is located within the table
+ *
+ * Return: acpi_subtable_header* or NULL
+ */
+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 < sizeof(struct acpi_subtable_header))
+ return NULL;
+
+ if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length)
+ return NULL;
+
+ entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, pptt_ref);
+
+ if (entry->length == 0)
+ return NULL;
+
+ 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 = ACPI_ADD_PTR(u32, node, sizeof(struct acpi_pptt_processor));
+ ref += resource;
+
+ return fetch_pptt_subtable(table_hdr, *ref);
+}
+
+/**
+ * acpi_pptt_match_type() - Return true if the PPTT type matches the request
+ *
+ * Match the type passed and special case the TYPE_UNIFIED so that
+ * it match both ACPI_PPTT_CACHE_TYPE_UNIFIED(_ALT) types.
+ *
+ * Return: true for match, false otherwise
+ */
+static inline bool acpi_pptt_match_type(int table_type, int type)
+{
+ return ((table_type & ACPI_PPTT_MASK_CACHE_TYPE) == type ||
+ table_type & ACPI_PPTT_CACHE_TYPE_UNIFIED & type);
+}
+
+/**
+ * acpi_pptt_walk_cache() - Attempt to find the requested acpi_pptt_cache
+ *
+ * Attempt to find a given cache level, while counting the max number
+ * of cache levels for the cache node.
+ *
+ * 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.
+ *
+ * Return: The cache structure and the level we terminated with.
+ */
+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 &&
+ acpi_pptt_match_type(cache->attributes, type)) {
+ if (*found != NULL && cache != *found)
+ pr_warn("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;
+}
+
+/**
+ * acpi_find_cache_level() - Given the cpu find a given cache node
+ *
+ * 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.
+ *
+ * Return: NULL or the cache node requested.
+ */
+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 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;
+}
+
+/**
+ * acpi_process_node() - Given a PPTT table, and a cpu node, count the caches
+ *
+ * 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.
+ *
+ * Return: Total number of levels found.
+ */
+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;
+}
+
+/**
+ * acpi_pptt_leaf_node() - Given a processor node, determine if its a leaf
+ *
+ * Determine if the *node parameter is a leaf node by iterating the
+ * PPTT table, looking for nodes which reference it.
+ *
+ * Return: 0 if we find a node referencing the passed node (or table error),
+ * or 1 if we don't.
+ */
+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;
+ u32 proc_sz;
+
+ table_end = (unsigned long)table_hdr + table_hdr->length;
+ node_entry = ACPI_PTR_DIFF(node, table_hdr);
+ entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr,
+ sizeof(struct acpi_table_pptt));
+ proc_sz = sizeof(struct acpi_pptt_processor *);
+
+ while ((unsigned long)entry + proc_sz < table_end) {
+ cpu_node = (struct acpi_pptt_processor *)entry;
+ if (entry->type == ACPI_PPTT_TYPE_PROCESSOR &&
+ cpu_node->parent == node_entry)
+ return 0;
+ if (entry->length == 0)
+ return 0;
+ entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
+ entry->length);
+
+ }
+ return 1;
+}
+
+/**
+ * acpi_find_processor_node() - Given a PPTT table find the requested processor
+ *
+ * Find the subtable entry describing the provided processor.
+ * This is done by iterating the PPTT table looking for processor nodes
+ * which have an acpi_processor_id that matches the acpi_cpu_id parameter
+ * passed into the function. If we find a node that matches this criteria
+ * we verify that its a leaf node in the topology rather than depending
+ * on the valid flag, which doesn't need to be set for leaf nodes.
+ *
+ * Return: NULL, or the processors acpi_pptt_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;
+ u32 proc_sz;
+
+ table_end = (unsigned long)table_hdr + table_hdr->length;
+ entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr,
+ sizeof(struct acpi_table_pptt));
+ proc_sz = sizeof(struct acpi_pptt_processor *);
+
+ /* find the processor structure associated with this cpuid */
+ while ((unsigned long)entry + proc_sz < table_end) {
+ cpu_node = (struct acpi_pptt_processor *)entry;
+
+ if (entry->length == 0) {
+ pr_warn("Invalid zero length subtable\n");
+ break;
+ }
+ if (entry->type == ACPI_PPTT_TYPE_PROCESSOR &&
+ acpi_cpu_id == cpu_node->acpi_processor_id &&
+ acpi_pptt_leaf_node(table_hdr, cpu_node)) {
+ return (struct acpi_pptt_processor *)entry;
+ }
+
+ entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
+ entry->length);
+ }
+
+ return NULL;
+}
+
+static int acpi_find_cache_levels(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;
+}
+
+/* Convert the linux cache_type to a ACPI PPTT cache type value */
+static u8 acpi_cache_type(enum cache_type type)
+{
+ switch (type) {
+ case CACHE_TYPE_DATA:
+ pr_debug("Looking for data cache\n");
+ return ACPI_PPTT_CACHE_TYPE_DATA;
+ case CACHE_TYPE_INST:
+ pr_debug("Looking for instruction cache\n");
+ return ACPI_PPTT_CACHE_TYPE_INSTR;
+ default:
+ case CACHE_TYPE_UNIFIED:
+ pr_debug("Looking for unified cache\n");
+ /*
+ * It is important that ACPI_PPTT_CACHE_TYPE_UNIFIED
+ * contains the bit pattern that will match both
+ * ACPI unified bit patterns because we use it later
+ * to match both cases.
+ */
+ return ACPI_PPTT_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);
+
+ while (cpu_node && !found) {
+ found = acpi_find_cache_level(table_hdr, cpu_node,
+ &total_levels, level, acpi_type);
+ *node = cpu_node;
+ cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
+ }
+
+ return found;
+}
+
+/* total number of attributes checked by the properties code */
+#define PPTT_CHECKED_ATTRIBUTES 4
+
+/**
+ * update_cache_properties() - Update cacheinfo for the given processor
+ *
+ * The ACPI spec implies that the fields in the cache structures are used to
+ * extend and correct the information probed from the hardware. Lets only
+ * set fields that we determine are VALID.
+ *
+ * Return: nothing. Side effect of updating the global cacheinfo
+ */
+static void update_cache_properties(struct cacheinfo *this_leaf,
+ struct acpi_pptt_cache *found_cache,
+ struct acpi_pptt_processor *cpu_node)
+{
+ int valid_flags = 0;
+
+ this_leaf->fw_token = cpu_node;
+ if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) {
+ this_leaf->size = found_cache->size;
+ valid_flags++;
+ }
+ if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID) {
+ this_leaf->coherency_line_size = found_cache->line_size;
+ valid_flags++;
+ }
+ if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID) {
+ this_leaf->number_of_sets = found_cache->number_of_sets;
+ valid_flags++;
+ }
+ if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID) {
+ this_leaf->ways_of_associativity = found_cache->associativity;
+ valid_flags++;
+ }
+ if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID) {
+ switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) {
+ case ACPI_PPTT_CACHE_POLICY_WT:
+ this_leaf->attributes = CACHE_WRITE_THROUGH;
+ break;
+ case ACPI_PPTT_CACHE_POLICY_WB:
+ this_leaf->attributes = CACHE_WRITE_BACK;
+ break;
+ }
+ }
+ if (found_cache->flags & ACPI_PPTT_ALLOCATION_TYPE_VALID) {
+ switch (found_cache->attributes & ACPI_PPTT_MASK_ALLOCATION_TYPE) {
+ case ACPI_PPTT_CACHE_READ_ALLOCATE:
+ this_leaf->attributes |= CACHE_READ_ALLOCATE;
+ break;
+ case ACPI_PPTT_CACHE_WRITE_ALLOCATE:
+ this_leaf->attributes |= CACHE_WRITE_ALLOCATE;
+ break;
+ case ACPI_PPTT_CACHE_RW_ALLOCATE:
+ case ACPI_PPTT_CACHE_RW_ALLOCATE_ALT:
+ this_leaf->attributes |=
+ CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE;
+ break;
+ }
+ }
+ /*
+ * If the above flags are valid, and the cache type is NOCACHE
+ * update the cache type as well.
+ */
+ if (this_leaf->type == CACHE_TYPE_NOCACHE &&
+ valid_flags == PPTT_CHECKED_ATTRIBUTES)
+ this_leaf->type = CACHE_TYPE_UNIFIED;
+}
+
+/*
+ * Update the kernel cache information for each level of cache
+ * associated with the given acpi cpu.
+ */
+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 = get_acpi_id_for_cpu(cpu);
+ 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++;
+ }
+}
+
+/**
+ * acpi_find_last_cache_level() - Determines the number of cache levels for a PE
+ * @cpu: Kernel logical cpu number
+ *
+ * Given a logical cpu number, returns the number of levels of cache represented
+ * in the PPTT. Errors caused by lack of a PPTT table, or otherwise, return 0
+ * indicating we didn't find any cache levels.
+ *
+ * Return: Cache levels visible to this core.
+ */
+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 = get_acpi_id_for_cpu(cpu);
+ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
+ if (ACPI_FAILURE(status)) {
+ pr_warn_once("No PPTT table found, cache topology may be inaccurate\n");
+ } else {
+ number_of_levels = acpi_find_cache_levels(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;
+}
+
+/**
+ * cache_setup_acpi() - Override CPU cache topology with data from the PPTT
+ * @cpu: Kernel logical cpu number
+ *
+ * Updates the global cache info provided by cpu_get_cacheinfo()
+ * when there are valid properties in the acpi_pptt_cache nodes. A
+ * successful parse may not result in any updates if none of the
+ * cache levels have any valid flags set. Futher, a unique value is
+ * associated with each known CPU cache entry. This unique value
+ * can be used to determine whether caches are shared between cpus.
+ *
+ * Return: -ENOENT on failure to find table, or 0 on success
+ */
+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_warn_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;
+}
--
2.13.6


2018-04-26 00:31:17

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 06/13] ACPI: Enable PPTT support on ARM64

Now that we have a PPTT parser, in preparation for its use
on arm64, lets build it.

Signed-off-by: Jeremy Linton <[email protected]>
Reviewed-by: Sudeep Holla <[email protected]>
---
arch/arm64/Kconfig | 1 +
drivers/acpi/Kconfig | 3 +++
drivers/acpi/Makefile | 1 +
3 files changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index eb2cf4938f6d..cff33d9eff0c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -7,6 +7,7 @@ config ARM64
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ACPI_MCFG if ACPI
select ACPI_SPCR_TABLE if ACPI
+ select ACPI_PPTT if ACPI
select ARCH_CLOCKSOURCE_DATA
select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEVMEM_IS_ALLOWED
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 516d7b36d6fb..b533eeb6139d 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -547,6 +547,9 @@ config ACPI_CONFIGFS

if ARM64
source "drivers/acpi/arm64/Kconfig"
+
+config ACPI_PPTT
+ bool
endif

config TPS68470_PMIC_OPREGION
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 48e202752754..6d59aa109a91 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o
obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
+obj-$(CONFIG_ACPI_PPTT) += pptt.o

# processor has its own "processor." module_param namespace
processor-y := processor_driver.o
--
2.13.6


2018-04-26 00:31:28

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 04/13] arm64/acpi: Create arch specific cpu to acpi id helper

Its helpful to be able to lookup the acpi_processor_id associated
with a logical cpu. Provide an arm64 helper to do this.

Signed-off-by: Jeremy Linton <[email protected]>
---
arch/arm64/include/asm/acpi.h | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 32f465a80e4e..0db62a4cbce2 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -86,6 +86,10 @@ static inline bool acpi_has_cpu_in_madt(void)
}

struct acpi_madt_generic_interrupt *acpi_cpu_get_madt_gicc(int cpu);
+static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
+{
+ return acpi_cpu_get_madt_gicc(cpu)->uid;
+}

static inline void arch_fix_phys_package_id(int num, u32 slot) { }
void __init acpi_init_cpus(void);
--
2.13.6


2018-04-26 00:32:20

by Jeremy Linton

[permalink] [raw]
Subject: [PATCH v8 01/13] drivers: base: cacheinfo: move cache_setup_of_node()

In preparation for the next patch, and to aid in
review of that patch, lets move cache_setup_of_node
further down in the module without any changes.

Signed-off-by: Jeremy Linton <[email protected]>
Reviewed-by: Sudeep Holla <[email protected]>
---
drivers/base/cacheinfo.c | 80 ++++++++++++++++++++++++------------------------
1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index edf726267282..09ccef7ddc99 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -32,46 +32,6 @@ struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu)
}

#ifdef CONFIG_OF
-static int cache_setup_of_node(unsigned int cpu)
-{
- struct device_node *np;
- struct cacheinfo *this_leaf;
- struct device *cpu_dev = get_cpu_device(cpu);
- struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
- unsigned int index = 0;
-
- /* skip if of_node is already populated */
- if (this_cpu_ci->info_list->of_node)
- return 0;
-
- if (!cpu_dev) {
- pr_err("No cpu device for CPU %d\n", cpu);
- return -ENODEV;
- }
- np = cpu_dev->of_node;
- if (!np) {
- pr_err("Failed to find cpu%d device node\n", cpu);
- return -ENOENT;
- }
-
- while (index < cache_leaves(cpu)) {
- this_leaf = this_cpu_ci->info_list + index;
- if (this_leaf->level != 1)
- np = of_find_next_cache_node(np);
- else
- np = of_node_get(np);/* cpu node itself */
- if (!np)
- break;
- this_leaf->of_node = np;
- index++;
- }
-
- if (index != cache_leaves(cpu)) /* not all OF nodes populated */
- return -ENOENT;
-
- return 0;
-}
-
static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
struct cacheinfo *sib_leaf)
{
@@ -202,6 +162,46 @@ static void cache_of_override_properties(unsigned int cpu)
cache_associativity(this_leaf);
}
}
+
+static int cache_setup_of_node(unsigned int cpu)
+{
+ struct device_node *np;
+ struct cacheinfo *this_leaf;
+ struct device *cpu_dev = get_cpu_device(cpu);
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ unsigned int index = 0;
+
+ /* skip if of_node is already populated */
+ if (this_cpu_ci->info_list->of_node)
+ return 0;
+
+ if (!cpu_dev) {
+ pr_err("No cpu device for CPU %d\n", cpu);
+ return -ENODEV;
+ }
+ np = cpu_dev->of_node;
+ if (!np) {
+ pr_err("Failed to find cpu%d device node\n", cpu);
+ return -ENOENT;
+ }
+
+ while (index < cache_leaves(cpu)) {
+ this_leaf = this_cpu_ci->info_list + index;
+ if (this_leaf->level != 1)
+ np = of_find_next_cache_node(np);
+ else
+ np = of_node_get(np);/* cpu node itself */
+ if (!np)
+ break;
+ this_leaf->of_node = np;
+ index++;
+ }
+
+ if (index != cache_leaves(cpu)) /* not all OF nodes populated */
+ return -ENOENT;
+
+ return 0;
+}
#else
static void cache_of_override_properties(unsigned int cpu) { }
static inline int cache_setup_of_node(unsigned int cpu) { return 0; }
--
2.13.6


2018-04-26 07:59:05

by Ard Biesheuvel

[permalink] [raw]
Subject: Re: [PATCH v8 00/13] Support PPTT for ARM64

On 26 April 2018 at 01:31, Jeremy Linton <[email protected]> wrote:
> ACPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
> used to describe the processor and cache topology. Ideally it is
> used to extend/override information provided by the hardware, but
> right now ARM64 is entirely dependent on firmware provided tables.
>
> This patch parses the table for the cache topology and CPU topology.
> When we enable ACPI/PPTT for arm64 we map the package_id to the
> PPTT node flagged as the physical package by the firmware.
> This results in topologies that match what the remainder of the
> system expects. Finally, we update the scheduler MC domain so that
> it generally reflects the LLC unless the LLC is too large for the
> NUMA domain (or package).
>

Acked-by: Ard Biesheuvel <[email protected]>
Tested-by: Ard Biesheuvel <[email protected]> # SynQuacer

Machine (7974MB)
Package L#0 + L3 L#0 (4096KB)
L2 L#0 (256KB)
L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
L2 L#1 (256KB)
L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
L2 L#2 (256KB)
L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4 + PU L#4 (P#4)
L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5 + PU L#5 (P#5)
L2 L#3 (256KB)
L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6 + PU L#6 (P#6)
L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7 + PU L#7 (P#7)
L2 L#4 (256KB)
L1d L#8 (32KB) + L1i L#8 (32KB) + Core L#8 + PU L#8 (P#8)
L1d L#9 (32KB) + L1i L#9 (32KB) + Core L#9 + PU L#9 (P#9)
L2 L#5 (256KB)
L1d L#10 (32KB) + L1i L#10 (32KB) + Core L#10 + PU L#10 (P#10)
L1d L#11 (32KB) + L1i L#11 (32KB) + Core L#11 + PU L#11 (P#11)
L2 L#6 (256KB)
L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12 + PU L#12 (P#12)
L1d L#13 (32KB) + L1i L#13 (32KB) + Core L#13 + PU L#13 (P#13)
L2 L#7 (256KB)
L1d L#14 (32KB) + L1i L#14 (32KB) + Core L#14 + PU L#14 (P#14)
L1d L#15 (32KB) + L1i L#15 (32KB) + Core L#15 + PU L#15 (P#15)
L2 L#8 (256KB)
L1d L#16 (32KB) + L1i L#16 (32KB) + Core L#16 + PU L#16 (P#16)
L1d L#17 (32KB) + L1i L#17 (32KB) + Core L#17 + PU L#17 (P#17)
L2 L#9 (256KB)
L1d L#18 (32KB) + L1i L#18 (32KB) + Core L#18 + PU L#18 (P#18)
L1d L#19 (32KB) + L1i L#19 (32KB) + Core L#19 + PU L#19 (P#19)
L2 L#10 (256KB)
L1d L#20 (32KB) + L1i L#20 (32KB) + Core L#20 + PU L#20 (P#20)
L1d L#21 (32KB) + L1i L#21 (32KB) + Core L#21 + PU L#21 (P#21)
L2 L#11 (256KB)
L1d L#22 (32KB) + L1i L#22 (32KB) + Core L#22 + PU L#22 (P#22)
L1d L#23 (32KB) + L1i L#23 (32KB) + Core L#23 + PU L#23 (P#23)
HostBridge L#0
PCIBridge
PCIBridge
PCI 1b21:0612
Block(Removable Media Device) L#0 "sr0"
Block(Disk) L#1 "sda"
PCIBridge
PCI 168c:0032
Net L#2 "wlp3s0"
HostBridge L#4
PCI 10de:128b
GPU L#3 "renderD128"
GPU L#4 "card0"
GPU L#5 "controlD64"


> For example on juno:
> [root@mammon-juno-rh topology]# lstopo-no-graphics
> Package L#0
> L2 L#0 (1024KB)
> L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
> L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
> L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
> L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
> L2 L#1 (2048KB)
> L1d L#4 (32KB) + L1i L#4 (48KB) + Core L#4 + PU L#4 (P#4)
> L1d L#5 (32KB) + L1i L#5 (48KB) + Core L#5 + PU L#5 (P#5)
> HostBridge L#0
> PCIBridge
> PCIBridge
> PCIBridge
> PCI 1095:3132
> Block(Disk) L#0 "sda"
> PCIBridge
> PCI 1002:68f9
> GPU L#1 "renderD128"
> GPU L#2 "card0"
> GPU L#3 "controlD64"
> PCIBridge
> PCI 11ab:4380
> Net L#4 "enp8s0"
>
> Git tree at:
> http://linux-arm.org/git?p=linux-jlinton.git
> branch: pptt_v8
>
> v7->v8:
> Modify the logic used to select the MC domain (the change
> shouldn't modify the sched domains on any existing machines
> compared to v7, only how they are built)
> Reduce the severity of some parsing messages.
> Fix s390 link problem.
> Further checks to deal with broken PPTT tables.
> Various style tweaks, SPDX license addition, etc.
>
> v6->v7:
> Add additional patch to use the last cache level within the NUMA
> or socket as the MC domain. This assures the MC domain is
> equal or smaller than the DIE.
>
> Various formatting/etc review comments.
>
> Rebase to 4.16rc2
>
> v5->v6:
> Add additional patches which re-factor how the initial DT code sets
> up the cacheinfo structure so that its not as dependent on the
> of_node stored in that tree. Once that is done we rename it
> for use with the ACPI code.
>
> Additionally there were a fair number of minor name/location/etc
> tweaks scattered about made in response to review comments.
>
> v4->v5:
> Update the cache type from NOCACHE to UNIFIED when all the cache
> attributes we update are valid. This fixes a problem where caches
> which are entirely created by the PPTT don't show up in lstopo.
>
> Give the PPTT its own firmware_node in the cache structure instead of
> sharing it with the of_node.
>
> Move some pieces around between patches.
>
> (see previous cover letters for futher changes)
>
> Jeremy Linton (13):
> drivers: base: cacheinfo: move cache_setup_of_node()
> drivers: base: cacheinfo: setup DT cache properties early
> cacheinfo: rename of_node to fw_token
> arm64/acpi: Create arch specific cpu to acpi id helper
> ACPI/PPTT: Add Processor Properties Topology Table parsing
> ACPI: Enable PPTT support on ARM64
> drivers: base cacheinfo: Add support for ACPI based firmware tables
> arm64: Add support for ACPI based firmware tables
> ACPI/PPTT: Add topology parsing code
> arm64: topology: rename cluster_id
> arm64: topology: enable ACPI/PPTT based CPU topology
> ACPI: Add PPTT to injectable table list
> arm64: topology: divorce MC scheduling domain from core_siblings
>
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/acpi.h | 4 +
> arch/arm64/include/asm/topology.h | 6 +-
> arch/arm64/kernel/cacheinfo.c | 15 +-
> arch/arm64/kernel/topology.c | 103 +++++-
> arch/riscv/kernel/cacheinfo.c | 1 -
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/pptt.c | 678 ++++++++++++++++++++++++++++++++++++++
> drivers/acpi/tables.c | 2 +-
> drivers/base/cacheinfo.c | 157 ++++-----
> include/linux/acpi.h | 4 +
> include/linux/cacheinfo.h | 18 +-
> 13 files changed, 886 insertions(+), 107 deletions(-)
> create mode 100644 drivers/acpi/pptt.c
>
> --
> 2.13.6
>

2018-04-26 10:28:58

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 04/13] arm64/acpi: Create arch specific cpu to acpi id helper



On 26/04/18 00:31, Jeremy Linton wrote:
> Its helpful to be able to lookup the acpi_processor_id associated
> with a logical cpu. Provide an arm64 helper to do this.
>

As I pointed out in the earlier version, this patch is not required.
The acpi_id stored in the acpi_processor can be used for this.
Won't the below change make it work ? I can't think of any reason why it
shouldn't.

Regards,
Sudeep

-->8

diff --git i/drivers/acpi/pptt.c w/drivers/acpi/pptt.c
index 0fc4b2654665..f421f58b4ae6 100644
--- i/drivers/acpi/pptt.c
+++ w/drivers/acpi/pptt.c
@@ -432,7 +432,7 @@ static void cache_setup_acpi_cpu(struct
acpi_table_header *table,
{
struct acpi_pptt_cache *found_cache;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
- u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
+ u32 acpi_cpu_id = per_cpu(processors, cpu)->acpi_id;
struct cacheinfo *this_leaf;
unsigned int index = 0;
struct acpi_pptt_processor *cpu_node = NULL;

2018-04-26 11:07:24

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 07/13] drivers: base cacheinfo: Add support for ACPI based firmware tables



On 26/04/18 00:31, Jeremy Linton wrote:
> Call ACPI cache parsing routines from base cacheinfo code if ACPI
> is enable. Also stub out cache_setup_acpi() so that individual
> architectures can enable ACPI topology parsing.
>

[...]

> +#ifndef CONFIG_ACPI
> +static inline int acpi_find_last_cache_level(unsigned int cpu)
> +{
> + /* ACPI kernels should be built with PPTT support */

This sounds incorrect for x86. But I understand why you have it there.
Does it makes sense to change above to .. ?

#if !defined(CONFIG_ACPI) || (defined(CONFIG_ACPI) && !(CONFIG_ACPI_PPTT))

--
Regards,
Sudeep

2018-04-26 18:35:59

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 04/13] arm64/acpi: Create arch specific cpu to acpi id helper

Hi,

On 04/26/2018 05:27 AM, Sudeep Holla wrote:
>
>
> On 26/04/18 00:31, Jeremy Linton wrote:
>> Its helpful to be able to lookup the acpi_processor_id associated
>> with a logical cpu. Provide an arm64 helper to do this.
>>
>
> As I pointed out in the earlier version, this patch is not required.
> The acpi_id stored in the acpi_processor can be used for this.
> Won't the below change make it work ? I can't think of any reason why it
> shouldn't.

So, I only noticed your previous email last night on the mail archive,
as I was applying your review/ack tags and couldn't find a response for
this patch, seem the spam/etc filters need some further tweaking!

At that point, I was pretty sure the suggestion wasn't going to work out
of the box as a lot of this code is running fairly early in the boot
process. I spent a bit of time and plugged the change in to verify that
assertion, and yes the per_cpu processor/acpi bits aren't setup early
enough to be used by much of this code. It is being called from
init_cpu_topology()/smp_prepare_cpus() which precedes
do_basic_setup/do_initcalls() which is what runs the acpi_init()
sequence which ends up eventually allocating the required data
structures. So without restructuring the core boot sequence, this seems
like a reasonable solution.


Thanks,


>
> Regards,
> Sudeep
>
> -->8
>
> diff --git i/drivers/acpi/pptt.c w/drivers/acpi/pptt.c
> index 0fc4b2654665..f421f58b4ae6 100644
> --- i/drivers/acpi/pptt.c
> +++ w/drivers/acpi/pptt.c
> @@ -432,7 +432,7 @@ static void cache_setup_acpi_cpu(struct
> acpi_table_header *table,
> {
> struct acpi_pptt_cache *found_cache;
> struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
> - u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
> + u32 acpi_cpu_id = per_cpu(processors, cpu)->acpi_id;
> struct cacheinfo *this_leaf;
> unsigned int index = 0;
> struct acpi_pptt_processor *cpu_node = NULL;
>


2018-04-26 18:58:52

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 07/13] drivers: base cacheinfo: Add support for ACPI based firmware tables

Hi,

On 04/26/2018 06:05 AM, Sudeep Holla wrote:
>
>
> On 26/04/18 00:31, Jeremy Linton wrote:
>> Call ACPI cache parsing routines from base cacheinfo code if ACPI
>> is enable. Also stub out cache_setup_acpi() so that individual
>> architectures can enable ACPI topology parsing.
>>
>
> [...]
>
>> +#ifndef CONFIG_ACPI
>> +static inline int acpi_find_last_cache_level(unsigned int cpu)
>> +{
>> + /* ACPI kernels should be built with PPTT support */
>
> This sounds incorrect for x86. But I understand why you have it there.
> Does it makes sense to change above to .. ?
>
> #if !defined(CONFIG_ACPI) || (defined(CONFIG_ACPI) && !(CONFIG_ACPI_PPTT))
>
I'm not sure what that buys us, if anything you want more non-users of
the function to be falling through to the function prototype rather than
the static inline. The only place any of this matters (as long as the
compiler/linker is tossing the static inline) is arm64 because its the
only arch making a call to acpi_find_last_cache_level(). ACPI_PPTT is
also only visible on arm64 at the moment due to being wrapped in a if
ARM64 in the Kconfig

Put another way, I wouldn't expect an arch to have a 'user' visible
option to enable/disable parsing the PPTT. If an arch can handle
ACPI/PPTT topology then I would expect it to be fixed to the CONFIG_ACPI
state. What happens when acpi_find_last_cache_level() is called should
only be dependent on whether ACPI is enabled, the PPTT parser itself
will handle the cases of a missing table.

2018-04-27 11:04:33

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v8 05/13] ACPI/PPTT: Add Processor Properties Topology Table parsing

On Thu, Apr 26, 2018 at 1:31 AM, Jeremy Linton <[email protected]> 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.
>
> An additional patch later in the set adds the ability to report
> peers in the topology using find_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, within a given
> package, etc.
>
> Signed-off-by: Jeremy Linton <[email protected]>
> Acked-by: Sudeep Holla <[email protected]>
> ---
> drivers/acpi/pptt.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 518 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..cced71ef851a
> --- /dev/null
> +++ b/drivers/acpi/pptt.c
> @@ -0,0 +1,518 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * pptt.c - parsing of Processor Properties Topology Table
> + *
> + * Copyright (C) 2018, ARM
> + *
> + * 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.
> + *
> + * The PPTT structure is an inverted tree, with each node potentially
> + * holding one or two inverted tree data structures describing
> + * the caches available at that level. Each cache structure optionally
> + * contains properties describing the cache at a given level which can be
> + * used to override hardware probed values.
> + */
> +#define pr_fmt(fmt) "ACPI PPTT: " fmt
> +
> +#include <linux/acpi.h>
> +#include <linux/cacheinfo.h>
> +#include <acpi/processor.h>
> +
> +/**
> + * fetch_pptt_subtable() - Find/Verify that the PPTT ref is a valid subtable

The parens above are at least redundant (if not harmful). Everywhere
else in a similar context too.

Also kerneldoc comments document function arguments too as a rule, so
please do that here and wherever you use kerneldoc comments in the
patchset.

> + *
> + * Given the PPTT table, find and verify that the subtable entry
> + * is located within the table
> + *
> + * Return: acpi_subtable_header* or NULL
> + */
> +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 < sizeof(struct acpi_subtable_header))
> + return NULL;
> +
> + if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length)
> + return NULL;
> +
> + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, pptt_ref);
> +
> + if (entry->length == 0)
> + return NULL;
> +
> + if (pptt_ref + entry->length > table_hdr->length)
> + return NULL;
> +
> + return entry;
> +}

Apart from the above I'm not entirely sure why you need the changes in
patch [09/13] to go in a separate patch. All of them are new code
going into the file created by this patch, so why not to put them
here?

2018-04-27 12:51:25

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 07/13] drivers: base cacheinfo: Add support for ACPI based firmware tables



On 26/04/18 19:57, Jeremy Linton wrote:
> Hi,
>
> On 04/26/2018 06:05 AM, Sudeep Holla wrote:
>>
>>
>> On 26/04/18 00:31, Jeremy Linton wrote:
>>> Call ACPI cache parsing routines from base cacheinfo code if ACPI
>>> is enable. Also stub out cache_setup_acpi() so that individual
>>> architectures can enable ACPI topology parsing.
>>>
>>
>> [...]
>>
>>> +#ifndef CONFIG_ACPI
>>> +static inline int acpi_find_last_cache_level(unsigned int cpu)
>>> +{
>>> +    /* ACPI kernels should be built with PPTT support */
>>
>> This sounds incorrect for x86. But I understand why you have it there.
>> Does it makes sense to change above to .. ?
>>
>> #if !defined(CONFIG_ACPI) || (defined(CONFIG_ACPI) &&
>> !(CONFIG_ACPI_PPTT))
>>
> I'm not sure what that buys us, if anything you want more non-users of
> the function to be falling through to the function prototype rather than
> the static inline. The only place any of this matters (as long as the
> compiler/linker is tossing the static inline) is arm64 because its the
> only arch making a call to acpi_find_last_cache_level(). ACPI_PPTT is
> also only visible on arm64 at the moment due to being wrapped in a if
> ARM64 in the Kconfig
>

Fair enough.

> Put another way, I wouldn't expect an arch to have a 'user' visible
> option to enable/disable parsing the PPTT. If an arch can handle
> ACPI/PPTT topology then I would expect it to be fixed to the CONFIG_ACPI
> state. What happens when acpi_find_last_cache_level() is called should
> only be dependent on whether ACPI is enabled, the PPTT parser itself
> will handle the cases of a missing table.

Agreed. But technically that statement is still incorrect as x86 ACPI
build need not have PPTT enabled. IMO you can reword it, but I will
leave that to Rafael :)

Other than that, it looks good.

Acked-by: Sudeep Holla <[email protected]>

--
Regards,
Sudeep

2018-04-27 13:09:55

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 04/13] arm64/acpi: Create arch specific cpu to acpi id helper



On 26/04/18 19:33, Jeremy Linton wrote:
> Hi,
>
> On 04/26/2018 05:27 AM, Sudeep Holla wrote:
>>
>>
>> On 26/04/18 00:31, Jeremy Linton wrote:
>>> Its helpful to be able to lookup the acpi_processor_id associated
>>> with a logical cpu. Provide an arm64 helper to do this.
>>>
>>
>> As I pointed out in the earlier version, this patch is not required.
>> The acpi_id stored in the acpi_processor can be used for this.
>> Won't the below change make it work ? I can't think of any reason why it
>> shouldn't.
>
> So, I only noticed your previous email last night on the mail archive,
> as I was applying your review/ack tags and couldn't find a response for
> this patch, seem the spam/etc filters need some further tweaking!
>

Ah that's bad.

> At that point, I was pretty sure the suggestion wasn't going to work out
> of the box as a lot of this code is running fairly early in the boot
> process. I spent a bit of time and plugged the change in to verify that
> assertion, and yes the per_cpu processor/acpi bits aren't setup early
> enough to be used by much of this code. It is being called from
> init_cpu_topology()/smp_prepare_cpus() which precedes
> do_basic_setup/do_initcalls() which is what runs the acpi_init()
> sequence which ends up eventually allocating the required data
> structures. So without restructuring the core boot sequence, this seems
> like a reasonable solution.
>

OK makes sense. I completely ignored topology related patches as I
haven't looked at them yet and assumed cacheinfo is the only user. Sorry
for that.

--
Regards,
Sudeep

2018-04-27 16:22:12

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 05/13] ACPI/PPTT: Add Processor Properties Topology Table parsing

Hi,

Thanks for taking a look at this.

On 04/27/2018 06:02 AM, Rafael J. Wysocki wrote:
> On Thu, Apr 26, 2018 at 1:31 AM, Jeremy Linton <[email protected]> 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.
>>
>> An additional patch later in the set adds the ability to report
>> peers in the topology using find_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, within a given
>> package, etc.
>>
>> Signed-off-by: Jeremy Linton <[email protected]>
>> Acked-by: Sudeep Holla <[email protected]>
>> ---
>> drivers/acpi/pptt.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 518 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..cced71ef851a
>> --- /dev/null
>> +++ b/drivers/acpi/pptt.c
>> @@ -0,0 +1,518 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * pptt.c - parsing of Processor Properties Topology Table
>> + *
>> + * Copyright (C) 2018, ARM
>> + *
>> + * 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.
>> + *
>> + * The PPTT structure is an inverted tree, with each node potentially
>> + * holding one or two inverted tree data structures describing
>> + * the caches available at that level. Each cache structure optionally
>> + * contains properties describing the cache at a given level which can be
>> + * used to override hardware probed values.
>> + */
>> +#define pr_fmt(fmt) "ACPI PPTT: " fmt
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/cacheinfo.h>
>> +#include <acpi/processor.h>
>> +
>> +/**
>> + * fetch_pptt_subtable() - Find/Verify that the PPTT ref is a valid subtable
>
> The parens above are at least redundant (if not harmful). Everywhere
> else in a similar context too.

The kerneldoc ones? I guess i'm confused the kernel doc example in
doc-guide/kernel-doc has

* function_name() - Brief description of function.


>
> Also kerneldoc comments document function arguments too as a rule, so
> please do that here and wherever you use kerneldoc comments in the
> patchset.

Ok, sure.

>
>> + *
>> + * Given the PPTT table, find and verify that the subtable entry
>> + * is located within the table
>> + *
>> + * Return: acpi_subtable_header* or NULL
>> + */
>> +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 < sizeof(struct acpi_subtable_header))
>> + return NULL;
>> +
>> + if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length)
>> + return NULL;
>> +
>> + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, pptt_ref);
>> +
>> + if (entry->length == 0)
>> + return NULL;
>> +
>> + if (pptt_ref + entry->length > table_hdr->length)
>> + return NULL;
>> +
>> + return entry;
>> +}
>
> Apart from the above I'm not entirely sure why you need the changes in
> patch [09/13] to go in a separate patch. All of them are new code
> going into the file created by this patch, so why not to put them
> here?


Ok, I was doing that because Lorenzo asked for it, but he hasn't said
much so I will collapse it back together. That makes me happy, as
splitting chunks between patches is a pain anyway.


2018-04-30 08:00:14

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v8 05/13] ACPI/PPTT: Add Processor Properties Topology Table parsing

On Friday, April 27, 2018 6:20:44 PM CEST Jeremy Linton wrote:
> Hi,
>
> Thanks for taking a look at this.
>
> On 04/27/2018 06:02 AM, Rafael J. Wysocki wrote:
> > On Thu, Apr 26, 2018 at 1:31 AM, Jeremy Linton <[email protected]> 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.
> >>
> >> An additional patch later in the set adds the ability to report
> >> peers in the topology using find_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, within a given
> >> package, etc.
> >>
> >> Signed-off-by: Jeremy Linton <[email protected]>
> >> Acked-by: Sudeep Holla <[email protected]>
> >> ---
> >> drivers/acpi/pptt.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >> 1 file changed, 518 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..cced71ef851a
> >> --- /dev/null
> >> +++ b/drivers/acpi/pptt.c
> >> @@ -0,0 +1,518 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * pptt.c - parsing of Processor Properties Topology Table
> >> + *
> >> + * Copyright (C) 2018, ARM
> >> + *
> >> + * 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.
> >> + *
> >> + * The PPTT structure is an inverted tree, with each node potentially
> >> + * holding one or two inverted tree data structures describing
> >> + * the caches available at that level. Each cache structure optionally
> >> + * contains properties describing the cache at a given level which can be
> >> + * used to override hardware probed values.
> >> + */
> >> +#define pr_fmt(fmt) "ACPI PPTT: " fmt
> >> +
> >> +#include <linux/acpi.h>
> >> +#include <linux/cacheinfo.h>
> >> +#include <acpi/processor.h>
> >> +
> >> +/**
> >> + * fetch_pptt_subtable() - Find/Verify that the PPTT ref is a valid subtable
> >
> > The parens above are at least redundant (if not harmful). Everywhere
> > else in a similar context too.
>
> The kerneldoc ones? I guess i'm confused the kernel doc example in
> doc-guide/kernel-doc has
>
> * function_name() - Brief description of function.

Well, OK, the parens not harmful, then, but it works without them.


2018-05-01 14:35:19

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings



On 26/04/18 00:31, Jeremy Linton wrote:
> Now that we have an accurate view of the physical topology
> we need to represent it correctly to the scheduler. Generally MC
> should equal the LLC in the system, but there are a number of
> special cases that need to be dealt with.
>
> In the case of NUMA in socket, we need to assure that the sched
> domain we build for the MC layer isn't larger than the DIE above it.
> Similarly for LLC's that might exist in cross socket interconnect or
> directory hardware we need to assure that MC is shrunk to the socket
> or NUMA node.
>
> This patch builds a sibling mask for the LLC, and then picks the
> smallest of LLC, socket siblings, or NUMA node siblings, which
> gives us the behavior described above. This is ever so slightly
> different than the similar alternative where we look for a cache
> layer less than or equal to the socket/NUMA siblings.
>
> The logic to pick the MC layer affects all arm64 machines, but
> only changes the behavior for DT/MPIDR systems if the NUMA domain
> is smaller than the core siblings (generally set to the cluster).
> Potentially this fixes a possible bug in DT systems, but really
> it only affects ACPI systems where the core siblings is correctly
> set to the socket siblings. Thus all currently available ACPI
> systems should have MC equal to LLC, including the NUMA in socket
> machines where the LLC is partitioned between the NUMA nodes.
>
> Signed-off-by: Jeremy Linton <[email protected]>
> ---
> arch/arm64/include/asm/topology.h | 2 ++
> arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
> 2 files changed, 33 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
> index 6b10459e6905..df48212f767b 100644
> --- a/arch/arm64/include/asm/topology.h
> +++ b/arch/arm64/include/asm/topology.h
> @@ -8,8 +8,10 @@ struct cpu_topology {
> int thread_id;
> int core_id;
> int package_id;
> + int llc_id;
> cpumask_t thread_sibling;
> cpumask_t core_sibling;
> + cpumask_t llc_siblings;
> };
>
> extern struct cpu_topology cpu_topology[NR_CPUS];
> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> index bd1aae438a31..20b4341dc527 100644
> --- a/arch/arm64/kernel/topology.c
> +++ b/arch/arm64/kernel/topology.c
> @@ -13,6 +13,7 @@
>
> #include <linux/acpi.h>
> #include <linux/arch_topology.h>
> +#include <linux/cacheinfo.h>
> #include <linux/cpu.h>
> #include <linux/cpumask.h>
> #include <linux/init.h>
> @@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);
>
> const struct cpumask *cpu_coregroup_mask(int cpu)
> {
> - return &cpu_topology[cpu].core_sibling;
> + const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
> +
> + /* Find the smaller of NUMA, core or LLC siblings */
> + if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
> + /* not numa in package, lets use the package siblings */
> + core_mask = &cpu_topology[cpu].core_sibling;
> + }
> + if (cpu_topology[cpu].llc_id != -1) {
> + if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
> + core_mask = &cpu_topology[cpu].llc_siblings;
> + }
> +
> + return core_mask;
> }
>
> static void update_siblings_masks(unsigned int cpuid)
> @@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
> for_each_possible_cpu(cpu) {
> cpu_topo = &cpu_topology[cpu];
>
> + if (cpuid_topo->llc_id == cpu_topo->llc_id)
> + cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
> +

Would this not result in cpuid_topo->llc_siblings = cpu_possible_mask
on DT systems where llc_id is not set/defaults to -1 and still pass the
condition. Does it make sense to add additional -1 check ?

> if (cpuid_topo->package_id != cpu_topo->package_id)
> continue;
>
> @@ -291,6 +307,10 @@ static void __init reset_cpu_topology(void)
> cpu_topo->core_id = 0;
> cpu_topo->package_id = -1;
>
> + cpu_topo->llc_id = -1;
> + cpumask_clear(&cpu_topo->llc_siblings);
> + cpumask_set_cpu(cpu, &cpu_topo->llc_siblings);
> +
> cpumask_clear(&cpu_topo->core_sibling);
> cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
> cpumask_clear(&cpu_topo->thread_sibling);
> @@ -311,6 +331,8 @@ static int __init parse_acpi_topology(void)
> is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
>
> for_each_possible_cpu(cpu) {
> + int i;
> +
> topology_id = find_acpi_cpu_topology(cpu, 0);
> if (topology_id < 0)
> return topology_id;
> @@ -325,6 +347,14 @@ static int __init parse_acpi_topology(void)
> }
> topology_id = find_acpi_cpu_topology_package(cpu);
> cpu_topology[cpu].package_id = topology_id;
> +
> + i = acpi_find_last_cache_level(cpu);
> +
> + if (i > 0) {
> + topology_id = find_acpi_cpu_cache_topology(cpu, i);
> + if (topology_id > 0)
> + cpu_topology[cpu].llc_id = topology_id;
> + }

[nit] s/topology_id/cache_id/ or s/topology_id/cache_topology_id/ ?

Otherwise looks fine to me. You can add with above things fixed.

Acked-by: Sudeep Holla <[email protected]>

--
Regards,
Sudeep

2018-05-01 14:41:18

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 10/13] arm64: topology: rename cluster_id



On 26/04/18 00:31, Jeremy Linton wrote:
> Lets match the name of the arm64 topology field
> to the kernel macro that uses it.

[nit] You can add a note that cluster id is not architectural defined
for ARM platforms just to elaborate on the intention for this change.

Acked-by: Sudeep Holla <[email protected]>

--
Regards,
Sudeep

2018-05-01 14:48:18

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology



On 26/04/18 00:31, Jeremy Linton wrote:
> Propagate the topology information from the PPTT tree to the
> cpu_topology array. We can get the thread id and core_id by assuming
> certain levels of the PPTT tree correspond to those concepts.
> The package_id is flagged in the tree and can be found by calling
> find_acpi_cpu_topology_package() which terminates
> its search when it finds an ACPI node flagged as the physical
> package. If the tree doesn't contain enough levels to represent
> all of the requested levels then the root node will be returned
> for all subsequent levels.
>

Acked-by: Sudeep Holla <[email protected]>

[..]

> @@ -304,6 +345,8 @@ void __init init_cpu_topology(void)
> * Discard anything that was parsed if we hit an error so we
> * don't use partial information.
> */
> - if (of_have_populated_dt() && parse_dt_topology())
> + if ((!acpi_disabled) && parse_acpi_topology())

[nit] not sure if extra () is need above, but I am fine either way.

--
Regards,
Sudeep

2018-05-02 08:24:55

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology

On Tue, May 1, 2018 at 4:46 PM, Sudeep Holla <[email protected]> wrote:
>
>
> On 26/04/18 00:31, Jeremy Linton wrote:
>> Propagate the topology information from the PPTT tree to the
>> cpu_topology array. We can get the thread id and core_id by assuming
>> certain levels of the PPTT tree correspond to those concepts.
>> The package_id is flagged in the tree and can be found by calling
>> find_acpi_cpu_topology_package() which terminates
>> its search when it finds an ACPI node flagged as the physical
>> package. If the tree doesn't contain enough levels to represent
>> all of the requested levels then the root node will be returned
>> for all subsequent levels.
>>
>
> Acked-by: Sudeep Holla <[email protected]>
>
> [..]
>
>> @@ -304,6 +345,8 @@ void __init init_cpu_topology(void)
>> * Discard anything that was parsed if we hit an error so we
>> * don't use partial information.
>> */
>> - if (of_have_populated_dt() && parse_dt_topology())
>> + if ((!acpi_disabled) && parse_acpi_topology())
>
> [nit] not sure if extra () is need above,

No, it isn't.

> but I am fine either way.

The redundant parens need to go away, really.

2018-05-02 11:50:30

by Morten Rasmussen

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

On Tue, May 01, 2018 at 03:33:33PM +0100, Sudeep Holla wrote:
>
>
> On 26/04/18 00:31, Jeremy Linton wrote:
> > Now that we have an accurate view of the physical topology
> > we need to represent it correctly to the scheduler. Generally MC
> > should equal the LLC in the system, but there are a number of
> > special cases that need to be dealt with.
> >
> > In the case of NUMA in socket, we need to assure that the sched
> > domain we build for the MC layer isn't larger than the DIE above it.
> > Similarly for LLC's that might exist in cross socket interconnect or
> > directory hardware we need to assure that MC is shrunk to the socket
> > or NUMA node.
> >
> > This patch builds a sibling mask for the LLC, and then picks the
> > smallest of LLC, socket siblings, or NUMA node siblings, which
> > gives us the behavior described above. This is ever so slightly
> > different than the similar alternative where we look for a cache
> > layer less than or equal to the socket/NUMA siblings.
> >
> > The logic to pick the MC layer affects all arm64 machines, but
> > only changes the behavior for DT/MPIDR systems if the NUMA domain
> > is smaller than the core siblings (generally set to the cluster).
> > Potentially this fixes a possible bug in DT systems, but really
> > it only affects ACPI systems where the core siblings is correctly
> > set to the socket siblings. Thus all currently available ACPI
> > systems should have MC equal to LLC, including the NUMA in socket
> > machines where the LLC is partitioned between the NUMA nodes.
> >
> > Signed-off-by: Jeremy Linton <[email protected]>
> > ---
> > arch/arm64/include/asm/topology.h | 2 ++
> > arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
> > 2 files changed, 33 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
> > index 6b10459e6905..df48212f767b 100644
> > --- a/arch/arm64/include/asm/topology.h
> > +++ b/arch/arm64/include/asm/topology.h
> > @@ -8,8 +8,10 @@ struct cpu_topology {
> > int thread_id;
> > int core_id;
> > int package_id;
> > + int llc_id;
> > cpumask_t thread_sibling;
> > cpumask_t core_sibling;
> > + cpumask_t llc_siblings;
> > };
> >
> > extern struct cpu_topology cpu_topology[NR_CPUS];
> > diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> > index bd1aae438a31..20b4341dc527 100644
> > --- a/arch/arm64/kernel/topology.c
> > +++ b/arch/arm64/kernel/topology.c
> > @@ -13,6 +13,7 @@
> >
> > #include <linux/acpi.h>
> > #include <linux/arch_topology.h>
> > +#include <linux/cacheinfo.h>
> > #include <linux/cpu.h>
> > #include <linux/cpumask.h>
> > #include <linux/init.h>
> > @@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);
> >
> > const struct cpumask *cpu_coregroup_mask(int cpu)
> > {
> > - return &cpu_topology[cpu].core_sibling;
> > + const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
> > +
> > + /* Find the smaller of NUMA, core or LLC siblings */
> > + if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
> > + /* not numa in package, lets use the package siblings */
> > + core_mask = &cpu_topology[cpu].core_sibling;
> > + }
> > + if (cpu_topology[cpu].llc_id != -1) {
> > + if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
> > + core_mask = &cpu_topology[cpu].llc_siblings;
> > + }
> > +
> > + return core_mask;
> > }
> >
> > static void update_siblings_masks(unsigned int cpuid)
> > @@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
> > for_each_possible_cpu(cpu) {
> > cpu_topo = &cpu_topology[cpu];
> >
> > + if (cpuid_topo->llc_id == cpu_topo->llc_id)
> > + cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
> > +
>
> Would this not result in cpuid_topo->llc_siblings = cpu_possible_mask
> on DT systems where llc_id is not set/defaults to -1 and still pass the
> condition. Does it make sense to add additional -1 check ?

I don't think mask will be used by the current code if llc_id == -1 as
the user does the check. Is it better to have the mask empty than
default to cpu_possible_mask? If we require all users to implement a
check it shouldn't matter.

2018-05-02 22:33:56

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

Hi,

On 05/02/2018 06:49 AM, Morten Rasmussen wrote:
> On Tue, May 01, 2018 at 03:33:33PM +0100, Sudeep Holla wrote:
>>
>>
>> On 26/04/18 00:31, Jeremy Linton wrote:
>>> Now that we have an accurate view of the physical topology
>>> we need to represent it correctly to the scheduler. Generally MC
>>> should equal the LLC in the system, but there are a number of
>>> special cases that need to be dealt with.
>>>
>>> In the case of NUMA in socket, we need to assure that the sched
>>> domain we build for the MC layer isn't larger than the DIE above it.
>>> Similarly for LLC's that might exist in cross socket interconnect or
>>> directory hardware we need to assure that MC is shrunk to the socket
>>> or NUMA node.
>>>
>>> This patch builds a sibling mask for the LLC, and then picks the
>>> smallest of LLC, socket siblings, or NUMA node siblings, which
>>> gives us the behavior described above. This is ever so slightly
>>> different than the similar alternative where we look for a cache
>>> layer less than or equal to the socket/NUMA siblings.
>>>
>>> The logic to pick the MC layer affects all arm64 machines, but
>>> only changes the behavior for DT/MPIDR systems if the NUMA domain
>>> is smaller than the core siblings (generally set to the cluster).
>>> Potentially this fixes a possible bug in DT systems, but really
>>> it only affects ACPI systems where the core siblings is correctly
>>> set to the socket siblings. Thus all currently available ACPI
>>> systems should have MC equal to LLC, including the NUMA in socket
>>> machines where the LLC is partitioned between the NUMA nodes.
>>>
>>> Signed-off-by: Jeremy Linton <[email protected]>
>>> ---
>>> arch/arm64/include/asm/topology.h | 2 ++
>>> arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
>>> 2 files changed, 33 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
>>> index 6b10459e6905..df48212f767b 100644
>>> --- a/arch/arm64/include/asm/topology.h
>>> +++ b/arch/arm64/include/asm/topology.h
>>> @@ -8,8 +8,10 @@ struct cpu_topology {
>>> int thread_id;
>>> int core_id;
>>> int package_id;
>>> + int llc_id;
>>> cpumask_t thread_sibling;
>>> cpumask_t core_sibling;
>>> + cpumask_t llc_siblings;
>>> };
>>>
>>> extern struct cpu_topology cpu_topology[NR_CPUS];
>>> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
>>> index bd1aae438a31..20b4341dc527 100644
>>> --- a/arch/arm64/kernel/topology.c
>>> +++ b/arch/arm64/kernel/topology.c
>>> @@ -13,6 +13,7 @@
>>>
>>> #include <linux/acpi.h>
>>> #include <linux/arch_topology.h>
>>> +#include <linux/cacheinfo.h>
>>> #include <linux/cpu.h>
>>> #include <linux/cpumask.h>
>>> #include <linux/init.h>
>>> @@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);
>>>
>>> const struct cpumask *cpu_coregroup_mask(int cpu)
>>> {
>>> - return &cpu_topology[cpu].core_sibling;
>>> + const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
>>> +
>>> + /* Find the smaller of NUMA, core or LLC siblings */
>>> + if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
>>> + /* not numa in package, lets use the package siblings */
>>> + core_mask = &cpu_topology[cpu].core_sibling;
>>> + }
>>> + if (cpu_topology[cpu].llc_id != -1) {
>>> + if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
>>> + core_mask = &cpu_topology[cpu].llc_siblings;
>>> + }
>>> +
>>> + return core_mask;
>>> }
>>>
>>> static void update_siblings_masks(unsigned int cpuid)
>>> @@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
>>> for_each_possible_cpu(cpu) {
>>> cpu_topo = &cpu_topology[cpu];
>>>
>>> + if (cpuid_topo->llc_id == cpu_topo->llc_id)
>>> + cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
>>> +
>>
>> Would this not result in cpuid_topo->llc_siblings = cpu_possible_mask
>> on DT systems where llc_id is not set/defaults to -1 and still pass the
>> condition. Does it make sense to add additional -1 check ?
>
> I don't think mask will be used by the current code if llc_id == -1 as
> the user does the check. Is it better to have the mask empty than
> default to cpu_possible_mask? If we require all users to implement a
> check it shouldn't matter.
>

Right.

There is also the other way of thinking about it, which is if you remove
the if llc_id == -1 check in cpu_coregroup_mask() does it make more
sense to have llc_siblings default equal all the cores, or just the one
being requested?

2018-05-02 22:34:46

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

Hi,

Thanks for taking a look at this.

On 05/01/2018 09:33 AM, Sudeep Holla wrote:
>
>
> On 26/04/18 00:31, Jeremy Linton wrote:
>> Now that we have an accurate view of the physical topology
>> we need to represent it correctly to the scheduler. Generally MC
>> should equal the LLC in the system, but there are a number of
>> special cases that need to be dealt with.
>>
>> In the case of NUMA in socket, we need to assure that the sched
>> domain we build for the MC layer isn't larger than the DIE above it.
>> Similarly for LLC's that might exist in cross socket interconnect or
>> directory hardware we need to assure that MC is shrunk to the socket
>> or NUMA node.
>>
>> This patch builds a sibling mask for the LLC, and then picks the
>> smallest of LLC, socket siblings, or NUMA node siblings, which
>> gives us the behavior described above. This is ever so slightly
>> different than the similar alternative where we look for a cache
>> layer less than or equal to the socket/NUMA siblings.
>>
>> The logic to pick the MC layer affects all arm64 machines, but
>> only changes the behavior for DT/MPIDR systems if the NUMA domain
>> is smaller than the core siblings (generally set to the cluster).
>> Potentially this fixes a possible bug in DT systems, but really
>> it only affects ACPI systems where the core siblings is correctly
>> set to the socket siblings. Thus all currently available ACPI
>> systems should have MC equal to LLC, including the NUMA in socket
>> machines where the LLC is partitioned between the NUMA nodes.
>>
>> Signed-off-by: Jeremy Linton <[email protected]>
>> ---
>> arch/arm64/include/asm/topology.h | 2 ++
>> arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
>> 2 files changed, 33 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
>> index 6b10459e6905..df48212f767b 100644
>> --- a/arch/arm64/include/asm/topology.h
>> +++ b/arch/arm64/include/asm/topology.h
>> @@ -8,8 +8,10 @@ struct cpu_topology {
>> int thread_id;
>> int core_id;
>> int package_id;
>> + int llc_id;
>> cpumask_t thread_sibling;
>> cpumask_t core_sibling;
>> + cpumask_t llc_siblings;
>> };
>>
>> extern struct cpu_topology cpu_topology[NR_CPUS];
>> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
>> index bd1aae438a31..20b4341dc527 100644
>> --- a/arch/arm64/kernel/topology.c
>> +++ b/arch/arm64/kernel/topology.c
>> @@ -13,6 +13,7 @@
>>
>> #include <linux/acpi.h>
>> #include <linux/arch_topology.h>
>> +#include <linux/cacheinfo.h>
>> #include <linux/cpu.h>
>> #include <linux/cpumask.h>
>> #include <linux/init.h>
>> @@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);
>>
>> const struct cpumask *cpu_coregroup_mask(int cpu)
>> {
>> - return &cpu_topology[cpu].core_sibling;
>> + const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
>> +
>> + /* Find the smaller of NUMA, core or LLC siblings */
>> + if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
>> + /* not numa in package, lets use the package siblings */
>> + core_mask = &cpu_topology[cpu].core_sibling;
>> + }
>> + if (cpu_topology[cpu].llc_id != -1) {
>> + if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
>> + core_mask = &cpu_topology[cpu].llc_siblings;
>> + }
>> +
>> + return core_mask;
>> }
>>
>> static void update_siblings_masks(unsigned int cpuid)
>> @@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
>> for_each_possible_cpu(cpu) {
>> cpu_topo = &cpu_topology[cpu];
>>
>> + if (cpuid_topo->llc_id == cpu_topo->llc_id)
>> + cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
>> +
>
> Would this not result in cpuid_topo->llc_siblings = cpu_possible_mask
> on DT systems where llc_id is not set/defaults to -1 and still pass the
> condition. Does it make sense to add additional -1 check ?
(see comment in Morton's thread)

>
>> if (cpuid_topo->package_id != cpu_topo->package_id)
>> continue;
>>
>> @@ -291,6 +307,10 @@ static void __init reset_cpu_topology(void)
>> cpu_topo->core_id = 0;
>> cpu_topo->package_id = -1;
>>
>> + cpu_topo->llc_id = -1;
>> + cpumask_clear(&cpu_topo->llc_siblings);
>> + cpumask_set_cpu(cpu, &cpu_topo->llc_siblings);
>> +
>> cpumask_clear(&cpu_topo->core_sibling);
>> cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
>> cpumask_clear(&cpu_topo->thread_sibling);
>> @@ -311,6 +331,8 @@ static int __init parse_acpi_topology(void)
>> is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
>>
>> for_each_possible_cpu(cpu) {
>> + int i;
>> +
>> topology_id = find_acpi_cpu_topology(cpu, 0);
>> if (topology_id < 0)
>> return topology_id;
>> @@ -325,6 +347,14 @@ static int __init parse_acpi_topology(void)
>> }
>> topology_id = find_acpi_cpu_topology_package(cpu);
>> cpu_topology[cpu].package_id = topology_id;
>> +
>> + i = acpi_find_last_cache_level(cpu);
>> +
>> + if (i > 0) {
>> + topology_id = find_acpi_cpu_cache_topology(cpu, i);
>> + if (topology_id > 0)
>> + cpu_topology[cpu].llc_id = topology_id;
>> + }
>
> [nit] s/topology_id/cache_id/ or s/topology_id/cache_topology_id/ ?

Sure.

>
> Otherwise looks fine to me. You can add with above things fixed.
>
> Acked-by: Sudeep Holla <[email protected]>
>

Thanks,

2018-05-02 22:36:30

by Jeremy Linton

[permalink] [raw]
Subject: Re: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology

Hi,

On 05/02/2018 03:24 AM, Rafael J. Wysocki wrote:
> On Tue, May 1, 2018 at 4:46 PM, Sudeep Holla <[email protected]> wrote:
>>
>>
>> On 26/04/18 00:31, Jeremy Linton wrote:
>>> Propagate the topology information from the PPTT tree to the
>>> cpu_topology array. We can get the thread id and core_id by assuming
>>> certain levels of the PPTT tree correspond to those concepts.
>>> The package_id is flagged in the tree and can be found by calling
>>> find_acpi_cpu_topology_package() which terminates
>>> its search when it finds an ACPI node flagged as the physical
>>> package. If the tree doesn't contain enough levels to represent
>>> all of the requested levels then the root node will be returned
>>> for all subsequent levels.
>>>
>>
>> Acked-by: Sudeep Holla <[email protected]>
>>
>> [..]
>>
>>> @@ -304,6 +345,8 @@ void __init init_cpu_topology(void)
>>> * Discard anything that was parsed if we hit an error so we
>>> * don't use partial information.
>>> */
>>> - if (of_have_populated_dt() && parse_dt_topology())
>>> + if ((!acpi_disabled) && parse_acpi_topology())
>>
>> [nit] not sure if extra () is need above,
>
> No, it isn't.
>
>> but I am fine either way.
>
> The redundant parens need to go away, really.
>

Yah, I missed this one, is there a linter everyone is using that finds
these?

Thanks,

2018-05-03 08:42:40

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology

On Thu, May 3, 2018 at 12:35 AM, Jeremy Linton <[email protected]> wrote:
> Hi,
>
>
> On 05/02/2018 03:24 AM, Rafael J. Wysocki wrote:
>>
>> On Tue, May 1, 2018 at 4:46 PM, Sudeep Holla <[email protected]> wrote:
>>>
>>>
>>>
>>> On 26/04/18 00:31, Jeremy Linton wrote:
>>>>
>>>> Propagate the topology information from the PPTT tree to the
>>>> cpu_topology array. We can get the thread id and core_id by assuming
>>>> certain levels of the PPTT tree correspond to those concepts.
>>>> The package_id is flagged in the tree and can be found by calling
>>>> find_acpi_cpu_topology_package() which terminates
>>>> its search when it finds an ACPI node flagged as the physical
>>>> package. If the tree doesn't contain enough levels to represent
>>>> all of the requested levels then the root node will be returned
>>>> for all subsequent levels.
>>>>
>>>
>>> Acked-by: Sudeep Holla <[email protected]>
>>>
>>> [..]
>>>
>>>> @@ -304,6 +345,8 @@ void __init init_cpu_topology(void)
>>>> * Discard anything that was parsed if we hit an error so we
>>>> * don't use partial information.
>>>> */
>>>> - if (of_have_populated_dt() && parse_dt_topology())
>>>> + if ((!acpi_disabled) && parse_acpi_topology())
>>>
>>>
>>> [nit] not sure if extra () is need above,
>>
>>
>> No, it isn't.
>>
>>> but I am fine either way.
>>
>>
>> The redundant parens need to go away, really.
>>
>
> Yah, I missed this one, is there a linter everyone is using that finds
> these?

I'm not actually sure. At least I can't recall any right away.

2018-05-03 11:21:44

by Morten Rasmussen

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

On Wed, May 02, 2018 at 05:32:54PM -0500, Jeremy Linton wrote:
> Hi,
>
> On 05/02/2018 06:49 AM, Morten Rasmussen wrote:
> >On Tue, May 01, 2018 at 03:33:33PM +0100, Sudeep Holla wrote:
> >>
> >>
> >>On 26/04/18 00:31, Jeremy Linton wrote:
> >>>Now that we have an accurate view of the physical topology
> >>>we need to represent it correctly to the scheduler. Generally MC
> >>>should equal the LLC in the system, but there are a number of
> >>>special cases that need to be dealt with.
> >>>
> >>>In the case of NUMA in socket, we need to assure that the sched
> >>>domain we build for the MC layer isn't larger than the DIE above it.
> >>>Similarly for LLC's that might exist in cross socket interconnect or
> >>>directory hardware we need to assure that MC is shrunk to the socket
> >>>or NUMA node.
> >>>
> >>>This patch builds a sibling mask for the LLC, and then picks the
> >>>smallest of LLC, socket siblings, or NUMA node siblings, which
> >>>gives us the behavior described above. This is ever so slightly
> >>>different than the similar alternative where we look for a cache
> >>>layer less than or equal to the socket/NUMA siblings.
> >>>
> >>>The logic to pick the MC layer affects all arm64 machines, but
> >>>only changes the behavior for DT/MPIDR systems if the NUMA domain
> >>>is smaller than the core siblings (generally set to the cluster).
> >>>Potentially this fixes a possible bug in DT systems, but really
> >>>it only affects ACPI systems where the core siblings is correctly
> >>>set to the socket siblings. Thus all currently available ACPI
> >>>systems should have MC equal to LLC, including the NUMA in socket
> >>>machines where the LLC is partitioned between the NUMA nodes.
> >>>
> >>>Signed-off-by: Jeremy Linton <[email protected]>
> >>>---
> >>> arch/arm64/include/asm/topology.h | 2 ++
> >>> arch/arm64/kernel/topology.c | 32 +++++++++++++++++++++++++++++++-
> >>> 2 files changed, 33 insertions(+), 1 deletion(-)
> >>>
> >>>diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
> >>>index 6b10459e6905..df48212f767b 100644
> >>>--- a/arch/arm64/include/asm/topology.h
> >>>+++ b/arch/arm64/include/asm/topology.h
> >>>@@ -8,8 +8,10 @@ struct cpu_topology {
> >>> int thread_id;
> >>> int core_id;
> >>> int package_id;
> >>>+ int llc_id;
> >>> cpumask_t thread_sibling;
> >>> cpumask_t core_sibling;
> >>>+ cpumask_t llc_siblings;
> >>> };
> >>> extern struct cpu_topology cpu_topology[NR_CPUS];
> >>>diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> >>>index bd1aae438a31..20b4341dc527 100644
> >>>--- a/arch/arm64/kernel/topology.c
> >>>+++ b/arch/arm64/kernel/topology.c
> >>>@@ -13,6 +13,7 @@
> >>> #include <linux/acpi.h>
> >>> #include <linux/arch_topology.h>
> >>>+#include <linux/cacheinfo.h>
> >>> #include <linux/cpu.h>
> >>> #include <linux/cpumask.h>
> >>> #include <linux/init.h>
> >>>@@ -214,7 +215,19 @@ EXPORT_SYMBOL_GPL(cpu_topology);
> >>> const struct cpumask *cpu_coregroup_mask(int cpu)
> >>> {
> >>>- return &cpu_topology[cpu].core_sibling;
> >>>+ const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
> >>>+
> >>>+ /* Find the smaller of NUMA, core or LLC siblings */
> >>>+ if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
> >>>+ /* not numa in package, lets use the package siblings */
> >>>+ core_mask = &cpu_topology[cpu].core_sibling;
> >>>+ }
> >>>+ if (cpu_topology[cpu].llc_id != -1) {
> >>>+ if (cpumask_subset(&cpu_topology[cpu].llc_siblings, core_mask))
> >>>+ core_mask = &cpu_topology[cpu].llc_siblings;
> >>>+ }
> >>>+
> >>>+ return core_mask;
> >>> }
> >>> static void update_siblings_masks(unsigned int cpuid)
> >>>@@ -226,6 +239,9 @@ static void update_siblings_masks(unsigned int cpuid)
> >>> for_each_possible_cpu(cpu) {
> >>> cpu_topo = &cpu_topology[cpu];
> >>>+ if (cpuid_topo->llc_id == cpu_topo->llc_id)
> >>>+ cpumask_set_cpu(cpu, &cpuid_topo->llc_siblings);
> >>>+
> >>
> >>Would this not result in cpuid_topo->llc_siblings = cpu_possible_mask
> >>on DT systems where llc_id is not set/defaults to -1 and still pass the
> >>condition. Does it make sense to add additional -1 check ?
> >
> >I don't think mask will be used by the current code if llc_id == -1 as
> >the user does the check. Is it better to have the mask empty than
> >default to cpu_possible_mask? If we require all users to implement a
> >check it shouldn't matter.
> >
>
> Right.
>
> There is also the other way of thinking about it, which is if you remove the
> if llc_id == -1 check in cpu_coregroup_mask() does it make more sense to
> have llc_siblings default equal all the cores, or just the one being
> requested?

Since we define cpu_coregroup_mask() to be the smallest of LLC, package,
and NUMA node, letting it default to just one cpu would change/break the
topology on non-PPTT systems. Wouldn't it?

If we want to drop the check llc_siblings should be default to either
core_siblings or cpumask_of_node(). But I don't really see the point as
any user of llc_siblings that really care about where the LLC is
would have to check if llc_sibling is just assigned a default value or
it is indeed representing the LLC. I'm fine with just expecting the user
to check llc_id to see if the llc_sibling mask is valid or not.

2018-05-03 15:13:34

by Morten Rasmussen

[permalink] [raw]
Subject: Re: [PATCH v8 13/13] arm64: topology: divorce MC scheduling domain from core_siblings

On Wed, Apr 25, 2018 at 06:31:21PM -0500, Jeremy Linton wrote:
> Now that we have an accurate view of the physical topology
> we need to represent it correctly to the scheduler. Generally MC
> should equal the LLC in the system, but there are a number of
> special cases that need to be dealt with.
>
> In the case of NUMA in socket, we need to assure that the sched
> domain we build for the MC layer isn't larger than the DIE above it.
> Similarly for LLC's that might exist in cross socket interconnect or
> directory hardware we need to assure that MC is shrunk to the socket
> or NUMA node.
>
> This patch builds a sibling mask for the LLC, and then picks the
> smallest of LLC, socket siblings, or NUMA node siblings, which
> gives us the behavior described above. This is ever so slightly
> different than the similar alternative where we look for a cache
> layer less than or equal to the socket/NUMA siblings.
>
> The logic to pick the MC layer affects all arm64 machines, but
> only changes the behavior for DT/MPIDR systems if the NUMA domain
> is smaller than the core siblings (generally set to the cluster).
> Potentially this fixes a possible bug in DT systems, but really
> it only affects ACPI systems where the core siblings is correctly
> set to the socket siblings. Thus all currently available ACPI
> systems should have MC equal to LLC, including the NUMA in socket
> machines where the LLC is partitioned between the NUMA nodes.
>
> Signed-off-by: Jeremy Linton <[email protected]>

This patch looks good to me.

Acked-by: Morten Rasmussen <[email protected]>

2018-05-03 15:16:09

by Morten Rasmussen

[permalink] [raw]
Subject: Re: [PATCH v8 11/13] arm64: topology: enable ACPI/PPTT based CPU topology

On Wed, Apr 25, 2018 at 06:31:19PM -0500, Jeremy Linton wrote:
> Propagate the topology information from the PPTT tree to the
> cpu_topology array. We can get the thread id and core_id by assuming
> certain levels of the PPTT tree correspond to those concepts.
> The package_id is flagged in the tree and can be found by calling
> find_acpi_cpu_topology_package() which terminates
> its search when it finds an ACPI node flagged as the physical
> package. If the tree doesn't contain enough levels to represent
> all of the requested levels then the root node will be returned
> for all subsequent levels.
>
> Signed-off-by: Jeremy Linton <[email protected]>

Acked-by: Morten Rasmussen <[email protected]>

2018-05-03 15:16:14

by Morten Rasmussen

[permalink] [raw]
Subject: Re: [PATCH v8 10/13] arm64: topology: rename cluster_id

On Wed, Apr 25, 2018 at 06:31:18PM -0500, Jeremy Linton wrote:
> Lets match the name of the arm64 topology field
> to the kernel macro that uses it.
>
> Signed-off-by: Jeremy Linton <[email protected]>

Acked-by: Morten Rasmussen <[email protected]>

2018-05-04 08:12:18

by vkilari

[permalink] [raw]
Subject: RE: [PATCH v8 00/13] Support PPTT for ARM64



> -----Original Message-----
> From: Jeremy Linton <[email protected]>
> Sent: Thursday, April 26, 2018 5:01 AM
> To: [email protected]
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; linux-
> [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; Jeremy Linton <[email protected]>
> Subject: [PATCH v8 00/13] Support PPTT for ARM64
>
> ACPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
used to
> describe the processor and cache topology. Ideally it is used to
extend/override
> information provided by the hardware, but right now ARM64 is entirely
> dependent on firmware provided tables.
>
> This patch parses the table for the cache topology and CPU topology.
> When we enable ACPI/PPTT for arm64 we map the package_id to the PPTT
> node flagged as the physical package by the firmware.
> This results in topologies that match what the remainder of the system
expects.
> Finally, we update the scheduler MC domain so that it generally reflects
the
> LLC unless the LLC is too large for the NUMA domain (or package).
>
> For example on juno:
> [root@mammon-juno-rh topology]# lstopo-no-graphics
> Package L#0
> L2 L#0 (1024KB)
> L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
> L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
> L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
> L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
> L2 L#1 (2048KB)
> L1d L#4 (32KB) + L1i L#4 (48KB) + Core L#4 + PU L#4 (P#4)
> L1d L#5 (32KB) + L1i L#5 (48KB) + Core L#5 + PU L#5 (P#5)
> HostBridge L#0
> PCIBridge
> PCIBridge
> PCIBridge
> PCI 1095:3132
> Block(Disk) L#0 "sda"
> PCIBridge
> PCI 1002:68f9
> GPU L#1 "renderD128"
> GPU L#2 "card0"
> GPU L#3 "controlD64"
> PCIBridge
> PCI 11ab:4380
> Net L#4 "enp8s0"
>
> Git tree at:
> http://linux-arm.org/git?p=linux-jlinton.git
> branch: pptt_v8

Tested-by: Vijaya Kumar K <[email protected]>

>
> v7->v8:
> Modify the logic used to select the MC domain (the change
> shouldn't modify the sched domains on any existing machines
> compared to v7, only how they are built) Reduce the severity of some
parsing
> messages.
> Fix s390 link problem.
> Further checks to deal with broken PPTT tables.
> Various style tweaks, SPDX license addition, etc.
>
> v6->v7:
> Add additional patch to use the last cache level within the NUMA
> or socket as the MC domain. This assures the MC domain is
> equal or smaller than the DIE.
>
> Various formatting/etc review comments.
>
> Rebase to 4.16rc2
>
> v5->v6:
> Add additional patches which re-factor how the initial DT code sets
> up the cacheinfo structure so that its not as dependent on the
> of_node stored in that tree. Once that is done we rename it
> for use with the ACPI code.
>
> Additionally there were a fair number of minor name/location/etc
> tweaks scattered about made in response to review comments.
>
> v4->v5:
> Update the cache type from NOCACHE to UNIFIED when all the cache
> attributes we update are valid. This fixes a problem where caches
> which are entirely created by the PPTT don't show up in lstopo.
>
> Give the PPTT its own firmware_node in the cache structure instead of
> sharing it with the of_node.
>
> Move some pieces around between patches.
>
> (see previous cover letters for futher changes)
>
> Jeremy Linton (13):
> drivers: base: cacheinfo: move cache_setup_of_node()
> drivers: base: cacheinfo: setup DT cache properties early
> cacheinfo: rename of_node to fw_token
> arm64/acpi: Create arch specific cpu to acpi id helper
> ACPI/PPTT: Add Processor Properties Topology Table parsing
> ACPI: Enable PPTT support on ARM64
> drivers: base cacheinfo: Add support for ACPI based firmware tables
> arm64: Add support for ACPI based firmware tables
> ACPI/PPTT: Add topology parsing code
> arm64: topology: rename cluster_id
> arm64: topology: enable ACPI/PPTT based CPU topology
> ACPI: Add PPTT to injectable table list
> arm64: topology: divorce MC scheduling domain from core_siblings
>
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/acpi.h | 4 +
> arch/arm64/include/asm/topology.h | 6 +-
> arch/arm64/kernel/cacheinfo.c | 15 +-
> arch/arm64/kernel/topology.c | 103 +++++-
> arch/riscv/kernel/cacheinfo.c | 1 -
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/pptt.c | 678
> ++++++++++++++++++++++++++++++++++++++
> drivers/acpi/tables.c | 2 +-
> drivers/base/cacheinfo.c | 157 ++++-----
> include/linux/acpi.h | 4 +
> include/linux/cacheinfo.h | 18 +-
> 13 files changed, 886 insertions(+), 107 deletions(-) create mode 100644
> drivers/acpi/pptt.c
>
> --
> 2.13.6



2018-05-04 11:35:50

by Xiongfeng Wang

[permalink] [raw]
Subject: Re: [PATCH v8 00/13] Support PPTT for ARM64

Tested-by: Xiongfeng Wang <[email protected]>

Tested on D05 board. 'lscpu' prints the following info:
localhost:~ # lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 64
On-line CPU(s) list: 0-63
Thread(s) per core: 1
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 4
L1d cache: 32K
L1i cache: 48K
L2 cache: 1024K
L3 cache: 16384K
NUMA node0 CPU(s): 0-15
NUMA node1 CPU(s): 16-31
NUMA node2 CPU(s): 32-47
NUMA node3 CPU(s): 48-63

'sched_domain' is as follows
localhost:~ # cat /proc/schedstat
version 15
timestamp 4294936236
cpu0 0 0 0 0 0 0 2471285600 2634828800 4813
domain0 00000000,0000ffff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
domain1 00000000,ffffffff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
domain2 ffffffff,ffffffff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


On 2018/4/26 7:31, Jeremy Linton wrote:
> ACPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
> used to describe the processor and cache topology. Ideally it is
> used to extend/override information provided by the hardware, but
> right now ARM64 is entirely dependent on firmware provided tables.
>
> This patch parses the table for the cache topology and CPU topology.
> When we enable ACPI/PPTT for arm64 we map the package_id to the
> PPTT node flagged as the physical package by the firmware.
> This results in topologies that match what the remainder of the
> system expects. Finally, we update the scheduler MC domain so that
> it generally reflects the LLC unless the LLC is too large for the
> NUMA domain (or package).
>
> For example on juno:
> [root@mammon-juno-rh topology]# lstopo-no-graphics
> Package L#0
> L2 L#0 (1024KB)
> L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
> L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
> L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
> L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
> L2 L#1 (2048KB)
> L1d L#4 (32KB) + L1i L#4 (48KB) + Core L#4 + PU L#4 (P#4)
> L1d L#5 (32KB) + L1i L#5 (48KB) + Core L#5 + PU L#5 (P#5)
> HostBridge L#0
> PCIBridge
> PCIBridge
> PCIBridge
> PCI 1095:3132
> Block(Disk) L#0 "sda"
> PCIBridge
> PCI 1002:68f9
> GPU L#1 "renderD128"
> GPU L#2 "card0"
> GPU L#3 "controlD64"
> PCIBridge
> PCI 11ab:4380
> Net L#4 "enp8s0"
>
> Git tree at:
> http://linux-arm.org/git?p=linux-jlinton.git
> branch: pptt_v8
>
> v7->v8:
> Modify the logic used to select the MC domain (the change
> shouldn't modify the sched domains on any existing machines
> compared to v7, only how they are built)
> Reduce the severity of some parsing messages.
> Fix s390 link problem.
> Further checks to deal with broken PPTT tables.
> Various style tweaks, SPDX license addition, etc.
>
> v6->v7:
> Add additional patch to use the last cache level within the NUMA
> or socket as the MC domain. This assures the MC domain is
> equal or smaller than the DIE.
>
> Various formatting/etc review comments.
>
> Rebase to 4.16rc2
>
> v5->v6:
> Add additional patches which re-factor how the initial DT code sets
> up the cacheinfo structure so that its not as dependent on the
> of_node stored in that tree. Once that is done we rename it
> for use with the ACPI code.
>
> Additionally there were a fair number of minor name/location/etc
> tweaks scattered about made in response to review comments.
>
> v4->v5:
> Update the cache type from NOCACHE to UNIFIED when all the cache
> attributes we update are valid. This fixes a problem where caches
> which are entirely created by the PPTT don't show up in lstopo.
>
> Give the PPTT its own firmware_node in the cache structure instead of
> sharing it with the of_node.
>
> Move some pieces around between patches.
>
> (see previous cover letters for futher changes)
>
> Jeremy Linton (13):
> drivers: base: cacheinfo: move cache_setup_of_node()
> drivers: base: cacheinfo: setup DT cache properties early
> cacheinfo: rename of_node to fw_token
> arm64/acpi: Create arch specific cpu to acpi id helper
> ACPI/PPTT: Add Processor Properties Topology Table parsing
> ACPI: Enable PPTT support on ARM64
> drivers: base cacheinfo: Add support for ACPI based firmware tables
> arm64: Add support for ACPI based firmware tables
> ACPI/PPTT: Add topology parsing code
> arm64: topology: rename cluster_id
> arm64: topology: enable ACPI/PPTT based CPU topology
> ACPI: Add PPTT to injectable table list
> arm64: topology: divorce MC scheduling domain from core_siblings
>
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/acpi.h | 4 +
> arch/arm64/include/asm/topology.h | 6 +-
> arch/arm64/kernel/cacheinfo.c | 15 +-
> arch/arm64/kernel/topology.c | 103 +++++-
> arch/riscv/kernel/cacheinfo.c | 1 -
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/pptt.c | 678 ++++++++++++++++++++++++++++++++++++++
> drivers/acpi/tables.c | 2 +-
> drivers/base/cacheinfo.c | 157 ++++-----
> include/linux/acpi.h | 4 +
> include/linux/cacheinfo.h | 18 +-
> 13 files changed, 886 insertions(+), 107 deletions(-)
> create mode 100644 drivers/acpi/pptt.c
>


2018-05-04 11:46:41

by Sudeep Holla

[permalink] [raw]
Subject: Re: [PATCH v8 00/13] Support PPTT for ARM64

Hi Vijaya Kumar,

On 04/05/18 09:10, [email protected] wrote:
>
[...]

CPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
> used to
>> describe the processor and cache topology. Ideally it is used to
> extend/override

FYI, these messages go no where to the git commit log. Only individual
patch logs/messages will go and not the cover letter ones. Check if you
are happy with those.

--
Regards,
Sudeep

2018-05-09 13:21:57

by Tomasz Nowicki

[permalink] [raw]
Subject: Re: [PATCH v8 00/13] Support PPTT for ARM64

On 26.04.2018 01:31, Jeremy Linton wrote:
> ACPI 6.2 adds the Processor Properties Topology Table (PPTT), which is
> used to describe the processor and cache topology. Ideally it is
> used to extend/override information provided by the hardware, but
> right now ARM64 is entirely dependent on firmware provided tables.
>
> This patch parses the table for the cache topology and CPU topology.
> When we enable ACPI/PPTT for arm64 we map the package_id to the
> PPTT node flagged as the physical package by the firmware.
> This results in topologies that match what the remainder of the
> system expects. Finally, we update the scheduler MC domain so that
> it generally reflects the LLC unless the LLC is too large for the
> NUMA domain (or package).

Tested-by: Tomasz Nowicki <[email protected]>

Tested on ThunderX2:

Machine (511GB total)
NUMANode L#0 (P#0 256GB)
Package L#0 + L3 L#0 (32MB)
L2 L#0 (256KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0
PU L#0 (P#0)
PU L#1 (P#32)
PU L#2 (P#64)
PU L#3 (P#96)
L2 L#1 (256KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1
PU L#4 (P#1)
PU L#5 (P#33)
PU L#6 (P#65)
PU L#7 (P#97)
L2 L#2 (256KB) + L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2
PU L#8 (P#2)
PU L#9 (P#34)
PU L#10 (P#66)
PU L#11 (P#98)
L2 L#3 (256KB) + L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3
PU L#12 (P#3)
PU L#13 (P#35)
PU L#14 (P#67)
PU L#15 (P#99)
L2 L#4 (256KB) + L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4
PU L#16 (P#4)
PU L#17 (P#36)
PU L#18 (P#68)
PU L#19 (P#100)
L2 L#5 (256KB) + L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5
PU L#20 (P#5)
PU L#21 (P#37)
PU L#22 (P#69)
PU L#23 (P#101)
L2 L#6 (256KB) + L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6
PU L#24 (P#6)
PU L#25 (P#38)
PU L#26 (P#70)
PU L#27 (P#102)
L2 L#7 (256KB) + L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7
PU L#28 (P#7)
PU L#29 (P#39)
PU L#30 (P#71)
PU L#31 (P#103)
L2 L#8 (256KB) + L1d L#8 (32KB) + L1i L#8 (32KB) + Core L#8
PU L#32 (P#8)
PU L#33 (P#40)
PU L#34 (P#72)
PU L#35 (P#104)
L2 L#9 (256KB) + L1d L#9 (32KB) + L1i L#9 (32KB) + Core L#9
PU L#36 (P#9)
PU L#37 (P#41)
PU L#38 (P#73)
PU L#39 (P#105)
L2 L#10 (256KB) + L1d L#10 (32KB) + L1i L#10 (32KB) + Core L#10
PU L#40 (P#10)
PU L#41 (P#42)
PU L#42 (P#74)
PU L#43 (P#106)
L2 L#11 (256KB) + L1d L#11 (32KB) + L1i L#11 (32KB) + Core L#11
PU L#44 (P#11)
PU L#45 (P#43)
PU L#46 (P#75)
PU L#47 (P#107)
L2 L#12 (256KB) + L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12
PU L#48 (P#12)
PU L#49 (P#44)
PU L#50 (P#76)
PU L#51 (P#108)
L2 L#13 (256KB) + L1d L#13 (32KB) + L1i L#13 (32KB) + Core L#13
PU L#52 (P#13)
PU L#53 (P#45)
PU L#54 (P#77)
PU L#55 (P#109)
L2 L#14 (256KB) + L1d L#14 (32KB) + L1i L#14 (32KB) + Core L#14
PU L#56 (P#14)
PU L#57 (P#46)
PU L#58 (P#78)
PU L#59 (P#110)
L2 L#15 (256KB) + L1d L#15 (32KB) + L1i L#15 (32KB) + Core L#15
PU L#60 (P#15)
PU L#61 (P#47)
PU L#62 (P#79)
PU L#63 (P#111)
L2 L#16 (256KB) + L1d L#16 (32KB) + L1i L#16 (32KB) + Core L#16
PU L#64 (P#16)
PU L#65 (P#48)
PU L#66 (P#80)
PU L#67 (P#112)
L2 L#17 (256KB) + L1d L#17 (32KB) + L1i L#17 (32KB) + Core L#17
PU L#68 (P#17)
PU L#69 (P#49)
PU L#70 (P#81)
PU L#71 (P#113)
L2 L#18 (256KB) + L1d L#18 (32KB) + L1i L#18 (32KB) + Core L#18
PU L#72 (P#18)
PU L#73 (P#50)
PU L#74 (P#82)
PU L#75 (P#114)
L2 L#19 (256KB) + L1d L#19 (32KB) + L1i L#19 (32KB) + Core L#19
PU L#76 (P#19)
PU L#77 (P#51)
PU L#78 (P#83)
PU L#79 (P#115)
L2 L#20 (256KB) + L1d L#20 (32KB) + L1i L#20 (32KB) + Core L#20
PU L#80 (P#20)
PU L#81 (P#52)
PU L#82 (P#84)
PU L#83 (P#116)
L2 L#21 (256KB) + L1d L#21 (32KB) + L1i L#21 (32KB) + Core L#21
PU L#84 (P#21)
PU L#85 (P#53)
PU L#86 (P#85)
PU L#87 (P#117)
L2 L#22 (256KB) + L1d L#22 (32KB) + L1i L#22 (32KB) + Core L#22
PU L#88 (P#22)
PU L#89 (P#54)
PU L#90 (P#86)
PU L#91 (P#118)
L2 L#23 (256KB) + L1d L#23 (32KB) + L1i L#23 (32KB) + Core L#23
PU L#92 (P#23)
PU L#93 (P#55)
PU L#94 (P#87)
PU L#95 (P#119)
L2 L#24 (256KB) + L1d L#24 (32KB) + L1i L#24 (32KB) + Core L#24
PU L#96 (P#24)
PU L#97 (P#56)
PU L#98 (P#88)
PU L#99 (P#120)
L2 L#25 (256KB) + L1d L#25 (32KB) + L1i L#25 (32KB) + Core L#25
PU L#100 (P#25)
PU L#101 (P#57)
PU L#102 (P#89)
PU L#103 (P#121)
L2 L#26 (256KB) + L1d L#26 (32KB) + L1i L#26 (32KB) + Core L#26
PU L#104 (P#26)
PU L#105 (P#58)
PU L#106 (P#90)
PU L#107 (P#122)
L2 L#27 (256KB) + L1d L#27 (32KB) + L1i L#27 (32KB) + Core L#27
PU L#108 (P#27)
PU L#109 (P#59)
PU L#110 (P#91)
PU L#111 (P#123)
L2 L#28 (256KB) + L1d L#28 (32KB) + L1i L#28 (32KB) + Core L#28
PU L#112 (P#28)
PU L#113 (P#60)
PU L#114 (P#92)
PU L#115 (P#124)
L2 L#29 (256KB) + L1d L#29 (32KB) + L1i L#29 (32KB) + Core L#29
PU L#116 (P#29)
PU L#117 (P#61)
PU L#118 (P#93)
PU L#119 (P#125)
L2 L#30 (256KB) + L1d L#30 (32KB) + L1i L#30 (32KB) + Core L#30
PU L#120 (P#30)
PU L#121 (P#62)
PU L#122 (P#94)
PU L#123 (P#126)
L2 L#31 (256KB) + L1d L#31 (32KB) + L1i L#31 (32KB) + Core L#31
PU L#124 (P#31)
PU L#125 (P#63)
PU L#126 (P#95)
PU L#127 (P#127)
HostBridge L#0
PCIBridge
PCI 8086:1584
Net L#0 "enp2s0"
PCIBridge
PCI 8086:0953
PCIBridge
2 x { PCI 14e4:16a1 }
PCIBridge
PCI 8086:1583
Net L#1 "enp19s0f0"
PCI 8086:1583
Net L#2 "enp19s0f1"
PCIBridge
PCIBridge
PCI 1a03:2000
PCI 14e4:9027
Block(Disk) L#3 "sda"
PCI 14e4:9027
NUMANode L#1 (P#1 256GB)
Package L#1 + L3 L#1 (32MB)
L2 L#32 (256KB) + L1d L#32 (32KB) + L1i L#32 (32KB) + Core L#32
PU L#128 (P#128)
PU L#129 (P#160)
PU L#130 (P#192)
PU L#131 (P#224)
L2 L#33 (256KB) + L1d L#33 (32KB) + L1i L#33 (32KB) + Core L#33
PU L#132 (P#129)
PU L#133 (P#161)
PU L#134 (P#193)
PU L#135 (P#225)
L2 L#34 (256KB) + L1d L#34 (32KB) + L1i L#34 (32KB) + Core L#34
PU L#136 (P#130)
PU L#137 (P#162)
PU L#138 (P#194)
PU L#139 (P#226)
L2 L#35 (256KB) + L1d L#35 (32KB) + L1i L#35 (32KB) + Core L#35
PU L#140 (P#131)
PU L#141 (P#163)
PU L#142 (P#195)
PU L#143 (P#227)
L2 L#36 (256KB) + L1d L#36 (32KB) + L1i L#36 (32KB) + Core L#36
PU L#144 (P#132)
PU L#145 (P#164)
PU L#146 (P#196)
PU L#147 (P#228)
L2 L#37 (256KB) + L1d L#37 (32KB) + L1i L#37 (32KB) + Core L#37
PU L#148 (P#133)
PU L#149 (P#165)
PU L#150 (P#197)
PU L#151 (P#229)
L2 L#38 (256KB) + L1d L#38 (32KB) + L1i L#38 (32KB) + Core L#38
PU L#152 (P#134)
PU L#153 (P#166)
PU L#154 (P#198)
PU L#155 (P#230)
L2 L#39 (256KB) + L1d L#39 (32KB) + L1i L#39 (32KB) + Core L#39
PU L#156 (P#135)
PU L#157 (P#167)
PU L#158 (P#199)
PU L#159 (P#231)
L2 L#40 (256KB) + L1d L#40 (32KB) + L1i L#40 (32KB) + Core L#40
PU L#160 (P#136)
PU L#161 (P#168)
PU L#162 (P#200)
PU L#163 (P#232)
L2 L#41 (256KB) + L1d L#41 (32KB) + L1i L#41 (32KB) + Core L#41
PU L#164 (P#137)
PU L#165 (P#169)
PU L#166 (P#201)
PU L#167 (P#233)
L2 L#42 (256KB) + L1d L#42 (32KB) + L1i L#42 (32KB) + Core L#42
PU L#168 (P#138)
PU L#169 (P#170)
PU L#170 (P#202)
PU L#171 (P#234)
L2 L#43 (256KB) + L1d L#43 (32KB) + L1i L#43 (32KB) + Core L#43
PU L#172 (P#139)
PU L#173 (P#171)
PU L#174 (P#203)
PU L#175 (P#235)
L2 L#44 (256KB) + L1d L#44 (32KB) + L1i L#44 (32KB) + Core L#44
PU L#176 (P#140)
PU L#177 (P#172)
PU L#178 (P#204)
PU L#179 (P#236)
L2 L#45 (256KB) + L1d L#45 (32KB) + L1i L#45 (32KB) + Core L#45
PU L#180 (P#141)
PU L#181 (P#173)
PU L#182 (P#205)
PU L#183 (P#237)
L2 L#46 (256KB) + L1d L#46 (32KB) + L1i L#46 (32KB) + Core L#46
PU L#184 (P#142)
PU L#185 (P#174)
PU L#186 (P#206)
PU L#187 (P#238)
L2 L#47 (256KB) + L1d L#47 (32KB) + L1i L#47 (32KB) + Core L#47
PU L#188 (P#143)
PU L#189 (P#175)
PU L#190 (P#207)
PU L#191 (P#239)
L2 L#48 (256KB) + L1d L#48 (32KB) + L1i L#48 (32KB) + Core L#48
PU L#192 (P#144)
PU L#193 (P#176)
PU L#194 (P#208)
PU L#195 (P#240)
L2 L#49 (256KB) + L1d L#49 (32KB) + L1i L#49 (32KB) + Core L#49
PU L#196 (P#145)
PU L#197 (P#177)
PU L#198 (P#209)
PU L#199 (P#241)
L2 L#50 (256KB) + L1d L#50 (32KB) + L1i L#50 (32KB) + Core L#50
PU L#200 (P#146)
PU L#201 (P#178)
PU L#202 (P#210)
PU L#203 (P#242)
L2 L#51 (256KB) + L1d L#51 (32KB) + L1i L#51 (32KB) + Core L#51
PU L#204 (P#147)
PU L#205 (P#179)
PU L#206 (P#211)
PU L#207 (P#243)
L2 L#52 (256KB) + L1d L#52 (32KB) + L1i L#52 (32KB) + Core L#52
PU L#208 (P#148)
PU L#209 (P#180)
PU L#210 (P#212)
PU L#211 (P#244)
L2 L#53 (256KB) + L1d L#53 (32KB) + L1i L#53 (32KB) + Core L#53
PU L#212 (P#149)
PU L#213 (P#181)
PU L#214 (P#213)
PU L#215 (P#245)
L2 L#54 (256KB) + L1d L#54 (32KB) + L1i L#54 (32KB) + Core L#54
PU L#216 (P#150)
PU L#217 (P#182)
PU L#218 (P#214)
PU L#219 (P#246)
L2 L#55 (256KB) + L1d L#55 (32KB) + L1i L#55 (32KB) + Core L#55
PU L#220 (P#151)
PU L#221 (P#183)
PU L#222 (P#215)
PU L#223 (P#247)
L2 L#56 (256KB) + L1d L#56 (32KB) + L1i L#56 (32KB) + Core L#56
PU L#224 (P#152)
PU L#225 (P#184)
PU L#226 (P#216)
PU L#227 (P#248)
L2 L#57 (256KB) + L1d L#57 (32KB) + L1i L#57 (32KB) + Core L#57
PU L#228 (P#153)
PU L#229 (P#185)
PU L#230 (P#217)
PU L#231 (P#249)
L2 L#58 (256KB) + L1d L#58 (32KB) + L1i L#58 (32KB) + Core L#58
PU L#232 (P#154)
PU L#233 (P#186)
PU L#234 (P#218)
PU L#235 (P#250)
L2 L#59 (256KB) + L1d L#59 (32KB) + L1i L#59 (32KB) + Core L#59
PU L#236 (P#155)
PU L#237 (P#187)
PU L#238 (P#219)
PU L#239 (P#251)
L2 L#60 (256KB) + L1d L#60 (32KB) + L1i L#60 (32KB) + Core L#60
PU L#240 (P#156)
PU L#241 (P#188)
PU L#242 (P#220)
PU L#243 (P#252)
L2 L#61 (256KB) + L1d L#61 (32KB) + L1i L#61 (32KB) + Core L#61
PU L#244 (P#157)
PU L#245 (P#189)
PU L#246 (P#221)
PU L#247 (P#253)
L2 L#62 (256KB) + L1d L#62 (32KB) + L1i L#62 (32KB) + Core L#62
PU L#248 (P#158)
PU L#249 (P#190)
PU L#250 (P#222)
PU L#251 (P#254)
L2 L#63 (256KB) + L1d L#63 (32KB) + L1i L#63 (32KB) + Core L#63
PU L#252 (P#159)
PU L#253 (P#191)
PU L#254 (P#223)
PU L#255 (P#255)
HostBridge L#7
PCIBridge
PCI 8086:0953
PCIBridge
PCI 8086:10d3
Net L#4 "enp146s0"
PCIBridge
PCI 1000:00c4

$ lscpu
Architecture: aarch64
Byte Order: Little Endian
CPU(s): 256
On-line CPU(s) list: 0-255
Thread(s) per core: 4
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 2
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 32768K
NUMA node0 CPU(s): 0-127
NUMA node1 CPU(s): 128-255

$ lscpu -ap
# The following is the parsable format, which can be fed to other
# programs. Each different item in every column has an unique ID
# starting from zero.
# CPU,Core,Socket,Node,,L1d,L1i,L2,L3
0,0,0,0,,0,0,0,0
1,1,0,0,,1,1,1,0
2,2,0,0,,2,2,2,0
3,3,0,0,,3,3,3,0
4,4,0,0,,4,4,4,0
5,5,0,0,,5,5,5,0
6,6,0,0,,6,6,6,0
7,7,0,0,,7,7,7,0
8,8,0,0,,8,8,8,0
9,9,0,0,,9,9,9,0
10,10,0,0,,10,10,10,0
11,11,0,0,,11,11,11,0
12,12,0,0,,12,12,12,0
13,13,0,0,,13,13,13,0
14,14,0,0,,14,14,14,0
15,15,0,0,,15,15,15,0
16,16,0,0,,16,16,16,0
17,17,0,0,,17,17,17,0
18,18,0,0,,18,18,18,0
19,19,0,0,,19,19,19,0
20,20,0,0,,20,20,20,0
21,21,0,0,,21,21,21,0
22,22,0,0,,22,22,22,0
23,23,0,0,,23,23,23,0
24,24,0,0,,24,24,24,0
25,25,0,0,,25,25,25,0
26,26,0,0,,26,26,26,0
27,27,0,0,,27,27,27,0
28,28,0,0,,28,28,28,0
29,29,0,0,,29,29,29,0
30,30,0,0,,30,30,30,0
31,31,0,0,,31,31,31,0
32,0,0,0,,0,0,0,0
33,1,0,0,,1,1,1,0
34,2,0,0,,2,2,2,0
35,3,0,0,,3,3,3,0
36,4,0,0,,4,4,4,0
37,5,0,0,,5,5,5,0
38,6,0,0,,6,6,6,0
39,7,0,0,,7,7,7,0
40,8,0,0,,8,8,8,0
41,9,0,0,,9,9,9,0
42,10,0,0,,10,10,10,0
43,11,0,0,,11,11,11,0
44,12,0,0,,12,12,12,0
45,13,0,0,,13,13,13,0
46,14,0,0,,14,14,14,0
47,15,0,0,,15,15,15,0
48,16,0,0,,16,16,16,0
49,17,0,0,,17,17,17,0
50,18,0,0,,18,18,18,0
51,19,0,0,,19,19,19,0
52,20,0,0,,20,20,20,0
53,21,0,0,,21,21,21,0
54,22,0,0,,22,22,22,0
55,23,0,0,,23,23,23,0
56,24,0,0,,24,24,24,0
57,25,0,0,,25,25,25,0
58,26,0,0,,26,26,26,0
59,27,0,0,,27,27,27,0
60,28,0,0,,28,28,28,0
61,29,0,0,,29,29,29,0
62,30,0,0,,30,30,30,0
63,31,0,0,,31,31,31,0
64,0,0,0,,0,0,0,0
65,1,0,0,,1,1,1,0
66,2,0,0,,2,2,2,0
67,3,0,0,,3,3,3,0
68,4,0,0,,4,4,4,0
69,5,0,0,,5,5,5,0
70,6,0,0,,6,6,6,0
71,7,0,0,,7,7,7,0
72,8,0,0,,8,8,8,0
73,9,0,0,,9,9,9,0
74,10,0,0,,10,10,10,0
75,11,0,0,,11,11,11,0
76,12,0,0,,12,12,12,0
77,13,0,0,,13,13,13,0
78,14,0,0,,14,14,14,0
79,15,0,0,,15,15,15,0
80,16,0,0,,16,16,16,0
81,17,0,0,,17,17,17,0
82,18,0,0,,18,18,18,0
83,19,0,0,,19,19,19,0
84,20,0,0,,20,20,20,0
85,21,0,0,,21,21,21,0
86,22,0,0,,22,22,22,0
87,23,0,0,,23,23,23,0
88,24,0,0,,24,24,24,0
89,25,0,0,,25,25,25,0
90,26,0,0,,26,26,26,0
91,27,0,0,,27,27,27,0
92,28,0,0,,28,28,28,0
93,29,0,0,,29,29,29,0
94,30,0,0,,30,30,30,0
95,31,0,0,,31,31,31,0
96,0,0,0,,0,0,0,0
97,1,0,0,,1,1,1,0
98,2,0,0,,2,2,2,0
99,3,0,0,,3,3,3,0
100,4,0,0,,4,4,4,0
101,5,0,0,,5,5,5,0
102,6,0,0,,6,6,6,0
103,7,0,0,,7,7,7,0
104,8,0,0,,8,8,8,0
105,9,0,0,,9,9,9,0
106,10,0,0,,10,10,10,0
107,11,0,0,,11,11,11,0
108,12,0,0,,12,12,12,0
109,13,0,0,,13,13,13,0
110,14,0,0,,14,14,14,0
111,15,0,0,,15,15,15,0
112,16,0,0,,16,16,16,0
113,17,0,0,,17,17,17,0
114,18,0,0,,18,18,18,0
115,19,0,0,,19,19,19,0
116,20,0,0,,20,20,20,0
117,21,0,0,,21,21,21,0
118,22,0,0,,22,22,22,0
119,23,0,0,,23,23,23,0
120,24,0,0,,24,24,24,0
121,25,0,0,,25,25,25,0
122,26,0,0,,26,26,26,0
123,27,0,0,,27,27,27,0
124,28,0,0,,28,28,28,0
125,29,0,0,,29,29,29,0
126,30,0,0,,30,30,30,0
127,31,0,0,,31,31,31,0
128,32,1,1,,32,32,32,1
129,33,1,1,,33,33,33,1
130,34,1,1,,34,34,34,1
131,35,1,1,,35,35,35,1
132,36,1,1,,36,36,36,1
133,37,1,1,,37,37,37,1
134,38,1,1,,38,38,38,1
135,39,1,1,,39,39,39,1
136,40,1,1,,40,40,40,1
137,41,1,1,,41,41,41,1
138,42,1,1,,42,42,42,1
139,43,1,1,,43,43,43,1
140,44,1,1,,44,44,44,1
141,45,1,1,,45,45,45,1
142,46,1,1,,46,46,46,1
143,47,1,1,,47,47,47,1
144,48,1,1,,48,48,48,1
145,49,1,1,,49,49,49,1
146,50,1,1,,50,50,50,1
147,51,1,1,,51,51,51,1
148,52,1,1,,52,52,52,1
149,53,1,1,,53,53,53,1
150,54,1,1,,54,54,54,1
151,55,1,1,,55,55,55,1
152,56,1,1,,56,56,56,1
153,57,1,1,,57,57,57,1
154,58,1,1,,58,58,58,1
155,59,1,1,,59,59,59,1
156,60,1,1,,60,60,60,1
157,61,1,1,,61,61,61,1
158,62,1,1,,62,62,62,1
159,63,1,1,,63,63,63,1
160,32,1,1,,32,32,32,1
161,33,1,1,,33,33,33,1
162,34,1,1,,34,34,34,1
163,35,1,1,,35,35,35,1
164,36,1,1,,36,36,36,1
165,37,1,1,,37,37,37,1
166,38,1,1,,38,38,38,1
167,39,1,1,,39,39,39,1
168,40,1,1,,40,40,40,1
169,41,1,1,,41,41,41,1
170,42,1,1,,42,42,42,1
171,43,1,1,,43,43,43,1
172,44,1,1,,44,44,44,1
173,45,1,1,,45,45,45,1
174,46,1,1,,46,46,46,1
175,47,1,1,,47,47,47,1
176,48,1,1,,48,48,48,1
177,49,1,1,,49,49,49,1
178,50,1,1,,50,50,50,1
179,51,1,1,,51,51,51,1
180,52,1,1,,52,52,52,1
181,53,1,1,,53,53,53,1
182,54,1,1,,54,54,54,1
183,55,1,1,,55,55,55,1
184,56,1,1,,56,56,56,1
185,57,1,1,,57,57,57,1
186,58,1,1,,58,58,58,1
187,59,1,1,,59,59,59,1
188,60,1,1,,60,60,60,1
189,61,1,1,,61,61,61,1
190,62,1,1,,62,62,62,1
191,63,1,1,,63,63,63,1
192,32,1,1,,32,32,32,1
193,33,1,1,,33,33,33,1
194,34,1,1,,34,34,34,1
195,35,1,1,,35,35,35,1
196,36,1,1,,36,36,36,1
197,37,1,1,,37,37,37,1
198,38,1,1,,38,38,38,1
199,39,1,1,,39,39,39,1
200,40,1,1,,40,40,40,1
201,41,1,1,,41,41,41,1
202,42,1,1,,42,42,42,1
203,43,1,1,,43,43,43,1
204,44,1,1,,44,44,44,1
205,45,1,1,,45,45,45,1
206,46,1,1,,46,46,46,1
207,47,1,1,,47,47,47,1
208,48,1,1,,48,48,48,1
209,49,1,1,,49,49,49,1
210,50,1,1,,50,50,50,1
211,51,1,1,,51,51,51,1
212,52,1,1,,52,52,52,1
213,53,1,1,,53,53,53,1
214,54,1,1,,54,54,54,1
215,55,1,1,,55,55,55,1
216,56,1,1,,56,56,56,1
217,57,1,1,,57,57,57,1
218,58,1,1,,58,58,58,1
219,59,1,1,,59,59,59,1
220,60,1,1,,60,60,60,1
221,61,1,1,,61,61,61,1
222,62,1,1,,62,62,62,1
223,63,1,1,,63,63,63,1
224,32,1,1,,32,32,32,1
225,33,1,1,,33,33,33,1
226,34,1,1,,34,34,34,1
227,35,1,1,,35,35,35,1
228,36,1,1,,36,36,36,1
229,37,1,1,,37,37,37,1
230,38,1,1,,38,38,38,1
231,39,1,1,,39,39,39,1
232,40,1,1,,40,40,40,1
233,41,1,1,,41,41,41,1
234,42,1,1,,42,42,42,1
235,43,1,1,,43,43,43,1
236,44,1,1,,44,44,44,1
237,45,1,1,,45,45,45,1
238,46,1,1,,46,46,46,1
239,47,1,1,,47,47,47,1
240,48,1,1,,48,48,48,1
241,49,1,1,,49,49,49,1
242,50,1,1,,50,50,50,1
243,51,1,1,,51,51,51,1
244,52,1,1,,52,52,52,1
245,53,1,1,,53,53,53,1
246,54,1,1,,54,54,54,1
247,55,1,1,,55,55,55,1
248,56,1,1,,56,56,56,1
249,57,1,1,,57,57,57,1
250,58,1,1,,58,58,58,1
251,59,1,1,,59,59,59,1
252,60,1,1,,60,60,60,1
253,61,1,1,,61,61,61,1
254,62,1,1,,62,62,62,1
255,63,1,1,,63,63,63,1

>
> For example on juno:
> [root@mammon-juno-rh topology]# lstopo-no-graphics
> Package L#0
> L2 L#0 (1024KB)
> L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
> L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
> L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
> L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
> L2 L#1 (2048KB)
> L1d L#4 (32KB) + L1i L#4 (48KB) + Core L#4 + PU L#4 (P#4)
> L1d L#5 (32KB) + L1i L#5 (48KB) + Core L#5 + PU L#5 (P#5)
> HostBridge L#0
> PCIBridge
> PCIBridge
> PCIBridge
> PCI 1095:3132
> Block(Disk) L#0 "sda"
> PCIBridge
> PCI 1002:68f9
> GPU L#1 "renderD128"
> GPU L#2 "card0"
> GPU L#3 "controlD64"
> PCIBridge
> PCI 11ab:4380
> Net L#4 "enp8s0"
>
> Git tree at:
> http://linux-arm.org/git?p=linux-jlinton.git
> branch: pptt_v8
>
> v7->v8:
> Modify the logic used to select the MC domain (the change
> shouldn't modify the sched domains on any existing machines
> compared to v7, only how they are built)
> Reduce the severity of some parsing messages.
> Fix s390 link problem.
> Further checks to deal with broken PPTT tables.
> Various style tweaks, SPDX license addition, etc.
>
> v6->v7:
> Add additional patch to use the last cache level within the NUMA
> or socket as the MC domain. This assures the MC domain is
> equal or smaller than the DIE.
>
> Various formatting/etc review comments.
>
> Rebase to 4.16rc2
>
> v5->v6:
> Add additional patches which re-factor how the initial DT code sets
> up the cacheinfo structure so that its not as dependent on the
> of_node stored in that tree. Once that is done we rename it
> for use with the ACPI code.
>
> Additionally there were a fair number of minor name/location/etc
> tweaks scattered about made in response to review comments.
>
> v4->v5:
> Update the cache type from NOCACHE to UNIFIED when all the cache
> attributes we update are valid. This fixes a problem where caches
> which are entirely created by the PPTT don't show up in lstopo.
>
> Give the PPTT its own firmware_node in the cache structure instead of
> sharing it with the of_node.
>
> Move some pieces around between patches.
>
> (see previous cover letters for futher changes)
>
> Jeremy Linton (13):
> drivers: base: cacheinfo: move cache_setup_of_node()
> drivers: base: cacheinfo: setup DT cache properties early
> cacheinfo: rename of_node to fw_token
> arm64/acpi: Create arch specific cpu to acpi id helper
> ACPI/PPTT: Add Processor Properties Topology Table parsing
> ACPI: Enable PPTT support on ARM64
> drivers: base cacheinfo: Add support for ACPI based firmware tables
> arm64: Add support for ACPI based firmware tables
> ACPI/PPTT: Add topology parsing code
> arm64: topology: rename cluster_id
> arm64: topology: enable ACPI/PPTT based CPU topology
> ACPI: Add PPTT to injectable table list
> arm64: topology: divorce MC scheduling domain from core_siblings
>
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/acpi.h | 4 +
> arch/arm64/include/asm/topology.h | 6 +-
> arch/arm64/kernel/cacheinfo.c | 15 +-
> arch/arm64/kernel/topology.c | 103 +++++-
> arch/riscv/kernel/cacheinfo.c | 1 -
> drivers/acpi/Kconfig | 3 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/pptt.c | 678 ++++++++++++++++++++++++++++++++++++++
> drivers/acpi/tables.c | 2 +-
> drivers/base/cacheinfo.c | 157 ++++-----
> include/linux/acpi.h | 4 +
> include/linux/cacheinfo.h | 18 +-
> 13 files changed, 886 insertions(+), 107 deletions(-)
> create mode 100644 drivers/acpi/pptt.c
>