blob: 5f7cd5dddfee17d31fef99a39b3e716aee09409c [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
Subrata Banika4c91e12024-03-16 17:57:28 +05303#include <commonlib/helpers.h>
Lee Leahy2da95242015-06-12 17:30:33 -07004#include <cpu/cpu.h>
Elyes Haouasae1ca822022-10-07 10:02:38 +02005#include <types.h>
Lee Leahy2da95242015-06-12 17:30:33 -07006
Patrick Rudolphadcf7822020-08-27 20:50:18 +02007#if ENV_X86_32
Lee Leahy2da95242015-06-12 17:30:33 -07008/* Standard macro to see if a specific flag is changeable */
9static inline int flag_is_changeable_p(uint32_t flag)
10{
11 uint32_t f1, f2;
12
13 asm(
14 "pushfl\n\t"
15 "pushfl\n\t"
16 "popl %0\n\t"
17 "movl %0,%1\n\t"
18 "xorl %2,%0\n\t"
19 "pushl %0\n\t"
20 "popfl\n\t"
21 "pushfl\n\t"
22 "popl %0\n\t"
23 "popfl\n\t"
24 : "=&r" (f1), "=&r" (f2)
25 : "ir" (flag));
26 return ((f1^f2) & flag) != 0;
27}
28
29/* Probe for the CPUID instruction */
30int cpu_have_cpuid(void)
31{
32 return flag_is_changeable_p(X86_EFLAGS_ID);
33}
34
Stefan Reinauer96938852015-06-18 01:23:48 -070035#else
36
37int cpu_have_cpuid(void)
38{
39 return 1;
40}
41#endif
42
Elyes HAOUAS1c9bd9c2019-06-26 17:49:31 +020043unsigned int cpu_cpuid_extended_level(void)
Lee Leahy2da95242015-06-12 17:30:33 -070044{
45 return cpuid_eax(0x80000000);
46}
47
Felix Heldff4d6be2023-09-12 14:18:49 +020048unsigned int cpu_phys_address_size(void)
Lee Leahy2da95242015-06-12 17:30:33 -070049{
50 if (!(cpu_have_cpuid()))
51 return 32;
52
Jeremy Compostella1eff77b2023-09-07 10:33:30 -070053 if (cpu_cpuid_extended_level() >= 0x80000008) {
54 int size = cpuid_eax(0x80000008) & 0xff;
55 size -= get_reserved_phys_addr_bits();
56 return size;
57 }
Lee Leahy2da95242015-06-12 17:30:33 -070058
59 if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36))
60 return 36;
61 return 32;
62}
Subrata Banik53b08c32018-12-10 14:11:35 +053063
Jeremy Compostellaba757a72023-12-20 09:07:04 -080064unsigned int soc_phys_address_size(void)
65{
66 if (CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH)
67 return CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH;
68
69 return cpu_phys_address_size();
70}
71
Subrata Banik53b08c32018-12-10 14:11:35 +053072/*
73 * Get processor id using cpuid eax=1
74 * return value in EAX register
75 */
76uint32_t cpu_get_cpuid(void)
77{
78 return cpuid_eax(1);
79}
80
81/*
82 * Get processor feature flag using cpuid eax=1
83 * return value in ECX register
84 */
85uint32_t cpu_get_feature_flags_ecx(void)
86{
87 return cpuid_ecx(1);
88}
89
90/*
91 * Get processor feature flag using cpuid eax=1
92 * return value in EDX register
93 */
94uint32_t cpu_get_feature_flags_edx(void)
95{
96 return cpuid_edx(1);
97}
Subrata Banik0c6c0da2021-07-23 21:00:58 +053098
99enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void)
100{
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530101 if (cpu_is_intel()) {
Felix Held3581a682023-09-23 03:44:55 +0200102 if (cpuid_get_max_func() < 4)
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530103 return CPUID_COMMAND_UNSUPPORTED;
104 return CPUID_TYPE_INTEL;
105 } else if (cpu_is_amd()) {
Felix Held9acae392023-09-21 20:33:10 +0200106 if (cpu_cpuid_extended_level() < 0x80000001)
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530107 return CPUID_COMMAND_UNSUPPORTED;
108
Felix Held1d466f22023-09-21 20:34:43 +0200109 if (!(cpuid_ecx(0x80000001) & (1 << 22)))
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530110 return CPUID_COMMAND_UNSUPPORTED;
111
112 return CPUID_TYPE_AMD;
113 } else {
114 return CPUID_TYPE_INVALID;
115 }
116}
117
118static uint32_t cpu_get_cache_info_leaf(void)
119{
Subrata Banik72f1e622021-09-01 12:35:15 +0530120 uint32_t leaf = (cpu_check_deterministic_cache_cpuid_supported() == CPUID_TYPE_AMD) ?
121 DETERMINISTIC_CACHE_PARAMETERS_CPUID_AMD :
122 DETERMINISTIC_CACHE_PARAMETERS_CPUID_IA;
123
124 return leaf;
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530125}
126
127size_t cpu_get_cache_ways_assoc_info(const struct cpu_cache_info *info)
128{
129 if (!info)
130 return 0;
131
132 return info->num_ways;
133}
134
135uint8_t cpu_get_cache_type(const struct cpu_cache_info *info)
136{
137 if (!info)
138 return 0;
139
140 return info->type;
141}
142
143uint8_t cpu_get_cache_level(const struct cpu_cache_info *info)
144{
145 if (!info)
146 return 0;
147
148 return info->level;
149}
150
151size_t cpu_get_cache_phy_partition_info(const struct cpu_cache_info *info)
152{
153 if (!info)
154 return 0;
155
156 return info->physical_partitions;
157}
158
159size_t cpu_get_cache_line_size(const struct cpu_cache_info *info)
160{
161 if (!info)
162 return 0;
163
164 return info->line_size;
165}
166
167size_t cpu_get_cache_sets(const struct cpu_cache_info *info)
168{
169 if (!info)
170 return 0;
171
172 return info->num_sets;
173}
174
175bool cpu_is_cache_full_assoc(const struct cpu_cache_info *info)
176{
177 if (!info)
178 return false;
179
180 return info->fully_associative;
181}
182
183size_t cpu_get_max_cache_share(const struct cpu_cache_info *info)
184{
185 if (!info)
186 return 0;
187
188 return info->num_cores_shared;
189}
190
191size_t get_cache_size(const struct cpu_cache_info *info)
192{
193 if (!info)
194 return 0;
195
196 return info->num_ways * info->physical_partitions * info->line_size * info->num_sets;
197}
198
Patrick Rudolph6a13b522023-10-03 18:03:51 +0200199/*
200 * Returns the sub-states supported by the specified CPU
201 * C-state level.
202 *
203 * Level 0 corresponds to the lowest C-state (C0).
204 * Higher levels are processor specific.
205 */
206uint8_t cpu_get_c_substate_support(const int state)
207{
208 if ((cpuid_get_max_func() < 5) ||
209 !(cpuid_ecx(5) & CPUID_FEATURE_MONITOR_MWAIT) || (state > 4))
210 return 0;
211
212 return (cpuid_edx(5) >> (state * 4)) & 0xf;
213}
214
Subrata Banik0c6c0da2021-07-23 21:00:58 +0530215bool fill_cpu_cache_info(uint8_t level, struct cpu_cache_info *info)
216{
217 if (!info)
218 return false;
219
220 uint32_t leaf = cpu_get_cache_info_leaf();
221 if (!leaf)
222 return false;
223
224 struct cpuid_result cache_info_res = cpuid_ext(leaf, level);
225
226 info->type = CPUID_CACHE_TYPE(cache_info_res);
227 info->level = CPUID_CACHE_LEVEL(cache_info_res);
228 info->num_ways = CPUID_CACHE_WAYS_OF_ASSOC(cache_info_res) + 1;
229 info->num_sets = CPUID_CACHE_NO_OF_SETS(cache_info_res) + 1;
230 info->line_size = CPUID_CACHE_COHER_LINE(cache_info_res) + 1;
231 info->physical_partitions = CPUID_CACHE_PHYS_LINE(cache_info_res) + 1;
232 info->num_cores_shared = CPUID_CACHE_SHARING_CACHE(cache_info_res) + 1;
233 info->fully_associative = CPUID_CACHE_FULL_ASSOC(cache_info_res);
234 info->size = get_cache_size(info);
235
236 return true;
237}
Subrata Banika4c91e12024-03-16 17:57:28 +0530238
239bool is_cache_sets_power_of_two(void)
240{
241 struct cpu_cache_info info;
242
243 if (!fill_cpu_cache_info(CACHE_L3, &info))
244 return false;
245
246 size_t cache_sets = cpu_get_cache_sets(&info);
247
Paul Menzel4dac5202024-03-17 23:33:04 +0100248 return IS_POWER_OF_2(cache_sets);
Subrata Banika4c91e12024-03-16 17:57:28 +0530249}