xref: /openbmc/linux/arch/loongarch/kernel/acpi.c (revision 2cc39179)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * acpi.c - Architecture-Specific Low-Level ACPI Boot Support
4  *
5  * Author: Jianmin Lv <lvjianmin@loongson.cn>
6  *         Huacai Chen <chenhuacai@loongson.cn>
7  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
8  */
9 
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>
16 #include <asm/io.h>
17 #include <asm/numa.h>
18 #include <asm/loongson.h>
19 
20 int acpi_disabled;
21 EXPORT_SYMBOL(acpi_disabled);
22 int acpi_noirq;
23 int acpi_pci_disabled;
24 EXPORT_SYMBOL(acpi_pci_disabled);
25 int acpi_strict = 1; /* We have no workarounds on LoongArch */
26 int num_processors;
27 int disabled_cpus;
28 enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
29 
30 u64 acpi_saved_sp;
31 
32 #define MAX_CORE_PIC 256
33 
34 #define PREFIX			"ACPI: "
35 
36 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
37 {
38 	if (irqp != NULL)
39 		*irqp = acpi_register_gsi(NULL, gsi, -1, -1);
40 	return (*irqp >= 0) ? 0 : -EINVAL;
41 }
42 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
43 
44 int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi)
45 {
46 	if (gsi)
47 		*gsi = isa_irq;
48 	return 0;
49 }
50 
51 /*
52  * success: return IRQ number (>=0)
53  * failure: return < 0
54  */
55 int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
56 {
57 	struct irq_fwspec fwspec;
58 
59 	switch (gsi) {
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;
64 
65 		return irq_create_fwspec_mapping(&fwspec);
66 
67 	case GSI_MIN_LPC_IRQ ... GSI_MAX_LPC_IRQ:
68 		if (!pch_lpc_domain)
69 			return -EINVAL;
70 
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;
75 
76 		return irq_create_fwspec_mapping(&fwspec);
77 
78 	case GSI_MIN_PCH_IRQ ... GSI_MAX_PCH_IRQ:
79 		if (!pch_pic_domain[0])
80 			return -EINVAL;
81 
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;
86 
87 		return irq_create_fwspec_mapping(&fwspec);
88 	}
89 
90 	return -EINVAL;
91 }
92 EXPORT_SYMBOL_GPL(acpi_register_gsi);
93 
94 void acpi_unregister_gsi(u32 gsi)
95 {
96 
97 }
98 EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
99 
100 void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size)
101 {
102 
103 	if (!phys || !size)
104 		return NULL;
105 
106 	return early_memremap(phys, size);
107 }
108 void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
109 {
110 	if (!map || !size)
111 		return;
112 
113 	early_memunmap(map, size);
114 }
115 
116 void __init __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
117 {
118 	if (!memblock_is_memory(phys))
119 		return ioremap(phys, size);
120 	else
121 		return ioremap_cache(phys, size);
122 }
123 
124 void __init acpi_boot_table_init(void)
125 {
126 	/*
127 	 * If acpi_disabled, bail out
128 	 */
129 	if (acpi_disabled)
130 		return;
131 
132 	/*
133 	 * Initialize the ACPI boot-time table parser.
134 	 */
135 	if (acpi_table_init()) {
136 		disable_acpi();
137 		return;
138 	}
139 }
140 
141 #ifdef CONFIG_SMP
142 static int set_processor_mask(u32 id, u32 flags)
143 {
144 
145 	int cpu, cpuid = id;
146 
147 	if (num_processors >= nr_cpu_ids) {
148 		pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached."
149 			" processor 0x%x ignored.\n", nr_cpu_ids, cpuid);
150 
151 		return -ENODEV;
152 
153 	}
154 	if (cpuid == loongson_sysconf.boot_cpu_id)
155 		cpu = 0;
156 	else
157 		cpu = cpumask_next_zero(-1, cpu_present_mask);
158 
159 	if (flags & ACPI_MADT_ENABLED) {
160 		num_processors++;
161 		set_cpu_possible(cpu, true);
162 		set_cpu_present(cpu, true);
163 		__cpu_number_map[cpuid] = cpu;
164 		__cpu_logical_map[cpu] = cpuid;
165 	} else
166 		disabled_cpus++;
167 
168 	return cpu;
169 }
170 #endif
171 
172 static void __init acpi_process_madt(void)
173 {
174 #ifdef CONFIG_SMP
175 	int i;
176 
177 	for (i = 0; i < NR_CPUS; i++) {
178 		__cpu_number_map[i] = -1;
179 		__cpu_logical_map[i] = -1;
180 	}
181 #endif
182 
183 	loongson_sysconf.nr_cpus = num_processors;
184 }
185 
186 int __init acpi_boot_init(void)
187 {
188 	/*
189 	 * If acpi_disabled, bail out
190 	 */
191 	if (acpi_disabled)
192 		return -1;
193 
194 	loongson_sysconf.boot_cpu_id = read_csr_cpuid();
195 
196 	/*
197 	 * Process the Multiple APIC Description Table (MADT), if present
198 	 */
199 	acpi_process_madt();
200 
201 	/* Do not enable ACPI SPCR console by default */
202 	acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
203 
204 	return 0;
205 }
206 
207 #ifdef CONFIG_ACPI_NUMA
208 
209 static __init int setup_node(int pxm)
210 {
211 	return acpi_map_pxm_to_node(pxm);
212 }
213 
214 /*
215  * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
216  * I/O localities since SRAT does not list them.  I/O localities are
217  * not supported at this point.
218  */
219 unsigned int numa_distance_cnt;
220 
221 static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit)
222 {
223 	return slit->locality_count;
224 }
225 
226 void __init numa_set_distance(int from, int to, int distance)
227 {
228 	if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) {
229 		pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
230 				from, to, distance);
231 		return;
232 	}
233 
234 	node_distances[from][to] = distance;
235 }
236 
237 /* Callback for Proximity Domain -> CPUID mapping */
238 void __init
239 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
240 {
241 	int pxm, node;
242 
243 	if (srat_disabled())
244 		return;
245 	if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
246 		bad_srat();
247 		return;
248 	}
249 	if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
250 		return;
251 	pxm = pa->proximity_domain_lo;
252 	if (acpi_srat_revision >= 2) {
253 		pxm |= (pa->proximity_domain_hi[0] << 8);
254 		pxm |= (pa->proximity_domain_hi[1] << 16);
255 		pxm |= (pa->proximity_domain_hi[2] << 24);
256 	}
257 	node = setup_node(pxm);
258 	if (node < 0) {
259 		pr_err("SRAT: Too many proximity domains %x\n", pxm);
260 		bad_srat();
261 		return;
262 	}
263 
264 	if (pa->apic_id >= CONFIG_NR_CPUS) {
265 		pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n",
266 				pxm, pa->apic_id, node);
267 		return;
268 	}
269 
270 	early_numa_add_cpu(pa->apic_id, node);
271 
272 	set_cpuid_to_node(pa->apic_id, node);
273 	node_set(node, numa_nodes_parsed);
274 	pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node);
275 }
276 
277 void __init acpi_numa_arch_fixup(void) {}
278 #endif
279 
280 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
281 {
282 	memblock_reserve(addr, size);
283 }
284 
285 #ifdef CONFIG_ACPI_HOTPLUG_CPU
286 
287 #include <acpi/processor.h>
288 
289 static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
290 {
291 #ifdef CONFIG_ACPI_NUMA
292 	int nid;
293 
294 	nid = acpi_get_node(handle);
295 	if (nid != NUMA_NO_NODE) {
296 		set_cpuid_to_node(physid, nid);
297 		node_set(nid, numa_nodes_parsed);
298 		set_cpu_numa_node(cpu, nid);
299 		cpumask_set_cpu(cpu, cpumask_of_node(nid));
300 	}
301 #endif
302 	return 0;
303 }
304 
305 int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu)
306 {
307 	int cpu;
308 
309 	cpu = set_processor_mask(physid, ACPI_MADT_ENABLED);
310 	if (cpu < 0) {
311 		pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
312 		return cpu;
313 	}
314 
315 	acpi_map_cpu2node(handle, cpu, physid);
316 
317 	*pcpu = cpu;
318 
319 	return 0;
320 }
321 EXPORT_SYMBOL(acpi_map_cpu);
322 
323 int acpi_unmap_cpu(int cpu)
324 {
325 #ifdef CONFIG_ACPI_NUMA
326 	set_cpuid_to_node(cpu_logical_map(cpu), NUMA_NO_NODE);
327 #endif
328 	set_cpu_present(cpu, false);
329 	num_processors--;
330 
331 	pr_info("cpu%d hot remove!\n", cpu);
332 
333 	return 0;
334 }
335 EXPORT_SYMBOL(acpi_unmap_cpu);
336 
337 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
338