xref: /linux/arch/riscv/kernel/cacheinfo.c (revision 37744feebc086908fd89760650f458ab19071750)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2017 SiFive
4  */
5 
6 #include <linux/cacheinfo.h>
7 #include <linux/cpu.h>
8 #include <linux/of.h>
9 #include <linux/of_device.h>
10 
11 static void ci_leaf_init(struct cacheinfo *this_leaf,
12 			 struct device_node *node,
13 			 enum cache_type type, unsigned int level)
14 {
15 	this_leaf->level = level;
16 	this_leaf->type = type;
17 }
18 
19 static int __init_cache_level(unsigned int cpu)
20 {
21 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
22 	struct device_node *np = of_cpu_device_node_get(cpu);
23 	struct device_node *prev = NULL;
24 	int levels = 0, leaves = 0, level;
25 
26 	if (of_property_read_bool(np, "cache-size"))
27 		++leaves;
28 	if (of_property_read_bool(np, "i-cache-size"))
29 		++leaves;
30 	if (of_property_read_bool(np, "d-cache-size"))
31 		++leaves;
32 	if (leaves > 0)
33 		levels = 1;
34 
35 	prev = np;
36 	while ((np = of_find_next_cache_node(np))) {
37 		of_node_put(prev);
38 		prev = np;
39 		if (!of_device_is_compatible(np, "cache"))
40 			break;
41 		if (of_property_read_u32(np, "cache-level", &level))
42 			break;
43 		if (level <= levels)
44 			break;
45 		if (of_property_read_bool(np, "cache-size"))
46 			++leaves;
47 		if (of_property_read_bool(np, "i-cache-size"))
48 			++leaves;
49 		if (of_property_read_bool(np, "d-cache-size"))
50 			++leaves;
51 		levels = level;
52 	}
53 
54 	of_node_put(np);
55 	this_cpu_ci->num_levels = levels;
56 	this_cpu_ci->num_leaves = leaves;
57 
58 	return 0;
59 }
60 
61 static int __populate_cache_leaves(unsigned int cpu)
62 {
63 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
64 	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
65 	struct device_node *np = of_cpu_device_node_get(cpu);
66 	struct device_node *prev = NULL;
67 	int levels = 1, level = 1;
68 
69 	if (of_property_read_bool(np, "cache-size"))
70 		ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
71 	if (of_property_read_bool(np, "i-cache-size"))
72 		ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
73 	if (of_property_read_bool(np, "d-cache-size"))
74 		ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
75 
76 	prev = np;
77 	while ((np = of_find_next_cache_node(np))) {
78 		of_node_put(prev);
79 		prev = np;
80 		if (!of_device_is_compatible(np, "cache"))
81 			break;
82 		if (of_property_read_u32(np, "cache-level", &level))
83 			break;
84 		if (level <= levels)
85 			break;
86 		if (of_property_read_bool(np, "cache-size"))
87 			ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
88 		if (of_property_read_bool(np, "i-cache-size"))
89 			ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
90 		if (of_property_read_bool(np, "d-cache-size"))
91 			ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
92 		levels = level;
93 	}
94 	of_node_put(np);
95 
96 	return 0;
97 }
98 
99 DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
100 DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
101