Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  ARM64 cacheinfo support
0004  *
0005  *  Copyright (C) 2015 ARM Ltd.
0006  *  All Rights Reserved
0007  */
0008 
0009 #include <linux/acpi.h>
0010 #include <linux/cacheinfo.h>
0011 #include <linux/of.h>
0012 
0013 #define MAX_CACHE_LEVEL         7   /* Max 7 level supported */
0014 /* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */
0015 #define CLIDR_CTYPE_SHIFT(level)    (3 * (level - 1))
0016 #define CLIDR_CTYPE_MASK(level)     (7 << CLIDR_CTYPE_SHIFT(level))
0017 #define CLIDR_CTYPE(clidr, level)   \
0018     (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level))
0019 
0020 int cache_line_size(void)
0021 {
0022     if (coherency_max_size != 0)
0023         return coherency_max_size;
0024 
0025     return cache_line_size_of_cpu();
0026 }
0027 EXPORT_SYMBOL_GPL(cache_line_size);
0028 
0029 static inline enum cache_type get_cache_type(int level)
0030 {
0031     u64 clidr;
0032 
0033     if (level > MAX_CACHE_LEVEL)
0034         return CACHE_TYPE_NOCACHE;
0035     clidr = read_sysreg(clidr_el1);
0036     return CLIDR_CTYPE(clidr, level);
0037 }
0038 
0039 static void ci_leaf_init(struct cacheinfo *this_leaf,
0040              enum cache_type type, unsigned int level)
0041 {
0042     this_leaf->level = level;
0043     this_leaf->type = type;
0044 }
0045 
0046 int init_cache_level(unsigned int cpu)
0047 {
0048     unsigned int ctype, level, leaves;
0049     int fw_level;
0050     struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
0051 
0052     for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
0053         ctype = get_cache_type(level);
0054         if (ctype == CACHE_TYPE_NOCACHE) {
0055             level--;
0056             break;
0057         }
0058         /* Separate instruction and data caches */
0059         leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
0060     }
0061 
0062     if (acpi_disabled)
0063         fw_level = of_find_last_cache_level(cpu);
0064     else
0065         fw_level = acpi_find_last_cache_level(cpu);
0066 
0067     if (fw_level < 0)
0068         return fw_level;
0069 
0070     if (level < fw_level) {
0071         /*
0072          * some external caches not specified in CLIDR_EL1
0073          * the information may be available in the device tree
0074          * only unified external caches are considered here
0075          */
0076         leaves += (fw_level - level);
0077         level = fw_level;
0078     }
0079 
0080     this_cpu_ci->num_levels = level;
0081     this_cpu_ci->num_leaves = leaves;
0082     return 0;
0083 }
0084 
0085 int populate_cache_leaves(unsigned int cpu)
0086 {
0087     unsigned int level, idx;
0088     enum cache_type type;
0089     struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
0090     struct cacheinfo *this_leaf = this_cpu_ci->info_list;
0091 
0092     for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
0093          idx < this_cpu_ci->num_leaves; idx++, level++) {
0094         type = get_cache_type(level);
0095         if (type == CACHE_TYPE_SEPARATE) {
0096             ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
0097             ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
0098         } else {
0099             ci_leaf_init(this_leaf++, type, level);
0100         }
0101     }
0102     return 0;
0103 }