1 /* $NetBSD: OsdHardware.c,v 1.6 2010/07/10 21:31:00 gsutre 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 * OS Services Layer 40 * 41 * 6.7: Address Space Access: Port Input/Output 42 * 6.8: Address Space Access: Memory and Memory Mapped I/O 43 * 6.9: Address Space Access: PCI Configuration Space 44 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: OsdHardware.c,v 1.6 2010/07/10 21:31:00 gsutre Exp $"); 48 49 #include <sys/param.h> 50 #include <sys/device.h> 51 52 #include <dev/acpi/acpica.h> 53 #include <dev/acpi/acpivar.h> 54 #include <dev/acpi/acpi_pci.h> 55 56 #include <machine/acpi_machdep.h> 57 58 /* 59 * ACPICA doesn't provide much in the way of letting us know which 60 * hardware resources it wants to use. We therefore have to resort 61 * to calling machinde-dependent code to do the access for us. 62 */ 63 64 /* 65 * AcpiOsReadPort: 66 * 67 * Read a value from an input port. 68 */ 69 ACPI_STATUS 70 AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width) 71 { 72 73 switch (Width) { 74 case 8: 75 *Value = acpi_md_OsIn8(Address); 76 break; 77 78 case 16: 79 *Value = acpi_md_OsIn16(Address); 80 break; 81 82 case 32: 83 *Value = acpi_md_OsIn32(Address); 84 break; 85 86 default: 87 return AE_BAD_PARAMETER; 88 } 89 90 return AE_OK; 91 } 92 93 /* 94 * AcpiOsWritePort: 95 * 96 * Write a value to an output port. 97 */ 98 ACPI_STATUS 99 AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width) 100 { 101 102 switch (Width) { 103 case 8: 104 acpi_md_OsOut8(Address, Value); 105 break; 106 107 case 16: 108 acpi_md_OsOut16(Address, Value); 109 break; 110 111 case 32: 112 acpi_md_OsOut32(Address, Value); 113 break; 114 115 default: 116 return AE_BAD_PARAMETER; 117 } 118 119 return AE_OK; 120 } 121 122 /* 123 * AcpiOsReadMemory: 124 * 125 * Read a value from a memory location. 126 */ 127 ACPI_STATUS 128 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT32 *Value, UINT32 Width) 129 { 130 void *LogicalAddress; 131 ACPI_STATUS rv = AE_OK; 132 133 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 134 if (LogicalAddress == NULL) 135 return AE_NOT_EXIST; 136 137 switch (Width) { 138 case 8: 139 *Value = *(volatile uint8_t *) LogicalAddress; 140 break; 141 142 case 16: 143 *Value = *(volatile uint16_t *) LogicalAddress; 144 break; 145 146 case 32: 147 *Value = *(volatile uint32_t *) LogicalAddress; 148 break; 149 150 default: 151 rv = AE_BAD_PARAMETER; 152 } 153 154 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 155 156 return rv; 157 } 158 159 /* 160 * AcpiOsWriteMemory: 161 * 162 * Write a value to a memory location. 163 */ 164 ACPI_STATUS 165 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT32 Value, UINT32 Width) 166 { 167 void *LogicalAddress; 168 ACPI_STATUS rv = AE_OK; 169 170 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 171 if (LogicalAddress == NULL) 172 return AE_NOT_FOUND; 173 174 switch (Width) { 175 case 8: 176 *(volatile uint8_t *) LogicalAddress = Value; 177 break; 178 179 case 16: 180 *(volatile uint16_t *) LogicalAddress = Value; 181 break; 182 183 case 32: 184 *(volatile uint32_t *) LogicalAddress = Value; 185 break; 186 187 default: 188 rv = AE_BAD_PARAMETER; 189 } 190 191 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 192 193 return rv; 194 } 195 196 /* 197 * AcpiOsReadPciConfiguration: 198 * 199 * Read a value from a PCI configuration register. 200 */ 201 ACPI_STATUS 202 AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, void *Value, 203 UINT32 Width) 204 { 205 pcitag_t tag; 206 pcireg_t tmp; 207 208 /* XXX Need to deal with "segment" ("hose" in Alpha terminology). */ 209 210 if (PciId->Bus >= 256 || PciId->Device >= 32 || PciId->Function >= 8) 211 return AE_BAD_PARAMETER; 212 213 tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device, 214 PciId->Function); 215 tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3); 216 217 switch (Width) { 218 case 8: 219 *(uint8_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xff; 220 break; 221 222 case 16: 223 *(uint16_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xffff; 224 break; 225 226 case 32: 227 *(uint32_t *) Value = tmp; 228 break; 229 230 default: 231 return AE_BAD_PARAMETER; 232 } 233 234 return AE_OK; 235 } 236 237 /* 238 * AcpiOsWritePciConfiguration: 239 * 240 * Write a value to a PCI configuration register. 241 */ 242 ACPI_STATUS 243 AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, 244 ACPI_INTEGER Value, UINT32 Width) 245 { 246 pcitag_t tag; 247 pcireg_t tmp; 248 249 /* XXX Need to deal with "segment" ("hose" in Alpha terminology). */ 250 251 tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device, 252 PciId->Function); 253 254 switch (Width) { 255 case 8: 256 tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3); 257 tmp &= ~(0xff << ((Register & 3) * 8)); 258 tmp |= (Value << ((Register & 3) * 8)); 259 break; 260 261 case 16: 262 tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3); 263 tmp &= ~(0xffff << ((Register & 3) * 8)); 264 tmp |= (Value << ((Register & 3) * 8)); 265 break; 266 267 case 32: 268 tmp = Value; 269 break; 270 271 default: 272 return AE_BAD_PARAMETER; 273 } 274 275 pci_conf_write(acpi_softc->sc_pc, tag, Register & ~3, tmp); 276 277 return AE_OK; 278 } 279 280 /* 281 * acpi_os_derive_pciid_rec: 282 * 283 * Helper function for AcpiOsDerivePciId. The parameters are: 284 * - chandle: a handle to the node whose PCI id shall be derived. 285 * - rhandle: a handle the PCI root bridge upstream of chandle. 286 * - pciid: where the derived PCI id is returned. 287 * 288 * This function assumes that rhandle is a proper ancestor of chandle, 289 * and that pciid has already been filled by ACPICA: 290 * - segment# and bus# obtained from _SEG and _BBN on rhandle, 291 * - device# and function# obtained from _ADR on the ACPI device node 292 * whose scope chandle is in). 293 */ 294 static ACPI_STATUS 295 acpi_os_derive_pciid_rec(ACPI_HANDLE chandle, ACPI_HANDLE rhandle, ACPI_PCI_ID *pciid) 296 { 297 ACPI_HANDLE phandle; 298 ACPI_INTEGER address; 299 ACPI_OBJECT_TYPE objtype; 300 ACPI_STATUS rv; 301 uint16_t valb; 302 303 KASSERT(chandle != rhandle); 304 305 /* 306 * Get parent device node. This is should not fail since chandle has 307 * at least one ancestor that is a device node: rhandle. 308 */ 309 phandle = chandle; 310 do { 311 rv = AcpiGetParent(phandle, &phandle); 312 if (ACPI_FAILURE(rv)) 313 return rv; 314 rv = AcpiGetType(phandle, &objtype); 315 if (ACPI_FAILURE(rv)) 316 return rv; 317 } 318 while (objtype != ACPI_TYPE_DEVICE); 319 320 /* 321 * If the parent is rhandle then we have nothing to do since ACPICA 322 * has pre-filled the PCI id to the best it could. 323 */ 324 if (phandle == rhandle) 325 return AE_OK; 326 327 /* Recursive call to get PCI id of the parent */ 328 rv = acpi_os_derive_pciid_rec(phandle, rhandle, pciid); 329 if (ACPI_FAILURE(rv)) 330 return rv; 331 332 /* 333 * If this is not an ACPI device, return the PCI id of its parent. 334 */ 335 rv = AcpiGetType(chandle, &objtype); 336 if (ACPI_FAILURE(rv)) 337 return rv; 338 if (objtype != ACPI_TYPE_DEVICE) 339 return AE_OK; 340 341 /* 342 * This is an ACPI device node. Its parent device node is not a PCI 343 * root bridge. Check that it is a PCI-to-PCI bridge and get its 344 * secondary bus#. 345 */ 346 rv = acpi_pcidev_ppb_downbus(pciid->Segment, pciid->Bus, pciid->Device, 347 pciid->Function, &valb); 348 if (ACPI_FAILURE(rv)) 349 return rv; 350 351 /* Get address (contains dev# and fun# for PCI devices). */ 352 rv = acpi_eval_integer(chandle, METHOD_NAME__ADR, &address); 353 if (ACPI_FAILURE(rv)) 354 return rv; 355 356 pciid->Bus = valb; 357 pciid->Device = ACPI_HIWORD(ACPI_LODWORD(address)); 358 pciid->Function = ACPI_LOWORD(ACPI_LODWORD(address)); 359 return AE_OK; 360 } 361 362 /* 363 * AcpiOsDerivePciId: 364 * 365 * Derive correct PCI bus# by traversing bridges. 366 * 367 * In ACPICA release 20100331 (as well as older versions), the interface 368 * of this function is not correctly documented in the ACPICA programmer 369 * reference. The correct interface parameters to this function are: 370 * - rhandle: a handle the PCI root bridge upstream of handle. 371 * - chandle: a handle to the PCI_Config operation region. 372 * - PciId: where the derived PCI id is returned. 373 */ 374 void 375 AcpiOsDerivePciId( 376 ACPI_HANDLE rhandle, 377 ACPI_HANDLE chandle, 378 ACPI_PCI_ID **PciId) 379 { 380 ACPI_PCI_ID pciid; 381 ACPI_STATUS rv; 382 383 if (chandle == rhandle) 384 return; 385 386 pciid = **PciId; 387 rv = acpi_os_derive_pciid_rec(chandle, rhandle, &pciid); 388 if (ACPI_FAILURE(rv)) 389 return; 390 391 (*PciId)->Bus = pciid.Bus; 392 } 393