1/* $NetBSD: acpi_machdep.c,v 1.3.2.1 2012/11/22 00:39:00 riz 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.3.2.1 2012/11/22 00:39:00 riz 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 76ACPI_STATUS 77acpi_md_OsInitialize(void) 78{ 79 return AE_OK; 80} 81 82ACPI_PHYSICAL_ADDRESS 83acpi_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 96struct acpi_md_override { 97 int irq; 98 int pin; 99 int flags; 100}; 101 102static ACPI_STATUS 103acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 104{ 105 ACPI_MADT_INTERRUPT_OVERRIDE *iop; 106 struct acpi_md_override *ovrp; 107 108 if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 109 return AE_OK; 110 } 111 112 iop = (void *)hdrp; 113 ovrp = aux; 114 if (iop->SourceIrq == ovrp->irq) { 115 ovrp->pin = iop->GlobalIrq; 116 ovrp->flags = iop->IntiFlags; 117 } 118 return AE_OK; 119} 120 121ACPI_STATUS 122acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 123 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep) 124{ 125 void *ih; 126 struct pic *pic; 127#if NIOAPIC > 0 128 struct ioapic_softc *sc; 129 struct acpi_md_override ovr; 130 struct mp_intr_map tmpmap, *mip, **mipp = NULL; 131#endif 132 int irq, pin, type, redir, mpflags; 133 134 /* 135 * ACPI interrupts default to level-triggered active-low. 136 */ 137 138 type = IST_LEVEL; 139 mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO; 140 redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; 141 142#if NIOAPIC > 0 143 144 /* 145 * Apply any MADT override setting. 146 */ 147 148 ovr.irq = InterruptNumber; 149 ovr.pin = -1; 150 if (acpi_madt_map() == AE_OK) { 151 acpi_madt_walk(acpi_md_findoverride, &ovr); 152 acpi_madt_unmap(); 153 } else { 154 aprint_debug("acpi_madt_map() failed, can't check for MADT override\n"); 155 } 156 157 if (ovr.pin != -1) { 158 bool sci = InterruptNumber == AcpiGbl_FADT.SciInterrupt; 159 int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK; 160 int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK; 161 162 InterruptNumber = ovr.pin; 163 if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH || 164 (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) { 165 mpflags &= ~MPS_INTPO_ACTLO; 166 mpflags |= MPS_INTPO_ACTHI; 167 redir &= ~IOAPIC_REDLO_ACTLO; 168 } 169 if (trigger == ACPI_MADT_TRIGGER_EDGE || 170 (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) { 171 type = IST_EDGE; 172 mpflags &= ~(MPS_INTTR_LEVEL << 2); 173 mpflags |= (MPS_INTTR_EDGE << 2); 174 redir &= ~IOAPIC_REDLO_LEVEL; 175 } 176 } 177 178 /* 179 * If the interrupt is handled via IOAPIC, update the map. 180 * If the map isn't set up yet, install a temporary one. 181 */ 182 183 sc = ioapic_find_bybase(InterruptNumber); 184 if (sc != NULL) { 185 pic = &sc->sc_pic; 186 187 if (pic->pic_type == PIC_IOAPIC) { 188 pin = (int)InterruptNumber - pic->pic_vecbase; 189 irq = -1; 190 } else { 191 irq = pin = (int)InterruptNumber; 192 } 193 194 mip = sc->sc_pins[pin].ip_map; 195 if (mip) { 196 mip->flags &= ~0xf; 197 mip->flags |= mpflags; 198 mip->redir &= ~(IOAPIC_REDLO_LEVEL | 199 IOAPIC_REDLO_ACTLO); 200 mip->redir |= redir; 201 } else { 202 mipp = &sc->sc_pins[pin].ip_map; 203 *mipp = &tmpmap; 204 tmpmap.redir = redir; 205 tmpmap.flags = mpflags; 206 } 207 } else 208#endif 209 { 210 pic = &i8259_pic; 211 irq = pin = (int)InterruptNumber; 212 } 213 214 /* 215 * XXX probably, IPL_BIO is enough. 216 */ 217 ih = intr_establish(irq, pic, pin, type, IPL_TTY, 218 (int (*)(void *)) ServiceRoutine, Context, false); 219 220#if NIOAPIC > 0 221 if (mipp) { 222 *mipp = NULL; 223 } 224#endif 225 226 if (ih == NULL) 227 return AE_NO_MEMORY; 228 229 *cookiep = ih; 230 231 return AE_OK; 232} 233 234void 235acpi_md_OsRemoveInterruptHandler(void *cookie) 236{ 237 intr_disestablish(cookie); 238} 239 240ACPI_STATUS 241acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 242 uint32_t Length, void **LogicalAddress) 243{ 244 int rv; 245 246 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 247 Length, 0, (bus_space_handle_t *)LogicalAddress); 248 249 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 250} 251 252void 253acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 254{ 255 (void) _x86_memio_unmap(x86_bus_space_mem, 256 (bus_space_handle_t)LogicalAddress, Length, NULL); 257} 258 259ACPI_STATUS 260acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 261 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 262{ 263 paddr_t pa; 264 265 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 266 *PhysicalAddress = pa; 267 return AE_OK; 268 } 269 270 return AE_ERROR; 271} 272 273BOOLEAN 274acpi_md_OsReadable(void *Pointer, uint32_t Length) 275{ 276 BOOLEAN rv = TRUE; 277 vaddr_t sva, eva; 278 pt_entry_t *pte; 279 280 sva = trunc_page((vaddr_t) Pointer); 281 eva = round_page((vaddr_t) Pointer + Length); 282 283 if (sva < VM_MIN_KERNEL_ADDRESS) 284 return FALSE; 285 286 for (; sva < eva; sva += PAGE_SIZE) { 287 pte = kvtopte(sva); 288 if ((*pte & PG_V) == 0) { 289 rv = FALSE; 290 break; 291 } 292 } 293 294 return rv; 295} 296 297BOOLEAN 298acpi_md_OsWritable(void *Pointer, uint32_t Length) 299{ 300 BOOLEAN rv = FALSE; 301 vaddr_t sva, eva; 302 pt_entry_t *pte; 303 304 sva = trunc_page((vaddr_t) Pointer); 305 eva = round_page((vaddr_t) Pointer + Length); 306 307 if (sva < VM_MIN_KERNEL_ADDRESS) 308 return FALSE; 309 310 for (; sva < eva; sva += PAGE_SIZE) { 311 pte = kvtopte(sva); 312 if ((*pte & (PG_V|PG_W)) != (PG_V|PG_W)) { 313 rv = FALSE; 314 break; 315 } 316 } 317 318 return rv; 319} 320 321void 322acpi_md_OsDisableInterrupt(void) 323{ 324 x86_disable_intr(); 325} 326 327void 328acpi_md_OsEnableInterrupt(void) 329{ 330 x86_enable_intr(); 331} 332 333uint32_t 334acpi_md_ncpus(void) 335{ 336 return kcpuset_countset(kcpuset_attached); 337} 338 339void 340acpi_md_callback(struct acpi_softc *sc) 341{ 342#ifdef MPBIOS 343 if (!mpbios_scanned) 344#endif 345 mpacpi_find_interrupts(sc); 346 347#ifndef XEN 348 acpi_md_sleep_init(); 349#endif 350} 351