1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ARM64 cacheinfo support 4 * 5 * Copyright (C) 2015 ARM Ltd. 6 * All Rights Reserved 7 */ 8 9 #include <linux/acpi.h> 10 #include <linux/cacheinfo.h> 11 #include <linux/of.h> 12 13 #define MAX_CACHE_LEVEL 7 /* Max 7 level supported */ 14 /* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */ 15 #define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1)) 16 #define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level)) 17 #define CLIDR_CTYPE(clidr, level) \ 18 (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level)) 19 20 static inline enum cache_type get_cache_type(int level) 21 { 22 u64 clidr; 23 24 if (level > MAX_CACHE_LEVEL) 25 return CACHE_TYPE_NOCACHE; 26 clidr = read_sysreg(clidr_el1); 27 return CLIDR_CTYPE(clidr, level); 28 } 29 30 static void ci_leaf_init(struct cacheinfo *this_leaf, 31 enum cache_type type, unsigned int level) 32 { 33 this_leaf->level = level; 34 this_leaf->type = type; 35 } 36 37 static int __init_cache_level(unsigned int cpu) 38 { 39 unsigned int ctype, level, leaves, fw_level; 40 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); 41 42 for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { 43 ctype = get_cache_type(level); 44 if (ctype == CACHE_TYPE_NOCACHE) { 45 level--; 46 break; 47 } 48 /* Separate instruction and data caches */ 49 leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; 50 } 51 52 if (acpi_disabled) 53 fw_level = of_find_last_cache_level(cpu); 54 else 55 fw_level = acpi_find_last_cache_level(cpu); 56 57 if (level < fw_level) { 58 /* 59 * some external caches not specified in CLIDR_EL1 60 * the information may be available in the device tree 61 * only unified external caches are considered here 62 */ 63 leaves += (fw_level - level); 64 level = fw_level; 65 } 66 67 this_cpu_ci->num_levels = level; 68 this_cpu_ci->num_leaves = leaves; 69 return 0; 70 } 71 72 static int __populate_cache_leaves(unsigned int cpu) 73 { 74 unsigned int level, idx; 75 enum cache_type type; 76 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); 77 struct cacheinfo *this_leaf = this_cpu_ci->info_list; 78 79 for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && 80 idx < this_cpu_ci->num_leaves; idx++, level++) { 81 type = get_cache_type(level); 82 if (type == CACHE_TYPE_SEPARATE) { 83 ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); 84 ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); 85 } else { 86 ci_leaf_init(this_leaf++, type, level); 87 } 88 } 89 return 0; 90 } 91 92 DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) 93 DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) 94