aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@arm.com>2016-10-28 04:45:31 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-10 11:30:53 -0500
commitdfea747d2aba77443acf7ce6fa37caa729bd034c (patch)
treeb58072f13d4eaef5d2e1ae98840725a065a2a9a3
parent8e1073b1ffff5a90c1af75862309c5ed87ef545c (diff)
drivers: base: cacheinfo: support DT overrides for cache properties
Few architectures like x86, ia64 and s390 derive the cache topology and all the properties using a specific architected mechanism while some other architectures like powerpc all those information id derived from the device tree. On ARM, both the mechanism is used. While all the cache properties can be derived in a architected way, it needs to rely on device tree to get the cache topology information. However there are few platforms where this architected mechanism is broken and the device tree properties can be used to override these incorrect values. This patch adds support for overriding the cache properties values to the values specified in the device tree. Cc: Alex Van Brunt <avanbrunt@nvidia.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/base/cacheinfo.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index f19d50bd8925..2376628c599c 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -88,7 +88,120 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
88{ 88{
89 return sib_leaf->of_node == this_leaf->of_node; 89 return sib_leaf->of_node == this_leaf->of_node;
90} 90}
91
92/* OF properties to query for a given cache type */
93struct cache_type_info {
94 const char *size_prop;
95 const char *line_size_props[2];
96 const char *nr_sets_prop;
97};
98
99static const struct cache_type_info cache_type_info[] = {
100 {
101 .size_prop = "cache-size",
102 .line_size_props = { "cache-line-size",
103 "cache-block-size", },
104 .nr_sets_prop = "cache-sets",
105 }, {
106 .size_prop = "i-cache-size",
107 .line_size_props = { "i-cache-line-size",
108 "i-cache-block-size", },
109 .nr_sets_prop = "i-cache-sets",
110 }, {
111 .size_prop = "d-cache-size",
112 .line_size_props = { "d-cache-line-size",
113 "d-cache-block-size", },
114 .nr_sets_prop = "d-cache-sets",
115 },
116};
117
118static inline int get_cacheinfo_idx(enum cache_type type)
119{
120 if (type == CACHE_TYPE_UNIFIED)
121 return 0;
122 return type;
123}
124
125static void cache_size(struct cacheinfo *this_leaf)
126{
127 const char *propname;
128 const __be32 *cache_size;
129 int ct_idx;
130
131 ct_idx = get_cacheinfo_idx(this_leaf->type);
132 propname = cache_type_info[ct_idx].size_prop;
133
134 cache_size = of_get_property(this_leaf->of_node, propname, NULL);
135 if (cache_size)
136 this_leaf->size = of_read_number(cache_size, 1);
137}
138
139/* not cache_line_size() because that's a macro in include/linux/cache.h */
140static void cache_get_line_size(struct cacheinfo *this_leaf)
141{
142 const __be32 *line_size;
143 int i, lim, ct_idx;
144
145 ct_idx = get_cacheinfo_idx(this_leaf->type);
146 lim = ARRAY_SIZE(cache_type_info[ct_idx].line_size_props);
147
148 for (i = 0; i < lim; i++) {
149 const char *propname;
150
151 propname = cache_type_info[ct_idx].line_size_props[i];
152 line_size = of_get_property(this_leaf->of_node, propname, NULL);
153 if (line_size)
154 break;
155 }
156
157 if (line_size)
158 this_leaf->coherency_line_size = of_read_number(line_size, 1);
159}
160
161static void cache_nr_sets(struct cacheinfo *this_leaf)
162{
163 const char *propname;
164 const __be32 *nr_sets;
165 int ct_idx;
166
167 ct_idx = get_cacheinfo_idx(this_leaf->type);
168 propname = cache_type_info[ct_idx].nr_sets_prop;
169
170 nr_sets = of_get_property(this_leaf->of_node, propname, NULL);
171 if (nr_sets)
172 this_leaf->number_of_sets = of_read_number(nr_sets, 1);
173}
174
175static void cache_associativity(struct cacheinfo *this_leaf)
176{
177 unsigned int line_size = this_leaf->coherency_line_size;
178 unsigned int nr_sets = this_leaf->number_of_sets;
179 unsigned int size = this_leaf->size;
180
181 /*
182 * If the cache is fully associative, there is no need to
183 * check the other properties.
184 */
185 if (!(nr_sets == 1) && (nr_sets > 0 && size > 0 && line_size > 0))
186 this_leaf->ways_of_associativity = (size / nr_sets) / line_size;
187}
188
189static void cache_of_override_properties(unsigned int cpu)
190{
191 int index;
192 struct cacheinfo *this_leaf;
193 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
194
195 for (index = 0; index < cache_leaves(cpu); index++) {
196 this_leaf = this_cpu_ci->info_list + index;
197 cache_size(this_leaf);
198 cache_get_line_size(this_leaf);
199 cache_nr_sets(this_leaf);
200 cache_associativity(this_leaf);
201 }
202}
91#else 203#else
204static void cache_of_override_properties(unsigned int cpu) { }
92static inline int cache_setup_of_node(unsigned int cpu) { return 0; } 205static inline int cache_setup_of_node(unsigned int cpu) { return 0; }
93static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, 206static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf,
94 struct cacheinfo *sib_leaf) 207 struct cacheinfo *sib_leaf)
@@ -171,6 +284,12 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
171 } 284 }
172} 285}
173 286
287static void cache_override_properties(unsigned int cpu)
288{
289 if (of_have_populated_dt())
290 return cache_of_override_properties(cpu);
291}
292
174static void free_cache_attributes(unsigned int cpu) 293static void free_cache_attributes(unsigned int cpu)
175{ 294{
176 if (!per_cpu_cacheinfo(cpu)) 295 if (!per_cpu_cacheinfo(cpu))
@@ -216,6 +335,8 @@ static int detect_cache_attributes(unsigned int cpu)
216 pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu); 335 pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu);
217 goto free_ci; 336 goto free_ci;
218 } 337 }
338
339 cache_override_properties(cpu);
219 return 0; 340 return 0;
220 341
221free_ci: 342free_ci: