// SPDX-License-Identifier: GPL-2.0 #include #include #include static int __init parse_dt_topology(void) { return 0; } /* * cpu topology table */ struct cpu_topology cpu_topology[NR_CPUS]; EXPORT_SYMBOL_GPL(cpu_topology); const struct cpumask *cpu_coregroup_mask(int cpu) { const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu)); /* Find the smaller of NUMA, core or LLC siblings */ if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) { /* not numa in package, lets use the package siblings */ core_mask = &cpu_topology[cpu].core_sibling; } if (cpu_topology[cpu].llc_id != -1) { if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask)) core_mask = &cpu_topology[cpu].llc_sibling; } return core_mask; } static void update_siblings_masks(int cpuid) { struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; int cpu; /* update core and thread sibling masks */ for_each_online_cpu(cpu) { cpu_topo = &cpu_topology[cpu]; if (cpuid_topo->llc_id == cpu_topo->llc_id) { cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling); cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling); } if (cpuid_topo->package_id != cpu_topo->package_id) continue; cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); if (cpuid_topo->core_id != cpu_topo->core_id) continue; cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); } } void store_cpu_topology(int cpuid) { struct cpu_topology *cpuid_topo = &cpu_topology[cpuid]; if (cpuid_topo->package_id != -1) goto topology_populated; cpuid_topo->core_id = cpu_to_rcid(cpuid) & CORE_ID_MASK; cpuid_topo->package_id = rcid_to_package(cpu_to_rcid(cpuid)); cpuid_topo->llc_id = rcid_to_package(cpuid); cpuid_topo->thread_id = (cpu_to_rcid(cpuid) >> THREAD_ID_SHIFT) & THREAD_ID_MASK; pr_debug("CPU%u: socket %d core %d thread %d\n", cpuid, cpuid_topo->package_id, cpuid_topo->core_id, cpuid_topo->thread_id); topology_populated: update_siblings_masks(cpuid); } static void clear_cpu_topology(int cpu) { struct cpu_topology *cpu_topo = &cpu_topology[cpu]; cpumask_clear(&cpu_topo->llc_sibling); cpumask_set_cpu(cpu, &cpu_topo->llc_sibling); cpumask_clear(&cpu_topo->core_sibling); cpumask_set_cpu(cpu, &cpu_topo->core_sibling); cpumask_clear(&cpu_topo->thread_sibling); cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); } static void __init reset_cpu_topology(void) { int cpu; for_each_possible_cpu(cpu) { struct cpu_topology *cpu_topo = &cpu_topology[cpu]; cpu_topo->thread_id = -1; cpu_topo->core_id = 0; cpu_topo->package_id = -1; cpu_topo->llc_id = -1; clear_cpu_topology(cpu); } } void remove_cpu_topology(int cpu) { int sibling; for_each_cpu(sibling, topology_core_cpumask(cpu)) cpumask_clear_cpu(cpu, topology_core_cpumask(sibling)); for_each_cpu(sibling, topology_sibling_cpumask(cpu)) cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling)); for_each_cpu(sibling, topology_llc_cpumask(cpu)) cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling)); clear_cpu_topology(cpu); } #ifdef CONFIG_ACPI static int __init parse_acpi_topology(void) { return 0; } #else static inline int __init parse_acpi_topology(void) { return -EINVAL; } #endif void __init init_cpu_topology(void) { reset_cpu_topology(); /* * Discard anything that was parsed if we hit an error so we * don't use partial information. */ if (!acpi_disabled && parse_acpi_topology()) reset_cpu_topology(); else if (of_have_populated_dt() && parse_dt_topology()) reset_cpu_topology(); }