1 // SPDX-License-Identifier: GPL-2.0
3 * acpi.c - Architecture-Specific Low-Level ACPI Boot Support
5 * Author: Jianmin Lv <lvjianmin@loongson.cn>
6 * Huacai Chen <chenhuacai@loongson.cn>
7 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
10 #include <linux/init.h>
11 #include <linux/acpi.h>
12 #include <linux/irq.h>
13 #include <linux/irqdomain.h>
14 #include <linux/memblock.h>
15 #include <linux/serial_core.h>
18 #include <asm/loongson.h>
21 EXPORT_SYMBOL(acpi_disabled);
23 int acpi_pci_disabled;
24 EXPORT_SYMBOL(acpi_pci_disabled);
25 int acpi_strict = 1; /* We have no workarounds on LoongArch */
28 enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
32 #define MAX_CORE_PIC 256
34 #define PREFIX "ACPI: "
36 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
39 *irqp = acpi_register_gsi(NULL, gsi, -1, -1);
40 return (*irqp >= 0) ? 0 : -EINVAL;
42 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
44 int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi)
52 * success: return IRQ number (>=0)
55 int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
57 struct irq_fwspec fwspec;
60 case GSI_MIN_CPU_IRQ ... GSI_MAX_CPU_IRQ:
61 fwspec.fwnode = liointc_domain->fwnode;
62 fwspec.param[0] = gsi - GSI_MIN_CPU_IRQ;
63 fwspec.param_count = 1;
65 return irq_create_fwspec_mapping(&fwspec);
67 case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
71 fwspec.fwnode = pch_lpc_domain->fwnode;
72 fwspec.param[0] = gsi - GSI_MIN_LPC_IRQ;
73 fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
74 fwspec.param_count = 2;
76 return irq_create_fwspec_mapping(&fwspec);
78 case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
79 if (!pch_pic_domain[0])
82 fwspec.fwnode = pch_pic_domain[0]->fwnode;
83 fwspec.param[0] = gsi - GSI_MIN_PCH_IRQ;
84 fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
85 fwspec.param_count = 2;
87 return irq_create_fwspec_mapping(&fwspec);
92 EXPORT_SYMBOL_GPL(acpi_register_gsi);
94 void acpi_unregister_gsi(u32 gsi)
98 EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
100 void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size)
106 return early_memremap(phys, size);
108 void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
113 early_memunmap(map, size);
116 void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
118 if (!memblock_is_memory(phys))
119 return ioremap(phys, size);
121 return ioremap_cache(phys, size);
124 void __init acpi_boot_table_init(void)
127 * If acpi_disabled, bail out
133 * Initialize the ACPI boot-time table parser.
135 if (acpi_table_init()) {
141 static int set_processor_mask(u32 id, u32 flags)
146 if (num_processors >= nr_cpu_ids) {
147 pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached."
148 " processor 0x%x ignored.\n", nr_cpu_ids, cpuid);
153 if (cpuid == loongson_sysconf.boot_cpu_id)
156 cpu = cpumask_next_zero(-1, cpu_present_mask);
158 if (flags & ACPI_MADT_ENABLED) {
160 set_cpu_possible(cpu, true);
161 set_cpu_present(cpu, true);
162 __cpu_number_map[cpuid] = cpu;
163 __cpu_logical_map[cpu] = cpuid;
170 static void __init acpi_process_madt(void)
174 for (i = 0; i < NR_CPUS; i++) {
175 __cpu_number_map[i] = -1;
176 __cpu_logical_map[i] = -1;
179 loongson_sysconf.nr_cpus = num_processors;
182 int __init acpi_boot_init(void)
185 * If acpi_disabled, bail out
190 loongson_sysconf.boot_cpu_id = read_csr_cpuid();
193 * Process the Multiple APIC Description Table (MADT), if present
197 /* Do not enable ACPI SPCR console by default */
198 acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
203 #ifdef CONFIG_ACPI_NUMA
205 static __init int setup_node(int pxm)
207 return acpi_map_pxm_to_node(pxm);
211 * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for
212 * I/O localities since SRAT does not list them. I/O localities are
213 * not supported at this point.
215 unsigned int numa_distance_cnt;
217 static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit)
219 return slit->locality_count;
222 void __init numa_set_distance(int from, int to, int distance)
224 if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) {
225 pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
230 node_distances[from][to] = distance;
233 /* Callback for Proximity Domain -> CPUID mapping */
235 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
241 if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
245 if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
247 pxm = pa->proximity_domain_lo;
248 if (acpi_srat_revision >= 2) {
249 pxm |= (pa->proximity_domain_hi[0] << 8);
250 pxm |= (pa->proximity_domain_hi[1] << 16);
251 pxm |= (pa->proximity_domain_hi[2] << 24);
253 node = setup_node(pxm);
255 pr_err("SRAT: Too many proximity domains %x\n", pxm);
260 if (pa->apic_id >= CONFIG_NR_CPUS) {
261 pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n",
262 pxm, pa->apic_id, node);
266 early_numa_add_cpu(pa->apic_id, node);
268 set_cpuid_to_node(pa->apic_id, node);
269 node_set(node, numa_nodes_parsed);
270 pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node);
273 void __init acpi_numa_arch_fixup(void) {}
276 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
278 memblock_reserve(addr, size);
281 #ifdef CONFIG_ACPI_HOTPLUG_CPU
283 #include <acpi/processor.h>
285 static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
287 #ifdef CONFIG_ACPI_NUMA
290 nid = acpi_get_node(handle);
291 if (nid != NUMA_NO_NODE) {
292 set_cpuid_to_node(physid, nid);
293 node_set(nid, numa_nodes_parsed);
294 set_cpu_numa_node(cpu, nid);
295 cpumask_set_cpu(cpu, cpumask_of_node(nid));
301 int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu)
305 cpu = set_processor_mask(physid, ACPI_MADT_ENABLED);
307 pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
311 acpi_map_cpu2node(handle, cpu, physid);
317 EXPORT_SYMBOL(acpi_map_cpu);
319 int acpi_unmap_cpu(int cpu)
321 #ifdef CONFIG_ACPI_NUMA
322 set_cpuid_to_node(cpu_logical_map(cpu), NUMA_NO_NODE);
324 set_cpu_present(cpu, false);
327 pr_info("cpu%d hot remove!\n", cpu);
331 EXPORT_SYMBOL(acpi_unmap_cpu);
333 #endif /* CONFIG_ACPI_HOTPLUG_CPU */