1 1.32 riastrad /* $NetBSD: acpi_mcfg.c,v 1.32 2025/03/03 19:38:26 riastradh Exp $ */ 2 1.1 msaitoh 3 1.1 msaitoh /*- 4 1.1 msaitoh * Copyright (C) 2015 NONAKA Kimihiro <nonaka (at) NetBSD.org> 5 1.1 msaitoh * All rights reserved. 6 1.1 msaitoh * 7 1.1 msaitoh * Redistribution and use in source and binary forms, with or without 8 1.1 msaitoh * modification, are permitted provided that the following conditions 9 1.1 msaitoh * are met: 10 1.1 msaitoh * 1. Redistributions of source code must retain the above copyright 11 1.1 msaitoh * notice, this list of conditions and the following disclaimer. 12 1.1 msaitoh * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 msaitoh * notice, this list of conditions and the following disclaimer in the 14 1.1 msaitoh * documentation and/or other materials provided with the distribution. 15 1.1 msaitoh * 16 1.1 msaitoh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 msaitoh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 msaitoh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 msaitoh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 msaitoh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 msaitoh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 msaitoh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 msaitoh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 msaitoh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 msaitoh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 msaitoh */ 27 1.1 msaitoh 28 1.8 jmcneill #include "opt_pci.h" 29 1.8 jmcneill 30 1.1 msaitoh #include <sys/cdefs.h> 31 1.32 riastrad __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.32 2025/03/03 19:38:26 riastradh Exp $"); 32 1.1 msaitoh 33 1.1 msaitoh #include <sys/param.h> 34 1.1 msaitoh #include <sys/device.h> 35 1.1 msaitoh #include <sys/kmem.h> 36 1.1 msaitoh #include <sys/systm.h> 37 1.1 msaitoh 38 1.1 msaitoh #include <dev/pci/pcireg.h> 39 1.1 msaitoh #include <dev/pci/pcivar.h> 40 1.26 jmcneill #include <dev/pci/pci_resource.h> 41 1.1 msaitoh #include <dev/pci/pcidevs.h> 42 1.1 msaitoh 43 1.1 msaitoh #include <dev/acpi/acpireg.h> 44 1.1 msaitoh #include <dev/acpi/acpivar.h> 45 1.1 msaitoh #include <dev/acpi/acpi_mcfg.h> 46 1.1 msaitoh 47 1.1 msaitoh #include "locators.h" 48 1.1 msaitoh 49 1.2 christos #define _COMPONENT ACPI_RESOURCE_COMPONENT 50 1.2 christos ACPI_MODULE_NAME ("acpi_mcfg") 51 1.2 christos 52 1.1 msaitoh #define EXTCONF_OFFSET(d, f, r) ((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r)) 53 1.1 msaitoh 54 1.10 jmcneill #define PCIDEV_SET_VALID(mb, d, f) ((mb)->valid_devs[(d)] |= __BIT((f))) 55 1.10 jmcneill #define PCIDEV_SET_INVALID(mb, d, f) ((mb)->valid_devs[(d)] &= ~__BIT((f))) 56 1.10 jmcneill #define PCIDEV_IS_VALID(mb, d, f) ((mb)->valid_devs[(d)] & __BIT((f))) 57 1.10 jmcneill 58 1.10 jmcneill #define EXTCONF_SET_VALID(mb, d, f) ((mb)->valid_extconf[(d)] |= __BIT((f))) 59 1.10 jmcneill #define EXTCONF_SET_INVALID(mb, d, f) ((mb)->valid_extconf[(d)] &= ~__BIT((f))) 60 1.10 jmcneill #define EXTCONF_IS_VALID(mb, d, f) ((mb)->valid_extconf[(d)] & __BIT((f))) 61 1.1 msaitoh 62 1.1 msaitoh struct mcfg_segment { 63 1.1 msaitoh uint64_t ms_address; /* Base address */ 64 1.1 msaitoh int ms_segment; /* Segment # */ 65 1.1 msaitoh int ms_bus_start; /* Start bus # */ 66 1.1 msaitoh int ms_bus_end; /* End bus # */ 67 1.1 msaitoh bus_space_tag_t ms_bst; 68 1.1 msaitoh struct mcfg_bus { 69 1.1 msaitoh bus_space_handle_t bsh[32][8]; 70 1.1 msaitoh uint8_t valid_devs[32]; 71 1.10 jmcneill uint8_t valid_extconf[32]; 72 1.1 msaitoh int valid_ndevs; 73 1.1 msaitoh pcitag_t last_probed; 74 1.1 msaitoh } *ms_bus; 75 1.1 msaitoh }; 76 1.1 msaitoh 77 1.1 msaitoh static struct mcfg_segment *mcfg_segs; 78 1.1 msaitoh static int mcfg_nsegs; 79 1.1 msaitoh static ACPI_TABLE_MCFG *mcfg; 80 1.1 msaitoh static int mcfg_inited; 81 1.1 msaitoh static struct acpi_softc *acpi_sc; 82 1.1 msaitoh 83 1.1 msaitoh static const struct acpimcfg_ops mcfg_default_ops = { 84 1.1 msaitoh .ao_validate = acpimcfg_default_validate, 85 1.1 msaitoh 86 1.1 msaitoh .ao_read = acpimcfg_default_read, 87 1.1 msaitoh .ao_write = acpimcfg_default_write, 88 1.1 msaitoh }; 89 1.1 msaitoh static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops; 90 1.1 msaitoh 91 1.1 msaitoh /* 92 1.1 msaitoh * default operations. 93 1.1 msaitoh */ 94 1.1 msaitoh bool 95 1.1 msaitoh acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end) 96 1.1 msaitoh { 97 1.1 msaitoh 98 1.1 msaitoh /* Always Ok */ 99 1.1 msaitoh return true; 100 1.1 msaitoh } 101 1.1 msaitoh 102 1.1 msaitoh uint32_t 103 1.1 msaitoh acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh, 104 1.1 msaitoh bus_addr_t addr) 105 1.1 msaitoh { 106 1.1 msaitoh 107 1.1 msaitoh return bus_space_read_4(bst, bsh, addr); 108 1.1 msaitoh } 109 1.1 msaitoh 110 1.1 msaitoh void 111 1.1 msaitoh acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh, 112 1.1 msaitoh bus_addr_t addr, uint32_t data) 113 1.1 msaitoh { 114 1.1 msaitoh 115 1.1 msaitoh bus_space_write_4(bst, bsh, addr, data); 116 1.1 msaitoh } 117 1.1 msaitoh 118 1.1 msaitoh 119 1.1 msaitoh /* 120 1.1 msaitoh * Check MCFG memory region at system resource 121 1.1 msaitoh */ 122 1.1 msaitoh struct acpimcfg_memrange { 123 1.1 msaitoh const char *hid; 124 1.1 msaitoh uint64_t address; 125 1.1 msaitoh int bus_start; 126 1.1 msaitoh int bus_end; 127 1.1 msaitoh bool found; 128 1.1 msaitoh }; 129 1.1 msaitoh 130 1.1 msaitoh static ACPI_STATUS 131 1.1 msaitoh acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx) 132 1.1 msaitoh { 133 1.1 msaitoh struct acpimcfg_memrange *mr = ctx; 134 1.1 msaitoh const char *type; 135 1.1 msaitoh uint64_t size, mapaddr, mapsize; 136 1.1 msaitoh int n; 137 1.1 msaitoh 138 1.1 msaitoh switch (res->Type) { 139 1.1 msaitoh case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 140 1.1 msaitoh type = "FIXED_MEMORY32"; 141 1.1 msaitoh mapaddr = res->Data.FixedMemory32.Address; 142 1.1 msaitoh mapsize = res->Data.FixedMemory32.AddressLength; 143 1.1 msaitoh break; 144 1.1 msaitoh 145 1.1 msaitoh case ACPI_RESOURCE_TYPE_ADDRESS32: 146 1.1 msaitoh /* XXX Only fixed size supported for now */ 147 1.1 msaitoh if (res->Data.Address32.Address.AddressLength == 0 || 148 1.1 msaitoh res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) 149 1.1 msaitoh goto out; 150 1.1 msaitoh 151 1.1 msaitoh if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE) 152 1.1 msaitoh goto out; 153 1.1 msaitoh 154 1.1 msaitoh if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED || 155 1.1 msaitoh res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED) 156 1.1 msaitoh goto out; 157 1.1 msaitoh 158 1.1 msaitoh type = "ADDRESS32"; 159 1.1 msaitoh mapaddr = res->Data.Address32.Address.Minimum; 160 1.1 msaitoh mapsize = res->Data.Address32.Address.AddressLength; 161 1.1 msaitoh break; 162 1.1 msaitoh 163 1.1 msaitoh #ifdef _LP64 164 1.1 msaitoh case ACPI_RESOURCE_TYPE_ADDRESS64: 165 1.1 msaitoh /* XXX Only fixed size supported for now */ 166 1.1 msaitoh if (res->Data.Address64.Address.AddressLength == 0 || 167 1.1 msaitoh res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) 168 1.1 msaitoh goto out; 169 1.1 msaitoh 170 1.1 msaitoh if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE) 171 1.1 msaitoh goto out; 172 1.1 msaitoh 173 1.1 msaitoh if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED || 174 1.1 msaitoh res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED) 175 1.1 msaitoh goto out; 176 1.1 msaitoh 177 1.1 msaitoh type = "ADDRESS64"; 178 1.1 msaitoh mapaddr = res->Data.Address64.Address.Minimum; 179 1.1 msaitoh mapsize = res->Data.Address64.Address.AddressLength; 180 1.1 msaitoh break; 181 1.1 msaitoh #endif 182 1.1 msaitoh 183 1.1 msaitoh default: 184 1.1 msaitoh out: 185 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n", 186 1.1 msaitoh mr->hid, res->Type); 187 1.1 msaitoh return_ACPI_STATUS(AE_OK); 188 1.1 msaitoh } 189 1.1 msaitoh 190 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), " 191 1.1 msaitoh "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n", 192 1.1 msaitoh mr->hid, res->Type, type, mapaddr, mapsize); 193 1.1 msaitoh 194 1.1 msaitoh if (mr->address < mapaddr || mr->address >= mapaddr + mapsize) 195 1.1 msaitoh return_ACPI_STATUS(AE_OK); 196 1.1 msaitoh 197 1.1 msaitoh size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS; 198 1.1 msaitoh 199 1.1 msaitoh /* full map */ 200 1.1 msaitoh if (mr->address + size <= mapaddr + mapsize) { 201 1.1 msaitoh mr->found = true; 202 1.1 msaitoh return_ACPI_STATUS(AE_CTRL_TERMINATE); 203 1.1 msaitoh } 204 1.1 msaitoh 205 1.1 msaitoh /* partial map */ 206 1.1 msaitoh n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS; 207 1.1 msaitoh /* bus_start == bus_end is not allowed. */ 208 1.1 msaitoh if (n > 1) { 209 1.1 msaitoh mr->bus_end = mr->bus_start + n - 1; 210 1.1 msaitoh mr->found = true; 211 1.1 msaitoh return_ACPI_STATUS(AE_CTRL_TERMINATE); 212 1.1 msaitoh } 213 1.1 msaitoh 214 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, " 215 1.1 msaitoh "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64 216 1.1 msaitoh ", actual 0x%016" PRIx64 "\n", 217 1.1 msaitoh mr->bus_start, mr->bus_end, mr->address, size, mapsize); 218 1.1 msaitoh 219 1.1 msaitoh return_ACPI_STATUS(AE_OK); 220 1.1 msaitoh } 221 1.1 msaitoh 222 1.1 msaitoh static ACPI_STATUS 223 1.1 msaitoh acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx, 224 1.1 msaitoh void **retval) 225 1.1 msaitoh { 226 1.1 msaitoh struct acpimcfg_memrange *mr = ctx; 227 1.1 msaitoh ACPI_STATUS status; 228 1.1 msaitoh 229 1.1 msaitoh status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr); 230 1.1 msaitoh if (ACPI_FAILURE(status)) 231 1.1 msaitoh return_ACPI_STATUS(status); 232 1.1 msaitoh 233 1.1 msaitoh if (mr->found) 234 1.1 msaitoh return_ACPI_STATUS(AE_CTRL_TERMINATE); 235 1.1 msaitoh 236 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, " 237 1.1 msaitoh "address 0x%016" PRIx64 ": no valid region\n", mr->hid, 238 1.1 msaitoh mr->bus_start, mr->bus_end, mr->address); 239 1.1 msaitoh 240 1.1 msaitoh return_ACPI_STATUS(AE_OK); 241 1.1 msaitoh } 242 1.1 msaitoh 243 1.1 msaitoh static bool 244 1.1 msaitoh acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end) 245 1.1 msaitoh { 246 1.1 msaitoh static const char *system_resource_hid[] = { 247 1.1 msaitoh "PNP0C01", /* System Board */ 248 1.1 msaitoh "PNP0C02" /* General ID for reserving resources */ 249 1.1 msaitoh }; 250 1.1 msaitoh struct acpimcfg_memrange mr; 251 1.1 msaitoh ACPI_STATUS status; 252 1.1 msaitoh int i; 253 1.1 msaitoh 254 1.1 msaitoh mr.address = address; 255 1.1 msaitoh mr.bus_start = bus_start; 256 1.1 msaitoh mr.bus_end = *bus_end; 257 1.1 msaitoh mr.found = false; 258 1.1 msaitoh 259 1.1 msaitoh for (i = 0; i < __arraycount(system_resource_hid); i++) { 260 1.1 msaitoh mr.hid = system_resource_hid[i]; 261 1.1 msaitoh status = AcpiGetDevices(__UNCONST(system_resource_hid[i]), 262 1.1 msaitoh acpimcfg_check_system_resource, &mr, NULL); 263 1.1 msaitoh if (ACPI_FAILURE(status)) 264 1.1 msaitoh continue; 265 1.1 msaitoh if (mr.found) { 266 1.1 msaitoh *bus_end = mr.bus_end; 267 1.1 msaitoh return true; 268 1.1 msaitoh } 269 1.1 msaitoh } 270 1.1 msaitoh return false; 271 1.1 msaitoh } 272 1.1 msaitoh 273 1.1 msaitoh 274 1.1 msaitoh /* 275 1.1 msaitoh * ACPI MCFG 276 1.1 msaitoh */ 277 1.1 msaitoh void 278 1.1 msaitoh acpimcfg_probe(struct acpi_softc *sc) 279 1.1 msaitoh { 280 1.1 msaitoh ACPI_MCFG_ALLOCATION *ama; 281 1.1 msaitoh ACPI_STATUS status; 282 1.1 msaitoh uint32_t offset; 283 1.1 msaitoh int i, nsegs; 284 1.1 msaitoh 285 1.1 msaitoh if (acpi_sc != NULL) 286 1.1 msaitoh panic("acpi_sc != NULL"); 287 1.1 msaitoh acpi_sc = sc; 288 1.1 msaitoh 289 1.1 msaitoh status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg); 290 1.1 msaitoh if (ACPI_FAILURE(status)) { 291 1.1 msaitoh mcfg = NULL; 292 1.1 msaitoh return; 293 1.1 msaitoh } 294 1.1 msaitoh 295 1.1 msaitoh nsegs = 0; 296 1.1 msaitoh offset = sizeof(ACPI_TABLE_MCFG); 297 1.1 msaitoh ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); 298 1.6 maxv for (i = 0; offset + sizeof(ACPI_MCFG_ALLOCATION) <= 299 1.6 maxv mcfg->Header.Length; i++) { 300 1.1 msaitoh aprint_debug_dev(sc->sc_dev, 301 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", 302 1.1 msaitoh ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber, 303 1.1 msaitoh ama->Address); 304 1.1 msaitoh nsegs++; 305 1.1 msaitoh offset += sizeof(ACPI_MCFG_ALLOCATION); 306 1.11 jmcneill ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); 307 1.1 msaitoh } 308 1.1 msaitoh if (nsegs == 0) { 309 1.1 msaitoh mcfg = NULL; 310 1.1 msaitoh return; 311 1.1 msaitoh } 312 1.1 msaitoh 313 1.1 msaitoh mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP); 314 1.1 msaitoh mcfg_nsegs = nsegs; 315 1.1 msaitoh } 316 1.1 msaitoh 317 1.1 msaitoh int 318 1.1 msaitoh acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops) 319 1.1 msaitoh { 320 1.1 msaitoh ACPI_MCFG_ALLOCATION *ama; 321 1.1 msaitoh struct mcfg_segment *seg; 322 1.1 msaitoh uint32_t offset; 323 1.1 msaitoh int i, n, nsegs, bus_end; 324 1.1 msaitoh 325 1.1 msaitoh if (mcfg == NULL) 326 1.1 msaitoh return ENXIO; 327 1.1 msaitoh 328 1.1 msaitoh if (mcfg_inited) 329 1.1 msaitoh return 0; 330 1.1 msaitoh 331 1.1 msaitoh if (ops != NULL) 332 1.1 msaitoh mcfg_ops = ops; 333 1.1 msaitoh 334 1.1 msaitoh nsegs = 0; 335 1.1 msaitoh offset = sizeof(ACPI_TABLE_MCFG); 336 1.1 msaitoh ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); 337 1.1 msaitoh for (i = 0; offset < mcfg->Header.Length; i++) { 338 1.1 msaitoh #ifndef _LP64 339 1.1 msaitoh if (ama->Address >= 0x100000000ULL) { 340 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 341 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 342 1.1 msaitoh ": ignore (64bit address)\n", ama->PciSegment, 343 1.1 msaitoh ama->StartBusNumber, ama->EndBusNumber, 344 1.1 msaitoh ama->Address); 345 1.1 msaitoh goto next; 346 1.1 msaitoh } 347 1.1 msaitoh #endif 348 1.1 msaitoh /* 349 1.1 msaitoh * Some (broken?) BIOSen have an MCFG table for an empty 350 1.1 msaitoh * bus range. Ignore those tables. 351 1.1 msaitoh */ 352 1.1 msaitoh if (ama->StartBusNumber > ama->EndBusNumber) { 353 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 354 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 355 1.1 msaitoh ": ignore (bus %d > %d)\n", ama->PciSegment, 356 1.1 msaitoh ama->StartBusNumber, ama->EndBusNumber, 357 1.1 msaitoh ama->Address, ama->StartBusNumber, 358 1.1 msaitoh ama->EndBusNumber); 359 1.1 msaitoh goto next; 360 1.1 msaitoh } 361 1.1 msaitoh 362 1.1 msaitoh /* Validate MCFG memory range */ 363 1.1 msaitoh bus_end = ama->EndBusNumber; 364 1.1 msaitoh if (mcfg_ops->ao_validate != NULL && 365 1.1 msaitoh !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber, 366 1.1 msaitoh &bus_end)) { 367 1.22 skrll if (!acpimcfg_find_system_resource(ama->Address, 368 1.1 msaitoh ama->StartBusNumber, &bus_end)) { 369 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 370 1.1 msaitoh "MCFG: segment %d, bus %d-%d, " 371 1.1 msaitoh "address 0x%016" PRIx64 372 1.1 msaitoh ": ignore (invalid address)\n", 373 1.1 msaitoh ama->PciSegment, 374 1.1 msaitoh ama->StartBusNumber, ama->EndBusNumber, 375 1.1 msaitoh ama->Address); 376 1.1 msaitoh goto next; 377 1.1 msaitoh } 378 1.1 msaitoh } 379 1.1 msaitoh if (ama->EndBusNumber != bus_end) { 380 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 381 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 382 1.1 msaitoh " -> bus %d-%d\n", ama->PciSegment, 383 1.1 msaitoh ama->StartBusNumber, ama->EndBusNumber, 384 1.1 msaitoh ama->Address, ama->StartBusNumber, bus_end); 385 1.1 msaitoh } 386 1.1 msaitoh 387 1.13 jmcneill #ifndef __HAVE_PCI_GET_SEGMENT 388 1.1 msaitoh if (ama->PciSegment != 0) { 389 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 390 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 391 1.1 msaitoh ": ignore (non PCI segment 0)\n", ama->PciSegment, 392 1.1 msaitoh ama->StartBusNumber, bus_end, ama->Address); 393 1.1 msaitoh goto next; 394 1.1 msaitoh } 395 1.13 jmcneill #endif 396 1.1 msaitoh 397 1.1 msaitoh seg = &mcfg_segs[nsegs++]; 398 1.1 msaitoh seg->ms_address = ama->Address; 399 1.1 msaitoh seg->ms_segment = ama->PciSegment; 400 1.1 msaitoh seg->ms_bus_start = ama->StartBusNumber; 401 1.1 msaitoh seg->ms_bus_end = bus_end; 402 1.1 msaitoh seg->ms_bst = memt; 403 1.1 msaitoh n = seg->ms_bus_end - seg->ms_bus_start + 1; 404 1.1 msaitoh seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP); 405 1.1 msaitoh 406 1.1 msaitoh next: 407 1.1 msaitoh offset += sizeof(ACPI_MCFG_ALLOCATION); 408 1.11 jmcneill ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); 409 1.1 msaitoh } 410 1.1 msaitoh if (nsegs == 0) 411 1.1 msaitoh return ENOENT; 412 1.1 msaitoh 413 1.1 msaitoh for (i = 0; i < nsegs; i++) { 414 1.1 msaitoh seg = &mcfg_segs[i]; 415 1.1 msaitoh aprint_verbose_dev(acpi_sc->sc_dev, 416 1.1 msaitoh "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", 417 1.1 msaitoh seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end, 418 1.1 msaitoh seg->ms_address); 419 1.1 msaitoh } 420 1.1 msaitoh 421 1.1 msaitoh /* Update # of segment */ 422 1.1 msaitoh mcfg_nsegs = nsegs; 423 1.1 msaitoh mcfg_inited = true; 424 1.1 msaitoh 425 1.1 msaitoh return 0; 426 1.1 msaitoh } 427 1.1 msaitoh 428 1.1 msaitoh static int 429 1.1 msaitoh acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag) 430 1.1 msaitoh { 431 1.1 msaitoh pcireg_t id; 432 1.1 msaitoh int i; 433 1.1 msaitoh 434 1.1 msaitoh id = pci_conf_read(pc, tag, PCI_ID_REG); 435 1.1 msaitoh for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) { 436 1.1 msaitoh if (pci_conf_read(pc, tag, i) != id) 437 1.1 msaitoh return false; 438 1.1 msaitoh } 439 1.1 msaitoh return true; 440 1.1 msaitoh } 441 1.1 msaitoh 442 1.1 msaitoh static struct mcfg_segment * 443 1.12 jmcneill acpimcfg_get_segment(pci_chipset_tag_t pc, int bus) 444 1.1 msaitoh { 445 1.1 msaitoh struct mcfg_segment *seg; 446 1.12 jmcneill u_int segment; 447 1.1 msaitoh int i; 448 1.1 msaitoh 449 1.12 jmcneill segment = pci_get_segment(pc); 450 1.1 msaitoh for (i = 0; i < mcfg_nsegs; i++) { 451 1.1 msaitoh seg = &mcfg_segs[i]; 452 1.12 jmcneill if (segment == seg->ms_segment && 453 1.12 jmcneill bus >= seg->ms_bus_start && bus <= seg->ms_bus_end) 454 1.1 msaitoh return seg; 455 1.1 msaitoh } 456 1.1 msaitoh return NULL; 457 1.1 msaitoh } 458 1.1 msaitoh 459 1.1 msaitoh static int 460 1.1 msaitoh acpimcfg_device_probe(const struct pci_attach_args *pa) 461 1.1 msaitoh { 462 1.1 msaitoh pci_chipset_tag_t pc = pa->pa_pc; 463 1.1 msaitoh struct mcfg_segment *seg; 464 1.1 msaitoh struct mcfg_bus *mb; 465 1.1 msaitoh pcitag_t tag; 466 1.1 msaitoh pcireg_t reg; 467 1.1 msaitoh int bus = pa->pa_bus; 468 1.1 msaitoh int dev = pa->pa_device; 469 1.1 msaitoh int func = pa->pa_function; 470 1.1 msaitoh int last_dev, last_func, end_func; 471 1.1 msaitoh int alias = 0; 472 1.5 msaitoh const struct pci_quirkdata *qd; 473 1.5 msaitoh bool force_hasextcnf = false; 474 1.5 msaitoh bool force_noextcnf = false; 475 1.1 msaitoh int i, j; 476 1.1 msaitoh 477 1.12 jmcneill seg = acpimcfg_get_segment(pc, bus); 478 1.1 msaitoh if (seg == NULL) 479 1.1 msaitoh return 0; 480 1.1 msaitoh 481 1.1 msaitoh mb = &seg->ms_bus[bus - seg->ms_bus_start]; 482 1.1 msaitoh tag = pci_make_tag(pc, bus, dev, func); 483 1.1 msaitoh 484 1.1 msaitoh /* Mark invalid between last probed device to probed device. */ 485 1.1 msaitoh pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); 486 1.1 msaitoh if (dev != 0 || func != 0) { 487 1.1 msaitoh for (i = last_dev; i <= dev; i++) { 488 1.1 msaitoh end_func = (i == dev) ? func : 8; 489 1.1 msaitoh for (j = last_func; j < end_func; j++) { 490 1.1 msaitoh if (i == last_dev && j == last_func) 491 1.1 msaitoh continue; 492 1.10 jmcneill PCIDEV_SET_INVALID(mb, i, j); 493 1.1 msaitoh } 494 1.1 msaitoh last_func = 0; 495 1.1 msaitoh } 496 1.1 msaitoh } 497 1.1 msaitoh mb->last_probed = tag; 498 1.1 msaitoh 499 1.5 msaitoh reg = pci_conf_read(pc, tag, PCI_ID_REG); 500 1.5 msaitoh qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); 501 1.5 msaitoh if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0) 502 1.5 msaitoh force_hasextcnf = true; 503 1.5 msaitoh if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0) 504 1.5 msaitoh force_noextcnf = true; 505 1.23 skrll 506 1.1 msaitoh /* Probe extended configuration space. */ 507 1.5 msaitoh if ((!force_hasextcnf) && ((force_noextcnf) || 508 1.5 msaitoh ((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) 509 1.5 msaitoh || (reg == 0) 510 1.5 msaitoh || (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) { 511 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 512 1.1 msaitoh "MCFG: %03d:%02d:%d: invalid config space " 513 1.1 msaitoh "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func, 514 1.1 msaitoh PCI_CONF_SIZE, reg, alias ? "true" : "false"); 515 1.1 msaitoh EXTCONF_SET_INVALID(mb, dev, func); 516 1.1 msaitoh } 517 1.1 msaitoh 518 1.10 jmcneill aprint_debug_dev(acpi_sc->sc_dev, 519 1.10 jmcneill "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n", 520 1.10 jmcneill bus, dev, func, PCI_CONF_SIZE, reg, 521 1.10 jmcneill EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N'); 522 1.10 jmcneill mb->valid_ndevs++; 523 1.10 jmcneill 524 1.1 msaitoh return 0; 525 1.1 msaitoh } 526 1.1 msaitoh 527 1.1 msaitoh static void 528 1.1 msaitoh acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus) 529 1.1 msaitoh { 530 1.1 msaitoh static const int wildcard[PCICF_NLOCS] = { 531 1.1 msaitoh PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT 532 1.1 msaitoh }; 533 1.1 msaitoh 534 1.1 msaitoh sc->sc_bus = bus; /* XXX */ 535 1.7 jmcneill sc->sc_pc = pc; 536 1.1 msaitoh 537 1.1 msaitoh pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL); 538 1.1 msaitoh } 539 1.1 msaitoh 540 1.1 msaitoh int 541 1.1 msaitoh acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus) 542 1.1 msaitoh { 543 1.1 msaitoh struct pci_softc *sc = device_private(self); 544 1.1 msaitoh struct mcfg_segment *seg = NULL; 545 1.1 msaitoh struct mcfg_bus *mb; 546 1.1 msaitoh bus_space_handle_t bsh; 547 1.1 msaitoh bus_addr_t baddr; 548 1.3 hannken pcitag_t tag; 549 1.3 hannken pcireg_t reg; 550 1.3 hannken bool is_e7520_mch; 551 1.1 msaitoh int boff; 552 1.1 msaitoh int last_dev, last_func; 553 1.1 msaitoh int i, j; 554 1.1 msaitoh int error; 555 1.1 msaitoh 556 1.1 msaitoh if (!mcfg_inited) 557 1.1 msaitoh return ENXIO; 558 1.1 msaitoh 559 1.12 jmcneill seg = acpimcfg_get_segment(pc, bus); 560 1.1 msaitoh if (seg == NULL) 561 1.1 msaitoh return ENOENT; 562 1.1 msaitoh 563 1.1 msaitoh boff = bus - seg->ms_bus_start; 564 1.1 msaitoh if (seg->ms_bus[boff].valid_ndevs > 0) 565 1.1 msaitoh return 0; 566 1.1 msaitoh 567 1.1 msaitoh mb = &seg->ms_bus[boff]; 568 1.17 jmcneill baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS); 569 1.1 msaitoh 570 1.21 jmcneill /* Map extended configuration space of all dev/func. */ 571 1.1 msaitoh error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, 572 1.1 msaitoh &bsh); 573 1.1 msaitoh if (error != 0) 574 1.1 msaitoh return error; 575 1.1 msaitoh for (i = 0; i < 32; i++) { 576 1.1 msaitoh for (j = 0; j < 8; j++) { 577 1.1 msaitoh error = bus_space_subregion(seg->ms_bst, bsh, 578 1.1 msaitoh EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, 579 1.1 msaitoh &mb->bsh[i][j]); 580 1.1 msaitoh if (error != 0) 581 1.1 msaitoh break; 582 1.1 msaitoh } 583 1.1 msaitoh } 584 1.1 msaitoh if (error != 0) 585 1.1 msaitoh return error; 586 1.1 msaitoh 587 1.1 msaitoh aprint_debug("\n"); 588 1.1 msaitoh 589 1.1 msaitoh /* Probe extended configuration space of all devices. */ 590 1.1 msaitoh memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); 591 1.10 jmcneill memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf)); 592 1.1 msaitoh mb->valid_ndevs = 0; 593 1.1 msaitoh mb->last_probed = pci_make_tag(pc, bus, 0, 0); 594 1.1 msaitoh 595 1.3 hannken /* 596 1.3 hannken * On an Intel E7520 we have to temporarily disable 597 1.3 hannken * Enhanced Config Access error detection and reporting 598 1.3 hannken * by setting the appropriate error mask in HI_ERRMASK register. 599 1.3 hannken * 600 1.3 hannken * See "Intel E7520 Memory Controller Hub (MCH) Datasheet", 601 1.3 hannken * Document 303006-002, pg. 82 602 1.3 hannken */ 603 1.3 hannken tag = pci_make_tag(pc, 0, 0, 1); 604 1.3 hannken reg = pci_conf_read(pc, tag, PCI_ID_REG); 605 1.3 hannken is_e7520_mch = (reg == 606 1.3 hannken PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER)); 607 1.3 hannken if (is_e7520_mch) { 608 1.3 hannken reg = pci_conf_read(pc, tag, 0x54); 609 1.3 hannken pci_conf_write(pc, tag, 0x54, reg | 0x20); 610 1.3 hannken } 611 1.3 hannken 612 1.1 msaitoh acpimcfg_scan_bus(sc, pc, bus); 613 1.1 msaitoh 614 1.3 hannken if (is_e7520_mch) { 615 1.3 hannken pci_conf_write(pc, tag, 0x54, reg); 616 1.3 hannken } 617 1.3 hannken 618 1.10 jmcneill /* Unmap configuration space of all dev/func. */ 619 1.1 msaitoh bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS); 620 1.1 msaitoh memset(mb->bsh, 0, sizeof(mb->bsh)); 621 1.1 msaitoh 622 1.1 msaitoh if (mb->valid_ndevs == 0) { 623 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 624 1.1 msaitoh "MCFG: bus %d: no valid devices.\n", bus); 625 1.1 msaitoh memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); 626 1.1 msaitoh goto out; 627 1.1 msaitoh } 628 1.1 msaitoh 629 1.1 msaitoh /* Mark invalid on remaining all devices. */ 630 1.1 msaitoh pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); 631 1.1 msaitoh for (i = last_dev; i < 32; i++) { 632 1.1 msaitoh for (j = last_func; j < 8; j++) { 633 1.1 msaitoh if (i == last_dev && j == last_func) { 634 1.1 msaitoh /* Don't mark invalid to last probed device. */ 635 1.1 msaitoh continue; 636 1.1 msaitoh } 637 1.10 jmcneill PCIDEV_SET_INVALID(mb, i, j); 638 1.1 msaitoh } 639 1.1 msaitoh last_func = 0; 640 1.1 msaitoh } 641 1.1 msaitoh 642 1.10 jmcneill /* Map configuration space per dev/func. */ 643 1.1 msaitoh for (i = 0; i < 32; i++) { 644 1.1 msaitoh for (j = 0; j < 8; j++) { 645 1.10 jmcneill if (!PCIDEV_IS_VALID(mb, i, j)) 646 1.1 msaitoh continue; 647 1.1 msaitoh error = bus_space_map(seg->ms_bst, 648 1.1 msaitoh baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, 649 1.1 msaitoh 0, &mb->bsh[i][j]); 650 1.1 msaitoh if (error != 0) { 651 1.1 msaitoh /* Unmap all handles when map failed. */ 652 1.1 msaitoh do { 653 1.1 msaitoh while (--j >= 0) { 654 1.10 jmcneill if (!PCIDEV_IS_VALID(mb, i, j)) 655 1.1 msaitoh continue; 656 1.1 msaitoh bus_space_unmap(seg->ms_bst, 657 1.1 msaitoh mb->bsh[i][j], 658 1.1 msaitoh PCI_EXTCONF_SIZE); 659 1.1 msaitoh } 660 1.1 msaitoh j = 8; 661 1.1 msaitoh } while (--i >= 0); 662 1.1 msaitoh memset(mb->valid_devs, 0, 663 1.1 msaitoh sizeof(mb->valid_devs)); 664 1.1 msaitoh goto out; 665 1.1 msaitoh } 666 1.1 msaitoh } 667 1.1 msaitoh } 668 1.1 msaitoh 669 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus); 670 1.1 msaitoh for (i = 0; i < 32; i++) { 671 1.1 msaitoh for (j = 0; j < 8; j++) { 672 1.10 jmcneill if (PCIDEV_IS_VALID(mb, i, j)) { 673 1.1 msaitoh aprint_debug_dev(acpi_sc->sc_dev, 674 1.1 msaitoh "MCFG: %03d:%02d:%d\n", bus, i, j); 675 1.1 msaitoh } 676 1.1 msaitoh } 677 1.1 msaitoh } 678 1.1 msaitoh 679 1.1 msaitoh error = 0; 680 1.1 msaitoh out: 681 1.1 msaitoh 682 1.1 msaitoh return error; 683 1.1 msaitoh } 684 1.1 msaitoh 685 1.26 jmcneill #ifdef PCI_RESOURCE 686 1.32 riastrad struct acpimcfg_configure_bus_context { 687 1.32 riastrad struct pci_resource_info pciinfo; 688 1.32 riastrad bool bus_found; 689 1.32 riastrad }; 690 1.32 riastrad 691 1.24 jmcneill ACPI_STATUS 692 1.8 jmcneill acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) 693 1.8 jmcneill { 694 1.32 riastrad struct acpimcfg_configure_bus_context *C = ctx; 695 1.32 riastrad struct pci_resource_info *pciinfo = &C->pciinfo; 696 1.20 thorpej bus_addr_t addr; 697 1.20 thorpej bus_size_t size; 698 1.26 jmcneill int type; 699 1.8 jmcneill 700 1.15 jmcneill if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && 701 1.15 jmcneill res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && 702 1.8 jmcneill res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) 703 1.8 jmcneill return AE_OK; 704 1.8 jmcneill 705 1.8 jmcneill if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER) 706 1.8 jmcneill return AE_OK; 707 1.8 jmcneill 708 1.8 jmcneill if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && 709 1.26 jmcneill res->Data.Address.ResourceType != ACPI_IO_RANGE && 710 1.26 jmcneill res->Data.Address.ResourceType != ACPI_BUS_NUMBER_RANGE) 711 1.8 jmcneill return AE_OK; 712 1.8 jmcneill 713 1.8 jmcneill if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && 714 1.8 jmcneill res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) { 715 1.26 jmcneill type = PCI_RANGE_PMEM; 716 1.8 jmcneill } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && 717 1.8 jmcneill res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) { 718 1.26 jmcneill if (res->Type == ACPI_RESOURCE_TYPE_ADDRESS64) { 719 1.26 jmcneill type = PCI_RANGE_PMEM; 720 1.26 jmcneill } else { 721 1.26 jmcneill type = PCI_RANGE_MEM; 722 1.26 jmcneill } 723 1.26 jmcneill } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) { 724 1.26 jmcneill type = PCI_RANGE_BUS; 725 1.19 jmcneill } else { 726 1.19 jmcneill KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE); 727 1.26 jmcneill type = PCI_RANGE_IO; 728 1.8 jmcneill } 729 1.8 jmcneill 730 1.8 jmcneill switch (res->Type) { 731 1.8 jmcneill case ACPI_RESOURCE_TYPE_ADDRESS16: 732 1.8 jmcneill aprint_debug( 733 1.8 jmcneill "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n", 734 1.8 jmcneill res->Data.Address16.Address.Minimum, 735 1.8 jmcneill res->Data.Address16.Address.AddressLength, 736 1.26 jmcneill pci_resource_typename(type)); 737 1.20 thorpej addr = res->Data.Address16.Address.Minimum; 738 1.20 thorpej size = res->Data.Address16.Address.AddressLength; 739 1.8 jmcneill break; 740 1.8 jmcneill case ACPI_RESOURCE_TYPE_ADDRESS32: 741 1.8 jmcneill aprint_debug( 742 1.8 jmcneill "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n", 743 1.8 jmcneill res->Data.Address32.Address.Minimum, 744 1.8 jmcneill res->Data.Address32.Address.AddressLength, 745 1.26 jmcneill pci_resource_typename(type)); 746 1.20 thorpej addr = res->Data.Address32.Address.Minimum; 747 1.20 thorpej size = res->Data.Address32.Address.AddressLength; 748 1.8 jmcneill break; 749 1.8 jmcneill case ACPI_RESOURCE_TYPE_ADDRESS64: 750 1.8 jmcneill aprint_debug( 751 1.8 jmcneill "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n", 752 1.8 jmcneill res->Data.Address64.Address.Minimum, 753 1.8 jmcneill res->Data.Address64.Address.AddressLength, 754 1.26 jmcneill pci_resource_typename(type)); 755 1.20 thorpej addr = res->Data.Address64.Address.Minimum; 756 1.20 thorpej size = res->Data.Address64.Address.AddressLength; 757 1.8 jmcneill break; 758 1.20 thorpej 759 1.20 thorpej default: 760 1.20 thorpej return AE_OK; 761 1.8 jmcneill } 762 1.8 jmcneill 763 1.30 mlelstv if (size > 0) { 764 1.31 riastrad pci_resource_add_range(pciinfo, type, addr, addr + size - 1); 765 1.32 riastrad if (type == PCI_RANGE_BUS) 766 1.32 riastrad C->bus_found = true; 767 1.30 mlelstv } 768 1.20 thorpej 769 1.26 jmcneill return AE_OK; 770 1.8 jmcneill } 771 1.8 jmcneill 772 1.8 jmcneill int 773 1.8 jmcneill acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, 774 1.26 jmcneill int bus, bool mapcfgspace) 775 1.8 jmcneill { 776 1.32 riastrad struct acpimcfg_configure_bus_context context, *C = &context; 777 1.8 jmcneill struct mcfg_segment *seg; 778 1.8 jmcneill struct mcfg_bus *mb; 779 1.8 jmcneill bus_space_handle_t bsh[256]; 780 1.8 jmcneill bool bsh_mapped[256]; 781 1.26 jmcneill int error, boff, b, d, f, endbus; 782 1.8 jmcneill bus_addr_t baddr; 783 1.8 jmcneill ACPI_STATUS rv; 784 1.8 jmcneill 785 1.26 jmcneill if (mapcfgspace) { 786 1.26 jmcneill seg = acpimcfg_get_segment(pc, bus); 787 1.30 mlelstv aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Bus=%d, Seg=%p\n", 788 1.30 mlelstv bus, seg); 789 1.26 jmcneill if (seg == NULL) { 790 1.26 jmcneill return ENOENT; 791 1.26 jmcneill } 792 1.26 jmcneill endbus = seg->ms_bus_end; 793 1.8 jmcneill 794 1.26 jmcneill /* 795 1.26 jmcneill * Map config space for all possible busses and mark them valid 796 1.26 jmcneill * during configuration so pci_configure_bus can access them 797 1.26 jmcneill * through our chipset tag with acpimcfg_conf_read/write below. 798 1.26 jmcneill */ 799 1.26 jmcneill memset(bsh_mapped, 0, sizeof(bsh_mapped)); 800 1.26 jmcneill for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { 801 1.26 jmcneill boff = b - seg->ms_bus_start; 802 1.26 jmcneill mb = &seg->ms_bus[boff]; 803 1.26 jmcneill baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); 804 1.26 jmcneill 805 1.26 jmcneill /* Map extended configuration space of all dev/func. */ 806 1.26 jmcneill error = bus_space_map(seg->ms_bst, baddr, 807 1.26 jmcneill ACPIMCFG_SIZE_PER_BUS, 0, &bsh[b]); 808 1.26 jmcneill if (error != 0) { 809 1.26 jmcneill goto cleanup; 810 1.26 jmcneill } 811 1.26 jmcneill bsh_mapped[b] = true; 812 1.26 jmcneill for (d = 0; d < 32; d++) { 813 1.26 jmcneill for (f = 0; f < 8; f++) { 814 1.26 jmcneill error = bus_space_subregion(seg->ms_bst, 815 1.26 jmcneill bsh[b], EXTCONF_OFFSET(d, f, 0), 816 1.26 jmcneill PCI_EXTCONF_SIZE, &mb->bsh[d][f]); 817 1.26 jmcneill if (error != 0) { 818 1.26 jmcneill break; 819 1.26 jmcneill } 820 1.26 jmcneill } 821 1.26 jmcneill } 822 1.26 jmcneill if (error != 0) { 823 1.26 jmcneill goto cleanup; 824 1.26 jmcneill } 825 1.20 thorpej 826 1.26 jmcneill memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); 827 1.8 jmcneill } 828 1.26 jmcneill } else { 829 1.26 jmcneill endbus = 255; 830 1.8 jmcneill } 831 1.8 jmcneill 832 1.32 riastrad memset(C, 0, sizeof(*C)); 833 1.32 riastrad C->pciinfo.pc = pc; 834 1.20 thorpej rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, 835 1.32 riastrad &C->pciinfo); 836 1.8 jmcneill if (ACPI_FAILURE(rv)) { 837 1.30 mlelstv aprint_debug_dev(acpi_sc->sc_dev, "MCFG: Walk _CRS: %ld\n", 838 1.30 mlelstv (long)rv); 839 1.8 jmcneill error = ENXIO; 840 1.8 jmcneill goto cleanup; 841 1.8 jmcneill } 842 1.32 riastrad 843 1.32 riastrad /* 844 1.32 riastrad * Paranoia: In case _CRS didn't list any bus ranges, guess 845 1.32 riastrad * from the MCFG. 846 1.32 riastrad */ 847 1.32 riastrad if (!C->bus_found) { 848 1.32 riastrad aprint_error_dev(acpi_sc->sc_dev, 849 1.32 riastrad "no PCI bus range in _CRS, guessing %d-%d from MCFG\n", 850 1.32 riastrad bus, endbus); 851 1.32 riastrad pci_resource_add_range(&C->pciinfo, PCI_RANGE_BUS, 852 1.32 riastrad bus, endbus); 853 1.32 riastrad } 854 1.32 riastrad 855 1.26 jmcneill error = 0; 856 1.8 jmcneill 857 1.32 riastrad pci_resource_init(&C->pciinfo); 858 1.8 jmcneill 859 1.8 jmcneill cleanup: 860 1.26 jmcneill if (mapcfgspace) { 861 1.26 jmcneill /* 862 1.26 jmcneill * Unmap config space for the segment's busses. Valid devices 863 1.26 jmcneill * will be re-mapped later on by acpimcfg_map_bus. 864 1.26 jmcneill */ 865 1.26 jmcneill for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { 866 1.26 jmcneill boff = b - seg->ms_bus_start; 867 1.26 jmcneill mb = &seg->ms_bus[boff]; 868 1.26 jmcneill memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); 869 1.26 jmcneill 870 1.26 jmcneill if (bsh_mapped[b]) { 871 1.26 jmcneill bus_space_unmap(seg->ms_bst, bsh[b], 872 1.26 jmcneill ACPIMCFG_SIZE_PER_BUS); 873 1.26 jmcneill } 874 1.26 jmcneill } 875 1.8 jmcneill } 876 1.8 jmcneill 877 1.8 jmcneill return error; 878 1.8 jmcneill } 879 1.8 jmcneill #else 880 1.8 jmcneill int 881 1.8 jmcneill acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, 882 1.26 jmcneill int bus, bool mapcfgspace) 883 1.8 jmcneill { 884 1.8 jmcneill return ENXIO; 885 1.8 jmcneill } 886 1.8 jmcneill #endif 887 1.8 jmcneill 888 1.1 msaitoh int 889 1.1 msaitoh acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data) 890 1.1 msaitoh { 891 1.1 msaitoh struct mcfg_segment *seg = NULL; 892 1.1 msaitoh struct mcfg_bus *mb; 893 1.1 msaitoh int bus, dev, func; 894 1.1 msaitoh 895 1.1 msaitoh KASSERT(reg < PCI_EXTCONF_SIZE); 896 1.1 msaitoh KASSERT((reg & 3) == 0); 897 1.1 msaitoh 898 1.1 msaitoh if (!mcfg_inited) { 899 1.1 msaitoh *data = -1; 900 1.1 msaitoh return ENXIO; 901 1.1 msaitoh } 902 1.1 msaitoh 903 1.1 msaitoh pci_decompose_tag(pc, tag, &bus, &dev, &func); 904 1.1 msaitoh 905 1.12 jmcneill seg = acpimcfg_get_segment(pc, bus); 906 1.1 msaitoh if (seg == NULL) { 907 1.1 msaitoh *data = -1; 908 1.1 msaitoh return ERANGE; 909 1.1 msaitoh } 910 1.1 msaitoh 911 1.1 msaitoh mb = &seg->ms_bus[bus - seg->ms_bus_start]; 912 1.10 jmcneill if (!PCIDEV_IS_VALID(mb, dev, func)) { 913 1.10 jmcneill *data = -1; 914 1.10 jmcneill return EINVAL; 915 1.10 jmcneill } 916 1.10 jmcneill if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) { 917 1.1 msaitoh *data = -1; 918 1.1 msaitoh return EINVAL; 919 1.1 msaitoh } 920 1.1 msaitoh 921 1.1 msaitoh *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg); 922 1.1 msaitoh return 0; 923 1.1 msaitoh } 924 1.1 msaitoh 925 1.1 msaitoh int 926 1.1 msaitoh acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 927 1.1 msaitoh { 928 1.1 msaitoh struct mcfg_segment *seg = NULL; 929 1.1 msaitoh struct mcfg_bus *mb; 930 1.1 msaitoh int bus, dev, func; 931 1.1 msaitoh 932 1.1 msaitoh KASSERT(reg < PCI_EXTCONF_SIZE); 933 1.1 msaitoh KASSERT((reg & 3) == 0); 934 1.1 msaitoh 935 1.1 msaitoh if (!mcfg_inited) 936 1.1 msaitoh return ENXIO; 937 1.1 msaitoh 938 1.1 msaitoh pci_decompose_tag(pc, tag, &bus, &dev, &func); 939 1.1 msaitoh 940 1.12 jmcneill seg = acpimcfg_get_segment(pc, bus); 941 1.1 msaitoh if (seg == NULL) 942 1.1 msaitoh return ERANGE; 943 1.1 msaitoh 944 1.1 msaitoh mb = &seg->ms_bus[bus - seg->ms_bus_start]; 945 1.10 jmcneill if (!PCIDEV_IS_VALID(mb, dev, func)) 946 1.10 jmcneill return EINVAL; 947 1.10 jmcneill if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) 948 1.1 msaitoh return EINVAL; 949 1.1 msaitoh 950 1.1 msaitoh mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data); 951 1.1 msaitoh return 0; 952 1.1 msaitoh } 953 1.18 jmcneill 954 1.18 jmcneill bool 955 1.18 jmcneill acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg) 956 1.18 jmcneill { 957 1.18 jmcneill struct mcfg_segment *seg = NULL; 958 1.18 jmcneill struct mcfg_bus *mb; 959 1.18 jmcneill int bus, dev, func; 960 1.18 jmcneill 961 1.18 jmcneill if (!mcfg_inited) 962 1.18 jmcneill return false; 963 1.18 jmcneill 964 1.18 jmcneill pci_decompose_tag(pc, tag, &bus, &dev, &func); 965 1.18 jmcneill 966 1.18 jmcneill seg = acpimcfg_get_segment(pc, bus); 967 1.18 jmcneill if (seg == NULL) 968 1.18 jmcneill return false; 969 1.18 jmcneill 970 1.18 jmcneill mb = &seg->ms_bus[bus - seg->ms_bus_start]; 971 1.18 jmcneill if (!PCIDEV_IS_VALID(mb, dev, func)) 972 1.18 jmcneill return false; 973 1.18 jmcneill if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) 974 1.18 jmcneill return false; 975 1.18 jmcneill 976 1.18 jmcneill return true; 977 1.18 jmcneill } 978