cacheinfo.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2017 SiFive
  4. */
  5. #include <linux/acpi.h>
  6. #include <linux/cpu.h>
  7. #include <linux/of.h>
  8. #include <asm/cacheinfo.h>
  9. static struct riscv_cacheinfo_ops *rv_cache_ops;
  10. void riscv_set_cacheinfo_ops(struct riscv_cacheinfo_ops *ops)
  11. {
  12. rv_cache_ops = ops;
  13. }
  14. EXPORT_SYMBOL_GPL(riscv_set_cacheinfo_ops);
  15. const struct attribute_group *
  16. cache_get_priv_group(struct cacheinfo *this_leaf)
  17. {
  18. if (rv_cache_ops && rv_cache_ops->get_priv_group)
  19. return rv_cache_ops->get_priv_group(this_leaf);
  20. return NULL;
  21. }
  22. static struct cacheinfo *get_cacheinfo(u32 level, enum cache_type type)
  23. {
  24. /*
  25. * Using raw_smp_processor_id() elides a preemptability check, but this
  26. * is really indicative of a larger problem: the cacheinfo UABI assumes
  27. * that cores have a homonogenous view of the cache hierarchy. That
  28. * happens to be the case for the current set of RISC-V systems, but
  29. * likely won't be true in general. Since there's no way to provide
  30. * correct information for these systems via the current UABI we're
  31. * just eliding the check for now.
  32. */
  33. struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(raw_smp_processor_id());
  34. struct cacheinfo *this_leaf;
  35. int index;
  36. for (index = 0; index < this_cpu_ci->num_leaves; index++) {
  37. this_leaf = this_cpu_ci->info_list + index;
  38. if (this_leaf->level == level && this_leaf->type == type)
  39. return this_leaf;
  40. }
  41. return NULL;
  42. }
  43. uintptr_t get_cache_size(u32 level, enum cache_type type)
  44. {
  45. struct cacheinfo *this_leaf = get_cacheinfo(level, type);
  46. return this_leaf ? this_leaf->size : 0;
  47. }
  48. uintptr_t get_cache_geometry(u32 level, enum cache_type type)
  49. {
  50. struct cacheinfo *this_leaf = get_cacheinfo(level, type);
  51. return this_leaf ? (this_leaf->ways_of_associativity << 16 |
  52. this_leaf->coherency_line_size) :
  53. 0;
  54. }
  55. static void ci_leaf_init(struct cacheinfo *this_leaf,
  56. enum cache_type type, unsigned int level)
  57. {
  58. this_leaf->level = level;
  59. this_leaf->type = type;
  60. }
  61. int init_cache_level(unsigned int cpu)
  62. {
  63. return init_of_cache_level(cpu);
  64. }
  65. int populate_cache_leaves(unsigned int cpu)
  66. {
  67. struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
  68. struct cacheinfo *this_leaf = this_cpu_ci->info_list;
  69. struct device_node *np, *prev;
  70. int levels = 1, level = 1;
  71. if (!acpi_disabled) {
  72. int ret, fw_levels, split_levels;
  73. ret = acpi_get_cache_info(cpu, &fw_levels, &split_levels);
  74. if (ret)
  75. return ret;
  76. BUG_ON((split_levels > fw_levels) ||
  77. (split_levels + fw_levels > this_cpu_ci->num_leaves));
  78. for (; level <= this_cpu_ci->num_levels; level++) {
  79. if (level <= split_levels) {
  80. ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
  81. ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
  82. } else {
  83. ci_leaf_init(this_leaf++, CACHE_TYPE_UNIFIED, level);
  84. }
  85. }
  86. return 0;
  87. }
  88. np = of_cpu_device_node_get(cpu);
  89. if (!np)
  90. return -ENOENT;
  91. if (of_property_present(np, "cache-size"))
  92. ci_leaf_init(this_leaf++, CACHE_TYPE_UNIFIED, level);
  93. if (of_property_present(np, "i-cache-size"))
  94. ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
  95. if (of_property_present(np, "d-cache-size"))
  96. ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
  97. prev = np;
  98. while ((np = of_find_next_cache_node(np))) {
  99. of_node_put(prev);
  100. prev = np;
  101. if (!of_device_is_compatible(np, "cache"))
  102. break;
  103. if (of_property_read_u32(np, "cache-level", &level))
  104. break;
  105. if (level <= levels)
  106. break;
  107. if (of_property_present(np, "cache-size"))
  108. ci_leaf_init(this_leaf++, CACHE_TYPE_UNIFIED, level);
  109. if (of_property_present(np, "i-cache-size"))
  110. ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
  111. if (of_property_present(np, "d-cache-size"))
  112. ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
  113. levels = level;
  114. }
  115. of_node_put(np);
  116. return 0;
  117. }