blob: e674afae306fa81fac6bc3fb574c38fd2091a7c0 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Martin Roth9df9e9392016-01-12 15:55:28 -07002
Lee Leahy2da95242015-06-12 17:30:33 -07003#include <cpu/cpu.h>
Elyes Haouasae1ca822022-10-07 10:02:38 +02004#include <types.h>
Lee Leahy2da95242015-06-12 17:30:33 -07005
Patrick Rudolphadcf7822020-08-27 20:50:18 +02006#if ENV_X86_32
Lee Leahy2da95242015-06-12 17:30:33 -07007/* Standard macro to see if a specific flag is changeable */
8static inline int flag_is_changeable_p(uint32_t flag)
9{
10 uint32_t f1, f2;
11
12 asm(
13 "pushfl\n\t"
14 "pushfl\n\t"
15 "popl %0\n\t"
16 "movl %0,%1\n\t"
17 "xorl %2,%0\n\t"
18 "pushl %0\n\t"
19 "popfl\n\t"
20 "pushfl\n\t"
21 "popl %0\n\t"
22 "popfl\n\t"
23 : "=&r" (f1), "=&r" (f2)
24 : "ir" (flag));
25 return ((f1^f2) & flag) != 0;
26}
27
28/* Probe for the CPUID instruction */
29int cpu_have_cpuid(void)
30{
31 return flag_is_changeable_p(X86_EFLAGS_ID);
32}
33
Stefan Reinauer96938852015-06-18 01:23:48 -070034#else
35
36int cpu_have_cpuid(void)
37{
38 return 1;
39}
40#endif
41
Elyes HAOUAS1c9bd9c2019-06-26 17:49:31 +020042unsigned int cpu_cpuid_extended_level(void)
Lee Leahy2da95242015-06-12 17:30:33 -070043{
44 return cpuid_eax(0x80000000);
45}
46
47int cpu_phys_address_size(void)
48{
49 if (!(cpu_have_cpuid()))
50 return 32;
51
52 if (cpu_cpuid_extended_level() >= 0x80000008)
53 return cpuid_eax(0x80000008) & 0xff;
54
55 if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36))
56 return 36;
57 return 32;
58}
Subrata Banik53b08c32018-12-10 14:11:35 +053059
60/*
61 * Get processor id using cpuid eax=1
62 * return value in EAX register
63 */
64uint32_t cpu_get_cpuid(void)
65{
66 return cpuid_eax(1);
67}
68
69/*
70 * Get processor feature flag using cpuid eax=1
71 * return value in ECX register
72 */
73uint32_t cpu_get_feature_flags_ecx(void)
74{
75 return cpuid_ecx(1);
76}
77
78/*
79 * Get processor feature flag using cpuid eax=1
80 * return value in EDX register
81 */
82uint32_t cpu_get_feature_flags_edx(void)
83{
84 return cpuid_edx(1);
85}
Subrata Banik0c6c0da2021-07-23 21:00:58 +053086
87enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void)
88{
89 struct cpuid_result res;
90
91 if (cpu_is_intel()) {
92 res = cpuid(0);
93 if (res.eax < 4)
94 return CPUID_COMMAND_UNSUPPORTED;
95 return CPUID_TYPE_INTEL;
96 } else if (cpu_is_amd()) {
97 res = cpuid(0x80000000);
98 if (res.eax < 0x80000001)
99 return CPUID_COMMAND_UNSUPPORTED;
100
101 res = cpuid(0x80000001);
102 if (!(res.ecx & (1 << 22)))
103 return CPUID_COMMAND_UNSUPPORTED;
104
105 return CPUID_TYPE_AMD;
106 } else {
107 return CPUID_TYPE_INVALID;
108 }
109}
110
111static uint32_t cpu_get_cache_info_leaf(void)
112{
Subrata Banik72f1e622021-09-01 12:35:15 +0530113 uint32_t leaf = (cpu_check_deterministic_cache_cpuid_supported() == CPUID_TYPE_AMD) ?
114 DETERMINISTIC_CACHE_PARAMETERS_CPUID_AMD :
115 DETERMINISTIC_CACHE_PARAMETERS_CPUID_IA;
116
117 return leaf;
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530118}
119
120size_t cpu_get_cache_ways_assoc_info(const struct cpu_cache_info *info)
121{
122 if (!info)
123 return 0;
124
125 return info->num_ways;
126}
127
128uint8_t cpu_get_cache_type(const struct cpu_cache_info *info)
129{
130 if (!info)
131 return 0;
132
133 return info->type;
134}
135
136uint8_t cpu_get_cache_level(const struct cpu_cache_info *info)
137{
138 if (!info)
139 return 0;
140
141 return info->level;
142}
143
144size_t cpu_get_cache_phy_partition_info(const struct cpu_cache_info *info)
145{
146 if (!info)
147 return 0;
148
149 return info->physical_partitions;
150}
151
152size_t cpu_get_cache_line_size(const struct cpu_cache_info *info)
153{
154 if (!info)
155 return 0;
156
157 return info->line_size;
158}
159
160size_t cpu_get_cache_sets(const struct cpu_cache_info *info)
161{
162 if (!info)
163 return 0;
164
165 return info->num_sets;
166}
167
168bool cpu_is_cache_full_assoc(const struct cpu_cache_info *info)
169{
170 if (!info)
171 return false;
172
173 return info->fully_associative;
174}
175
176size_t cpu_get_max_cache_share(const struct cpu_cache_info *info)
177{
178 if (!info)
179 return 0;
180
181 return info->num_cores_shared;
182}
183
184size_t get_cache_size(const struct cpu_cache_info *info)
185{
186 if (!info)
187 return 0;
188
189 return info->num_ways * info->physical_partitions * info->line_size * info->num_sets;
190}
191
192bool fill_cpu_cache_info(uint8_t level, struct cpu_cache_info *info)
193{
194 if (!info)
195 return false;
196
197 uint32_t leaf = cpu_get_cache_info_leaf();
198 if (!leaf)
199 return false;
200
201 struct cpuid_result cache_info_res = cpuid_ext(leaf, level);
202
203 info->type = CPUID_CACHE_TYPE(cache_info_res);
204 info->level = CPUID_CACHE_LEVEL(cache_info_res);
205 info->num_ways = CPUID_CACHE_WAYS_OF_ASSOC(cache_info_res) + 1;
206 info->num_sets = CPUID_CACHE_NO_OF_SETS(cache_info_res) + 1;
207 info->line_size = CPUID_CACHE_COHER_LINE(cache_info_res) + 1;
208 info->physical_partitions = CPUID_CACHE_PHYS_LINE(cache_info_res) + 1;
209 info->num_cores_shared = CPUID_CACHE_SHARING_CACHE(cache_info_res) + 1;
210 info->fully_associative = CPUID_CACHE_FULL_ASSOC(cache_info_res);
211 info->size = get_cache_size(info);
212
213 return true;
214}