powerpc/cacheinfo: Lookup cache by dt node and thread-group id
Currently the cacheinfo code on powerpc indexes the "cache" objects (modelling the L1/L2/L3 caches) where the key is device-tree node corresponding to that cache. On some of the POWER server platforms thread-groups within the core share different sets of caches (Eg: On SMT8 POWER9 systems, threads 0,2,4,6 of a core share L1 cache and threads 1,3,5,7 of the same core share another L1 cache). On such platforms, there is a single device-tree node corresponding to that cache and the cache-configuration within the threads of the core is indicated via "ibm,thread-groups" device-tree property. Since the current code is not aware of the "ibm,thread-groups" property, on the aforementoined systems, cacheinfo code still treats all the threads in the core to be sharing the cache because of the single device-tree node (In the earlier example, the cacheinfo code would says CPUs 0-7 share L1 cache). In this patch, we make the powerpc cacheinfo code aware of the "ibm,thread-groups" property. We indexe the "cache" objects by the key-pair (device-tree node, thread-group id). For any CPUX, for a given level of cache, the thread-group id is defined to be the first CPU in the "ibm,thread-groups" cache-group containing CPUX. For levels of cache which are not represented in "ibm,thread-groups" property, the thread-group id is -1. [parth: Remove "static" keyword for the definition of "thread_group_l1_cache_map" and "thread_group_l2_cache_map" to get rid of the compile error.] Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com> Signed-off-by: Parth Shah <parth@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210728175607.591679-2-parth@linux.ibm.com
This commit is contained in:
committed by
Michael Ellerman
parent
86ff0bce2e
commit
a4bec516b9
@@ -33,6 +33,9 @@ extern bool coregroup_enabled;
|
|||||||
extern int cpu_to_chip_id(int cpu);
|
extern int cpu_to_chip_id(int cpu);
|
||||||
extern int *chip_id_lookup_table;
|
extern int *chip_id_lookup_table;
|
||||||
|
|
||||||
|
DECLARE_PER_CPU(cpumask_var_t, thread_group_l1_cache_map);
|
||||||
|
DECLARE_PER_CPU(cpumask_var_t, thread_group_l2_cache_map);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
struct smp_ops_t {
|
struct smp_ops_t {
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ struct cache {
|
|||||||
struct cpumask shared_cpu_map; /* online CPUs using this cache */
|
struct cpumask shared_cpu_map; /* online CPUs using this cache */
|
||||||
int type; /* split cache disambiguation */
|
int type; /* split cache disambiguation */
|
||||||
int level; /* level not explicit in device tree */
|
int level; /* level not explicit in device tree */
|
||||||
|
int group_id; /* id of the group of threads that share this cache */
|
||||||
struct list_head list; /* global list of cache objects */
|
struct list_head list; /* global list of cache objects */
|
||||||
struct cache *next_local; /* next cache of >= level */
|
struct cache *next_local; /* next cache of >= level */
|
||||||
};
|
};
|
||||||
@@ -142,22 +143,24 @@ static const char *cache_type_string(const struct cache *cache)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void cache_init(struct cache *cache, int type, int level,
|
static void cache_init(struct cache *cache, int type, int level,
|
||||||
struct device_node *ofnode)
|
struct device_node *ofnode, int group_id)
|
||||||
{
|
{
|
||||||
cache->type = type;
|
cache->type = type;
|
||||||
cache->level = level;
|
cache->level = level;
|
||||||
cache->ofnode = of_node_get(ofnode);
|
cache->ofnode = of_node_get(ofnode);
|
||||||
|
cache->group_id = group_id;
|
||||||
INIT_LIST_HEAD(&cache->list);
|
INIT_LIST_HEAD(&cache->list);
|
||||||
list_add(&cache->list, &cache_list);
|
list_add(&cache->list, &cache_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache *new_cache(int type, int level, struct device_node *ofnode)
|
static struct cache *new_cache(int type, int level,
|
||||||
|
struct device_node *ofnode, int group_id)
|
||||||
{
|
{
|
||||||
struct cache *cache;
|
struct cache *cache;
|
||||||
|
|
||||||
cache = kzalloc(sizeof(*cache), GFP_KERNEL);
|
cache = kzalloc(sizeof(*cache), GFP_KERNEL);
|
||||||
if (cache)
|
if (cache)
|
||||||
cache_init(cache, type, level, ofnode);
|
cache_init(cache, type, level, ofnode, group_id);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@@ -309,20 +312,24 @@ static struct cache *cache_find_first_sibling(struct cache *cache)
|
|||||||
return cache;
|
return cache;
|
||||||
|
|
||||||
list_for_each_entry(iter, &cache_list, list)
|
list_for_each_entry(iter, &cache_list, list)
|
||||||
if (iter->ofnode == cache->ofnode && iter->next_local == cache)
|
if (iter->ofnode == cache->ofnode &&
|
||||||
|
iter->group_id == cache->group_id &&
|
||||||
|
iter->next_local == cache)
|
||||||
return iter;
|
return iter;
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the first cache on a local list matching node */
|
/* return the first cache on a local list matching node and thread-group id */
|
||||||
static struct cache *cache_lookup_by_node(const struct device_node *node)
|
static struct cache *cache_lookup_by_node_group(const struct device_node *node,
|
||||||
|
int group_id)
|
||||||
{
|
{
|
||||||
struct cache *cache = NULL;
|
struct cache *cache = NULL;
|
||||||
struct cache *iter;
|
struct cache *iter;
|
||||||
|
|
||||||
list_for_each_entry(iter, &cache_list, list) {
|
list_for_each_entry(iter, &cache_list, list) {
|
||||||
if (iter->ofnode != node)
|
if (iter->ofnode != node ||
|
||||||
|
iter->group_id != group_id)
|
||||||
continue;
|
continue;
|
||||||
cache = cache_find_first_sibling(iter);
|
cache = cache_find_first_sibling(iter);
|
||||||
break;
|
break;
|
||||||
@@ -352,14 +359,15 @@ static int cache_is_unified_d(const struct device_node *np)
|
|||||||
CACHE_TYPE_UNIFIED_D : CACHE_TYPE_UNIFIED;
|
CACHE_TYPE_UNIFIED_D : CACHE_TYPE_UNIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache *cache_do_one_devnode_unified(struct device_node *node, int level)
|
static struct cache *cache_do_one_devnode_unified(struct device_node *node, int group_id,
|
||||||
|
int level)
|
||||||
{
|
{
|
||||||
pr_debug("creating L%d ucache for %pOFP\n", level, node);
|
pr_debug("creating L%d ucache for %pOFP\n", level, node);
|
||||||
|
|
||||||
return new_cache(cache_is_unified_d(node), level, node);
|
return new_cache(cache_is_unified_d(node), level, node, group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache *cache_do_one_devnode_split(struct device_node *node,
|
static struct cache *cache_do_one_devnode_split(struct device_node *node, int group_id,
|
||||||
int level)
|
int level)
|
||||||
{
|
{
|
||||||
struct cache *dcache, *icache;
|
struct cache *dcache, *icache;
|
||||||
@@ -367,8 +375,8 @@ static struct cache *cache_do_one_devnode_split(struct device_node *node,
|
|||||||
pr_debug("creating L%d dcache and icache for %pOFP\n", level,
|
pr_debug("creating L%d dcache and icache for %pOFP\n", level,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
dcache = new_cache(CACHE_TYPE_DATA, level, node);
|
dcache = new_cache(CACHE_TYPE_DATA, level, node, group_id);
|
||||||
icache = new_cache(CACHE_TYPE_INSTRUCTION, level, node);
|
icache = new_cache(CACHE_TYPE_INSTRUCTION, level, node, group_id);
|
||||||
|
|
||||||
if (!dcache || !icache)
|
if (!dcache || !icache)
|
||||||
goto err;
|
goto err;
|
||||||
@@ -382,31 +390,32 @@ err:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache *cache_do_one_devnode(struct device_node *node, int level)
|
static struct cache *cache_do_one_devnode(struct device_node *node, int group_id, int level)
|
||||||
{
|
{
|
||||||
struct cache *cache;
|
struct cache *cache;
|
||||||
|
|
||||||
if (cache_node_is_unified(node))
|
if (cache_node_is_unified(node))
|
||||||
cache = cache_do_one_devnode_unified(node, level);
|
cache = cache_do_one_devnode_unified(node, group_id, level);
|
||||||
else
|
else
|
||||||
cache = cache_do_one_devnode_split(node, level);
|
cache = cache_do_one_devnode_split(node, group_id, level);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cache *cache_lookup_or_instantiate(struct device_node *node,
|
static struct cache *cache_lookup_or_instantiate(struct device_node *node,
|
||||||
|
int group_id,
|
||||||
int level)
|
int level)
|
||||||
{
|
{
|
||||||
struct cache *cache;
|
struct cache *cache;
|
||||||
|
|
||||||
cache = cache_lookup_by_node(node);
|
cache = cache_lookup_by_node_group(node, group_id);
|
||||||
|
|
||||||
WARN_ONCE(cache && cache->level != level,
|
WARN_ONCE(cache && cache->level != level,
|
||||||
"cache level mismatch on lookup (got %d, expected %d)\n",
|
"cache level mismatch on lookup (got %d, expected %d)\n",
|
||||||
cache->level, level);
|
cache->level, level);
|
||||||
|
|
||||||
if (!cache)
|
if (!cache)
|
||||||
cache = cache_do_one_devnode(node, level);
|
cache = cache_do_one_devnode(node, group_id, level);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@@ -443,7 +452,27 @@ static void do_subsidiary_caches_debugcheck(struct cache *cache)
|
|||||||
of_node_get_device_type(cache->ofnode));
|
of_node_get_device_type(cache->ofnode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_subsidiary_caches(struct cache *cache)
|
/*
|
||||||
|
* If sub-groups of threads in a core containing @cpu_id share the
|
||||||
|
* L@level-cache (information obtained via "ibm,thread-groups"
|
||||||
|
* device-tree property), then we identify the group by the first
|
||||||
|
* thread-sibling in the group. We define this to be the group-id.
|
||||||
|
*
|
||||||
|
* In the absence of any thread-group information for L@level-cache,
|
||||||
|
* this function returns -1.
|
||||||
|
*/
|
||||||
|
static int get_group_id(unsigned int cpu_id, int level)
|
||||||
|
{
|
||||||
|
if (has_big_cores && level == 1)
|
||||||
|
return cpumask_first(per_cpu(thread_group_l1_cache_map,
|
||||||
|
cpu_id));
|
||||||
|
else if (thread_group_shares_l2 && level == 2)
|
||||||
|
return cpumask_first(per_cpu(thread_group_l2_cache_map,
|
||||||
|
cpu_id));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_subsidiary_caches(struct cache *cache, unsigned int cpu_id)
|
||||||
{
|
{
|
||||||
struct device_node *subcache_node;
|
struct device_node *subcache_node;
|
||||||
int level = cache->level;
|
int level = cache->level;
|
||||||
@@ -452,9 +481,11 @@ static void do_subsidiary_caches(struct cache *cache)
|
|||||||
|
|
||||||
while ((subcache_node = of_find_next_cache_node(cache->ofnode))) {
|
while ((subcache_node = of_find_next_cache_node(cache->ofnode))) {
|
||||||
struct cache *subcache;
|
struct cache *subcache;
|
||||||
|
int group_id;
|
||||||
|
|
||||||
level++;
|
level++;
|
||||||
subcache = cache_lookup_or_instantiate(subcache_node, level);
|
group_id = get_group_id(cpu_id, level);
|
||||||
|
subcache = cache_lookup_or_instantiate(subcache_node, group_id, level);
|
||||||
of_node_put(subcache_node);
|
of_node_put(subcache_node);
|
||||||
if (!subcache)
|
if (!subcache)
|
||||||
break;
|
break;
|
||||||
@@ -468,6 +499,7 @@ static struct cache *cache_chain_instantiate(unsigned int cpu_id)
|
|||||||
{
|
{
|
||||||
struct device_node *cpu_node;
|
struct device_node *cpu_node;
|
||||||
struct cache *cpu_cache = NULL;
|
struct cache *cpu_cache = NULL;
|
||||||
|
int group_id;
|
||||||
|
|
||||||
pr_debug("creating cache object(s) for CPU %i\n", cpu_id);
|
pr_debug("creating cache object(s) for CPU %i\n", cpu_id);
|
||||||
|
|
||||||
@@ -476,11 +508,13 @@ static struct cache *cache_chain_instantiate(unsigned int cpu_id)
|
|||||||
if (!cpu_node)
|
if (!cpu_node)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cpu_cache = cache_lookup_or_instantiate(cpu_node, 1);
|
group_id = get_group_id(cpu_id, 1);
|
||||||
|
|
||||||
|
cpu_cache = cache_lookup_or_instantiate(cpu_node, group_id, 1);
|
||||||
if (!cpu_cache)
|
if (!cpu_cache)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
do_subsidiary_caches(cpu_cache);
|
do_subsidiary_caches(cpu_cache, cpu_id);
|
||||||
|
|
||||||
cache_cpu_set(cpu_cache, cpu_id);
|
cache_cpu_set(cpu_cache, cpu_id);
|
||||||
out:
|
out:
|
||||||
@@ -848,13 +882,15 @@ static struct cache *cache_lookup_by_cpu(unsigned int cpu_id)
|
|||||||
{
|
{
|
||||||
struct device_node *cpu_node;
|
struct device_node *cpu_node;
|
||||||
struct cache *cache;
|
struct cache *cache;
|
||||||
|
int group_id;
|
||||||
|
|
||||||
cpu_node = of_get_cpu_node(cpu_id, NULL);
|
cpu_node = of_get_cpu_node(cpu_id, NULL);
|
||||||
WARN_ONCE(!cpu_node, "no OF node found for CPU %i\n", cpu_id);
|
WARN_ONCE(!cpu_node, "no OF node found for CPU %i\n", cpu_id);
|
||||||
if (!cpu_node)
|
if (!cpu_node)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cache = cache_lookup_by_node(cpu_node);
|
group_id = get_group_id(cpu_id, 1);
|
||||||
|
cache = cache_lookup_by_node_group(cpu_node, group_id);
|
||||||
of_node_put(cpu_node);
|
of_node_put(cpu_node);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
|
|||||||
@@ -122,14 +122,14 @@ static struct thread_groups_list tgl[NR_CPUS] __initdata;
|
|||||||
* On big-cores system, thread_group_l1_cache_map for each CPU corresponds to
|
* On big-cores system, thread_group_l1_cache_map for each CPU corresponds to
|
||||||
* the set its siblings that share the L1-cache.
|
* the set its siblings that share the L1-cache.
|
||||||
*/
|
*/
|
||||||
static DEFINE_PER_CPU(cpumask_var_t, thread_group_l1_cache_map);
|
DEFINE_PER_CPU(cpumask_var_t, thread_group_l1_cache_map);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On some big-cores system, thread_group_l2_cache_map for each CPU
|
* On some big-cores system, thread_group_l2_cache_map for each CPU
|
||||||
* corresponds to the set its siblings within the core that share the
|
* corresponds to the set its siblings within the core that share the
|
||||||
* L2-cache.
|
* L2-cache.
|
||||||
*/
|
*/
|
||||||
static DEFINE_PER_CPU(cpumask_var_t, thread_group_l2_cache_map);
|
DEFINE_PER_CPU(cpumask_var_t, thread_group_l2_cache_map);
|
||||||
|
|
||||||
/* SMP operations for this machine */
|
/* SMP operations for this machine */
|
||||||
struct smp_ops_t *smp_ops;
|
struct smp_ops_t *smp_ops;
|
||||||
|
|||||||
Reference in New Issue
Block a user