| 
 | 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->of_node = node;  | 
 | 24 | +	this_leaf->level = level;  | 
 | 25 | +	this_leaf->type = type;  | 
 | 26 | +	/* not a sector cache */  | 
 | 27 | +	this_leaf->physical_line_partition = 1;  | 
 | 28 | +	/* TODO: Add to DTS */  | 
 | 29 | +	this_leaf->attributes =  | 
 | 30 | +		CACHE_WRITE_BACK  | 
 | 31 | +		| CACHE_READ_ALLOCATE  | 
 | 32 | +		| CACHE_WRITE_ALLOCATE;  | 
 | 33 | +}  | 
 | 34 | + | 
 | 35 | +static int __init_cache_level(unsigned int cpu)  | 
 | 36 | +{  | 
 | 37 | +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);  | 
 | 38 | +	struct device_node *np = of_cpu_device_node_get(cpu);  | 
 | 39 | +	int levels = 0, leaves = 0, level;  | 
 | 40 | + | 
 | 41 | +	if (of_property_read_bool(np, "cache-size"))  | 
 | 42 | +		++leaves;  | 
 | 43 | +	if (of_property_read_bool(np, "i-cache-size"))  | 
 | 44 | +		++leaves;  | 
 | 45 | +	if (of_property_read_bool(np, "d-cache-size"))  | 
 | 46 | +		++leaves;  | 
 | 47 | +	if (leaves > 0)  | 
 | 48 | +		levels = 1;  | 
 | 49 | + | 
 | 50 | +	while ((np = of_find_next_cache_node(np))) {  | 
 | 51 | +		if (!of_device_is_compatible(np, "cache"))  | 
 | 52 | +			break;  | 
 | 53 | +		if (of_property_read_u32(np, "cache-level", &level))  | 
 | 54 | +			break;  | 
 | 55 | +		if (level <= levels)  | 
 | 56 | +			break;  | 
 | 57 | +		if (of_property_read_bool(np, "cache-size"))  | 
 | 58 | +			++leaves;  | 
 | 59 | +		if (of_property_read_bool(np, "i-cache-size"))  | 
 | 60 | +			++leaves;  | 
 | 61 | +		if (of_property_read_bool(np, "d-cache-size"))  | 
 | 62 | +			++leaves;  | 
 | 63 | +		levels = level;  | 
 | 64 | +	}  | 
 | 65 | + | 
 | 66 | +	this_cpu_ci->num_levels = levels;  | 
 | 67 | +	this_cpu_ci->num_leaves = leaves;  | 
 | 68 | +	return 0;  | 
 | 69 | +}  | 
 | 70 | + | 
 | 71 | +static int __populate_cache_leaves(unsigned int cpu)  | 
 | 72 | +{  | 
 | 73 | +	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);  | 
 | 74 | +	struct cacheinfo *this_leaf = this_cpu_ci->info_list;  | 
 | 75 | +	struct device_node *np = of_cpu_device_node_get(cpu);  | 
 | 76 | +	int levels = 1, level = 1;  | 
 | 77 | + | 
 | 78 | +	if (of_property_read_bool(np, "cache-size"))  | 
 | 79 | +		ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);  | 
 | 80 | +	if (of_property_read_bool(np, "i-cache-size"))  | 
 | 81 | +		ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);  | 
 | 82 | +	if (of_property_read_bool(np, "d-cache-size"))  | 
 | 83 | +		ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);  | 
 | 84 | + | 
 | 85 | +	while ((np = of_find_next_cache_node(np))) {  | 
 | 86 | +		if (!of_device_is_compatible(np, "cache"))  | 
 | 87 | +			break;  | 
 | 88 | +		if (of_property_read_u32(np, "cache-level", &level))  | 
 | 89 | +			break;  | 
 | 90 | +		if (level <= levels)  | 
 | 91 | +			break;  | 
 | 92 | +		if (of_property_read_bool(np, "cache-size"))  | 
 | 93 | +			ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);  | 
 | 94 | +		if (of_property_read_bool(np, "i-cache-size"))  | 
 | 95 | +			ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);  | 
 | 96 | +		if (of_property_read_bool(np, "d-cache-size"))  | 
 | 97 | +			ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);  | 
 | 98 | +		levels = level;  | 
 | 99 | +	}  | 
 | 100 | + | 
 | 101 | +	return 0;  | 
 | 102 | +}  | 
 | 103 | + | 
 | 104 | +DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)  | 
 | 105 | +DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)  | 
0 commit comments