1 /* 2 * Copyright (C) 2017 SiFive 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <linux/cacheinfo.h> 15 #include <linux/cpu.h> 16 #include <linux/of.h> 17 #include <linux/of_device.h> 18 19 static void ci_leaf_init(struct cacheinfo *this_leaf, 20 struct device_node *node, 21 enum cache_type type, unsigned int level) 22 { 23 this_leaf->level = level; 24 this_leaf->type = type; 25 /* not a sector cache */ 26 this_leaf->physical_line_partition = 1; 27 /* TODO: Add to DTS */ 28 this_leaf->attributes = 29 CACHE_WRITE_BACK 30 | CACHE_READ_ALLOCATE 31 | CACHE_WRITE_ALLOCATE; 32 } 33 34 static int __init_cache_level(unsigned int cpu) 35 { 36 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); 37 struct device_node *np = of_cpu_device_node_get(cpu); 38 int levels = 0, leaves = 0, level; 39 40 if (of_property_read_bool(np, "cache-size")) 41 ++leaves; 42 if (of_property_read_bool(np, "i-cache-size")) 43 ++leaves; 44 if (of_property_read_bool(np, "d-cache-size")) 45 ++leaves; 46 if (leaves > 0) 47 levels = 1; 48 49 while ((np = of_find_next_cache_node(np))) { 50 if (!of_device_is_compatible(np, "cache")) 51 break; 52 if (of_property_read_u32(np, "cache-level", &level)) 53 break; 54 if (level <= levels) 55 break; 56 if (of_property_read_bool(np, "cache-size")) 57 ++leaves; 58 if (of_property_read_bool(np, "i-cache-size")) 59 ++leaves; 60 if (of_property_read_bool(np, "d-cache-size")) 61 ++leaves; 62 levels = level; 63 } 64 65 this_cpu_ci->num_levels = levels; 66 this_cpu_ci->num_leaves = leaves; 67 return 0; 68 } 69 70 static int __populate_cache_leaves(unsigned int cpu) 71 { 72 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); 73 struct cacheinfo *this_leaf = this_cpu_ci->info_list; 74 struct device_node *np = of_cpu_device_node_get(cpu); 75 int levels = 1, level = 1; 76 77 if (of_property_read_bool(np, "cache-size")) 78 ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); 79 if (of_property_read_bool(np, "i-cache-size")) 80 ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); 81 if (of_property_read_bool(np, "d-cache-size")) 82 ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); 83 84 while ((np = of_find_next_cache_node(np))) { 85 if (!of_device_is_compatible(np, "cache")) 86 break; 87 if (of_property_read_u32(np, "cache-level", &level)) 88 break; 89 if (level <= levels) 90 break; 91 if (of_property_read_bool(np, "cache-size")) 92 ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); 93 if (of_property_read_bool(np, "i-cache-size")) 94 ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); 95 if (of_property_read_bool(np, "d-cache-size")) 96 ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); 97 levels = level; 98 } 99 100 return 0; 101 } 102 103 DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) 104 DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) 105