blob: c307f69e9b55ddeb45622d83d8f9b23a558b1bb9 [file] [log] [blame]
Thomas Gleixnerc9af7f32019-05-29 07:12:26 -07001// SPDX-License-Identifier: GPL-2.0-only
Sudeep Holla5d425c12015-01-08 10:42:34 +00002/*
3 * ARM64 cacheinfo support
4 *
5 * Copyright (C) 2015 ARM Ltd.
6 * All Rights Reserved
Sudeep Holla5d425c12015-01-08 10:42:34 +00007 */
8
Jeremy Linton85718902018-05-11 18:58:03 -05009#include <linux/acpi.h>
Sudeep Holla5d425c12015-01-08 10:42:34 +000010#include <linux/cacheinfo.h>
Sudeep Holla5d425c12015-01-08 10:42:34 +000011#include <linux/of.h>
12
Sudeep Holla5d425c12015-01-08 10:42:34 +000013#define MAX_CACHE_LEVEL 7 /* Max 7 level supported */
Sudeep Holla5d425c12015-01-08 10:42:34 +000014
Shaokun Zhang7b8c87b2019-05-28 10:16:54 +080015int cache_line_size(void)
16{
Shaokun Zhang7b8c87b2019-05-28 10:16:54 +080017 if (coherency_max_size != 0)
18 return coherency_max_size;
19
Masayoshi Mizuma8f5c9032019-06-14 09:11:41 -040020 return cache_line_size_of_cpu();
Shaokun Zhang7b8c87b2019-05-28 10:16:54 +080021}
22EXPORT_SYMBOL_GPL(cache_line_size);
23
Sudeep Holla5d425c12015-01-08 10:42:34 +000024static inline enum cache_type get_cache_type(int level)
25{
26 u64 clidr;
27
28 if (level > MAX_CACHE_LEVEL)
29 return CACHE_TYPE_NOCACHE;
Mark Rutlandadf75892016-09-08 13:55:38 +010030 clidr = read_sysreg(clidr_el1);
Sudeep Holla5d425c12015-01-08 10:42:34 +000031 return CLIDR_CTYPE(clidr, level);
32}
33
Sudeep Holla5d425c12015-01-08 10:42:34 +000034static void ci_leaf_init(struct cacheinfo *this_leaf,
35 enum cache_type type, unsigned int level)
36{
Sudeep Holla5d425c12015-01-08 10:42:34 +000037 this_leaf->level = level;
38 this_leaf->type = type;
Sudeep Holla5d425c12015-01-08 10:42:34 +000039}
40
Thomas Gleixner4b92d4a2021-08-31 13:48:34 +020041int init_cache_level(unsigned int cpu)
Sudeep Holla5d425c12015-01-08 10:42:34 +000042{
Sudeep Hollae75d18c2022-08-08 09:46:40 +010043 unsigned int ctype, level, leaves;
Pierre Gondoisbd500362023-01-04 19:30:28 +010044 int fw_level, ret;
Sudeep Holla5d425c12015-01-08 10:42:34 +000045 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
46
47 for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) {
48 ctype = get_cache_type(level);
49 if (ctype == CACHE_TYPE_NOCACHE) {
50 level--;
51 break;
52 }
53 /* Separate instruction and data caches */
54 leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1;
55 }
56
Pierre Gondoisbd500362023-01-04 19:30:28 +010057 if (acpi_disabled) {
Jeremy Linton85718902018-05-11 18:58:03 -050058 fw_level = of_find_last_cache_level(cpu);
Pierre Gondoisbd500362023-01-04 19:30:28 +010059 } else {
60 ret = acpi_get_cache_info(cpu, &fw_level, NULL);
61 if (ret < 0)
Pierre Gondoisd931b832023-01-24 16:40:47 +010062 fw_level = 0;
Pierre Gondoisbd500362023-01-04 19:30:28 +010063 }
Jeremy Linton85718902018-05-11 18:58:03 -050064
65 if (level < fw_level) {
Sudeep Holla9a802432017-01-16 10:40:44 +000066 /*
67 * some external caches not specified in CLIDR_EL1
68 * the information may be available in the device tree
69 * only unified external caches are considered here
70 */
Jeremy Linton85718902018-05-11 18:58:03 -050071 leaves += (fw_level - level);
72 level = fw_level;
Sudeep Holla9a802432017-01-16 10:40:44 +000073 }
74
Sudeep Holla5d425c12015-01-08 10:42:34 +000075 this_cpu_ci->num_levels = level;
76 this_cpu_ci->num_leaves = leaves;
77 return 0;
78}
79
Thomas Gleixner4b92d4a2021-08-31 13:48:34 +020080int populate_cache_leaves(unsigned int cpu)
Sudeep Holla5d425c12015-01-08 10:42:34 +000081{
82 unsigned int level, idx;
83 enum cache_type type;
84 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
85 struct cacheinfo *this_leaf = this_cpu_ci->info_list;
86
87 for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
88 idx < this_cpu_ci->num_leaves; idx++, level++) {
89 type = get_cache_type(level);
90 if (type == CACHE_TYPE_SEPARATE) {
91 ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
92 ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
93 } else {
94 ci_leaf_init(this_leaf++, type, level);
95 }
96 }
97 return 0;
98}