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