xref: /aosp_15_r20/external/coreboot/src/arch/x86/cpu_common.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/helpers.h>
4 #include <cpu/cpu.h>
5 #include <types.h>
6 
7 #if ENV_X86_32
8 /* Standard macro to see if a specific flag is changeable */
flag_is_changeable_p(uint32_t flag)9 static 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 */
cpu_have_cpuid(void)30 int cpu_have_cpuid(void)
31 {
32 	return flag_is_changeable_p(X86_EFLAGS_ID);
33 }
34 
35 #else
36 
cpu_have_cpuid(void)37 int cpu_have_cpuid(void)
38 {
39 	return 1;
40 }
41 #endif
42 
cpu_cpuid_extended_level(void)43 unsigned int cpu_cpuid_extended_level(void)
44 {
45 	return cpuid_eax(0x80000000);
46 }
47 
cpu_phys_address_size(void)48 unsigned int cpu_phys_address_size(void)
49 {
50 	if (!(cpu_have_cpuid()))
51 		return 32;
52 
53 	if (cpu_cpuid_extended_level() >= 0x80000008) {
54 		int size = cpuid_eax(0x80000008) & 0xff;
55 		size -= get_reserved_phys_addr_bits();
56 		return size;
57 	}
58 
59 	if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36))
60 		return 36;
61 	return 32;
62 }
63 
soc_phys_address_size(void)64 unsigned 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 
72 /*
73  * Get processor id using cpuid eax=1
74  * return value in EAX register
75  */
cpu_get_cpuid(void)76 uint32_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  */
cpu_get_feature_flags_ecx(void)85 uint32_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  */
cpu_get_feature_flags_edx(void)94 uint32_t cpu_get_feature_flags_edx(void)
95 {
96 	return cpuid_edx(1);
97 }
98 
cpu_check_deterministic_cache_cpuid_supported(void)99 enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void)
100 {
101 	if (cpu_is_intel()) {
102 		if (cpuid_get_max_func() < 4)
103 			return CPUID_COMMAND_UNSUPPORTED;
104 		return CPUID_TYPE_INTEL;
105 	} else if (cpu_is_amd()) {
106 		if (cpu_cpuid_extended_level() < 0x80000001)
107 			return CPUID_COMMAND_UNSUPPORTED;
108 
109 		if (!(cpuid_ecx(0x80000001) & (1 << 22)))
110 			return CPUID_COMMAND_UNSUPPORTED;
111 
112 		return CPUID_TYPE_AMD;
113 	} else {
114 		return CPUID_TYPE_INVALID;
115 	}
116 }
117 
cpu_get_cache_info_leaf(void)118 static uint32_t cpu_get_cache_info_leaf(void)
119 {
120 	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;
125 }
126 
cpu_get_cache_ways_assoc_info(const struct cpu_cache_info * info)127 size_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 
cpu_get_cache_type(const struct cpu_cache_info * info)135 uint8_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 
cpu_get_cache_level(const struct cpu_cache_info * info)143 uint8_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 
cpu_get_cache_phy_partition_info(const struct cpu_cache_info * info)151 size_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 
cpu_get_cache_line_size(const struct cpu_cache_info * info)159 size_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 
cpu_get_cache_sets(const struct cpu_cache_info * info)167 size_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 
cpu_is_cache_full_assoc(const struct cpu_cache_info * info)175 bool 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 
cpu_get_max_cache_share(const struct cpu_cache_info * info)183 size_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 
get_cache_size(const struct cpu_cache_info * info)191 size_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 
199 /*
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  */
cpu_get_c_substate_support(const int state)206 uint8_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 
fill_cpu_cache_info(uint8_t level,struct cpu_cache_info * info)215 bool 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 }
238 
is_cache_sets_power_of_two(void)239 bool 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 
248 	return IS_POWER_OF_2(cache_sets);
249 }
250