| #include <string.h> |
| |
| #include <cpuinfo/internal-api.h> |
| #include <cpuinfo/log.h> |
| #include <linux/api.h> |
| #include <riscv/linux/api.h> |
| |
| /* ISA structure to hold supported extensions. */ |
| struct cpuinfo_riscv_isa cpuinfo_isa; |
| |
| /* Helper function to bitmask flags and ensure operator precedence. */ |
| static inline bool bitmask_all(uint32_t flags, uint32_t mask) { |
| return (flags & mask) == mask; |
| } |
| |
| static int compare_riscv_linux_processors(const void* a, const void* b) { |
| /** |
| * For our purposes, it is only relevant that the list is sorted by |
| * micro-architecture, so the nature of ordering is irrelevant. |
| */ |
| return ((const struct cpuinfo_riscv_linux_processor*)a)->core.uarch - |
| ((const struct cpuinfo_riscv_linux_processor*)b)->core.uarch; |
| } |
| |
| /** |
| * Parses the core cpus list for each processor. This function is called once |
| * per-processor, with the IDs of all other processors in the core list. |
| * |
| * The 'processor_[start|count]' are populated in the processor's 'core' |
| * attribute, with 'start' being the smallest ID in the core list. |
| * |
| * The 'core_leader_id' of each processor is set to the smallest ID in it's |
| * cluster CPU list. |
| * |
| * Precondition: The element in the 'processors' list must be initialized with |
| * their 'core_leader_id' to their index in the list. |
| |
| * E.g. processors[0].core_leader_id = 0. |
| */ |
| static bool core_cpus_parser( |
| uint32_t processor, |
| uint32_t core_cpus_start, |
| uint32_t core_cpus_end, |
| struct cpuinfo_riscv_linux_processor* processors) { |
| uint32_t processor_start = UINT32_MAX; |
| uint32_t processor_count = 0; |
| |
| /* If the processor already has a leader, use it. */ |
| if (bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_CORE_CLUSTER)) { |
| processor_start = processors[processor].core_leader_id; |
| } |
| |
| for (size_t core_cpu = core_cpus_start; core_cpu < core_cpus_end; core_cpu++) { |
| if (!bitmask_all(processors[core_cpu].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| /** |
| * The first valid processor observed is the smallest ID in the |
| * list that attaches to this core. |
| */ |
| if (processor_start == UINT32_MAX) { |
| processor_start = core_cpu; |
| } |
| processors[core_cpu].core_leader_id = processor_start; |
| processor_count++; |
| } |
| /** |
| * If the cluster flag has not been set, assign the processor start. If |
| * it has been set, only apply the processor start if it's less than the |
| * held value. This can happen if the callback is invoked twice: |
| * |
| * e.g. core_cpu_list=1,10-12 |
| */ |
| if (!bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_CORE_CLUSTER) || |
| processors[processor].core.processor_start > processor_start) { |
| processors[processor].core.processor_start = processor_start; |
| processors[processor].core_leader_id = processor_start; |
| } |
| processors[processor].core.processor_count += processor_count; |
| processors[processor].flags |= CPUINFO_LINUX_FLAG_CORE_CLUSTER; |
| /* The parser has failed only if no processors were found. */ |
| return processor_count != 0; |
| } |
| |
| /** |
| * Parses the cluster cpu list for each processor. This function is called once |
| * per-processor, with the IDs of all other processors in the cluster. |
| * |
| * The 'cluster_leader_id' of each processor is set to the smallest ID in it's |
| * cluster CPU list. |
| * |
| * Precondition: The element in the 'processors' list must be initialized with |
| * their 'cluster_leader_id' to their index in the list. |
| * E.g. processors[0].cluster_leader_id = 0. |
| */ |
| static bool cluster_cpus_parser( |
| uint32_t processor, |
| uint32_t cluster_cpus_start, |
| uint32_t cluster_cpus_end, |
| struct cpuinfo_riscv_linux_processor* processors) { |
| uint32_t processor_start = UINT32_MAX; |
| uint32_t processor_count = 0; |
| uint32_t core_count = 0; |
| |
| /* If the processor already has a leader, use it. */ |
| if (bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_CLUSTER_CLUSTER)) { |
| processor_start = processors[processor].cluster_leader_id; |
| } |
| |
| for (size_t cluster_cpu = cluster_cpus_start; cluster_cpu < cluster_cpus_end; cluster_cpu++) { |
| if (!bitmask_all(processors[cluster_cpu].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| /** |
| * The first valid processor observed is the smallest ID in the |
| * list that attaches to this core. |
| */ |
| if (processor_start == UINT32_MAX) { |
| processor_start = cluster_cpu; |
| } |
| processors[cluster_cpu].cluster_leader_id = processor_start; |
| processor_count++; |
| /** |
| * A processor should only represent it's core if it is the |
| * assigned leader of that core. |
| */ |
| if (processors[cluster_cpu].core_leader_id == cluster_cpu) { |
| core_count++; |
| } |
| } |
| /** |
| * If the cluster flag has not been set, assign the processor start. If |
| * it has been set, only apply the processor start if it's less than the |
| * held value. This can happen if the callback is invoked twice: |
| * |
| * e.g. cluster_cpus_list=1,10-12 |
| */ |
| if (!bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_CLUSTER_CLUSTER) || |
| processors[processor].cluster.processor_start > processor_start) { |
| processors[processor].cluster.processor_start = processor_start; |
| processors[processor].cluster.core_start = processor_start; |
| processors[processor].cluster.cluster_id = processor_start; |
| processors[processor].cluster_leader_id = processor_start; |
| } |
| processors[processor].cluster.processor_count += processor_count; |
| processors[processor].cluster.core_count += core_count; |
| processors[processor].flags |= CPUINFO_LINUX_FLAG_CLUSTER_CLUSTER; |
| return true; |
| } |
| |
| /** |
| * Parses the package cpus list for each processor. This function is called once |
| * per-processor, with the IDs of all other processors in the package list. |
| * |
| * The 'processor_[start|count]' are populated in the processor's 'package' |
| * attribute, with 'start' being the smallest ID in the package list. |
| * |
| * The 'package_leader_id' of each processor is set to the smallest ID in it's |
| * cluster CPU list. |
| * |
| * Precondition: The element in the 'processors' list must be initialized with |
| * their 'package_leader_id' to their index in the list. |
| * E.g. processors[0].package_leader_id = 0. |
| */ |
| static bool package_cpus_parser( |
| uint32_t processor, |
| uint32_t package_cpus_start, |
| uint32_t package_cpus_end, |
| struct cpuinfo_riscv_linux_processor* processors) { |
| uint32_t processor_start = UINT32_MAX; |
| uint32_t processor_count = 0; |
| uint32_t cluster_count = 0; |
| uint32_t core_count = 0; |
| |
| /* If the processor already has a leader, use it. */ |
| if (bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER)) { |
| processor_start = processors[processor].package_leader_id; |
| } |
| |
| for (size_t package_cpu = package_cpus_start; package_cpu < package_cpus_end; package_cpu++) { |
| if (!bitmask_all(processors[package_cpu].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| /** |
| * The first valid processor observed is the smallest ID in the |
| * list that attaches to this package. |
| */ |
| if (processor_start == UINT32_MAX) { |
| processor_start = package_cpu; |
| } |
| processors[package_cpu].package_leader_id = processor_start; |
| processor_count++; |
| /** |
| * A processor should only represent it's core if it is the |
| * assigned leader of that core, and similarly for it's cluster. |
| */ |
| if (processors[package_cpu].cluster_leader_id == package_cpu) { |
| cluster_count++; |
| } |
| if (processors[package_cpu].core_leader_id == package_cpu) { |
| core_count++; |
| } |
| } |
| /** |
| * If the cluster flag has not been set, assign the processor start. If |
| * it has been set, only apply the processor start if it's less than the |
| * held value. This can happen if the callback is invoked twice: |
| * |
| * e.g. package_cpus_list=1,10-12 |
| */ |
| if (!bitmask_all(processors[processor].flags, CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER) || |
| processors[processor].package.processor_start > processor_start) { |
| processors[processor].package.processor_start = processor_start; |
| processors[processor].package.cluster_start = processor_start; |
| processors[processor].package.core_start = processor_start; |
| processors[processor].package_leader_id = processor_start; |
| } |
| processors[processor].package.processor_count += processor_count; |
| processors[processor].package.cluster_count += cluster_count; |
| processors[processor].package.core_count += core_count; |
| processors[processor].flags |= CPUINFO_LINUX_FLAG_PACKAGE_CLUSTER; |
| return true; |
| } |
| |
| /* Initialization for the RISC-V Linux system. */ |
| void cpuinfo_riscv_linux_init(void) { |
| struct cpuinfo_riscv_linux_processor* riscv_linux_processors = NULL; |
| struct cpuinfo_processor* processors = NULL; |
| struct cpuinfo_package* packages = NULL; |
| struct cpuinfo_cluster* clusters = NULL; |
| struct cpuinfo_core* cores = NULL; |
| struct cpuinfo_uarch_info* uarchs = NULL; |
| const struct cpuinfo_processor** linux_cpu_to_processor_map = NULL; |
| const struct cpuinfo_core** linux_cpu_to_core_map = NULL; |
| uint32_t* linux_cpu_to_uarch_index_map = NULL; |
| |
| /** |
| * The interesting set of processors are the number of 'present' |
| * processors on the system. There may be more 'possible' processors, |
| * but processor information cannot be gathered on non-present |
| * processors. |
| * |
| * Note: For SoCs, it is largely the case that all processors are known |
| * at boot and no processors are hotplugged at runtime, so the |
| * 'present' and 'possible' list is often the same. |
| * |
| * Note: This computes the maximum processor ID of the 'present' |
| * processors. It is not a count of the number of processors on the |
| * system. |
| */ |
| const uint32_t max_processor_id = |
| 1 + cpuinfo_linux_get_max_present_processor(cpuinfo_linux_get_max_processors_count()); |
| if (max_processor_id == 0) { |
| cpuinfo_log_error("failed to discover any processors"); |
| return; |
| } |
| |
| /** |
| * Allocate space to store all processor information. This array is |
| * sized to the max processor ID as opposed to the number of 'present' |
| * processors, to leverage pointer math in the common utility functions. |
| */ |
| riscv_linux_processors = calloc(max_processor_id, sizeof(struct cpuinfo_riscv_linux_processor)); |
| if (riscv_linux_processors == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %" PRIu32 " processors.", |
| max_processor_id * sizeof(struct cpuinfo_riscv_linux_processor), |
| max_processor_id); |
| goto cleanup; |
| } |
| |
| /** |
| * Attempt to detect all processors and apply the corresponding flag to |
| * each processor struct that we find. |
| */ |
| if (!cpuinfo_linux_detect_present_processors( |
| max_processor_id, |
| &riscv_linux_processors->flags, |
| sizeof(struct cpuinfo_riscv_linux_processor), |
| CPUINFO_LINUX_FLAG_PRESENT | CPUINFO_LINUX_FLAG_VALID)) { |
| cpuinfo_log_error("failed to detect present processors"); |
| goto cleanup; |
| } |
| |
| /* Populate processor information. */ |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| /* TODO: Determine if an 'smt_id' is available. */ |
| riscv_linux_processors[processor].processor.linux_id = processor; |
| } |
| |
| /* Populate core information. */ |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| |
| /* Populate processor start and count information. */ |
| if (!cpuinfo_linux_detect_core_cpus( |
| max_processor_id, |
| processor, |
| (cpuinfo_siblings_callback)core_cpus_parser, |
| riscv_linux_processors)) { |
| cpuinfo_log_error("failed to detect core cpus for processor %zu.", processor); |
| goto cleanup; |
| } |
| |
| /* Populate core ID information. */ |
| if (cpuinfo_linux_get_processor_core_id(processor, &riscv_linux_processors[processor].core.core_id)) { |
| riscv_linux_processors[processor].flags |= CPUINFO_LINUX_FLAG_CORE_ID; |
| } |
| |
| /** |
| * Populate the vendor and uarch of this core from this |
| * processor. When the final 'cores' list is constructed, only |
| * the values from the core leader will be honored. |
| */ |
| cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe( |
| processor, |
| &riscv_linux_processors[processor].core.vendor, |
| &riscv_linux_processors[processor].core.uarch); |
| |
| /* Populate frequency information of this core. */ |
| uint32_t frequency = cpuinfo_linux_get_processor_cur_frequency(processor); |
| if (frequency != 0) { |
| riscv_linux_processors[processor].core.frequency = frequency; |
| riscv_linux_processors[processor].flags |= CPUINFO_LINUX_FLAG_CUR_FREQUENCY; |
| } |
| } |
| |
| /* Populate cluster information. */ |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| if (!cpuinfo_linux_detect_cluster_cpus( |
| max_processor_id, |
| processor, |
| (cpuinfo_siblings_callback)cluster_cpus_parser, |
| riscv_linux_processors)) { |
| cpuinfo_log_warning("failed to detect cluster cpus for processor %zu.", processor); |
| goto cleanup; |
| } |
| |
| /** |
| * Populate the vendor, uarch and frequency of this cluster from |
| * this logical processor. When the 'clusters' list is |
| * constructed, only the values from the cluster leader will be |
| * honored. |
| */ |
| riscv_linux_processors[processor].cluster.vendor = riscv_linux_processors[processor].core.vendor; |
| riscv_linux_processors[processor].cluster.uarch = riscv_linux_processors[processor].core.uarch; |
| riscv_linux_processors[processor].cluster.frequency = riscv_linux_processors[processor].core.frequency; |
| } |
| |
| /* Populate package information. */ |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| if (!cpuinfo_linux_detect_package_cpus( |
| max_processor_id, |
| processor, |
| (cpuinfo_siblings_callback)package_cpus_parser, |
| riscv_linux_processors)) { |
| cpuinfo_log_warning("failed to detect package cpus for processor %zu.", processor); |
| goto cleanup; |
| } |
| } |
| |
| /* Populate ISA structure with hwcap information. */ |
| cpuinfo_riscv_linux_decode_isa_from_hwcap(&cpuinfo_isa); |
| |
| /** |
| * To efficiently compute the number of unique micro-architectures |
| * present on the system, sort the processor list by micro-architecture |
| * and then scan through the list to count the differences. |
| * |
| * Ensure this is done at the end of composing the processor list - the |
| * parsing functions assume that the position of the processor in the |
| * list matches it's Linux ID, which this sorting operation breaks. |
| */ |
| qsort(riscv_linux_processors, |
| max_processor_id, |
| sizeof(struct cpuinfo_riscv_linux_processor), |
| compare_riscv_linux_processors); |
| |
| /** |
| * Determine the number of *valid* detected processors, cores, |
| * clusters, packages and uarchs in the list. |
| */ |
| size_t valid_processors_count = 0; |
| size_t valid_cores_count = 0; |
| size_t valid_clusters_count = 0; |
| size_t valid_packages_count = 0; |
| size_t valid_uarchs_count = 0; |
| enum cpuinfo_uarch last_uarch = cpuinfo_uarch_unknown; |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| |
| /** |
| * All comparisons to the leader id values MUST be done against |
| * the 'linux_id' as opposed to 'processor'. The sort function |
| * above no longer allows us to make the assumption that these |
| * two values are the same. |
| */ |
| uint32_t linux_id = riscv_linux_processors[processor].processor.linux_id; |
| |
| valid_processors_count++; |
| if (riscv_linux_processors[processor].core_leader_id == linux_id) { |
| valid_cores_count++; |
| } |
| if (riscv_linux_processors[processor].cluster_leader_id == linux_id) { |
| valid_clusters_count++; |
| } |
| if (riscv_linux_processors[processor].package_leader_id == linux_id) { |
| valid_packages_count++; |
| } |
| /** |
| * As we've sorted by micro-architecture, when the uarch differs |
| * between two entries, a unique uarch has been observed. |
| */ |
| if (last_uarch != riscv_linux_processors[processor].core.uarch || valid_uarchs_count == 0) { |
| valid_uarchs_count++; |
| last_uarch = riscv_linux_processors[processor].core.uarch; |
| } |
| } |
| |
| /* Allocate and populate final public ABI structures. */ |
| processors = calloc(valid_processors_count, sizeof(struct cpuinfo_processor)); |
| if (processors == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %zu processors.", |
| valid_processors_count * sizeof(struct cpuinfo_processor), |
| valid_processors_count); |
| goto cleanup; |
| } |
| |
| cores = calloc(valid_cores_count, sizeof(struct cpuinfo_core)); |
| if (cores == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %zu cores.", |
| valid_cores_count * sizeof(struct cpuinfo_core), |
| valid_cores_count); |
| goto cleanup; |
| } |
| |
| clusters = calloc(valid_clusters_count, sizeof(struct cpuinfo_cluster)); |
| if (clusters == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %zu clusters.", |
| valid_clusters_count * sizeof(struct cpuinfo_cluster), |
| valid_clusters_count); |
| goto cleanup; |
| } |
| |
| packages = calloc(valid_packages_count, sizeof(struct cpuinfo_package)); |
| if (packages == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %zu packages.", |
| valid_packages_count * sizeof(struct cpuinfo_package), |
| valid_packages_count); |
| goto cleanup; |
| } |
| |
| uarchs = calloc(valid_uarchs_count, sizeof(struct cpuinfo_uarch_info)); |
| if (uarchs == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %zu packages.", |
| valid_uarchs_count * sizeof(struct cpuinfo_uarch_info), |
| valid_uarchs_count); |
| goto cleanup; |
| } |
| |
| linux_cpu_to_processor_map = calloc(max_processor_id, sizeof(struct cpuinfo_processor*)); |
| if (linux_cpu_to_processor_map == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %" PRIu32 " processor map.", |
| max_processor_id * sizeof(struct cpuinfo_processor*), |
| max_processor_id); |
| goto cleanup; |
| } |
| |
| linux_cpu_to_core_map = calloc(max_processor_id, sizeof(struct cpuinfo_core*)); |
| if (linux_cpu_to_core_map == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %" PRIu32 " core map.", |
| max_processor_id * sizeof(struct cpuinfo_core*), |
| max_processor_id); |
| goto cleanup; |
| } |
| |
| linux_cpu_to_uarch_index_map = calloc(max_processor_id, sizeof(struct cpuinfo_uarch_info*)); |
| if (linux_cpu_to_uarch_index_map == NULL) { |
| cpuinfo_log_error( |
| "failed to allocate %zu bytes for %" PRIu32 " uarch map.", |
| max_processor_id * sizeof(struct cpuinfo_uarch_info*), |
| max_processor_id); |
| goto cleanup; |
| } |
| |
| /* Transfer contents of processor list to ABI structures. */ |
| size_t valid_processors_index = 0; |
| size_t valid_cores_index = 0; |
| size_t valid_clusters_index = 0; |
| size_t valid_packages_index = 0; |
| size_t valid_uarchs_index = 0; |
| last_uarch = cpuinfo_uarch_unknown; |
| for (size_t processor = 0; processor < max_processor_id; processor++) { |
| if (!bitmask_all(riscv_linux_processors[processor].flags, CPUINFO_LINUX_FLAG_VALID)) { |
| continue; |
| } |
| |
| /** |
| * All comparisons to the leader id values MUST be done against |
| * the 'linux_id' as opposed to 'processor'. The sort function |
| * above no longer allows us to make the assumption that these |
| * two values are the same. |
| */ |
| uint32_t linux_id = riscv_linux_processors[processor].processor.linux_id; |
| |
| /* Create uarch entry if this uarch has not been seen before. */ |
| if (last_uarch != riscv_linux_processors[processor].core.uarch || valid_uarchs_index == 0) { |
| uarchs[valid_uarchs_index++].uarch = riscv_linux_processors[processor].core.uarch; |
| last_uarch = riscv_linux_processors[processor].core.uarch; |
| } |
| |
| /* Copy cpuinfo_processor information. */ |
| memcpy(&processors[valid_processors_index++], |
| &riscv_linux_processors[processor].processor, |
| sizeof(struct cpuinfo_processor)); |
| |
| /* Update uarch processor count. */ |
| uarchs[valid_uarchs_index - 1].processor_count++; |
| |
| /* Copy cpuinfo_core information, if this is the leader. */ |
| if (riscv_linux_processors[processor].core_leader_id == linux_id) { |
| memcpy(&cores[valid_cores_index++], |
| &riscv_linux_processors[processor].core, |
| sizeof(struct cpuinfo_core)); |
| /* Update uarch core count. */ |
| uarchs[valid_uarchs_index - 1].core_count++; |
| } |
| |
| /* Copy cpuinfo_cluster information, if this is the leader. */ |
| if (riscv_linux_processors[processor].cluster_leader_id == linux_id) { |
| memcpy(&clusters[valid_clusters_index++], |
| &riscv_linux_processors[processor].cluster, |
| sizeof(struct cpuinfo_cluster)); |
| } |
| |
| /* Copy cpuinfo_package information, if this is the leader. */ |
| if (riscv_linux_processors[processor].package_leader_id == linux_id) { |
| memcpy(&packages[valid_packages_index++], |
| &riscv_linux_processors[processor].package, |
| sizeof(struct cpuinfo_package)); |
| } |
| |
| /* Commit pointers on the final structures. */ |
| processors[valid_processors_index - 1].core = &cores[valid_cores_index - 1]; |
| processors[valid_processors_index - 1].cluster = &clusters[valid_clusters_index - 1]; |
| processors[valid_processors_index - 1].package = &packages[valid_packages_index - 1]; |
| |
| cores[valid_cores_index - 1].cluster = &clusters[valid_clusters_index - 1]; |
| cores[valid_cores_index - 1].package = &packages[valid_packages_index - 1]; |
| |
| clusters[valid_clusters_index - 1].package = &packages[valid_packages_index - 1]; |
| |
| linux_cpu_to_processor_map[linux_id] = &processors[valid_processors_index - 1]; |
| linux_cpu_to_core_map[linux_id] = &cores[valid_cores_index - 1]; |
| linux_cpu_to_uarch_index_map[linux_id] = valid_uarchs_index - 1; |
| } |
| |
| /* Commit */ |
| cpuinfo_processors = processors; |
| cpuinfo_processors_count = valid_processors_count; |
| cpuinfo_cores = cores; |
| cpuinfo_cores_count = valid_cores_count; |
| cpuinfo_clusters = clusters; |
| cpuinfo_clusters_count = valid_clusters_count; |
| cpuinfo_packages = packages; |
| cpuinfo_packages_count = valid_packages_count; |
| cpuinfo_uarchs = uarchs; |
| cpuinfo_uarchs_count = valid_uarchs_count; |
| |
| cpuinfo_linux_cpu_max = max_processor_id; |
| cpuinfo_linux_cpu_to_processor_map = linux_cpu_to_processor_map; |
| cpuinfo_linux_cpu_to_core_map = linux_cpu_to_core_map; |
| cpuinfo_linux_cpu_to_uarch_index_map = linux_cpu_to_uarch_index_map; |
| |
| __sync_synchronize(); |
| |
| cpuinfo_is_initialized = true; |
| |
| /* Mark all public structures NULL to prevent cleanup from erasing them. |
| */ |
| processors = NULL; |
| cores = NULL; |
| clusters = NULL; |
| packages = NULL; |
| uarchs = NULL; |
| linux_cpu_to_processor_map = NULL; |
| linux_cpu_to_core_map = NULL; |
| linux_cpu_to_uarch_index_map = NULL; |
| cleanup: |
| free(riscv_linux_processors); |
| free(processors); |
| free(cores); |
| free(clusters); |
| free(packages); |
| free(uarchs); |
| free(linux_cpu_to_processor_map); |
| free(linux_cpu_to_core_map); |
| free(linux_cpu_to_uarch_index_map); |
| } |