mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
6.4 KiB
299 lines
6.4 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* acpi.c - Architecture-Specific Low-Level ACPI Boot Support |
|
* |
|
* Author: Jianmin Lv <[email protected]> |
|
* Huacai Chen <[email protected]> |
|
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/acpi.h> |
|
#include <linux/irq.h> |
|
#include <linux/irqdomain.h> |
|
#include <linux/memblock.h> |
|
#include <linux/serial_core.h> |
|
#include <asm/io.h> |
|
#include <asm/numa.h> |
|
#include <asm/loongson.h> |
|
|
|
int acpi_disabled; |
|
EXPORT_SYMBOL(acpi_disabled); |
|
int acpi_noirq; |
|
int acpi_pci_disabled; |
|
EXPORT_SYMBOL(acpi_pci_disabled); |
|
int acpi_strict = 1; /* We have no workarounds on LoongArch */ |
|
int num_processors; |
|
int disabled_cpus; |
|
|
|
u64 acpi_saved_sp; |
|
|
|
#define MAX_CORE_PIC 256 |
|
|
|
#define PREFIX "ACPI: " |
|
|
|
void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size) |
|
{ |
|
|
|
if (!phys || !size) |
|
return NULL; |
|
|
|
return early_memremap(phys, size); |
|
} |
|
void __init __acpi_unmap_table(void __iomem *map, unsigned long size) |
|
{ |
|
if (!map || !size) |
|
return; |
|
|
|
early_memunmap(map, size); |
|
} |
|
|
|
void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) |
|
{ |
|
if (!memblock_is_memory(phys)) |
|
return ioremap(phys, size); |
|
else |
|
return ioremap_cache(phys, size); |
|
} |
|
|
|
#ifdef CONFIG_SMP |
|
static int set_processor_mask(u32 id, u32 flags) |
|
{ |
|
|
|
int cpu, cpuid = id; |
|
|
|
if (num_processors >= nr_cpu_ids) { |
|
pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached." |
|
" processor 0x%x ignored.\n", nr_cpu_ids, cpuid); |
|
|
|
return -ENODEV; |
|
|
|
} |
|
if (cpuid == loongson_sysconf.boot_cpu_id) |
|
cpu = 0; |
|
else |
|
cpu = cpumask_next_zero(-1, cpu_present_mask); |
|
|
|
if (flags & ACPI_MADT_ENABLED) { |
|
num_processors++; |
|
set_cpu_possible(cpu, true); |
|
set_cpu_present(cpu, true); |
|
__cpu_number_map[cpuid] = cpu; |
|
__cpu_logical_map[cpu] = cpuid; |
|
} else |
|
disabled_cpus++; |
|
|
|
return cpu; |
|
} |
|
#endif |
|
|
|
static int __init |
|
acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long end) |
|
{ |
|
struct acpi_madt_core_pic *processor = NULL; |
|
|
|
processor = (struct acpi_madt_core_pic *)header; |
|
if (BAD_MADT_ENTRY(processor, end)) |
|
return -EINVAL; |
|
|
|
acpi_table_print_madt_entry(&header->common); |
|
#ifdef CONFIG_SMP |
|
set_processor_mask(processor->core_id, processor->flags); |
|
#endif |
|
|
|
return 0; |
|
} |
|
|
|
static int __init |
|
acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long end) |
|
{ |
|
static int core = 0; |
|
struct acpi_madt_eio_pic *eiointc = NULL; |
|
|
|
eiointc = (struct acpi_madt_eio_pic *)header; |
|
if (BAD_MADT_ENTRY(eiointc, end)) |
|
return -EINVAL; |
|
|
|
core = eiointc->node * CORES_PER_EIO_NODE; |
|
set_bit(core, &(loongson_sysconf.cores_io_master)); |
|
|
|
return 0; |
|
} |
|
|
|
static void __init acpi_process_madt(void) |
|
{ |
|
#ifdef CONFIG_SMP |
|
int i; |
|
|
|
for (i = 0; i < NR_CPUS; i++) { |
|
__cpu_number_map[i] = -1; |
|
__cpu_logical_map[i] = -1; |
|
} |
|
#endif |
|
acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC, |
|
acpi_parse_processor, MAX_CORE_PIC); |
|
|
|
acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, |
|
acpi_parse_eio_master, MAX_IO_PICS); |
|
|
|
loongson_sysconf.nr_cpus = num_processors; |
|
} |
|
|
|
void __init acpi_boot_table_init(void) |
|
{ |
|
/* |
|
* If acpi_disabled, bail out |
|
*/ |
|
if (acpi_disabled) |
|
return; |
|
|
|
/* |
|
* Initialize the ACPI boot-time table parser. |
|
*/ |
|
if (acpi_table_init()) { |
|
disable_acpi(); |
|
return; |
|
} |
|
|
|
loongson_sysconf.boot_cpu_id = read_csr_cpuid(); |
|
|
|
/* |
|
* Process the Multiple APIC Description Table (MADT), if present |
|
*/ |
|
acpi_process_madt(); |
|
|
|
/* Do not enable ACPI SPCR console by default */ |
|
acpi_parse_spcr(earlycon_acpi_spcr_enable, false); |
|
} |
|
|
|
#ifdef CONFIG_ACPI_NUMA |
|
|
|
static __init int setup_node(int pxm) |
|
{ |
|
return acpi_map_pxm_to_node(pxm); |
|
} |
|
|
|
/* |
|
* Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for |
|
* I/O localities since SRAT does not list them. I/O localities are |
|
* not supported at this point. |
|
*/ |
|
unsigned int numa_distance_cnt; |
|
|
|
static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit) |
|
{ |
|
return slit->locality_count; |
|
} |
|
|
|
void __init numa_set_distance(int from, int to, int distance) |
|
{ |
|
if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) { |
|
pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n", |
|
from, to, distance); |
|
return; |
|
} |
|
|
|
node_distances[from][to] = distance; |
|
} |
|
|
|
/* Callback for Proximity Domain -> CPUID mapping */ |
|
void __init |
|
acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) |
|
{ |
|
int pxm, node; |
|
|
|
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 = setup_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_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", |
|
pxm, pa->apic_id, node); |
|
return; |
|
} |
|
|
|
early_numa_add_cpu(pa->apic_id, node); |
|
|
|
set_cpuid_to_node(pa->apic_id, node); |
|
node_set(node, numa_nodes_parsed); |
|
pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node); |
|
} |
|
|
|
void __init acpi_numa_arch_fixup(void) {} |
|
#endif |
|
|
|
void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) |
|
{ |
|
memblock_reserve(addr, size); |
|
} |
|
|
|
#ifdef CONFIG_ACPI_HOTPLUG_CPU |
|
|
|
#include <acpi/processor.h> |
|
|
|
static int __ref 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(physid, nid); |
|
node_set(nid, numa_nodes_parsed); |
|
set_cpu_numa_node(cpu, nid); |
|
cpumask_set_cpu(cpu, cpumask_of_node(nid)); |
|
} |
|
#endif |
|
return 0; |
|
} |
|
|
|
int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu) |
|
{ |
|
int cpu; |
|
|
|
cpu = set_processor_mask(physid, ACPI_MADT_ENABLED); |
|
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_logical_map(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 */
|
|
|