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