1 // SPDX-License-Identifier: GPL-2.0-only
3 * ARM64 cacheinfo support
5 * Copyright (C) 2015 ARM Ltd.
9 #include <linux/acpi.h>
10 #include <linux/cacheinfo.h>
13 #define MAX_CACHE_LEVEL 7 /* Max 7 level supported */
15 int cache_line_size(void)
17 if (coherency_max_size
!= 0)
18 return coherency_max_size
;
20 return cache_line_size_of_cpu();
22 EXPORT_SYMBOL_GPL(cache_line_size
);
24 static inline enum cache_type
get_cache_type(int level
)
28 if (level
> MAX_CACHE_LEVEL
)
29 return CACHE_TYPE_NOCACHE
;
30 clidr
= read_sysreg(clidr_el1
);
31 return CLIDR_CTYPE(clidr
, level
);
34 static void ci_leaf_init(struct cacheinfo
*this_leaf
,
35 enum cache_type type
, unsigned int level
)
37 this_leaf
->level
= level
;
38 this_leaf
->type
= type
;
41 static void detect_cache_level(unsigned int *level_p
, unsigned int *leaves_p
)
43 unsigned int ctype
, level
, leaves
;
45 for (level
= 1, leaves
= 0; level
<= MAX_CACHE_LEVEL
; level
++) {
46 ctype
= get_cache_type(level
);
47 if (ctype
== CACHE_TYPE_NOCACHE
) {
51 /* Separate instruction and data caches */
52 leaves
+= (ctype
== CACHE_TYPE_SEPARATE
) ? 2 : 1;
59 int early_cache_level(unsigned int cpu
)
61 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
63 detect_cache_level(&this_cpu_ci
->num_levels
, &this_cpu_ci
->num_leaves
);
68 int init_cache_level(unsigned int cpu
)
70 unsigned int level
, leaves
;
72 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
74 detect_cache_level(&level
, &leaves
);
77 fw_level
= of_find_last_cache_level(cpu
);
79 ret
= acpi_get_cache_info(cpu
, &fw_level
, NULL
);
84 if (level
< fw_level
) {
86 * some external caches not specified in CLIDR_EL1
87 * the information may be available in the device tree
88 * only unified external caches are considered here
90 leaves
+= (fw_level
- level
);
94 this_cpu_ci
->num_levels
= level
;
95 this_cpu_ci
->num_leaves
= leaves
;
99 int populate_cache_leaves(unsigned int cpu
)
101 unsigned int level
, idx
;
102 enum cache_type type
;
103 struct cpu_cacheinfo
*this_cpu_ci
= get_cpu_cacheinfo(cpu
);
104 struct cacheinfo
*this_leaf
= this_cpu_ci
->info_list
;
106 for (idx
= 0, level
= 1; level
<= this_cpu_ci
->num_levels
&&
107 idx
< this_cpu_ci
->num_leaves
; idx
++, level
++) {
108 type
= get_cache_type(level
);
109 if (type
== CACHE_TYPE_SEPARATE
) {
110 ci_leaf_init(this_leaf
++, CACHE_TYPE_DATA
, level
);
111 ci_leaf_init(this_leaf
++, CACHE_TYPE_INST
, level
);
113 ci_leaf_init(this_leaf
++, type
, level
);