1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2001 Mitsuru IWASAKI 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/param.h> 31 #include <sys/bus.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/sysctl.h> 35 36 #include <vm/vm.h> 37 #include <vm/pmap.h> 38 39 #include <contrib/dev/acpica/include/acpi.h> 40 #include <contrib/dev/acpica/include/accommon.h> 41 #include <contrib/dev/acpica/include/actables.h> 42 43 #include <dev/acpica/acpivar.h> 44 45 #include <machine/nexusvar.h> 46 47 uint32_t acpi_resume_beep; 48 SYSCTL_UINT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN, &acpi_resume_beep, 49 0, "Beep the PC speaker when resuming"); 50 51 uint32_t acpi_reset_video; 52 TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video); 53 54 static int intr_model = ACPI_INTR_PIC; 55 56 int 57 acpi_machdep_init(device_t dev) 58 { 59 struct acpi_softc *sc; 60 61 sc = device_get_softc(dev); 62 63 acpi_apm_init(sc); 64 acpi_install_wakeup_handler(sc); 65 66 if (intr_model == ACPI_INTR_PIC) 67 BUS_CONFIG_INTR(dev, AcpiGbl_FADT.SciInterrupt, 68 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); 69 else 70 acpi_SetIntrModel(intr_model); 71 72 SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx, 73 SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, 74 "reset_video", CTLFLAG_RW, &acpi_reset_video, 0, 75 "Call the VESA reset BIOS vector on the resume path"); 76 77 return (0); 78 } 79 80 void 81 acpi_SetDefaultIntrModel(int model) 82 { 83 84 intr_model = model; 85 } 86 87 /* Check BIOS date. If 1998 or older, disable ACPI. */ 88 int 89 acpi_machdep_quirks(int *quirks) 90 { 91 char *va; 92 int year; 93 94 /* BIOS address 0xffff5 contains the date in the format mm/dd/yy. */ 95 va = pmap_mapbios(0xffff0, 16); 96 sscanf(va + 11, "%2d", &year); 97 pmap_unmapbios(va, 16); 98 99 /* 100 * Date must be >= 1/1/1999 or we don't trust ACPI. Note that this 101 * check must be changed by my 114th birthday. 102 */ 103 if (year > 90 && year < 99) 104 *quirks = ACPI_Q_BROKEN; 105 106 return (0); 107 } 108 109 /* 110 * Map a table. First map the header to determine the table length and then map 111 * the entire table. 112 */ 113 static void * 114 map_table(vm_paddr_t pa, const char *sig) 115 { 116 ACPI_TABLE_HEADER *header; 117 vm_size_t length; 118 void *table; 119 120 header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER)); 121 if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) { 122 pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER)); 123 return (NULL); 124 } 125 length = header->Length; 126 pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER)); 127 table = pmap_mapbios(pa, length); 128 if (ACPI_FAILURE(AcpiUtChecksum(table, length))) { 129 if (bootverbose) 130 printf("ACPI: Failed checksum for table %s\n", sig); 131 #if (ACPI_CHECKSUM_ABORT) 132 pmap_unmapbios(table, length); 133 return (NULL); 134 #endif 135 } 136 return (table); 137 } 138 139 /* 140 * See if a given ACPI table is the requested table. Returns the 141 * length of the table if it matches or zero on failure. 142 */ 143 static int 144 probe_table(vm_paddr_t address, const char *sig) 145 { 146 ACPI_TABLE_HEADER *table; 147 int ret; 148 149 table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER)); 150 ret = strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) == 0; 151 pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER)); 152 return (ret); 153 } 154 155 /* 156 * Try to map a table at a given physical address previously returned 157 * by acpi_find_table(). 158 */ 159 void * 160 acpi_map_table(vm_paddr_t pa, const char *sig) 161 { 162 163 return (map_table(pa, sig)); 164 } 165 166 /* Unmap a table previously mapped via acpi_map_table(). */ 167 void 168 acpi_unmap_table(void *table) 169 { 170 ACPI_TABLE_HEADER *header; 171 172 header = (ACPI_TABLE_HEADER *)table; 173 pmap_unmapbios(table, header->Length); 174 } 175 176 /* 177 * Return the physical address of the requested table or zero if one 178 * is not found. 179 */ 180 vm_paddr_t 181 acpi_find_table(const char *sig) 182 { 183 ACPI_PHYSICAL_ADDRESS rsdp_ptr; 184 ACPI_TABLE_RSDP *rsdp; 185 ACPI_TABLE_RSDT *rsdt; 186 ACPI_TABLE_XSDT *xsdt; 187 ACPI_TABLE_HEADER *table; 188 vm_paddr_t addr; 189 int i, count; 190 191 if (resource_disabled("acpi", 0)) 192 return (0); 193 194 /* 195 * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn 196 * calls pmap_mapbios() to find the RSDP, we assume that we can use 197 * pmap_mapbios() to map the RSDP. 198 */ 199 if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0) 200 return (0); 201 rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP)); 202 if (rsdp == NULL) { 203 if (bootverbose) 204 printf("ACPI: Failed to map RSDP\n"); 205 return (0); 206 } 207 208 /* 209 * For ACPI >= 2.0, use the XSDT if it is available. 210 * Otherwise, use the RSDT. 211 */ 212 addr = 0; 213 if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) { 214 /* 215 * AcpiOsGetRootPointer only verifies the checksum for 216 * the version 1.0 portion of the RSDP. Version 2.0 has 217 * an additional checksum that we verify first. 218 */ 219 if (AcpiUtChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) { 220 if (bootverbose) 221 printf("ACPI: RSDP failed extended checksum\n"); 222 return (0); 223 } 224 xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT); 225 if (xsdt == NULL) { 226 if (bootverbose) 227 printf("ACPI: Failed to map XSDT\n"); 228 return (0); 229 } 230 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 231 sizeof(UINT64); 232 for (i = 0; i < count; i++) 233 if (probe_table(xsdt->TableOffsetEntry[i], sig)) { 234 addr = xsdt->TableOffsetEntry[i]; 235 break; 236 } 237 acpi_unmap_table(xsdt); 238 } else { 239 rsdt = map_table(rsdp->RsdtPhysicalAddress, ACPI_SIG_RSDT); 240 if (rsdt == NULL) { 241 if (bootverbose) 242 printf("ACPI: Failed to map RSDT\n"); 243 return (0); 244 } 245 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 246 sizeof(UINT32); 247 for (i = 0; i < count; i++) 248 if (probe_table(rsdt->TableOffsetEntry[i], sig)) { 249 addr = rsdt->TableOffsetEntry[i]; 250 break; 251 } 252 acpi_unmap_table(rsdt); 253 } 254 pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP)); 255 if (addr == 0) 256 return (0); 257 258 /* 259 * Verify that we can map the full table and that its checksum is 260 * correct, etc. 261 */ 262 table = map_table(addr, sig); 263 if (table == NULL) 264 return (0); 265 acpi_unmap_table(table); 266 267 return (addr); 268 } 269 270 /* 271 * ACPI nexus(4) driver. 272 */ 273 static int 274 nexus_acpi_probe(device_t dev) 275 { 276 int error; 277 278 error = acpi_identify(); 279 if (error) 280 return (error); 281 device_quiet(dev); 282 return (BUS_PROBE_DEFAULT); 283 } 284 285 static int 286 nexus_acpi_attach(device_t dev) 287 { 288 289 nexus_init_resources(); 290 bus_generic_probe(dev); 291 if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL) 292 panic("failed to add acpi0 device"); 293 294 return (bus_generic_attach(dev)); 295 } 296 297 static device_method_t nexus_acpi_methods[] = { 298 /* Device interface */ 299 DEVMETHOD(device_probe, nexus_acpi_probe), 300 DEVMETHOD(device_attach, nexus_acpi_attach), 301 { 0, 0 } 302 }; 303 304 DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver); 305 306 DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, 0, 0); 307