1 1.37 jmcneill /* $NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $ */ 2 1.1 cegger 3 1.1 cegger /* 4 1.6 jruoho * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. 5 1.1 cegger * All rights reserved. 6 1.1 cegger * 7 1.1 cegger * This code is derived from software contributed to The NetBSD Foundation 8 1.6 jruoho * by Christoph Egger and Gregoire Sutre. 9 1.1 cegger * 10 1.1 cegger * Redistribution and use in source and binary forms, with or without 11 1.1 cegger * modification, are permitted provided that the following conditions 12 1.1 cegger * are met: 13 1.1 cegger * 1. Redistributions of source code must retain the above copyright 14 1.1 cegger * notice, this list of conditions and the following disclaimer. 15 1.1 cegger * 2. The name of the author may not be used to endorse or promote products 16 1.1 cegger * derived from this software without specific prior written permission. 17 1.1 cegger * 18 1.1 cegger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 cegger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 cegger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 cegger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 cegger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 1.1 cegger * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 1.1 cegger * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 1.1 cegger * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 1.1 cegger * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 cegger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 cegger * SUCH DAMAGE. 29 1.1 cegger */ 30 1.1 cegger 31 1.1 cegger #include <sys/cdefs.h> 32 1.37 jmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $"); 33 1.1 cegger 34 1.1 cegger #include <sys/param.h> 35 1.1 cegger #include <sys/device.h> 36 1.1 cegger #include <sys/kmem.h> 37 1.3 jruoho #include <sys/systm.h> 38 1.1 cegger 39 1.6 jruoho #include <dev/pci/pcireg.h> 40 1.17 jruoho #include <dev/pci/pcivar.h> 41 1.6 jruoho #include <dev/pci/pcidevs.h> 42 1.6 jruoho #include <dev/pci/ppbreg.h> 43 1.6 jruoho 44 1.32 thorpej #include <dev/pci/pci_calls.h> 45 1.32 thorpej 46 1.1 cegger #include <dev/acpi/acpireg.h> 47 1.1 cegger #include <dev/acpi/acpivar.h> 48 1.1 cegger #include <dev/acpi/acpi_pci.h> 49 1.1 cegger 50 1.17 jruoho #include "locators.h" 51 1.17 jruoho 52 1.7 jruoho #define _COMPONENT ACPI_BUS_COMPONENT 53 1.7 jruoho ACPI_MODULE_NAME ("acpi_pci") 54 1.6 jruoho 55 1.7 jruoho #define ACPI_HILODWORD(x) ACPI_HIWORD(ACPI_LODWORD((x))) 56 1.7 jruoho #define ACPI_LOLODWORD(x) ACPI_LOWORD(ACPI_LODWORD((x))) 57 1.7 jruoho 58 1.7 jruoho static ACPI_STATUS acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *, 59 1.7 jruoho void *); 60 1.1 cegger 61 1.6 jruoho /* 62 1.11 jruoho * Regarding PCI Segment Groups (ACPI 4.0, p. 277): 63 1.6 jruoho * 64 1.6 jruoho * "The optional _SEG object is located under a PCI host bridge and 65 1.11 jruoho * evaluates to an integer that describes the PCI Segment Group (see PCI 66 1.11 jruoho * Firmware Specification v3.0)." 67 1.11 jruoho * 68 1.11 jruoho * "PCI Segment Group is purely a software concept managed by system 69 1.11 jruoho * firmware and used by OSPM. It is a logical collection of PCI buses 70 1.11 jruoho * (or bus segments). It is a way to logically group the PCI bus segments 71 1.11 jruoho * and PCI Express Hierarchies. _SEG is a level higher than _BBN." 72 1.6 jruoho * 73 1.6 jruoho * "PCI Segment Group supports more than 256 buses in a system by allowing 74 1.11 jruoho * the reuse of the PCI bus numbers. Within each PCI Segment Group, the bus 75 1.11 jruoho * numbers for the PCI buses must be unique. PCI buses in different PCI 76 1.11 jruoho * Segment Group are permitted to have the same bus number." 77 1.6 jruoho */ 78 1.1 cegger 79 1.6 jruoho /* 80 1.11 jruoho * Regarding PCI Base Bus Numbers (ACPI 4.0, p. 277): 81 1.6 jruoho * 82 1.6 jruoho * "For multi-root PCI platforms, the _BBN object evaluates to the PCI bus 83 1.11 jruoho * number that the BIOS assigns. This is needed to access a PCI_Config 84 1.11 jruoho * operation region for the specified bus. The _BBN object is located under 85 1.11 jruoho * a PCI host bridge and must be unique for every host bridge within a 86 1.11 jruoho * segment since it is the PCI bus number." 87 1.6 jruoho * 88 1.6 jruoho * Moreover, the ACPI FAQ (http://www.acpi.info/acpi_faq.htm) says: 89 1.6 jruoho * 90 1.6 jruoho * "For a multiple root bus machine, _BBN is required for each bus. _BBN 91 1.11 jruoho * should provide the bus number assigned to this bus by the BIOS at boot 92 1.11 jruoho * time." 93 1.6 jruoho */ 94 1.6 jruoho 95 1.6 jruoho /* 96 1.6 jruoho * acpi_pcidev_pciroot_bus: 97 1.6 jruoho * 98 1.6 jruoho * Derive the PCI bus number of a PCI root bridge from its resources. 99 1.6 jruoho * If successful, return AE_OK and fill *busp. Otherwise, return an 100 1.6 jruoho * exception code and leave *busp unchanged. 101 1.6 jruoho */ 102 1.29 jmcneill ACPI_STATUS 103 1.6 jruoho acpi_pcidev_pciroot_bus(ACPI_HANDLE handle, uint16_t *busp) 104 1.1 cegger { 105 1.1 cegger ACPI_STATUS rv; 106 1.6 jruoho int32_t bus; 107 1.6 jruoho 108 1.6 jruoho bus = -1; 109 1.11 jruoho 110 1.11 jruoho /* 111 1.11 jruoho * XXX: Use the ACPI resource parsing functions (acpi_resource.c) 112 1.11 jruoho * once bus number ranges have been implemented there. 113 1.11 jruoho */ 114 1.11 jruoho rv = AcpiWalkResources(handle, "_CRS", 115 1.6 jruoho acpi_pcidev_pciroot_bus_callback, &bus); 116 1.1 cegger 117 1.1 cegger if (ACPI_FAILURE(rv)) 118 1.6 jruoho return rv; 119 1.6 jruoho 120 1.15 gsutre if (bus == -1) 121 1.6 jruoho return AE_NOT_EXIST; 122 1.6 jruoho 123 1.15 gsutre /* Here it holds that 0 <= bus <= 0xFFFF. */ 124 1.6 jruoho *busp = (uint16_t)bus; 125 1.8 jruoho 126 1.6 jruoho return rv; 127 1.6 jruoho } 128 1.6 jruoho 129 1.6 jruoho static ACPI_STATUS 130 1.6 jruoho acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *res, void *context) 131 1.6 jruoho { 132 1.8 jruoho ACPI_RESOURCE_ADDRESS64 addr64; 133 1.6 jruoho int32_t *bus = context; 134 1.6 jruoho 135 1.8 jruoho /* Always continue the walk by returning AE_OK. */ 136 1.6 jruoho if ((res->Type != ACPI_RESOURCE_TYPE_ADDRESS16) && 137 1.6 jruoho (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32) && 138 1.6 jruoho (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)) 139 1.8 jruoho return AE_OK; 140 1.6 jruoho 141 1.6 jruoho if (ACPI_FAILURE(AcpiResourceToAddress64(res, &addr64))) 142 1.8 jruoho return AE_OK; 143 1.6 jruoho 144 1.6 jruoho if (addr64.ResourceType != ACPI_BUS_NUMBER_RANGE) 145 1.8 jruoho return AE_OK; 146 1.6 jruoho 147 1.6 jruoho if (*bus != -1) 148 1.6 jruoho return AE_ALREADY_EXISTS; 149 1.6 jruoho 150 1.19 christos if (addr64.Address.Minimum > 0xFFFF) 151 1.15 gsutre return AE_BAD_DATA; 152 1.15 gsutre 153 1.19 christos *bus = (int32_t)addr64.Address.Minimum; 154 1.8 jruoho 155 1.8 jruoho return AE_OK; 156 1.6 jruoho } 157 1.6 jruoho 158 1.6 jruoho /* 159 1.9 jruoho * acpi_pcidev_scan: 160 1.6 jruoho * 161 1.6 jruoho * Scan the ACPI device tree for PCI devices. A node is detected as a 162 1.6 jruoho * PCI device if it has an ancestor that is a PCI root bridge and such 163 1.6 jruoho * that all intermediate nodes are PCI-to-PCI bridges. Depth-first 164 1.6 jruoho * recursive implementation. 165 1.16 gsutre * 166 1.16 gsutre * PCI root bridges do not necessarily contain an _ADR, since they already 167 1.16 gsutre * contain an _HID (ACPI 4.0a, p. 197). However we require an _ADR for 168 1.16 gsutre * all non-root PCI devices. 169 1.6 jruoho */ 170 1.9 jruoho ACPI_STATUS 171 1.9 jruoho acpi_pcidev_scan(struct acpi_devnode *ad) 172 1.6 jruoho { 173 1.6 jruoho struct acpi_devnode *child; 174 1.6 jruoho struct acpi_pci_info *ap; 175 1.6 jruoho ACPI_INTEGER val; 176 1.6 jruoho ACPI_STATUS rv; 177 1.6 jruoho 178 1.13 gsutre ad->ad_pciinfo = NULL; 179 1.13 gsutre 180 1.14 gsutre /* 181 1.14 gsutre * We attach PCI information only to devices that are present, 182 1.14 gsutre * enabled, and functioning properly. 183 1.14 gsutre * Note: there is a possible race condition, because _STA may 184 1.14 gsutre * have changed since ad->ad_devinfo->CurrentStatus was set. 185 1.14 gsutre */ 186 1.16 gsutre if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 187 1.16 gsutre goto rec; 188 1.14 gsutre 189 1.22 christos if (!acpi_device_present(ad->ad_handle)) 190 1.22 christos goto rec; 191 1.22 christos 192 1.6 jruoho if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) { 193 1.8 jruoho 194 1.6 jruoho ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); 195 1.8 jruoho 196 1.11 jruoho /* 197 1.11 jruoho * If no _SEG exist, all PCI bus segments are assumed 198 1.11 jruoho * to be in the PCI segment group 0 (ACPI 4.0, p. 277). 199 1.11 jruoho * The segment group number is conveyed in the lower 200 1.11 jruoho * 16 bits of _SEG (the other bits are all reserved). 201 1.11 jruoho */ 202 1.8 jruoho rv = acpi_eval_integer(ad->ad_handle, "_SEG", &val); 203 1.8 jruoho 204 1.6 jruoho if (ACPI_SUCCESS(rv)) 205 1.6 jruoho ap->ap_segment = ACPI_LOWORD(val); 206 1.6 jruoho 207 1.16 gsutre /* Try to get downstream bus number using _CRS first. */ 208 1.16 gsutre rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_downbus); 209 1.8 jruoho 210 1.6 jruoho if (ACPI_FAILURE(rv)) { 211 1.8 jruoho rv = acpi_eval_integer(ad->ad_handle, "_BBN", &val); 212 1.8 jruoho 213 1.6 jruoho if (ACPI_SUCCESS(rv)) 214 1.16 gsutre ap->ap_downbus = ACPI_LOWORD(val); 215 1.6 jruoho } 216 1.6 jruoho 217 1.16 gsutre if (ap->ap_downbus > 255) { 218 1.13 gsutre aprint_error_dev(ad->ad_root, 219 1.16 gsutre "invalid PCI downstream bus for %s\n", ad->ad_name); 220 1.13 gsutre kmem_free(ap, sizeof(*ap)); 221 1.13 gsutre goto rec; 222 1.13 gsutre } 223 1.13 gsutre 224 1.16 gsutre ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; 225 1.16 gsutre 226 1.27 jmcneill ap->ap_pc = acpi_get_pci_chipset_tag(acpi_softc, ap->ap_segment, ap->ap_downbus); 227 1.27 jmcneill 228 1.16 gsutre /* 229 1.16 gsutre * This ACPI node denotes a PCI root bridge, but it may also 230 1.16 gsutre * denote a PCI device on the bridge's downstream bus segment. 231 1.16 gsutre */ 232 1.16 gsutre if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) { 233 1.16 gsutre ap->ap_bus = ap->ap_downbus; 234 1.16 gsutre ap->ap_device = 235 1.16 gsutre ACPI_HILODWORD(ad->ad_devinfo->Address); 236 1.16 gsutre ap->ap_function = 237 1.16 gsutre ACPI_LOLODWORD(ad->ad_devinfo->Address); 238 1.16 gsutre 239 1.16 gsutre if (ap->ap_device > 31 || 240 1.16 gsutre (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) 241 1.16 gsutre aprint_error_dev(ad->ad_root, 242 1.16 gsutre "invalid PCI address for %s\n", ad->ad_name); 243 1.16 gsutre else 244 1.16 gsutre ap->ap_flags |= ACPI_PCI_INFO_DEVICE; 245 1.16 gsutre } 246 1.6 jruoho 247 1.6 jruoho ad->ad_pciinfo = ap; 248 1.8 jruoho 249 1.6 jruoho goto rec; 250 1.6 jruoho } 251 1.6 jruoho 252 1.6 jruoho if ((ad->ad_parent != NULL) && 253 1.6 jruoho (ad->ad_parent->ad_pciinfo != NULL) && 254 1.16 gsutre (ad->ad_parent->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && 255 1.16 gsutre (ad->ad_devinfo->Valid & ACPI_VALID_ADR)) { 256 1.11 jruoho 257 1.6 jruoho /* 258 1.11 jruoho * Our parent is a PCI root bridge or a PCI-to-PCI 259 1.11 jruoho * bridge. We have the same PCI segment number, and 260 1.11 jruoho * our bus number is its downstream bus number. 261 1.6 jruoho */ 262 1.6 jruoho ap = kmem_zalloc(sizeof(*ap), KM_SLEEP); 263 1.8 jruoho 264 1.27 jmcneill ap->ap_pc = ad->ad_parent->ad_pciinfo->ap_pc; 265 1.6 jruoho ap->ap_segment = ad->ad_parent->ad_pciinfo->ap_segment; 266 1.6 jruoho ap->ap_bus = ad->ad_parent->ad_pciinfo->ap_downbus; 267 1.7 jruoho 268 1.7 jruoho ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address); 269 1.7 jruoho ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address); 270 1.1 cegger 271 1.15 gsutre if (ap->ap_device > 31 || 272 1.15 gsutre (ap->ap_function > 7 && ap->ap_function != 0xFFFF)) { 273 1.13 gsutre aprint_error_dev(ad->ad_root, 274 1.13 gsutre "invalid PCI address for %s\n", ad->ad_name); 275 1.13 gsutre kmem_free(ap, sizeof(*ap)); 276 1.13 gsutre goto rec; 277 1.13 gsutre } 278 1.13 gsutre 279 1.16 gsutre ap->ap_flags |= ACPI_PCI_INFO_DEVICE; 280 1.16 gsutre 281 1.15 gsutre if (ap->ap_function == 0xFFFF) { 282 1.15 gsutre /* 283 1.15 gsutre * Assume that this device is not a PCI-to-PCI bridge. 284 1.15 gsutre * XXX: Do we need to be smarter? 285 1.15 gsutre */ 286 1.15 gsutre } else { 287 1.15 gsutre /* 288 1.15 gsutre * Check whether this device is a PCI-to-PCI 289 1.15 gsutre * bridge and get its secondary bus number. 290 1.15 gsutre */ 291 1.27 jmcneill rv = acpi_pcidev_ppb_downbus( 292 1.27 jmcneill ad->ad_parent->ad_pciinfo->ap_pc, 293 1.27 jmcneill ap->ap_segment, ap->ap_bus, ap->ap_device, 294 1.27 jmcneill ap->ap_function, &ap->ap_downbus); 295 1.15 gsutre 296 1.16 gsutre if (ACPI_SUCCESS(rv)) 297 1.16 gsutre ap->ap_flags |= ACPI_PCI_INFO_BRIDGE; 298 1.15 gsutre } 299 1.6 jruoho 300 1.6 jruoho ad->ad_pciinfo = ap; 301 1.8 jruoho 302 1.6 jruoho goto rec; 303 1.6 jruoho } 304 1.9 jruoho 305 1.8 jruoho rec: 306 1.6 jruoho SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) { 307 1.9 jruoho rv = acpi_pcidev_scan(child); 308 1.8 jruoho 309 1.6 jruoho if (ACPI_FAILURE(rv)) 310 1.6 jruoho return rv; 311 1.1 cegger } 312 1.1 cegger 313 1.6 jruoho return AE_OK; 314 1.6 jruoho } 315 1.6 jruoho 316 1.6 jruoho /* 317 1.6 jruoho * acpi_pcidev_ppb_downbus: 318 1.6 jruoho * 319 1.6 jruoho * Retrieve the secondary bus number of the PCI-to-PCI bridge having the 320 1.13 gsutre * given PCI id. If successful, return AE_OK and fill *downbus. 321 1.13 gsutre * Otherwise, return an exception code and leave *downbus unchanged. 322 1.6 jruoho * 323 1.6 jruoho * XXX Need to deal with PCI segment groups (see also acpica/OsdHardware.c). 324 1.6 jruoho */ 325 1.6 jruoho ACPI_STATUS 326 1.27 jmcneill acpi_pcidev_ppb_downbus(pci_chipset_tag_t pc, uint16_t segment, uint16_t bus, 327 1.27 jmcneill uint16_t device, uint16_t function, uint16_t *downbus) 328 1.6 jruoho { 329 1.6 jruoho pcitag_t tag; 330 1.6 jruoho pcireg_t val; 331 1.6 jruoho 332 1.6 jruoho if (bus > 255 || device > 31 || function > 7) 333 1.6 jruoho return AE_BAD_PARAMETER; 334 1.1 cegger 335 1.6 jruoho tag = pci_make_tag(pc, bus, device, function); 336 1.1 cegger 337 1.6 jruoho /* Check that this device exists. */ 338 1.6 jruoho val = pci_conf_read(pc, tag, PCI_ID_REG); 339 1.8 jruoho 340 1.6 jruoho if (PCI_VENDOR(val) == PCI_VENDOR_INVALID || 341 1.6 jruoho PCI_VENDOR(val) == 0) 342 1.6 jruoho return AE_NOT_EXIST; 343 1.6 jruoho 344 1.6 jruoho /* Check that this device is a PCI-to-PCI bridge. */ 345 1.6 jruoho val = pci_conf_read(pc, tag, PCI_BHLC_REG); 346 1.8 jruoho 347 1.6 jruoho if (PCI_HDRTYPE_TYPE(val) != PCI_HDRTYPE_PPB) 348 1.6 jruoho return AE_TYPE; 349 1.6 jruoho 350 1.6 jruoho /* This is a PCI-to-PCI bridge. Get its secondary bus#. */ 351 1.26 msaitoh val = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG); 352 1.26 msaitoh *downbus = PCI_BRIDGE_BUS_NUM_SECONDARY(val); 353 1.8 jruoho 354 1.6 jruoho return AE_OK; 355 1.1 cegger } 356 1.1 cegger 357 1.1 cegger /* 358 1.1 cegger * acpi_pcidev_find: 359 1.1 cegger * 360 1.1 cegger * Finds a PCI device in the ACPI name space. 361 1.10 jruoho * 362 1.10 jruoho * Returns an ACPI device node on success and NULL on failure. 363 1.1 cegger */ 364 1.10 jruoho struct acpi_devnode * 365 1.10 jruoho acpi_pcidev_find(uint16_t segment, uint16_t bus, 366 1.10 jruoho uint16_t device, uint16_t function) 367 1.1 cegger { 368 1.6 jruoho struct acpi_softc *sc = acpi_softc; 369 1.6 jruoho struct acpi_devnode *ad; 370 1.1 cegger 371 1.6 jruoho if (sc == NULL) 372 1.10 jruoho return NULL; 373 1.1 cegger 374 1.33 skrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 375 1.8 jruoho 376 1.10 jruoho if (ad->ad_pciinfo != NULL && 377 1.16 gsutre (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_DEVICE) && 378 1.10 jruoho ad->ad_pciinfo->ap_segment == segment && 379 1.10 jruoho ad->ad_pciinfo->ap_bus == bus && 380 1.10 jruoho ad->ad_pciinfo->ap_device == device && 381 1.10 jruoho ad->ad_pciinfo->ap_function == function) 382 1.10 jruoho return ad; 383 1.1 cegger } 384 1.8 jruoho 385 1.10 jruoho return NULL; 386 1.1 cegger } 387 1.17 jruoho 388 1.23 jmcneill /* 389 1.27 jmcneill * acpi_pcidev_get_tag: 390 1.27 jmcneill * 391 1.27 jmcneill * Returns a PCI chipset tag for a PCI device in the ACPI name space. 392 1.27 jmcneill */ 393 1.27 jmcneill pci_chipset_tag_t 394 1.27 jmcneill acpi_pcidev_get_tag(uint16_t segment, uint16_t bus, 395 1.27 jmcneill uint16_t device, uint16_t function) 396 1.27 jmcneill { 397 1.27 jmcneill struct acpi_devnode *ad; 398 1.27 jmcneill 399 1.27 jmcneill ad = acpi_pcidev_find(segment, bus, device, function); 400 1.27 jmcneill if (ad == NULL || ad->ad_pciinfo == NULL) 401 1.27 jmcneill return NULL; 402 1.27 jmcneill 403 1.27 jmcneill return ad->ad_pciinfo->ap_pc; 404 1.27 jmcneill } 405 1.27 jmcneill 406 1.27 jmcneill /* 407 1.23 jmcneill * acpi_pciroot_find: 408 1.23 jmcneill * 409 1.23 jmcneill * Finds a PCI root bridge in the ACPI name space. 410 1.23 jmcneill * 411 1.23 jmcneill * Returns an ACPI device node on success and NULL on failure. 412 1.23 jmcneill */ 413 1.23 jmcneill struct acpi_devnode * 414 1.23 jmcneill acpi_pciroot_find(uint16_t segment, uint16_t bus) 415 1.23 jmcneill { 416 1.23 jmcneill struct acpi_softc *sc = acpi_softc; 417 1.23 jmcneill struct acpi_devnode *ad; 418 1.23 jmcneill 419 1.23 jmcneill if (sc == NULL) 420 1.23 jmcneill return NULL; 421 1.23 jmcneill 422 1.33 skrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 423 1.23 jmcneill 424 1.23 jmcneill if (ad->ad_pciinfo != NULL && 425 1.23 jmcneill (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) && 426 1.23 jmcneill ad->ad_pciinfo->ap_segment == segment && 427 1.23 jmcneill ad->ad_pciinfo->ap_bus == bus) 428 1.23 jmcneill return ad; 429 1.23 jmcneill } 430 1.23 jmcneill 431 1.23 jmcneill return NULL; 432 1.23 jmcneill } 433 1.17 jruoho 434 1.17 jruoho /* 435 1.17 jruoho * acpi_pcidev_find_dev: 436 1.17 jruoho * 437 1.17 jruoho * Returns the device corresponding to the given PCI info, or NULL 438 1.17 jruoho * if it doesn't exist. 439 1.17 jruoho */ 440 1.17 jruoho device_t 441 1.18 jruoho acpi_pcidev_find_dev(struct acpi_devnode *ad) 442 1.17 jruoho { 443 1.18 jruoho struct acpi_pci_info *ap; 444 1.17 jruoho struct pci_softc *pci; 445 1.17 jruoho device_t dv, pr; 446 1.17 jruoho deviter_t di; 447 1.17 jruoho 448 1.18 jruoho if (ad == NULL) 449 1.18 jruoho return NULL; 450 1.18 jruoho 451 1.18 jruoho if (ad->ad_pciinfo == NULL) 452 1.17 jruoho return NULL; 453 1.17 jruoho 454 1.18 jruoho ap = ad->ad_pciinfo; 455 1.18 jruoho 456 1.17 jruoho if (ap->ap_function == 0xFFFF) 457 1.17 jruoho return NULL; 458 1.17 jruoho 459 1.17 jruoho for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); 460 1.17 jruoho dv != NULL; dv = deviter_next(&di)) { 461 1.17 jruoho 462 1.17 jruoho pr = device_parent(dv); 463 1.17 jruoho 464 1.17 jruoho if (pr == NULL || device_is_a(pr, "pci") != true) 465 1.17 jruoho continue; 466 1.17 jruoho 467 1.17 jruoho pci = device_private(pr); 468 1.17 jruoho 469 1.17 jruoho if (pci->sc_bus == ap->ap_bus && 470 1.17 jruoho device_locator(dv, PCICF_DEV) == ap->ap_device && 471 1.17 jruoho device_locator(dv, PCICF_FUNCTION) == ap->ap_function) 472 1.17 jruoho break; 473 1.17 jruoho } 474 1.17 jruoho 475 1.17 jruoho deviter_release(&di); 476 1.17 jruoho 477 1.17 jruoho return dv; 478 1.17 jruoho } 479 1.24 jmcneill 480 1.24 jmcneill /* 481 1.31 thorpej * acpi_pci_bus_get_child_devhandle: 482 1.31 thorpej * 483 1.31 thorpej * Implements the "pci-bus-get-child-devhandle" device call for 484 1.31 thorpej * ACPI device handles 485 1.31 thorpej */ 486 1.31 thorpej static int 487 1.31 thorpej acpi_pci_bus_get_child_devhandle(device_t dev, devhandle_t call_handle, void *v) 488 1.31 thorpej { 489 1.31 thorpej struct pci_bus_get_child_devhandle_args *args = v; 490 1.31 thorpej struct acpi_devnode *ad; 491 1.31 thorpej ACPI_HANDLE hdl; 492 1.31 thorpej int b, d, f; 493 1.31 thorpej u_int segment; 494 1.31 thorpej 495 1.31 thorpej segment = pci_get_segment(args->pc); 496 1.31 thorpej 497 1.31 thorpej pci_decompose_tag(args->pc, args->tag, &b, &d, &f); 498 1.31 thorpej 499 1.31 thorpej ad = acpi_pcidev_find(segment, b, d, f); 500 1.31 thorpej 501 1.31 thorpej if (ad != NULL && (hdl = ad->ad_handle) != NULL) { 502 1.31 thorpej /* Found it! */ 503 1.34 thorpej args->devhandle = devhandle_from_acpi(call_handle, hdl); 504 1.31 thorpej return 0; 505 1.31 thorpej } 506 1.31 thorpej 507 1.31 thorpej return ENODEV; 508 1.31 thorpej } 509 1.32 thorpej ACPI_DEVICE_CALL_REGISTER(PCI_BUS_GET_CHILD_DEVHANDLE_STR, 510 1.31 thorpej acpi_pci_bus_get_child_devhandle) 511