1 /* $NetBSD: acpi_machdep.c,v 1.2 2011/07/01 18:22:39 dyoung 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.2 2011/07/01 18:22:39 dyoung Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/bus.h> 48 #include <sys/device.h> 49 50 #include <uvm/uvm_extern.h> 51 52 #include <machine/cpufunc.h> 53 54 #include <dev/acpi/acpica.h> 55 #include <dev/acpi/acpivar.h> 56 57 #include <machine/acpi_machdep.h> 58 #include <machine/mpbiosvar.h> 59 #include <machine/mpacpi.h> 60 #include <machine/i82093reg.h> 61 #include <machine/i82093var.h> 62 #include <machine/pic.h> 63 64 #include <dev/pci/pcivar.h> 65 66 #include <dev/isa/isareg.h> 67 #include <dev/isa/isavar.h> 68 69 #include "ioapic.h" 70 71 #include "acpica.h" 72 #include "opt_mpbios.h" 73 #include "opt_acpi.h" 74 75 extern uint32_t cpus_attached; 76 77 ACPI_STATUS 78 acpi_md_OsInitialize(void) 79 { 80 return AE_OK; 81 } 82 83 ACPI_PHYSICAL_ADDRESS 84 acpi_md_OsGetRootPointer(void) 85 { 86 ACPI_PHYSICAL_ADDRESS PhysicalAddress; 87 ACPI_STATUS Status; 88 89 Status = AcpiFindRootPointer(&PhysicalAddress); 90 91 if (ACPI_FAILURE(Status)) 92 PhysicalAddress = 0; 93 94 return PhysicalAddress; 95 } 96 97 ACPI_STATUS 98 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 99 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep) 100 { 101 void *ih; 102 struct pic *pic; 103 #if NIOAPIC > 0 104 struct ioapic_softc *sc; 105 #endif 106 int irq, pin, trigger; 107 108 #if NIOAPIC > 0 109 /* 110 * Can only match on ACPI global interrupt numbers if the ACPI 111 * interrupt info was extracted, which is in the ACPI case. 112 */ 113 if (mpacpi_sci_override != NULL) { 114 pic = mpacpi_sci_override->ioapic; 115 pin = mpacpi_sci_override->ioapic_pin; 116 if (mpacpi_sci_override->redir & IOAPIC_REDLO_LEVEL) 117 trigger = IST_LEVEL; 118 else 119 trigger = IST_EDGE; 120 if (pic->pic_type == PIC_IOAPIC) 121 irq = -1; 122 else 123 irq = (int)InterruptNumber; 124 goto sci_override; 125 } 126 #endif 127 128 /* 129 * There was no ACPI interrupt source override, 130 * 131 * If the interrupt is handled via IOAPIC, mark it 132 * as level-triggered, active low in the table. 133 */ 134 135 #if NIOAPIC > 0 136 sc = ioapic_find_bybase(InterruptNumber); 137 if (sc != NULL) { 138 pic = &sc->sc_pic; 139 struct mp_intr_map *mip; 140 141 if (pic->pic_type == PIC_IOAPIC) { 142 pin = (int)InterruptNumber - pic->pic_vecbase; 143 irq = -1; 144 } else { 145 irq = pin = (int)InterruptNumber; 146 } 147 148 mip = sc->sc_pins[pin].ip_map; 149 if (mip) { 150 mip->flags &= ~3; 151 mip->flags |= MPS_INTPO_ACTLO; 152 mip->redir |= IOAPIC_REDLO_ACTLO; 153 } 154 } else 155 #endif 156 { 157 pic = &i8259_pic; 158 irq = pin = (int)InterruptNumber; 159 } 160 161 trigger = IST_LEVEL; 162 163 #if NIOAPIC > 0 164 sci_override: 165 #endif 166 167 /* 168 * XXX probably, IPL_BIO is enough. 169 */ 170 ih = intr_establish(irq, pic, pin, trigger, IPL_TTY, 171 (int (*)(void *)) ServiceRoutine, Context, false); 172 173 if (ih == NULL) 174 return AE_NO_MEMORY; 175 176 *cookiep = ih; 177 178 return AE_OK; 179 } 180 181 void 182 acpi_md_OsRemoveInterruptHandler(void *cookie) 183 { 184 intr_disestablish(cookie); 185 } 186 187 ACPI_STATUS 188 acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 189 uint32_t Length, void **LogicalAddress) 190 { 191 int rv; 192 193 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 194 Length, 0, (bus_space_handle_t *)LogicalAddress); 195 196 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 197 } 198 199 void 200 acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 201 { 202 (void) _x86_memio_unmap(x86_bus_space_mem, 203 (bus_space_handle_t)LogicalAddress, Length, NULL); 204 } 205 206 ACPI_STATUS 207 acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 208 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 209 { 210 paddr_t pa; 211 212 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 213 *PhysicalAddress = pa; 214 return AE_OK; 215 } 216 217 return AE_ERROR; 218 } 219 220 BOOLEAN 221 acpi_md_OsReadable(void *Pointer, uint32_t Length) 222 { 223 BOOLEAN rv = TRUE; 224 vaddr_t sva, eva; 225 pt_entry_t *pte; 226 227 sva = trunc_page((vaddr_t) Pointer); 228 eva = round_page((vaddr_t) Pointer + Length); 229 230 if (sva < VM_MIN_KERNEL_ADDRESS) 231 return FALSE; 232 233 for (; sva < eva; sva += PAGE_SIZE) { 234 pte = kvtopte(sva); 235 if ((*pte & PG_V) == 0) { 236 rv = FALSE; 237 break; 238 } 239 } 240 241 return rv; 242 } 243 244 BOOLEAN 245 acpi_md_OsWritable(void *Pointer, uint32_t Length) 246 { 247 BOOLEAN rv = FALSE; 248 vaddr_t sva, eva; 249 pt_entry_t *pte; 250 251 sva = trunc_page((vaddr_t) Pointer); 252 eva = round_page((vaddr_t) Pointer + Length); 253 254 if (sva < VM_MIN_KERNEL_ADDRESS) 255 return FALSE; 256 257 for (; sva < eva; sva += PAGE_SIZE) { 258 pte = kvtopte(sva); 259 if ((*pte & (PG_V|PG_W)) != (PG_V|PG_W)) { 260 rv = FALSE; 261 break; 262 } 263 } 264 265 return rv; 266 } 267 268 void 269 acpi_md_OsDisableInterrupt(void) 270 { 271 x86_disable_intr(); 272 } 273 274 void 275 acpi_md_OsEnableInterrupt(void) 276 { 277 x86_enable_intr(); 278 } 279 280 uint32_t 281 acpi_md_ncpus(void) 282 { 283 return popcount32(cpus_attached); 284 } 285 286 void 287 acpi_md_callback(void) 288 { 289 #ifdef MPBIOS 290 if (!mpbios_scanned) 291 #endif 292 mpacpi_find_interrupts(acpi_softc); 293 294 #ifndef XEN 295 acpi_md_sleep_init(); 296 #endif 297 } 298