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)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 */ cpu_have_cpuid(void)30int cpu_have_cpuid(void) 31 { 32 return flag_is_changeable_p(X86_EFLAGS_ID); 33 } 34 35 #else 36 cpu_have_cpuid(void)37int cpu_have_cpuid(void) 38 { 39 return 1; 40 } 41 #endif 42 cpu_cpuid_extended_level(void)43unsigned int cpu_cpuid_extended_level(void) 44 { 45 return cpuid_eax(0x80000000); 46 } 47 cpu_phys_address_size(void)48unsigned 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)64unsigned 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)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 */ cpu_get_feature_flags_ecx(void)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 */ cpu_get_feature_flags_edx(void)94uint32_t cpu_get_feature_flags_edx(void) 95 { 96 return cpuid_edx(1); 97 } 98 cpu_check_deterministic_cache_cpuid_supported(void)99enum 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)118static 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)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 cpu_get_cache_type(const struct cpu_cache_info * info)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 cpu_get_cache_level(const struct cpu_cache_info * info)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 cpu_get_cache_phy_partition_info(const struct cpu_cache_info * info)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 cpu_get_cache_line_size(const struct cpu_cache_info * info)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 cpu_get_cache_sets(const struct cpu_cache_info * info)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 cpu_is_cache_full_assoc(const struct cpu_cache_info * info)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 cpu_get_max_cache_share(const struct cpu_cache_info * info)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 get_cache_size(const struct cpu_cache_info * info)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 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)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 fill_cpu_cache_info(uint8_t level,struct cpu_cache_info * info)215bool 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)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 248 return IS_POWER_OF_2(cache_sets); 249 } 250