aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/cpu_common.c132
-rw-r--r--src/arch/x86/include/arch/cpu.h76
2 files changed, 208 insertions, 0 deletions
diff --git a/src/arch/x86/cpu_common.c b/src/arch/x86/cpu_common.c
index 77d08c4196..835cddd686 100644
--- a/src/arch/x86/cpu_common.c
+++ b/src/arch/x86/cpu_common.c
@@ -82,3 +82,135 @@ uint32_t cpu_get_feature_flags_edx(void)
{
return cpuid_edx(1);
}
+
+enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void)
+{
+ struct cpuid_result res;
+
+ if (cpu_is_intel()) {
+ res = cpuid(0);
+ if (res.eax < 4)
+ return CPUID_COMMAND_UNSUPPORTED;
+ return CPUID_TYPE_INTEL;
+ } else if (cpu_is_amd()) {
+ res = cpuid(0x80000000);
+ if (res.eax < 0x80000001)
+ return CPUID_COMMAND_UNSUPPORTED;
+
+ res = cpuid(0x80000001);
+ if (!(res.ecx & (1 << 22)))
+ return CPUID_COMMAND_UNSUPPORTED;
+
+ return CPUID_TYPE_AMD;
+ } else {
+ return CPUID_TYPE_INVALID;
+ }
+}
+
+static uint32_t cpu_get_cache_info_leaf(void)
+{
+ switch (cpu_check_deterministic_cache_cpuid_supported()) {
+ case CPUID_TYPE_AMD:
+ return DETERMINISTIC_CACHE_PARAMETERS_CPUID_AMD;
+ case CPUID_TYPE_INTEL:
+ return DETERMINISTIC_CACHE_PARAMETERS_CPUID_IA;
+ default:
+ return 0;
+ }
+}
+
+size_t cpu_get_cache_ways_assoc_info(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->num_ways;
+}
+
+uint8_t cpu_get_cache_type(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->type;
+}
+
+uint8_t cpu_get_cache_level(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->level;
+}
+
+size_t cpu_get_cache_phy_partition_info(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->physical_partitions;
+}
+
+size_t cpu_get_cache_line_size(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->line_size;
+}
+
+size_t cpu_get_cache_sets(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->num_sets;
+}
+
+bool cpu_is_cache_full_assoc(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return false;
+
+ return info->fully_associative;
+}
+
+size_t cpu_get_max_cache_share(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->num_cores_shared;
+}
+
+size_t get_cache_size(const struct cpu_cache_info *info)
+{
+ if (!info)
+ return 0;
+
+ return info->num_ways * info->physical_partitions * info->line_size * info->num_sets;
+}
+
+bool fill_cpu_cache_info(uint8_t level, struct cpu_cache_info *info)
+{
+ if (!info)
+ return false;
+
+ uint32_t leaf = cpu_get_cache_info_leaf();
+ if (!leaf)
+ return false;
+
+ struct cpuid_result cache_info_res = cpuid_ext(leaf, level);
+
+ info->type = CPUID_CACHE_TYPE(cache_info_res);
+ info->level = CPUID_CACHE_LEVEL(cache_info_res);
+ info->num_ways = CPUID_CACHE_WAYS_OF_ASSOC(cache_info_res) + 1;
+ info->num_sets = CPUID_CACHE_NO_OF_SETS(cache_info_res) + 1;
+ info->line_size = CPUID_CACHE_COHER_LINE(cache_info_res) + 1;
+ info->physical_partitions = CPUID_CACHE_PHYS_LINE(cache_info_res) + 1;
+ info->num_cores_shared = CPUID_CACHE_SHARING_CACHE(cache_info_res) + 1;
+ info->fully_associative = CPUID_CACHE_FULL_ASSOC(cache_info_res);
+ info->size = get_cache_size(info);
+
+ return true;
+}
diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h
index 42201e282e..bec190e618 100644
--- a/src/arch/x86/include/arch/cpu.h
+++ b/src/arch/x86/include/arch/cpu.h
@@ -158,6 +158,10 @@ static inline unsigned int cpuid_get_max_func(void)
#define CPUID_CACHE(x, res) \
(((res) >> CPUID_CACHE_##x##_SHIFT) & CPUID_CACHE_##x##_MASK)
+#define CPUID_CACHE_SHARING_CACHE_SHIFT 14
+#define CPUID_CACHE_SHARING_CACHE_MASK 0xfff
+#define CPUID_CACHE_SHARING_CACHE(res) CPUID_CACHE(SHARING_CACHE, (res).eax)
+
#define CPUID_CACHE_FULL_ASSOC_SHIFT 9
#define CPUID_CACHE_FULL_ASSOC_MASK 0x1
#define CPUID_CACHE_FULL_ASSOC(res) CPUID_CACHE(FULL_ASSOC, (res).eax)
@@ -314,4 +318,76 @@ uint32_t cpu_get_feature_flags_edx(void);
*/
int cpu_index(void);
+#define DETERMINISTIC_CACHE_PARAMETERS_CPUID_IA 0x04
+#define DETERMINISTIC_CACHE_PARAMETERS_CPUID_AMD 0x8000001d
+
+enum cache_level {
+ CACHE_L1D = 0,
+ CACHE_L1I = 1,
+ CACHE_L2 = 2,
+ CACHE_L3 = 3,
+ CACHE_LINV = 0xFF,
+};
+
+enum cpu_type {
+ CPUID_COMMAND_UNSUPPORTED = 0,
+ CPUID_TYPE_AMD = 1,
+ CPUID_TYPE_INTEL = 2,
+ CPUID_TYPE_INVALID = 0xFF,
+};
+
+struct cpu_cache_info {
+ uint8_t type;
+ uint8_t level;
+ size_t num_ways;
+ size_t num_sets;
+ size_t line_size;
+ size_t size;
+ size_t physical_partitions;
+ size_t num_cores_shared;
+ bool fully_associative;
+};
+
+enum cpu_type cpu_check_deterministic_cache_cpuid_supported(void);
+
+/* cpu_get_cache_assoc_info to get cache ways of associativity information. */
+size_t cpu_get_cache_ways_assoc_info(const struct cpu_cache_info *info);
+
+/*
+ * cpu_get_cache_type to get cache type.
+ * Cache type can be between 0: no cache, 1: data cache, 2: instruction cache
+ * 3: unified cache and rests are reserved.
+ */
+uint8_t cpu_get_cache_type(const struct cpu_cache_info *info);
+
+/*
+ * cpu_get_cache_level to get cache level.
+ * Cache level can be between 0: reserved, 1: L1, 2: L2, 3: L3 and rests are reserved.
+ */
+uint8_t cpu_get_cache_level(const struct cpu_cache_info *info);
+
+/* cpu_get_cache_phy_partition_info to get cache physical partitions information. */
+size_t cpu_get_cache_phy_partition_info(const struct cpu_cache_info *info);
+
+/* cpu_get_cache_line_size to get cache line size in bytes. */
+size_t cpu_get_cache_line_size(const struct cpu_cache_info *info);
+
+/* cpu_get_cache_line_size to get cache number of sets information. */
+size_t cpu_get_cache_sets(const struct cpu_cache_info *info);
+
+/* cpu_is_cache_full_assoc checks if cache is fully associative. */
+bool cpu_is_cache_full_assoc(const struct cpu_cache_info *info);
+
+/* cpu_get_max_cache_share checks the number of cores are sharing this cache. */
+size_t cpu_get_max_cache_share(const struct cpu_cache_info *info);
+
+/* get_cache_size to calculate the cache size. */
+size_t get_cache_size(const struct cpu_cache_info *info);
+
+/*
+ * fill_cpu_cache_info to get all required cache info data and fill into cpu_cache_info
+ * structure by calling CPUID.EAX=leaf and ECX=Cache Level.
+ */
+bool fill_cpu_cache_info(uint8_t level, struct cpu_cache_info *info);
+
#endif /* ARCH_CPU_H */