/* OF properties to query for a given cache type */ struct cache_type_info { constchar *size_prop; constchar *line_size_props[2]; constchar *nr_sets_prop;
};
/* not cache_line_size() because that's a macro in include/linux/cache.h */ staticvoid cache_get_line_size(struct cacheinfo *this_leaf, struct device_node *np)
{ int i, lim, ct_idx;
/* * If the cache is fully associative, there is no need to * check the other properties.
*/ if (!(nr_sets == 1) && (nr_sets > 0 && size > 0 && line_size > 0))
this_leaf->ways_of_associativity = (size / nr_sets) / line_size;
}
staticvoid cache_of_set_props(struct cacheinfo *this_leaf, struct device_node *np)
{ /* * init_cache_level must setup the cache level correctly * overriding the architecturally specified levels, so * if type is NONE at this stage, it should be unified
*/ if (this_leaf->type == CACHE_TYPE_NOCACHE &&
cache_node_is_unified(this_leaf, np))
this_leaf->type = CACHE_TYPE_UNIFIED;
cache_size(this_leaf, np);
cache_get_line_size(this_leaf, np);
cache_nr_sets(this_leaf, np);
cache_associativity(this_leaf);
cache_of_set_id(this_leaf, np);
}
if (of_property_present(np, "cache-size"))
++leaves; if (of_property_present(np, "i-cache-size"))
++leaves; if (of_property_present(np, "d-cache-size"))
++leaves;
if (!leaves) { /* The '[i-|d-|]cache-size' property is required, but * if absent, fallback on the 'cache-unified' property.
*/ if (of_property_read_bool(np, "cache-unified")) return1; else return2;
}
int __weak cache_setup_acpi(unsignedint cpu)
{ return -ENOTSUPP;
}
unsignedint coherency_max_size;
staticint cache_setup_properties(unsignedint cpu)
{ int ret = 0;
if (of_have_populated_dt())
ret = cache_setup_of_node(cpu); elseif (!acpi_disabled)
ret = cache_setup_acpi(cpu);
// Assume there is no cache information available in DT/ACPI from now. if (ret && use_arch_cache_info())
use_arch_info = true;
return ret;
}
staticint cache_shared_cpu_map_setup(unsignedint cpu)
{ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); struct cacheinfo *this_leaf, *sib_leaf; unsignedint index, sib_index; int ret = 0;
if (this_cpu_ci->cpu_map_populated) return0;
/* * skip setting up cache properties if LLC is valid, just need * to update the shared cpu_map if the cache attributes were * populated early before all the cpus are brought online
*/ if (!last_level_cache_is_valid(cpu) && !use_arch_info) {
ret = cache_setup_properties(cpu); if (ret) return ret;
}
for (index = 0; index < cache_leaves(cpu); index++) { unsignedint i;
this_leaf = per_cpu_cacheinfo_idx(cpu, index);
cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
for_each_online_cpu(i) { if (i == cpu || !per_cpu_cacheinfo(i)) continue;/* skip if itself or no cacheinfo */ for (sib_index = 0; sib_index < cache_leaves(i); sib_index++) {
sib_leaf = per_cpu_cacheinfo_idx(i, sib_index);
/* * Comparing cache IDs only makes sense if the leaves * belong to the same cache level of same type. Skip * the check if level and type do not match.
*/ if (sib_leaf->level != this_leaf->level ||
sib_leaf->type != this_leaf->type) continue;
if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map);
cpumask_set_cpu(i, &this_leaf->shared_cpu_map); break;
}
}
} /* record the maximum cache line size */ if (this_leaf->coherency_line_size > coherency_max_size)
coherency_max_size = this_leaf->coherency_line_size;
}
/* shared_cpu_map is now populated for the cpu */
this_cpu_ci->cpu_map_populated = true; return0;
}
for (index = 0; index < cache_leaves(cpu); index++) {
this_leaf = per_cpu_cacheinfo_idx(cpu, index);
for_each_cpu(sibling, &this_leaf->shared_cpu_map) { if (sibling == cpu || !per_cpu_cacheinfo(sibling)) continue;/* skip if itself or no cacheinfo */
/* * Comparing cache IDs only makes sense if the leaves * belong to the same cache level of same type. Skip * the check if level and type do not match.
*/ if (sib_leaf->level != this_leaf->level ||
sib_leaf->type != this_leaf->type) continue;
int fetch_cache_info(unsignedint cpu)
{ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); unsignedint levels = 0, split_levels = 0; int ret;
if (acpi_disabled) {
ret = init_of_cache_level(cpu);
} else {
ret = acpi_get_cache_info(cpu, &levels, &split_levels); if (!ret) {
this_cpu_ci->num_levels = levels; /* * This assumes that: * - there cannot be any split caches (data/instruction) * above a unified cache * - data/instruction caches come by pair
*/
this_cpu_ci->num_leaves = levels + split_levels;
}
}
if (ret || !cache_leaves(cpu)) {
ret = early_cache_level(cpu); if (ret) return ret;
/* Since early initialization/allocation of the cacheinfo is allowed * via fetch_cache_info() and this also gets called as CPU hotplug * callbacks via cacheinfo_cpu_online, the init/alloc can be skipped * as it will happen only once (the cacheinfo memory is never freed). * Just populate the cacheinfo. However, if the cacheinfo has been * allocated early through the arch-specific early_cache_level() call, * there is a chance the info is wrong (this can happen on arm64). In * that case, call init_cache_level() anyway to give the arch-specific * code a chance to make things right.
*/ if (per_cpu_cacheinfo(cpu) && !ci_cacheinfo(cpu)->early_ci_levels) return0;
if (init_cache_level(cpu) || !cache_leaves(cpu)) return -ENOENT;
/* * Now that we have properly initialized the cache level info, make * sure we don't try to do that again the next time we are called * (e.g. as CPU hotplug callbacks).
*/
ci_cacheinfo(cpu)->early_ci_levels = false;
/* * Some architectures (e.g., x86) do not use early initialization. * Allocate memory now in such case.
*/ if (cache_leaves(cpu) <= early_leaves && per_cpu_cacheinfo(cpu)) return0;
int detect_cache_attributes(unsignedint cpu)
{ int ret;
ret = init_level_allocate_ci(cpu); if (ret) return ret;
/* * If LLC is valid the cache leaves were already populated so just go to * update the cpu map.
*/ if (!last_level_cache_is_valid(cpu)) { /* * populate_cache_leaves() may completely setup the cache leaves and * shared_cpu_map or it may leave it partially setup.
*/
ret = populate_cache_leaves(cpu); if (ret) goto free_ci;
}
/* * For systems using DT for cache hierarchy, fw_token * and shared_cpu_map will be set up here only if they are * not populated already
*/
ret = cache_shared_cpu_map_setup(cpu); if (ret) {
pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu); goto free_ci;
}
if (llc->type != CACHE_TYPE_DATA && llc->type != CACHE_TYPE_UNIFIED) return0;
if (online) {
*map = &llc->shared_cpu_map; return cpumask_weight(*map);
}
/* shared_cpu_map of offlined CPU will be cleared, so use sibling map */
for_each_cpu(sibling, &llc->shared_cpu_map) { if (sibling == cpu || !last_level_cache_is_valid(sibling)) continue;
sib_llc = per_cpu_cacheinfo_idx(sibling, cache_leaves(sibling) - 1);
*map = &sib_llc->shared_cpu_map; return cpumask_weight(*map);
}
return0;
}
/* * Calculate the size of the per-CPU data cache slice. This can be * used to estimate the size of the data cache slice that can be used * by one CPU under ideal circumstances. UNIFIED caches are counted * in addition to DATA caches. So, please consider code cache usage * when use the result. * * Because the cache inclusive/non-inclusive information isn't * available, we just use the size of the per-CPU slice of LLC to make * the result more predictable across architectures.
*/ staticvoid update_per_cpu_data_slice_size_cpu(unsignedint cpu)
{ struct cpu_cacheinfo *ci; struct cacheinfo *llc; unsignedint nr_shared;
if (!last_level_cache_is_valid(cpu)) return;
ci = ci_cacheinfo(cpu);
llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1);
if (llc->type != CACHE_TYPE_DATA && llc->type != CACHE_TYPE_UNIFIED) return;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.16Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-07)
¤
*Diese Quellcodebibliothek enthält Beispiele in vielen Programmiersprachen.
Man kann per Verzeichnistruktur darin navigieren.
Der Code wird farblich markiert angezeigt.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.