1 /* $NetBSD: acpi_machdep.c,v 1.8 2014/05/12 11:51:34 joerg Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Machine-dependent routines for ACPICA. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.8 2014/05/12 11:51:34 joerg Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/bus.h> 48 #include <sys/cpu.h> 49 #include <sys/device.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <machine/cpufunc.h> 54 55 #include <dev/acpi/acpica.h> 56 #include <dev/acpi/acpivar.h> 57 58 #include <machine/acpi_machdep.h> 59 #include <machine/mpbiosvar.h> 60 #include <machine/mpacpi.h> 61 #include <machine/i82093reg.h> 62 #include <machine/i82093var.h> 63 #include <machine/pic.h> 64 65 #include <dev/pci/pcivar.h> 66 67 #include <dev/isa/isareg.h> 68 #include <dev/isa/isavar.h> 69 70 #include "ioapic.h" 71 72 #include "acpica.h" 73 #include "opt_mpbios.h" 74 #include "opt_acpi.h" 75 76 ACPI_STATUS 77 acpi_md_OsInitialize(void) 78 { 79 return AE_OK; 80 } 81 82 ACPI_PHYSICAL_ADDRESS 83 acpi_md_OsGetRootPointer(void) 84 { 85 ACPI_PHYSICAL_ADDRESS PhysicalAddress; 86 ACPI_STATUS Status; 87 88 Status = AcpiFindRootPointer(&PhysicalAddress); 89 90 if (ACPI_FAILURE(Status)) 91 PhysicalAddress = 0; 92 93 return PhysicalAddress; 94 } 95 96 struct acpi_md_override { 97 int irq; 98 int pin; 99 int flags; 100 }; 101 102 #if NIOAPIC > 0 103 static ACPI_STATUS 104 acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 105 { 106 ACPI_MADT_INTERRUPT_OVERRIDE *iop; 107 struct acpi_md_override *ovrp; 108 109 if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 110 return AE_OK; 111 } 112 113 iop = (void *)hdrp; 114 ovrp = aux; 115 if (iop->SourceIrq == ovrp->irq) { 116 ovrp->pin = iop->GlobalIrq; 117 ovrp->flags = iop->IntiFlags; 118 } 119 return AE_OK; 120 } 121 #endif 122 123 ACPI_STATUS 124 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 125 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep) 126 { 127 void *ih; 128 struct pic *pic; 129 #if NIOAPIC > 0 130 struct ioapic_softc *sc; 131 struct acpi_md_override ovr; 132 struct mp_intr_map tmpmap, *mip, **mipp = NULL; 133 #endif 134 int irq, pin, type, redir, mpflags; 135 136 /* 137 * ACPI interrupts default to level-triggered active-low. 138 */ 139 140 type = IST_LEVEL; 141 mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO; 142 redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; 143 144 #if NIOAPIC > 0 145 146 /* 147 * Apply any MADT override setting. 148 */ 149 150 ovr.irq = InterruptNumber; 151 ovr.pin = -1; 152 if (acpi_madt_map() == AE_OK) { 153 acpi_madt_walk(acpi_md_findoverride, &ovr); 154 acpi_madt_unmap(); 155 } else { 156 aprint_debug("acpi_madt_map() failed, can't check for MADT override\n"); 157 } 158 159 if (ovr.pin != -1) { 160 bool sci = InterruptNumber == AcpiGbl_FADT.SciInterrupt; 161 int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK; 162 int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK; 163 164 InterruptNumber = ovr.pin; 165 if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH || 166 (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) { 167 mpflags &= ~MPS_INTPO_ACTLO; 168 mpflags |= MPS_INTPO_ACTHI; 169 redir &= ~IOAPIC_REDLO_ACTLO; 170 } 171 if (trigger == ACPI_MADT_TRIGGER_EDGE || 172 (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) { 173 type = IST_EDGE; 174 mpflags &= ~(MPS_INTTR_LEVEL << 2); 175 mpflags |= (MPS_INTTR_EDGE << 2); 176 redir &= ~IOAPIC_REDLO_LEVEL; 177 } 178 } 179 180 /* 181 * If the interrupt is handled via IOAPIC, update the map. 182 * If the map isn't set up yet, install a temporary one. 183 */ 184 185 sc = ioapic_find_bybase(InterruptNumber); 186 if (sc != NULL) { 187 pic = &sc->sc_pic; 188 189 if (pic->pic_type == PIC_IOAPIC) { 190 pin = (int)InterruptNumber - pic->pic_vecbase; 191 irq = -1; 192 } else { 193 irq = pin = (int)InterruptNumber; 194 } 195 196 mip = sc->sc_pins[pin].ip_map; 197 if (mip) { 198 mip->flags &= ~0xf; 199 mip->flags |= mpflags; 200 mip->redir &= ~(IOAPIC_REDLO_LEVEL | 201 IOAPIC_REDLO_ACTLO); 202 mip->redir |= redir; 203 } else { 204 mipp = &sc->sc_pins[pin].ip_map; 205 *mipp = &tmpmap; 206 tmpmap.redir = redir; 207 tmpmap.flags = mpflags; 208 } 209 } else 210 #endif 211 { 212 pic = &i8259_pic; 213 irq = pin = (int)InterruptNumber; 214 } 215 216 /* 217 * XXX probably, IPL_BIO is enough. 218 */ 219 ih = intr_establish(irq, pic, pin, type, IPL_TTY, 220 (int (*)(void *)) ServiceRoutine, Context, false); 221 222 #if NIOAPIC > 0 223 if (mipp) { 224 *mipp = NULL; 225 } 226 #endif 227 228 if (ih == NULL) 229 return AE_NO_MEMORY; 230 231 *cookiep = ih; 232 233 return AE_OK; 234 } 235 236 void 237 acpi_md_OsRemoveInterruptHandler(void *cookie) 238 { 239 intr_disestablish(cookie); 240 } 241 242 ACPI_STATUS 243 acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 244 uint32_t Length, void **LogicalAddress) 245 { 246 int rv; 247 248 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 249 Length, 0, (bus_space_handle_t *)LogicalAddress); 250 251 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 252 } 253 254 void 255 acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 256 { 257 (void) _x86_memio_unmap(x86_bus_space_mem, 258 (bus_space_handle_t)LogicalAddress, Length, NULL); 259 } 260 261 ACPI_STATUS 262 acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 263 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 264 { 265 paddr_t pa; 266 267 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 268 *PhysicalAddress = pa; 269 return AE_OK; 270 } 271 272 return AE_ERROR; 273 } 274 275 BOOLEAN 276 acpi_md_OsReadable(void *Pointer, uint32_t Length) 277 { 278 BOOLEAN rv = TRUE; 279 vaddr_t sva, eva; 280 pt_entry_t *pte; 281 282 sva = trunc_page((vaddr_t) Pointer); 283 eva = round_page((vaddr_t) Pointer + Length); 284 285 if (sva < VM_MIN_KERNEL_ADDRESS) 286 return FALSE; 287 288 for (; sva < eva; sva += PAGE_SIZE) { 289 pte = kvtopte(sva); 290 if ((*pte & PG_V) == 0) { 291 rv = FALSE; 292 break; 293 } 294 } 295 296 return rv; 297 } 298 299 BOOLEAN 300 acpi_md_OsWritable(void *Pointer, uint32_t Length) 301 { 302 BOOLEAN rv = TRUE; 303 vaddr_t sva, eva; 304 pt_entry_t *pte; 305 306 sva = trunc_page((vaddr_t) Pointer); 307 eva = round_page((vaddr_t) Pointer + Length); 308 309 if (sva < VM_MIN_KERNEL_ADDRESS) 310 return FALSE; 311 312 for (; sva < eva; sva += PAGE_SIZE) { 313 pte = kvtopte(sva); 314 if ((*pte & (PG_V|PG_W)) != (PG_V|PG_W)) { 315 rv = FALSE; 316 break; 317 } 318 } 319 320 return rv; 321 } 322 323 void 324 acpi_md_OsDisableInterrupt(void) 325 { 326 x86_disable_intr(); 327 } 328 329 void 330 acpi_md_OsEnableInterrupt(void) 331 { 332 x86_enable_intr(); 333 } 334 335 uint32_t 336 acpi_md_ncpus(void) 337 { 338 return kcpuset_countset(kcpuset_attached); 339 } 340 341 void 342 acpi_md_callback(struct acpi_softc *sc) 343 { 344 #ifdef MPBIOS 345 if (!mpbios_scanned) 346 #endif 347 mpacpi_find_interrupts(sc); 348 349 #ifndef XEN 350 acpi_md_sleep_init(); 351 #endif 352 } 353