Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kernel/cacheinfo.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* ARM64 cacheinfo support
4
*
5
* Copyright (C) 2015 ARM Ltd.
6
* All Rights Reserved
7
*/
8
9
#include <linux/acpi.h>
10
#include <linux/cacheinfo.h>
11
#include <linux/of.h>
12
13
#define MAX_CACHE_LEVEL 7 /* Max 7 level supported */
14
15
int cache_line_size(void)
16
{
17
if (coherency_max_size != 0)
18
return coherency_max_size;
19
20
return cache_line_size_of_cpu();
21
}
22
EXPORT_SYMBOL_GPL(cache_line_size);
23
24
static inline enum cache_type get_cache_type(int level)
25
{
26
u64 clidr;
27
28
if (level > MAX_CACHE_LEVEL)
29
return CACHE_TYPE_NOCACHE;
30
clidr = read_sysreg(clidr_el1);
31
return CLIDR_CTYPE(clidr, level);
32
}
33
34
static void ci_leaf_init(struct cacheinfo *this_leaf,
35
enum cache_type type, unsigned int level)
36
{
37
this_leaf->level = level;
38
this_leaf->type = type;
39
}
40
41
static void detect_cache_level(unsigned int *level_p, unsigned int *leaves_p)
42
{
43
unsigned int ctype, level, leaves;
44
45
for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
46
ctype = get_cache_type(level);
47
if (ctype == CACHE_TYPE_NOCACHE) {
48
level--;
49
break;
50
}
51
/* Separate instruction and data caches */
52
leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
53
}
54
55
*level_p = level;
56
*leaves_p = leaves;
57
}
58
59
int early_cache_level(unsigned int cpu)
60
{
61
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
62
63
detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves);
64
65
return 0;
66
}
67
68
int init_cache_level(unsigned int cpu)
69
{
70
unsigned int level, leaves;
71
int fw_level, ret;
72
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
73
74
detect_cache_level(&level, &leaves);
75
76
if (acpi_disabled) {
77
fw_level = of_find_last_cache_level(cpu);
78
} else {
79
ret = acpi_get_cache_info(cpu, &fw_level, NULL);
80
if (ret < 0)
81
fw_level = 0;
82
}
83
84
if (level < fw_level) {
85
/*
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
89
*/
90
leaves += (fw_level - level);
91
level = fw_level;
92
}
93
94
this_cpu_ci->num_levels = level;
95
this_cpu_ci->num_leaves = leaves;
96
return 0;
97
}
98
99
int populate_cache_leaves(unsigned int cpu)
100
{
101
unsigned int level, idx;
102
enum cache_type type;
103
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
104
struct cacheinfo *infos = this_cpu_ci->info_list;
105
106
for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
107
idx < this_cpu_ci->num_leaves; level++) {
108
type = get_cache_type(level);
109
if (type == CACHE_TYPE_SEPARATE) {
110
if (idx + 1 >= this_cpu_ci->num_leaves)
111
break;
112
ci_leaf_init(&infos[idx++], CACHE_TYPE_DATA, level);
113
ci_leaf_init(&infos[idx++], CACHE_TYPE_INST, level);
114
} else {
115
ci_leaf_init(&infos[idx++], type, level);
116
}
117
}
118
return 0;
119
}
120
121