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 */ 300