Merge tag 'riscv-for-linus-6.4-mw1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / arch / riscv / kernel / cacheinfo.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2017 SiFive
4  */
5
6 #include <linux/cpu.h>
7 #include <linux/of.h>
8 #include <asm/cacheinfo.h>
9
10 static struct riscv_cacheinfo_ops *rv_cache_ops;
11
12 void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops)
13 {
14         rv_cache_ops = ops;
15 }
16 EXPORT_SYMBOL_GPL(riscv_set_cacheinfo_ops);
17
18 const struct attribute_group *
19 cache_get_priv_group(struct cacheinfo *this_leaf)
20 {
21         if (rv_cache_ops && rv_cache_ops->get_priv_group)
22                 return rv_cache_ops->get_priv_group(this_leaf);
23         return NULL;
24 }
25
26 static struct cacheinfo *get_cacheinfo(u32 level, enum cache_type type)
27 {
28         /*
29          * Using raw_smp_processor_id() elides a preemptability check, but this
30          * is really indicative of a larger problem: the cacheinfo UABI assumes
31          * that cores have a homonogenous view of the cache hierarchy.  That
32          * happens to be the case for the current set of RISC-V systems, but
33          * likely won't be true in general.  Since there's no way to provide
34          * correct information for these systems via the current UABI we're
35          * just eliding the check for now.
36          */
37         struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(raw_smp_processor_id());
38         struct cacheinfo *this_leaf;
39         int index;
40
41         for (index = 0; index < this_cpu_ci->num_leaves; index++) {
42                 this_leaf = this_cpu_ci->info_list + index;
43                 if (this_leaf->level == level && this_leaf->type == type)
44                         return this_leaf;
45         }
46
47         return NULL;
48 }
49
50 uintptr_t get_cache_size(u32 level, enum cache_type type)
51 {
52         struct cacheinfo *this_leaf = get_cacheinfo(level, type);
53
54         return this_leaf ? this_leaf->size : 0;
55 }
56
57 uintptr_t get_cache_geometry(u32 level, enum cache_type type)
58 {
59         struct cacheinfo *this_leaf = get_cacheinfo(level, type);
60
61         return this_leaf ? (this_leaf->ways_of_associativity << 16 |
62                             this_leaf->coherency_line_size) :
63                            0;
64 }
65
66 static void ci_leaf_init(struct cacheinfo *this_leaf,
67                          struct device_node *node,
68                          enum cache_type type, unsigned int level)
69 {
70         this_leaf->level = level;
71         this_leaf->type = type;
72 }
73
74 int populate_cache_leaves(unsigned int cpu)
75 {
76         struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
77         struct cacheinfo *this_leaf = this_cpu_ci->info_list;
78         struct device_node *np = of_cpu_device_node_get(cpu);
79         struct device_node *prev = NULL;
80         int levels = 1, level = 1;
81
82         if (of_property_read_bool(np, "cache-size"))
83                 ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
84         if (of_property_read_bool(np, "i-cache-size"))
85                 ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
86         if (of_property_read_bool(np, "d-cache-size"))
87                 ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
88
89         prev = np;
90         while ((np = of_find_next_cache_node(np))) {
91                 of_node_put(prev);
92                 prev = np;
93                 if (!of_device_is_compatible(np, "cache"))
94                         break;
95                 if (of_property_read_u32(np, "cache-level", &level))
96                         break;
97                 if (level <= levels)
98                         break;
99                 if (of_property_read_bool(np, "cache-size"))
100                         ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
101                 if (of_property_read_bool(np, "i-cache-size"))
102                         ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
103                 if (of_property_read_bool(np, "d-cache-size"))
104                         ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
105                 levels = level;
106         }
107         of_node_put(np);
108
109         return 0;
110 }