GNU Linux-libre 6.1.90-gnu
[releases.git] / arch / loongarch / kernel / acpi.c
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
29 u64 acpi_saved_sp;
30
31 #define MAX_CORE_PIC 256
32
33 #define PREFIX                  "ACPI: "
34
35 void __init __iomem * __acpi_map_table(unsigned long phys, unsigned long size)
36 {
37
38         if (!phys || !size)
39                 return NULL;
40
41         return early_memremap(phys, size);
42 }
43 void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
44 {
45         if (!map || !size)
46                 return;
47
48         early_memunmap(map, size);
49 }
50
51 void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
52 {
53         if (!memblock_is_memory(phys))
54                 return ioremap(phys, size);
55         else
56                 return ioremap_cache(phys, size);
57 }
58
59 #ifdef CONFIG_SMP
60 static int set_processor_mask(u32 id, u32 flags)
61 {
62
63         int cpu, cpuid = id;
64
65         if (num_processors >= nr_cpu_ids) {
66                 pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached."
67                         " processor 0x%x ignored.\n", nr_cpu_ids, cpuid);
68
69                 return -ENODEV;
70
71         }
72         if (cpuid == loongson_sysconf.boot_cpu_id)
73                 cpu = 0;
74         else
75                 cpu = cpumask_next_zero(-1, cpu_present_mask);
76
77         if (flags & ACPI_MADT_ENABLED) {
78                 num_processors++;
79                 set_cpu_possible(cpu, true);
80                 set_cpu_present(cpu, true);
81                 __cpu_number_map[cpuid] = cpu;
82                 __cpu_logical_map[cpu] = cpuid;
83         } else
84                 disabled_cpus++;
85
86         return cpu;
87 }
88 #endif
89
90 static int __init
91 acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long end)
92 {
93         struct acpi_madt_core_pic *processor = NULL;
94
95         processor = (struct acpi_madt_core_pic *)header;
96         if (BAD_MADT_ENTRY(processor, end))
97                 return -EINVAL;
98
99         acpi_table_print_madt_entry(&header->common);
100 #ifdef CONFIG_SMP
101         set_processor_mask(processor->core_id, processor->flags);
102 #endif
103
104         return 0;
105 }
106
107 static int __init
108 acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long end)
109 {
110         static int core = 0;
111         struct acpi_madt_eio_pic *eiointc = NULL;
112
113         eiointc = (struct acpi_madt_eio_pic *)header;
114         if (BAD_MADT_ENTRY(eiointc, end))
115                 return -EINVAL;
116
117         core = eiointc->node * CORES_PER_EIO_NODE;
118         set_bit(core, &(loongson_sysconf.cores_io_master));
119
120         return 0;
121 }
122
123 static void __init acpi_process_madt(void)
124 {
125 #ifdef CONFIG_SMP
126         int i;
127
128         for (i = 0; i < NR_CPUS; i++) {
129                 __cpu_number_map[i] = -1;
130                 __cpu_logical_map[i] = -1;
131         }
132 #endif
133         acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC,
134                         acpi_parse_processor, MAX_CORE_PIC);
135
136         acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
137                         acpi_parse_eio_master, MAX_IO_PICS);
138
139         loongson_sysconf.nr_cpus = num_processors;
140 }
141
142 void __init acpi_boot_table_init(void)
143 {
144         /*
145          * If acpi_disabled, bail out
146          */
147         if (acpi_disabled)
148                 return;
149
150         /*
151          * Initialize the ACPI boot-time table parser.
152          */
153         if (acpi_table_init()) {
154                 disable_acpi();
155                 return;
156         }
157
158         loongson_sysconf.boot_cpu_id = read_csr_cpuid();
159
160         /*
161          * Process the Multiple APIC Description Table (MADT), if present
162          */
163         acpi_process_madt();
164
165         /* Do not enable ACPI SPCR console by default */
166         acpi_parse_spcr(earlycon_acpi_spcr_enable, false);
167 }
168
169 #ifdef CONFIG_ACPI_NUMA
170
171 static __init int setup_node(int pxm)
172 {
173         return acpi_map_pxm_to_node(pxm);
174 }
175
176 /*
177  * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
178  * I/O localities since SRAT does not list them.  I/O localities are
179  * not supported at this point.
180  */
181 unsigned int numa_distance_cnt;
182
183 static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit)
184 {
185         return slit->locality_count;
186 }
187
188 void __init numa_set_distance(int from, int to, int distance)
189 {
190         if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) {
191                 pr_warn_once("Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
192                                 from, to, distance);
193                 return;
194         }
195
196         node_distances[from][to] = distance;
197 }
198
199 /* Callback for Proximity Domain -> CPUID mapping */
200 void __init
201 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
202 {
203         int pxm, node;
204
205         if (srat_disabled())
206                 return;
207         if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
208                 bad_srat();
209                 return;
210         }
211         if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
212                 return;
213         pxm = pa->proximity_domain_lo;
214         if (acpi_srat_revision >= 2) {
215                 pxm |= (pa->proximity_domain_hi[0] << 8);
216                 pxm |= (pa->proximity_domain_hi[1] << 16);
217                 pxm |= (pa->proximity_domain_hi[2] << 24);
218         }
219         node = setup_node(pxm);
220         if (node < 0) {
221                 pr_err("SRAT: Too many proximity domains %x\n", pxm);
222                 bad_srat();
223                 return;
224         }
225
226         if (pa->apic_id >= CONFIG_NR_CPUS) {
227                 pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n",
228                                 pxm, pa->apic_id, node);
229                 return;
230         }
231
232         early_numa_add_cpu(pa->apic_id, node);
233
234         set_cpuid_to_node(pa->apic_id, node);
235         node_set(node, numa_nodes_parsed);
236         pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node);
237 }
238
239 void __init acpi_numa_arch_fixup(void) {}
240 #endif
241
242 void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
243 {
244         memblock_reserve(addr, size);
245 }
246
247 #ifdef CONFIG_ACPI_HOTPLUG_CPU
248
249 #include <acpi/processor.h>
250
251 static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
252 {
253 #ifdef CONFIG_ACPI_NUMA
254         int nid;
255
256         nid = acpi_get_node(handle);
257         if (nid != NUMA_NO_NODE) {
258                 set_cpuid_to_node(physid, nid);
259                 node_set(nid, numa_nodes_parsed);
260                 set_cpu_numa_node(cpu, nid);
261                 cpumask_set_cpu(cpu, cpumask_of_node(nid));
262         }
263 #endif
264         return 0;
265 }
266
267 int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu)
268 {
269         int cpu;
270
271         cpu = set_processor_mask(physid, ACPI_MADT_ENABLED);
272         if (cpu < 0) {
273                 pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
274                 return cpu;
275         }
276
277         acpi_map_cpu2node(handle, cpu, physid);
278
279         *pcpu = cpu;
280
281         return 0;
282 }
283 EXPORT_SYMBOL(acpi_map_cpu);
284
285 int acpi_unmap_cpu(int cpu)
286 {
287 #ifdef CONFIG_ACPI_NUMA
288         set_cpuid_to_node(cpu_logical_map(cpu), NUMA_NO_NODE);
289 #endif
290         set_cpu_present(cpu, false);
291         num_processors--;
292
293         pr_info("cpu%d hot remove!\n", cpu);
294
295         return 0;
296 }
297 EXPORT_SYMBOL(acpi_unmap_cpu);
298
299 #endif /* CONFIG_ACPI_HOTPLUG_CPU */