soc/intel/common: Order the CPUs based on their APIC IDs

The patch  defines acpi_set_cpu_apicid_order() which orders the APIC IDs
based on APIC IDs of Performance cores and Efficient cores, calculates
the total core count and total Performance cores count,  populates the
information in the cpu_apicid_order_info struct.
The helper function useful to present the Performance and Efficient
cores in order to OS through MADT table and _CPC object.

TEST=Verify the build for Gimble (Alder Lake board)

Change-Id: I8ab6053ffd036185d74d5469fbdf36d48e0021ce
Signed-off-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/72131
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Sridhar Siricilla 2023-03-30 11:25:36 +05:30
parent 450699d1c8
commit f8ac3dda02
1 changed files with 64 additions and 57 deletions

View File

@ -1,12 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <acpi/acpi.h>
#include <acpi/acpigen.h>
#include <intelblocks/acpi.h>
#include <soc/cpu.h>
#include <smp/spinlock.h>
#include <device/device.h>
#include <device/path.h>
#include <bootstate.h>
#include <commonlib/sort.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/mp.h>
#include <cpu/cpu.h>
#include <device/path.h>
#include <intelblocks/acpi.h>
#include <soc/cpu.h>
#include <types.h>
#define CPPC_NOM_FREQ_IDX 22
#define CPPC_NOM_PERF_IDX 3
@ -16,12 +19,62 @@ enum cpu_perf_eff_type {
CPU_TYPE_PERF,
};
DECLARE_SPIN_LOCK(cpu_lock);
static u8 global_cpu_type[CONFIG_MAX_CPUS];
struct cpu_apic_info_type {
/*
* Ordered APIC IDs based on core type.
* Array begins with Performance Cores' APIC IDs,
* then followed by Efficeint Cores's APIC IDs.
*/
int32_t apic_ids[CONFIG_MAX_CPUS];
static bool is_perf_core(void)
/* Total CPU count */
uint8_t total_cpu_cnt;
/*
* Total Performance core count. This will be used
* to identify the start of Efficient Cores's
* APIC ID list
*/
uint8_t perf_cpu_cnt;
};
static struct cpu_apic_info_type cpu_apic_info;
/*
* The function orders APIC IDs such that orders first Performance cores and then
* Efficient cores' APIC IDs in ascending order. Also calculates total number of
* Performance cores and all cores count in the system and populates the information
* in the cpu_apic_info sturct.
*/
static void acpi_set_hybrid_cpu_apicid_order(void *unused)
{
return get_soc_cpu_type() == CPUID_CORE_TYPE_INTEL_CORE;
size_t perf_core_cnt = 0, eff_core_cnt = 0;
int32_t eff_apic_ids[CONFIG_MAX_CPUS] = {0};
extern struct cpu_info cpu_infos[];
uint32_t i, j = 0;
for (i = 0; i < ARRAY_SIZE(cpu_apic_info.apic_ids); i++) {
if (cpu_infos[i].cpu->path.apic.core_type == CPU_TYPE_PERF)
cpu_apic_info.apic_ids[perf_core_cnt++] =
cpu_infos[i].cpu->path.apic.apic_id;
else
eff_apic_ids[eff_core_cnt++] =
cpu_infos[i].cpu->path.apic.apic_id;
}
if (perf_core_cnt > 1)
bubblesort(cpu_apic_info.apic_ids, perf_core_cnt, NUM_ASCENDING);
for (i = perf_core_cnt; j < eff_core_cnt; i++, j++)
cpu_apic_info.apic_ids[i] = eff_apic_ids[j];
if (eff_core_cnt > 1)
bubblesort(&cpu_apic_info.apic_ids[perf_core_cnt], eff_core_cnt, NUM_ASCENDING);
/* Populate total core count */
cpu_apic_info.total_cpu_cnt = perf_core_cnt + eff_core_cnt;
cpu_apic_info.perf_cpu_cnt = perf_core_cnt;
}
static enum cpu_perf_eff_type get_core_type(void)
@ -36,52 +89,6 @@ void set_dev_core_type(void)
info->cpu->path.apic.core_type = get_core_type();
}
static struct device *get_cpu_bus_first_child(void)
{
struct device *dev = dev_find_path(NULL, DEVICE_PATH_CPU_CLUSTER);
assert(dev != NULL);
return (dev->link_list)->children;
}
static u32 get_cpu_index(void)
{
u32 cpu_index = 0;
struct device *dev;
u32 my_apic_id = lapicid();
for (dev = get_cpu_bus_first_child(); dev; dev = dev->sibling)
if (my_apic_id > dev->path.apic.apic_id)
cpu_index++;
return cpu_index;
}
/*
* This function determines the type (performance or efficient) of the CPU that
* is executing it and stores the information (in a thread-safe manner) in an
* global_cpu_type array.
* It requires the SoC to implement a function `get_soc_cpu_type()` which will be
* called in a critical section to determine the type of the executing CPU.
*/
static void set_cpu_type(void *unused)
{
spin_lock(&cpu_lock);
u8 cpu_index = get_cpu_index();
if (is_perf_core())
global_cpu_type[cpu_index] = CPU_TYPE_PERF;
spin_unlock(&cpu_lock);
}
static void run_set_cpu_type(void *unused)
{
if (mp_run_on_all_cpus(set_cpu_type, NULL) != CB_SUCCESS) {
printk(BIOS_ERR, "cpu_hybrid: Failed to set global_cpu_type with CPU type info\n");
return;
}
}
static void acpi_get_cpu_nomi_perf(u16 *eff_core_nom_perf, u16 *perf_core_nom_perf)
{
u8 max_non_turbo_ratio = cpu_get_max_non_turbo_ratio();
@ -114,7 +121,7 @@ static void acpigen_cppc_update_nominal_freq_perf(const char *pkg_path, s32 core
acpi_get_cpu_nomi_perf(&eff_core_nom_perf, &perf_core_nom_perf);
if (global_cpu_type[core_id] == CPU_TYPE_PERF)
if (core_id < cpu_apic_info.perf_cpu_cnt)
acpigen_set_package_element_int(pkg_path, CPPC_NOM_PERF_IDX, perf_core_nom_perf);
else
acpigen_set_package_element_int(pkg_path, CPPC_NOM_PERF_IDX,
@ -144,4 +151,4 @@ void acpigen_write_CPPC_hybrid_method(s32 core_id)
acpigen_pop_len();
}
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, run_set_cpu_type, NULL);
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, acpi_set_hybrid_cpu_apicid_order, NULL);