1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * RISC-V Specific Low-Level ACPI Boot Support 4 * 5 * Copyright (C) 2013-2014, Linaro Ltd. 6 * Author: Al Stone <al.stone@linaro.org> 7 * Author: Graeme Gregory <graeme.gregory@linaro.org> 8 * Author: Hanjun Guo <hanjun.guo@linaro.org> 9 * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org> 10 * Author: Naresh Bhat <naresh.bhat@linaro.org> 11 * 12 * Copyright (C) 2021-2023, Ventana Micro Systems Inc. 13 * Author: Sunil V L <sunilvl@ventanamicro.com> 14 */ 15 16 #include <linux/acpi.h> 17 #include <linux/io.h> 18 #include <linux/pci.h> 19 #include <linux/efi.h> 20 21 int acpi_noirq = 1; /* skip ACPI IRQ initialization */ 22 int acpi_disabled = 1; 23 EXPORT_SYMBOL(acpi_disabled); 24 25 int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ 26 EXPORT_SYMBOL(acpi_pci_disabled); 27 28 static bool param_acpi_off __initdata; 29 static bool param_acpi_on __initdata; 30 static bool param_acpi_force __initdata; 31 32 static struct acpi_madt_rintc cpu_madt_rintc[NR_CPUS]; 33 34 static int __init parse_acpi(char *arg) 35 { 36 if (!arg) 37 return -EINVAL; 38 39 /* "acpi=off" disables both ACPI table parsing and interpreter */ 40 if (strcmp(arg, "off") == 0) 41 param_acpi_off = true; 42 else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */ 43 param_acpi_on = true; 44 else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */ 45 param_acpi_force = true; 46 else 47 return -EINVAL; /* Core will print when we return error */ 48 49 return 0; 50 } 51 early_param("acpi", parse_acpi); 52 53 /* 54 * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity 55 * checks on it 56 * 57 * Return 0 on success, <0 on failure 58 */ 59 static int __init acpi_fadt_sanity_check(void) 60 { 61 struct acpi_table_header *table; 62 struct acpi_table_fadt *fadt; 63 acpi_status status; 64 int ret = 0; 65 66 /* 67 * FADT is required on riscv; retrieve it to check its presence 68 * and carry out revision and ACPI HW reduced compliancy tests 69 */ 70 status = acpi_get_table(ACPI_SIG_FADT, 0, &table); 71 if (ACPI_FAILURE(status)) { 72 const char *msg = acpi_format_exception(status); 73 74 pr_err("Failed to get FADT table, %s\n", msg); 75 return -ENODEV; 76 } 77 78 fadt = (struct acpi_table_fadt *)table; 79 80 /* 81 * The revision in the table header is the FADT's Major revision. The 82 * FADT also has a minor revision, which is stored in the FADT itself. 83 * 84 * TODO: Currently, we check for 6.5 as the minimum version to check 85 * for HW_REDUCED flag. However, once RISC-V updates are released in 86 * the ACPI spec, we need to update this check for exact minor revision 87 */ 88 if (table->revision < 6 || (table->revision == 6 && fadt->minor_revision < 5)) 89 pr_err(FW_BUG "Unsupported FADT revision %d.%d, should be 6.5+\n", 90 table->revision, fadt->minor_revision); 91 92 if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { 93 pr_err("FADT not ACPI hardware reduced compliant\n"); 94 ret = -EINVAL; 95 } 96 97 /* 98 * acpi_get_table() creates FADT table mapping that 99 * should be released after parsing and before resuming boot 100 */ 101 acpi_put_table(table); 102 return ret; 103 } 104 105 /* 106 * acpi_boot_table_init() called from setup_arch(), always. 107 * 1. find RSDP and get its address, and then find XSDT 108 * 2. extract all tables and checksums them all 109 * 3. check ACPI FADT HW reduced flag 110 * 111 * We can parse ACPI boot-time tables such as MADT after 112 * this function is called. 113 * 114 * On return ACPI is enabled if either: 115 * 116 * - ACPI tables are initialized and sanity checks passed 117 * - acpi=force was passed in the command line and ACPI was not disabled 118 * explicitly through acpi=off command line parameter 119 * 120 * ACPI is disabled on function return otherwise 121 */ 122 void __init acpi_boot_table_init(void) 123 { 124 /* 125 * Enable ACPI instead of device tree unless 126 * - ACPI has been disabled explicitly (acpi=off), or 127 * - firmware has not populated ACPI ptr in EFI system table 128 * and ACPI has not been [force] enabled (acpi=on|force) 129 */ 130 if (param_acpi_off || 131 (!param_acpi_on && !param_acpi_force && 132 efi.acpi20 == EFI_INVALID_TABLE_ADDR)) 133 return; 134 135 /* 136 * ACPI is disabled at this point. Enable it in order to parse 137 * the ACPI tables and carry out sanity checks 138 */ 139 enable_acpi(); 140 141 /* 142 * If ACPI tables are initialized and FADT sanity checks passed, 143 * leave ACPI enabled and carry on booting; otherwise disable ACPI 144 * on initialization error. 145 * If acpi=force was passed on the command line it forces ACPI 146 * to be enabled even if its initialization failed. 147 */ 148 if (acpi_table_init() || acpi_fadt_sanity_check()) { 149 pr_err("Failed to init ACPI tables\n"); 150 if (!param_acpi_force) 151 disable_acpi(); 152 } 153 } 154 155 static int acpi_parse_madt_rintc(union acpi_subtable_headers *header, const unsigned long end) 156 { 157 struct acpi_madt_rintc *rintc = (struct acpi_madt_rintc *)header; 158 int cpuid; 159 160 if (!(rintc->flags & ACPI_MADT_ENABLED)) 161 return 0; 162 163 cpuid = riscv_hartid_to_cpuid(rintc->hart_id); 164 /* 165 * When CONFIG_SMP is disabled, mapping won't be created for 166 * all cpus. 167 * CPUs more than num_possible_cpus, will be ignored. 168 */ 169 if (cpuid >= 0 && cpuid < num_possible_cpus()) 170 cpu_madt_rintc[cpuid] = *rintc; 171 172 return 0; 173 } 174 175 /* 176 * Instead of parsing (and freeing) the ACPI table, cache 177 * the RINTC structures since they are frequently used 178 * like in cpuinfo. 179 */ 180 void __init acpi_init_rintc_map(void) 181 { 182 if (acpi_table_parse_madt(ACPI_MADT_TYPE_RINTC, acpi_parse_madt_rintc, 0) <= 0) { 183 pr_err("No valid RINTC entries exist\n"); 184 BUG(); 185 } 186 } 187 188 struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu) 189 { 190 return &cpu_madt_rintc[cpu]; 191 } 192 193 u32 get_acpi_id_for_cpu(int cpu) 194 { 195 return acpi_cpu_get_madt_rintc(cpu)->uid; 196 } 197 198 /* 199 * __acpi_map_table() will be called before paging_init(), so early_ioremap() 200 * or early_memremap() should be called here to for ACPI table mapping. 201 */ 202 void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size) 203 { 204 if (!size) 205 return NULL; 206 207 return early_ioremap(phys, size); 208 } 209 210 void __init __acpi_unmap_table(void __iomem *map, unsigned long size) 211 { 212 if (!map || !size) 213 return; 214 215 early_iounmap(map, size); 216 } 217 218 void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) 219 { 220 return (void __iomem *)memremap(phys, size, MEMREMAP_WB); 221 } 222 223 #ifdef CONFIG_PCI 224 225 /* 226 * These interfaces are defined just to enable building ACPI core. 227 * TODO: Update it with actual implementation when external interrupt 228 * controller support is added in RISC-V ACPI. 229 */ 230 int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, 231 int reg, int len, u32 *val) 232 { 233 return PCIBIOS_DEVICE_NOT_FOUND; 234 } 235 236 int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, 237 int reg, int len, u32 val) 238 { 239 return PCIBIOS_DEVICE_NOT_FOUND; 240 } 241 242 int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) 243 { 244 return -1; 245 } 246 247 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 248 { 249 return NULL; 250 } 251 #endif /* CONFIG_PCI */ 252