linux/arch/riscv/kernel/cacheinfo.c
<<
>>
Prefs
   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
  19static 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}
  26
  27static int __init_cache_level(unsigned int cpu)
  28{
  29        struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
  30        struct device_node *np = of_cpu_device_node_get(cpu);
  31        struct device_node *prev = NULL;
  32        int levels = 0, leaves = 0, level;
  33
  34        if (of_property_read_bool(np, "cache-size"))
  35                ++leaves;
  36        if (of_property_read_bool(np, "i-cache-size"))
  37                ++leaves;
  38        if (of_property_read_bool(np, "d-cache-size"))
  39                ++leaves;
  40        if (leaves > 0)
  41                levels = 1;
  42
  43        prev = np;
  44        while ((np = of_find_next_cache_node(np))) {
  45                of_node_put(prev);
  46                prev = np;
  47                if (!of_device_is_compatible(np, "cache"))
  48                        break;
  49                if (of_property_read_u32(np, "cache-level", &level))
  50                        break;
  51                if (level <= levels)
  52                        break;
  53                if (of_property_read_bool(np, "cache-size"))
  54                        ++leaves;
  55                if (of_property_read_bool(np, "i-cache-size"))
  56                        ++leaves;
  57                if (of_property_read_bool(np, "d-cache-size"))
  58                        ++leaves;
  59                levels = level;
  60        }
  61
  62        of_node_put(np);
  63        this_cpu_ci->num_levels = levels;
  64        this_cpu_ci->num_leaves = leaves;
  65
  66        return 0;
  67}
  68
  69static int __populate_cache_leaves(unsigned int cpu)
  70{
  71        struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
  72        struct cacheinfo *this_leaf = this_cpu_ci->info_list;
  73        struct device_node *np = of_cpu_device_node_get(cpu);
  74        struct device_node *prev = NULL;
  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        prev = np;
  85        while ((np = of_find_next_cache_node(np))) {
  86                of_node_put(prev);
  87                prev = np;
  88                if (!of_device_is_compatible(np, "cache"))
  89                        break;
  90                if (of_property_read_u32(np, "cache-level", &level))
  91                        break;
  92                if (level <= levels)
  93                        break;
  94                if (of_property_read_bool(np, "cache-size"))
  95                        ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level);
  96                if (of_property_read_bool(np, "i-cache-size"))
  97                        ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level);
  98                if (of_property_read_bool(np, "d-cache-size"))
  99                        ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level);
 100                levels = level;
 101        }
 102        of_node_put(np);
 103
 104        return 0;
 105}
 106
 107DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
 108DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
 109