2026-01-29 22:25:33 +08:00

305 lines
6.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/irqdomain.h>
#include <linux/memblock.h>
#include <asm/early_ioremap.h>
#ifdef CONFIG_ACPI_HOTPLUG_CPU
#include <acpi/processor.h>
#endif
int acpi_disabled = 1;
EXPORT_SYMBOL(acpi_disabled);
int acpi_noirq = 1; /* skip ACPI IRQ initialization */
int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);
static bool param_acpi_on __initdata;
static bool param_acpi_off __initdata;
int acpi_strict;
u64 arch_acpi_wakeup_start;
u64 acpi_saved_sp_s3;
#define MAX_LOCAL_APIC 256
#define PREFIX "ACPI: "
/*
* The default interrupt routing model is PIC (8259). This gets
* overridden if IOAPICs are enumerated (below).
*/
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC;
void __iomem *__init __acpi_map_table(unsigned long phys, unsigned long size)
{
if (!phys || !size)
return NULL;
return early_ioremap(phys, size);
}
void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
{
if (!map || !size)
return;
early_iounmap(map, size);
}
/*
* Following __acpi_xx functions should be implemented for sepecific cpu.
*/
int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
{
if (irqp != NULL)
*irqp = acpi_register_gsi(NULL, gsi, -1, -1);
return 0;
}
EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi)
{
if (gsi)
*gsi = isa_irq;
return 0;
}
int (*acpi_suspend_lowlevel)(void);
/*
* success: return IRQ number (>=0)
* failure: return < 0
*/
static struct irq_domain *irq_default_domain;
int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
{
u32 irq;
irq = irq_find_mapping(irq_default_domain, gsi);
return irq;
}
EXPORT_SYMBOL_GPL(acpi_register_gsi);
void acpi_unregister_gsi(u32 gsi)
{
}
EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
/*
* ACPI based hotplug support for CPU
*/
#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* wrapper to silence section mismatch warning */
int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
{
return 0;
}
EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu)
{
return 0;
}
EXPORT_SYMBOL(acpi_unmap_lsapic);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
u8 acpi_checksum(u8 *table, u32 length)
{
u8 ret = 0;
while (length--) {
ret += *table;
table++;
}
return -ret;
}
static int __init parse_acpi(char *arg)
{
if (!arg)
return -EINVAL;
/* disable both ACPI table parsing and interpreter */
if (strcmp(arg, "off") == 0)
param_acpi_off = true;
else if (strcmp(arg, "on") == 0) /* prefer ACPI over device tree */
param_acpi_on = true;
else
return -EINVAL; /* Core will printk when we return error. */
return 0;
}
early_param("acpi", parse_acpi);
/*
* __acpi_acquire_global_lock
* will always return -1 indicating owning the lock.
*
* __acpi_release_global_lock will always return 0 indicating
* no acquring request pending.
*/
int __acpi_acquire_global_lock(unsigned int *lock)
{
return -1;
}
int __acpi_release_global_lock(unsigned int *lock)
{
return 0;
}
#ifdef CONFIG_ACPI_NUMA
static int rcid_to_cpu(int physical_id)
{
int i;
for (i = 0; i < NR_CPUS; ++i) {
if (__cpu_to_rcid[i] == physical_id)
return i;
}
/* physical id not found */
return -1;
}
/* Callback for Proximity Domain -> CPUID mapping */
void __init
acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
{
int pxm, node;
int cpu; // logical core id
if (srat_disabled())
return;
if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
bad_srat();
return;
}
if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
return;
pxm = pa->proximity_domain_lo;
if (acpi_srat_revision >= 2) {
pxm |= (pa->proximity_domain_hi[0] << 8);
pxm |= (pa->proximity_domain_hi[1] << 16);
pxm |= (pa->proximity_domain_hi[2] << 24);
}
node = acpi_map_pxm_to_node(pxm);
if (node < 0) {
pr_err("SRAT: Too many proximity domains %x\n", pxm);
bad_srat();
return;
}
if (pa->apic_id >= CONFIG_NR_CPUS) {
pr_err("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", pxm, pa->apic_id, node);
return;
}
/* Record the mapping from logical core id to node id */
cpu = rcid_to_cpu(pa->apic_id);
if (cpu < 0) {
pr_err("SRAT: Can not find the logical id for physical Core 0x%02x\n", pa->apic_id);
return;
}
early_map_cpu_to_node(cpu, node);
node_set(node, numa_nodes_parsed);
pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node);
}
#ifdef CONFIG_MEMORY_HOTPLUG
static inline int save_add_info(void) { return 1; }
#else
static inline int save_add_info(void) { return 0; }
#endif
#endif
void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
{
}
#ifdef CONFIG_ACPI_HOTPLUG_CPU
static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
{
#ifdef CONFIG_ACPI_NUMA
int nid;
nid = acpi_get_node(handle);
if (nid != NUMA_NO_NODE) {
set_cpuid_to_node(cpu, nid);
node_set(nid, numa_nodes_parsed);
}
#endif
return 0;
}
int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
int *pcpu)
{
int cpu;
struct acpi_madt_local_apic *processor;
processor = kzalloc(sizeof(struct acpi_madt_local_apic), GFP_KERNEL);
processor->id = physid;
processor->processor_id = acpi_id;
processor->lapic_flags = ACPI_MADT_ENABLED;
cpu = set_processor_mask(processor);
if (cpu < 0) {
pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
return cpu;
}
acpi_map_cpu2node(handle, cpu, physid);
*pcpu = cpu;
return 0;
}
EXPORT_SYMBOL(acpi_map_cpu);
int acpi_unmap_cpu(int cpu)
{
#ifdef CONFIG_ACPI_NUMA
set_cpuid_to_node(cpu, NUMA_NO_NODE);
#endif
set_cpu_present(cpu, false);
num_processors--;
pr_info("cpu%d hot remove!\n", cpu);
return 0;
}
EXPORT_SYMBOL(acpi_unmap_cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
void __init acpi_boot_table_init(void)
{
/**
* ACPI is disabled by default.
* ACPI is only enabled when firmware passes ACPI table
* and sets boot parameter "acpi=on".
*/
if (param_acpi_on)
enable_acpi();
/*
* If acpi_disabled, bail out
*/
if (!acpi_disabled) {
pr_warn("Currently, ACPI is an experimental feature!\n");
if (acpi_table_init()) {
pr_err("Failed to init ACPI tables\n");
disable_acpi();
} else
pr_info("Successfully parsed ACPI table\n");
}
}