1 1.7 riastrad /* $NetBSD: pci_resource.c,v 1.7 2025/03/03 19:38:43 riastradh Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2022 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill /* 30 1.1 jmcneill * pci_resource.c -- 31 1.1 jmcneill * 32 1.1 jmcneill * Scan current PCI resource allocations and attempt to assign resources 33 1.1 jmcneill * to devices that are not configured WITHOUT changing any configuration 34 1.1 jmcneill * performed by system firmware. 35 1.1 jmcneill */ 36 1.1 jmcneill 37 1.1 jmcneill #include <sys/cdefs.h> 38 1.7 riastrad __KERNEL_RCSID(0, "$NetBSD: pci_resource.c,v 1.7 2025/03/03 19:38:43 riastradh Exp $"); 39 1.1 jmcneill 40 1.1 jmcneill #include <sys/param.h> 41 1.6 riastrad #include <sys/types.h> 42 1.6 riastrad 43 1.1 jmcneill #include <sys/bus.h> 44 1.6 riastrad #include <sys/kmem.h> 45 1.6 riastrad #include <sys/queue.h> 46 1.1 jmcneill #include <sys/systm.h> 47 1.1 jmcneill #include <sys/vmem.h> 48 1.1 jmcneill 49 1.1 jmcneill #include <dev/pci/pcireg.h> 50 1.1 jmcneill #include <dev/pci/pcivar.h> 51 1.1 jmcneill #include <dev/pci/pcidevs.h> 52 1.1 jmcneill #include <dev/pci/pci_resource.h> 53 1.1 jmcneill 54 1.1 jmcneill #define DPRINT aprint_debug 55 1.1 jmcneill 56 1.1 jmcneill #if defined(PCI_RESOURCE_TEST_VENDOR_ID) && \ 57 1.1 jmcneill defined(PCI_RESOURCE_TEST_PRODUCT_ID) 58 1.1 jmcneill #define IS_TEST_DEVICE(_pd) \ 59 1.1 jmcneill (PCI_VENDOR(pd->pd_id) == PCI_RESOURCE_TEST_VENDOR_ID && \ 60 1.1 jmcneill PCI_PRODUCT(pd->pd_id) == PCI_RESOURCE_TEST_PRODUCT_ID) 61 1.1 jmcneill #else 62 1.1 jmcneill #define IS_TEST_DEVICE(_pd) 0 63 1.1 jmcneill #endif 64 1.1 jmcneill 65 1.1 jmcneill #define PCI_MAX_DEVICE 32 66 1.1 jmcneill #define PCI_MAX_FUNC 8 67 1.1 jmcneill 68 1.1 jmcneill #define PCI_MAX_IORES 6 69 1.1 jmcneill 70 1.1 jmcneill #define PCI_RANGE_FOREACH(_type) \ 71 1.1 jmcneill for (u_int _type = PCI_RANGE_BUS; _type < NUM_PCI_RANGES; _type++) 72 1.1 jmcneill 73 1.1 jmcneill static const char *pci_range_typenames[NUM_PCI_RANGES] = { 74 1.1 jmcneill [PCI_RANGE_BUS] = "bus", 75 1.1 jmcneill [PCI_RANGE_IO] = "io", 76 1.1 jmcneill [PCI_RANGE_MEM] = "mem", 77 1.1 jmcneill [PCI_RANGE_PMEM] = "pmem", 78 1.1 jmcneill }; 79 1.1 jmcneill 80 1.1 jmcneill struct pci_bus; 81 1.1 jmcneill 82 1.1 jmcneill struct pci_iores { 83 1.1 jmcneill uint64_t pi_base; /* Base address */ 84 1.1 jmcneill uint64_t pi_size; /* Resource size */ 85 1.1 jmcneill uint8_t pi_type; /* PCI_MAPREG_TYPE_* */ 86 1.1 jmcneill u_int pi_bar; /* PCI bar number */ 87 1.1 jmcneill union { 88 1.1 jmcneill struct { 89 1.1 jmcneill uint8_t memtype; 90 1.1 jmcneill bool prefetch; 91 1.1 jmcneill } pi_mem; 92 1.1 jmcneill }; 93 1.1 jmcneill }; 94 1.1 jmcneill 95 1.1 jmcneill struct pci_device { 96 1.1 jmcneill bool pd_present; /* Device is present */ 97 1.1 jmcneill bool pd_configured; /* Device is configured */ 98 1.1 jmcneill struct pci_bus *pd_bus; /* Parent bus */ 99 1.1 jmcneill uint8_t pd_devno; /* Device number */ 100 1.1 jmcneill uint8_t pd_funcno; /* Function number */ 101 1.1 jmcneill pcitag_t pd_tag; /* PCI tag */ 102 1.1 jmcneill 103 1.1 jmcneill pcireg_t pd_id; /* Vendor ID, Device ID */ 104 1.1 jmcneill pcireg_t pd_class; /* Revision ID, Class Code */ 105 1.1 jmcneill pcireg_t pd_bhlc; /* BIST, Header Type, Primary Latency 106 1.1 jmcneill * Timer, Cache Line Size */ 107 1.1 jmcneill 108 1.1 jmcneill struct pci_iores pd_iores[PCI_MAX_IORES]; 109 1.1 jmcneill u_int pd_niores; 110 1.1 jmcneill 111 1.1 jmcneill bool pd_ppb; /* PCI-PCI bridge */ 112 1.1 jmcneill union { 113 1.1 jmcneill struct { 114 1.1 jmcneill pcireg_t bridge_bus; 115 1.6 riastrad struct pci_resource_arena *ranges[NUM_PCI_RANGES]; 116 1.1 jmcneill } pd_bridge; 117 1.1 jmcneill }; 118 1.1 jmcneill }; 119 1.1 jmcneill 120 1.1 jmcneill struct pci_bus { 121 1.1 jmcneill uint8_t pb_busno; /* Bus number */ 122 1.1 jmcneill struct pci_device *pb_bridge; /* Parent bridge, or NULL */ 123 1.1 jmcneill 124 1.1 jmcneill struct pci_device pb_device[PCI_MAX_DEVICE * PCI_MAX_FUNC]; 125 1.1 jmcneill /* Devices on bus */ 126 1.1 jmcneill u_int pb_lastdevno; /* Last device found */ 127 1.1 jmcneill 128 1.6 riastrad /* XXX Nothing seems to use pb_ranges? */ 129 1.6 riastrad struct pci_resource_arena *pb_ranges[NUM_PCI_RANGES]; 130 1.6 riastrad struct pci_resource_arena *pb_res[NUM_PCI_RANGES]; 131 1.1 jmcneill }; 132 1.1 jmcneill 133 1.1 jmcneill struct pci_resources { 134 1.1 jmcneill struct pci_bus **pr_bus; /* Bus list */ 135 1.1 jmcneill pci_chipset_tag_t pr_pc; /* Chipset tag */ 136 1.1 jmcneill uint8_t pr_startbus; /* First bus number */ 137 1.7 riastrad struct pci_resource_arena *pr_busranges; 138 1.1 jmcneill 139 1.6 riastrad struct pci_resource_arena *pr_ranges[NUM_PCI_RANGES]; 140 1.6 riastrad }; 141 1.6 riastrad 142 1.6 riastrad struct pci_resource_arena { 143 1.6 riastrad vmem_t *vmem; 144 1.7 riastrad SIMPLEQ_HEAD(, pci_resource_range) list; 145 1.6 riastrad }; 146 1.6 riastrad 147 1.6 riastrad struct pci_resource_range { 148 1.7 riastrad uint64_t start; 149 1.7 riastrad uint64_t end; 150 1.7 riastrad SIMPLEQ_ENTRY(pci_resource_range) entry; 151 1.1 jmcneill }; 152 1.1 jmcneill 153 1.5 jmcneill static int pci_resource_scan_bus(struct pci_resources *, 154 1.3 riastrad struct pci_device *, uint8_t); 155 1.1 jmcneill 156 1.1 jmcneill #define PCI_SBDF_FMT "%04x:%02x:%02x.%u" 157 1.1 jmcneill #define PCI_SBDF_FMT_ARGS(_pr, _pd) \ 158 1.1 jmcneill pci_get_segment((_pr)->pr_pc), \ 159 1.1 jmcneill (_pd)->pd_bus->pb_busno, \ 160 1.1 jmcneill (_pd)->pd_devno, \ 161 1.1 jmcneill (_pd)->pd_funcno 162 1.1 jmcneill 163 1.1 jmcneill #define PCICONF_RES_BUS(_pr, _busno) \ 164 1.1 jmcneill ((_pr)->pr_bus[(_busno) - (_pr)->pr_startbus]) 165 1.1 jmcneill #define PCICONF_BUS_DEVICE(_pb, _devno, _funcno) \ 166 1.1 jmcneill (&(_pb)->pb_device[(_devno) * PCI_MAX_FUNC + (_funcno)]) 167 1.1 jmcneill 168 1.7 riastrad static bool 169 1.7 riastrad pci_bus_in_range(struct pci_resources *pr, int busno) 170 1.7 riastrad { 171 1.7 riastrad struct pci_resource_range *range; 172 1.7 riastrad 173 1.7 riastrad SIMPLEQ_FOREACH(range, &pr->pr_busranges->list, entry) { 174 1.7 riastrad if (busno >= range->start && busno <= range->end) 175 1.7 riastrad return true; 176 1.7 riastrad } 177 1.7 riastrad return false; 178 1.7 riastrad } 179 1.7 riastrad 180 1.6 riastrad static void 181 1.6 riastrad pci_resource_arena_add_range(struct pci_resource_arena **arenas, 182 1.6 riastrad enum pci_range_type type, uint64_t start, uint64_t end) 183 1.6 riastrad { 184 1.6 riastrad struct pci_resource_arena *arena; 185 1.6 riastrad struct pci_resource_range *new, *range, *prev; 186 1.6 riastrad int error; 187 1.6 riastrad 188 1.7 riastrad KASSERTMSG(start <= end, "type=%d start=%" PRIu64 " end=%" PRIu64, 189 1.7 riastrad type, start, end); 190 1.7 riastrad 191 1.7 riastrad /* 192 1.7 riastrad * Warn if this is a bus range and the start/end are bad. The 193 1.7 riastrad * other types of ranges can have larger addresses. 194 1.7 riastrad */ 195 1.7 riastrad if (type == PCI_RANGE_BUS && 196 1.7 riastrad (start > UINT8_MAX || end > UINT8_MAX)) { 197 1.7 riastrad aprint_error("PCI: unexpected bus range" 198 1.7 riastrad " %" PRIu64 "-%" PRIu64 ", ignoring\n", 199 1.7 riastrad start, end); 200 1.7 riastrad return; 201 1.7 riastrad } 202 1.7 riastrad 203 1.6 riastrad /* 204 1.6 riastrad * Create an arena if we haven't already. 205 1.6 riastrad */ 206 1.6 riastrad if ((arena = arenas[type]) == NULL) { 207 1.6 riastrad arena = arenas[type] = kmem_zalloc(sizeof(*arenas[type]), 208 1.6 riastrad KM_SLEEP); 209 1.6 riastrad arena->vmem = vmem_create(pci_resource_typename(type), 210 1.6 riastrad 0, 0, 1, NULL, NULL, NULL, 0, VM_SLEEP, IPL_NONE); 211 1.7 riastrad SIMPLEQ_INIT(&arena->list); 212 1.6 riastrad } 213 1.6 riastrad 214 1.6 riastrad /* 215 1.6 riastrad * Reserve the range in the vmem for allocation. If there's 216 1.6 riastrad * already an overlapping range, just drop this one. 217 1.6 riastrad */ 218 1.6 riastrad error = vmem_add(arena->vmem, start, end - start + 1, VM_SLEEP); 219 1.6 riastrad if (error) { 220 1.6 riastrad /* XXX show some more context */ 221 1.6 riastrad aprint_error("overlapping %s range: %#" PRIx64 "-%#" PRIx64 "," 222 1.6 riastrad " discarding\n", 223 1.6 riastrad pci_resource_typename(type), start, end); 224 1.6 riastrad return; 225 1.6 riastrad } 226 1.6 riastrad 227 1.6 riastrad /* 228 1.6 riastrad * Add an entry to the list so we can iterate over them, in 229 1.6 riastrad * ascending address order for the sake of legible printing. 230 1.6 riastrad * (We don't expect to have so many entries that the linear 231 1.6 riastrad * time of insertion will cause trouble.) 232 1.6 riastrad */ 233 1.6 riastrad new = kmem_zalloc(sizeof(*new), KM_SLEEP); 234 1.6 riastrad new->start = start; 235 1.6 riastrad new->end = end; 236 1.6 riastrad prev = NULL; 237 1.7 riastrad SIMPLEQ_FOREACH(range, &arena->list, entry) { 238 1.6 riastrad if (new->start < range->start) 239 1.6 riastrad break; 240 1.7 riastrad KASSERT(new->start > range->end); 241 1.6 riastrad prev = range; 242 1.6 riastrad } 243 1.6 riastrad if (prev) { 244 1.7 riastrad SIMPLEQ_INSERT_AFTER(&arena->list, prev, new, entry); 245 1.6 riastrad } else { 246 1.7 riastrad SIMPLEQ_INSERT_HEAD(&arena->list, new, entry); 247 1.6 riastrad } 248 1.6 riastrad } 249 1.6 riastrad 250 1.1 jmcneill /* 251 1.6 riastrad * pci_resource_add_range -- 252 1.1 jmcneill * 253 1.6 riastrad * Add a contiguous range of addresses (inclusive of both bounds) for 254 1.6 riastrad * the specified type of resource. 255 1.1 jmcneill */ 256 1.6 riastrad void 257 1.6 riastrad pci_resource_add_range(struct pci_resource_info *info, 258 1.6 riastrad enum pci_range_type type, uint64_t start, uint64_t end) 259 1.1 jmcneill { 260 1.1 jmcneill 261 1.6 riastrad pci_resource_arena_add_range(info->ranges, type, start, end); 262 1.1 jmcneill } 263 1.1 jmcneill 264 1.1 jmcneill /* 265 1.1 jmcneill * pci_new_bus -- 266 1.1 jmcneill * 267 1.1 jmcneill * Create a new PCI bus and initialize its resource ranges. 268 1.1 jmcneill */ 269 1.1 jmcneill static struct pci_bus * 270 1.1 jmcneill pci_new_bus(struct pci_resources *pr, uint8_t busno, struct pci_device *bridge) 271 1.1 jmcneill { 272 1.1 jmcneill struct pci_bus *pb; 273 1.6 riastrad struct pci_resource_arena **ranges; 274 1.1 jmcneill 275 1.1 jmcneill pb = kmem_zalloc(sizeof(*pb), KM_SLEEP); 276 1.1 jmcneill pb->pb_busno = busno; 277 1.1 jmcneill pb->pb_bridge = bridge; 278 1.1 jmcneill if (bridge == NULL) { 279 1.1 jmcneill /* 280 1.1 jmcneill * No additional constraints on resource allocations for 281 1.1 jmcneill * the root bus. 282 1.1 jmcneill */ 283 1.1 jmcneill ranges = pr->pr_ranges; 284 1.1 jmcneill } else { 285 1.1 jmcneill /* 286 1.1 jmcneill * Resource allocations for this bus are constrained by the 287 1.1 jmcneill * bridge forwarding settings. 288 1.1 jmcneill */ 289 1.1 jmcneill ranges = bridge->pd_bridge.ranges; 290 1.1 jmcneill } 291 1.1 jmcneill memcpy(pb->pb_ranges, ranges, sizeof(pb->pb_ranges)); 292 1.1 jmcneill 293 1.1 jmcneill return pb; 294 1.1 jmcneill } 295 1.1 jmcneill 296 1.1 jmcneill /* 297 1.1 jmcneill * pci_resource_device_functions -- 298 1.1 jmcneill * 299 1.1 jmcneill * Returns the number of PCI functions for a a given bus and device. 300 1.1 jmcneill */ 301 1.1 jmcneill static uint8_t 302 1.1 jmcneill pci_resource_device_functions(struct pci_resources *pr, 303 1.1 jmcneill uint8_t busno, uint8_t devno) 304 1.1 jmcneill { 305 1.1 jmcneill struct pci_bus *pb; 306 1.1 jmcneill struct pci_device *pd; 307 1.1 jmcneill 308 1.1 jmcneill pb = PCICONF_RES_BUS(pr, busno); 309 1.1 jmcneill pd = PCICONF_BUS_DEVICE(pb, devno, 0); 310 1.1 jmcneill if (!pd->pd_present) { 311 1.1 jmcneill return 0; 312 1.1 jmcneill } 313 1.1 jmcneill 314 1.1 jmcneill return PCI_HDRTYPE_MULTIFN(pd->pd_bhlc) ? 8 : 1; 315 1.1 jmcneill } 316 1.1 jmcneill 317 1.1 jmcneill /* 318 1.1 jmcneill * pci_resource_device_print -- 319 1.1 jmcneill * 320 1.1 jmcneill * Log details about a device. 321 1.1 jmcneill */ 322 1.1 jmcneill static void 323 1.1 jmcneill pci_resource_device_print(struct pci_resources *pr, 324 1.1 jmcneill struct pci_device *pd) 325 1.1 jmcneill { 326 1.1 jmcneill struct pci_iores *pi; 327 1.6 riastrad struct pci_resource_range *range; 328 1.1 jmcneill u_int res; 329 1.1 jmcneill 330 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " %04x:%04x %02x 0x%06x", 331 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 332 1.1 jmcneill PCI_VENDOR(pd->pd_id), PCI_PRODUCT(pd->pd_id), 333 1.1 jmcneill PCI_REVISION(pd->pd_class), (pd->pd_class >> 8) & 0xffffff); 334 1.1 jmcneill 335 1.1 jmcneill switch (PCI_HDRTYPE_TYPE(pd->pd_bhlc)) { 336 1.1 jmcneill case PCI_HDRTYPE_DEVICE: 337 1.1 jmcneill DPRINT(" (device)\n"); 338 1.1 jmcneill break; 339 1.1 jmcneill case PCI_HDRTYPE_PPB: 340 1.1 jmcneill DPRINT(" (bridge %u -> %u-%u)\n", 341 1.1 jmcneill PCI_BRIDGE_BUS_NUM_PRIMARY(pd->pd_bridge.bridge_bus), 342 1.1 jmcneill PCI_BRIDGE_BUS_NUM_SECONDARY(pd->pd_bridge.bridge_bus), 343 1.1 jmcneill PCI_BRIDGE_BUS_NUM_SUBORDINATE(pd->pd_bridge.bridge_bus)); 344 1.1 jmcneill 345 1.6 riastrad if (pd->pd_bridge.ranges[PCI_RANGE_IO]) { 346 1.7 riastrad SIMPLEQ_FOREACH(range, 347 1.6 riastrad &pd->pd_bridge.ranges[PCI_RANGE_IO]->list, 348 1.6 riastrad entry) { 349 1.6 riastrad DPRINT("PCI: " PCI_SBDF_FMT 350 1.6 riastrad " [bridge] window io " 351 1.6 riastrad " %#" PRIx64 "-%#" PRIx64 352 1.6 riastrad "\n", 353 1.6 riastrad PCI_SBDF_FMT_ARGS(pr, pd), 354 1.6 riastrad range->start, 355 1.6 riastrad range->end); 356 1.6 riastrad } 357 1.6 riastrad } 358 1.6 riastrad if (pd->pd_bridge.ranges[PCI_RANGE_MEM]) { 359 1.7 riastrad SIMPLEQ_FOREACH(range, 360 1.6 riastrad &pd->pd_bridge.ranges[PCI_RANGE_MEM]->list, 361 1.6 riastrad entry) { 362 1.6 riastrad DPRINT("PCI: " PCI_SBDF_FMT 363 1.6 riastrad " [bridge] window mem" 364 1.6 riastrad " %#" PRIx64 "-%#" PRIx64 365 1.6 riastrad " (non-prefetchable)\n", 366 1.6 riastrad PCI_SBDF_FMT_ARGS(pr, pd), 367 1.6 riastrad range->start, 368 1.6 riastrad range->end); 369 1.6 riastrad } 370 1.6 riastrad } 371 1.6 riastrad if (pd->pd_bridge.ranges[PCI_RANGE_PMEM]) { 372 1.7 riastrad SIMPLEQ_FOREACH(range, 373 1.6 riastrad &pd->pd_bridge.ranges[PCI_RANGE_PMEM]->list, 374 1.6 riastrad entry) { 375 1.6 riastrad DPRINT("PCI: " PCI_SBDF_FMT 376 1.6 riastrad " [bridge] window mem" 377 1.6 riastrad " %#" PRIx64 "-%#" PRIx64 378 1.6 riastrad " (prefetchable)\n", 379 1.6 riastrad PCI_SBDF_FMT_ARGS(pr, pd), 380 1.6 riastrad range->start, 381 1.6 riastrad range->end); 382 1.6 riastrad } 383 1.1 jmcneill } 384 1.1 jmcneill 385 1.1 jmcneill break; 386 1.1 jmcneill default: 387 1.1 jmcneill DPRINT(" (0x%02x)\n", PCI_HDRTYPE_TYPE(pd->pd_bhlc)); 388 1.1 jmcneill } 389 1.1 jmcneill 390 1.1 jmcneill for (res = 0; res < pd->pd_niores; res++) { 391 1.1 jmcneill pi = &pd->pd_iores[res]; 392 1.1 jmcneill 393 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT 394 1.1 jmcneill " [device] resource BAR%u: %s @ %#" PRIx64 " size %#" 395 1.1 jmcneill PRIx64, 396 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), pi->pi_bar, 397 1.1 jmcneill pi->pi_type == PCI_MAPREG_TYPE_MEM ? "mem" : "io ", 398 1.1 jmcneill pi->pi_base, pi->pi_size); 399 1.1 jmcneill 400 1.1 jmcneill if (pi->pi_type == PCI_MAPREG_TYPE_MEM) { 401 1.1 jmcneill switch (pi->pi_mem.memtype) { 402 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_32BIT: 403 1.1 jmcneill DPRINT(", 32-bit"); 404 1.1 jmcneill break; 405 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_32BIT_1M: 406 1.1 jmcneill DPRINT(", 32-bit (1M)"); 407 1.1 jmcneill break; 408 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_64BIT: 409 1.1 jmcneill DPRINT(", 64-bit"); 410 1.1 jmcneill break; 411 1.1 jmcneill } 412 1.1 jmcneill DPRINT(" %sprefetchable", 413 1.1 jmcneill pi->pi_mem.prefetch ? "" : "non-"); 414 1.1 jmcneill } 415 1.1 jmcneill DPRINT("\n"); 416 1.1 jmcneill } 417 1.1 jmcneill } 418 1.1 jmcneill 419 1.1 jmcneill /* 420 1.1 jmcneill * pci_resource_scan_bar -- 421 1.1 jmcneill * 422 1.1 jmcneill * Determine the current BAR configuration for a given device. 423 1.1 jmcneill */ 424 1.1 jmcneill static void 425 1.1 jmcneill pci_resource_scan_bar(struct pci_resources *pr, 426 1.1 jmcneill struct pci_device *pd, pcireg_t mapreg_start, pcireg_t mapreg_end, 427 1.1 jmcneill bool is_ppb) 428 1.1 jmcneill { 429 1.1 jmcneill pci_chipset_tag_t pc = pr->pr_pc; 430 1.1 jmcneill pcitag_t tag = pd->pd_tag; 431 1.1 jmcneill pcireg_t mapreg = mapreg_start; 432 1.1 jmcneill pcireg_t ocmd, cmd, bar[2], mask[2]; 433 1.1 jmcneill uint64_t addr, size; 434 1.1 jmcneill struct pci_iores *pi; 435 1.1 jmcneill 436 1.1 jmcneill if (!is_ppb) { 437 1.1 jmcneill ocmd = cmd = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 438 1.1 jmcneill cmd &= ~(PCI_COMMAND_MASTER_ENABLE | 439 1.1 jmcneill PCI_COMMAND_MEM_ENABLE | 440 1.1 jmcneill PCI_COMMAND_IO_ENABLE); 441 1.1 jmcneill pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, cmd); 442 1.1 jmcneill } 443 1.1 jmcneill 444 1.1 jmcneill while (mapreg < mapreg_end) { 445 1.1 jmcneill u_int width = 4; 446 1.1 jmcneill 447 1.1 jmcneill bar[0] = pci_conf_read(pc, tag, mapreg); 448 1.1 jmcneill pci_conf_write(pc, tag, mapreg, 0xffffffff); 449 1.1 jmcneill mask[0] = pci_conf_read(pc, tag, mapreg); 450 1.1 jmcneill pci_conf_write(pc, tag, mapreg, bar[0]); 451 1.1 jmcneill 452 1.1 jmcneill switch (PCI_MAPREG_TYPE(mask[0])) { 453 1.1 jmcneill case PCI_MAPREG_TYPE_MEM: 454 1.1 jmcneill switch (PCI_MAPREG_MEM_TYPE(mask[0])) { 455 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_32BIT: 456 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_32BIT_1M: 457 1.1 jmcneill size = PCI_MAPREG_MEM_SIZE(mask[0]); 458 1.1 jmcneill addr = PCI_MAPREG_MEM_ADDR(bar[0]); 459 1.1 jmcneill break; 460 1.1 jmcneill case PCI_MAPREG_MEM_TYPE_64BIT: 461 1.1 jmcneill bar[1] = pci_conf_read(pc, tag, mapreg + 4); 462 1.1 jmcneill pci_conf_write(pc, tag, mapreg + 4, 0xffffffff); 463 1.1 jmcneill mask[1] = pci_conf_read(pc, tag, mapreg + 4); 464 1.1 jmcneill pci_conf_write(pc, tag, mapreg + 4, bar[1]); 465 1.1 jmcneill 466 1.1 jmcneill size = PCI_MAPREG_MEM64_SIZE( 467 1.1 jmcneill ((uint64_t)mask[1] << 32) | mask[0]); 468 1.1 jmcneill addr = PCI_MAPREG_MEM64_ADDR( 469 1.1 jmcneill ((uint64_t)bar[1] << 32) | bar[0]); 470 1.1 jmcneill width = 8; 471 1.1 jmcneill break; 472 1.1 jmcneill default: 473 1.1 jmcneill size = 0; 474 1.1 jmcneill } 475 1.1 jmcneill if (size > 0) { 476 1.1 jmcneill pi = &pd->pd_iores[pd->pd_niores++]; 477 1.1 jmcneill pi->pi_type = PCI_MAPREG_TYPE_MEM; 478 1.1 jmcneill pi->pi_base = addr; 479 1.1 jmcneill pi->pi_size = size; 480 1.1 jmcneill pi->pi_bar = (mapreg - mapreg_start) / 4; 481 1.1 jmcneill pi->pi_mem.memtype = 482 1.1 jmcneill PCI_MAPREG_MEM_TYPE(mask[0]); 483 1.1 jmcneill pi->pi_mem.prefetch = 484 1.1 jmcneill PCI_MAPREG_MEM_PREFETCHABLE(mask[0]); 485 1.1 jmcneill } 486 1.1 jmcneill break; 487 1.1 jmcneill case PCI_MAPREG_TYPE_IO: 488 1.1 jmcneill size = PCI_MAPREG_IO_SIZE(mask[0] | 0xffff0000); 489 1.1 jmcneill addr = PCI_MAPREG_IO_ADDR(bar[0]); 490 1.1 jmcneill if (size > 0) { 491 1.1 jmcneill pi = &pd->pd_iores[pd->pd_niores++]; 492 1.1 jmcneill pi->pi_type = PCI_MAPREG_TYPE_IO; 493 1.1 jmcneill pi->pi_base = addr; 494 1.1 jmcneill pi->pi_size = size; 495 1.1 jmcneill pi->pi_bar = (mapreg - mapreg_start) / 4; 496 1.1 jmcneill } 497 1.1 jmcneill break; 498 1.1 jmcneill } 499 1.1 jmcneill 500 1.1 jmcneill KASSERT(pd->pd_niores <= PCI_MAX_IORES); 501 1.1 jmcneill 502 1.1 jmcneill mapreg += width; 503 1.1 jmcneill } 504 1.1 jmcneill 505 1.1 jmcneill if (!is_ppb) { 506 1.1 jmcneill pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, ocmd); 507 1.1 jmcneill } 508 1.1 jmcneill } 509 1.1 jmcneill 510 1.1 jmcneill /* 511 1.1 jmcneill * pci_resource_scan_bridge -- 512 1.1 jmcneill * 513 1.1 jmcneill * Determine the current configuration of a PCI-PCI bridge. 514 1.1 jmcneill */ 515 1.1 jmcneill static void 516 1.1 jmcneill pci_resource_scan_bridge(struct pci_resources *pr, 517 1.1 jmcneill struct pci_device *pd) 518 1.1 jmcneill { 519 1.1 jmcneill pci_chipset_tag_t pc = pr->pr_pc; 520 1.1 jmcneill pcitag_t tag = pd->pd_tag; 521 1.1 jmcneill pcireg_t res, reshigh; 522 1.6 riastrad uint64_t iostart, ioend; 523 1.6 riastrad uint64_t memstart, memend; 524 1.6 riastrad uint64_t pmemstart, pmemend; 525 1.1 jmcneill 526 1.1 jmcneill pd->pd_ppb = true; 527 1.1 jmcneill 528 1.1 jmcneill res = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG); 529 1.1 jmcneill pd->pd_bridge.bridge_bus = res; 530 1.6 riastrad pci_resource_arena_add_range(pd->pd_bridge.ranges, 531 1.6 riastrad PCI_RANGE_BUS, 532 1.6 riastrad PCI_BRIDGE_BUS_NUM_SECONDARY(res), 533 1.6 riastrad PCI_BRIDGE_BUS_NUM_SUBORDINATE(res)); 534 1.1 jmcneill 535 1.1 jmcneill res = pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG); 536 1.6 riastrad iostart = PCI_BRIDGE_STATIO_IOBASE_ADDR(res); 537 1.6 riastrad ioend = PCI_BRIDGE_STATIO_IOLIMIT_ADDR(res); 538 1.1 jmcneill if (PCI_BRIDGE_IO_32BITS(res)) { 539 1.1 jmcneill reshigh = pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG); 540 1.6 riastrad iostart |= __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_BASE) << 16; 541 1.6 riastrad ioend |= __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_LIMIT) << 16; 542 1.6 riastrad } 543 1.6 riastrad if (iostart < ioend) { 544 1.6 riastrad pci_resource_arena_add_range(pd->pd_bridge.ranges, 545 1.6 riastrad PCI_RANGE_IO, iostart, ioend); 546 1.1 jmcneill } 547 1.1 jmcneill 548 1.1 jmcneill res = pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG); 549 1.6 riastrad memstart = PCI_BRIDGE_MEMORY_BASE_ADDR(res); 550 1.6 riastrad memend = PCI_BRIDGE_MEMORY_LIMIT_ADDR(res); 551 1.6 riastrad if (memstart < memend) { 552 1.6 riastrad pci_resource_arena_add_range(pd->pd_bridge.ranges, 553 1.6 riastrad PCI_RANGE_MEM, memstart, memend); 554 1.1 jmcneill } 555 1.1 jmcneill 556 1.1 jmcneill res = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG); 557 1.6 riastrad pmemstart = PCI_BRIDGE_PREFETCHMEM_BASE_ADDR(res); 558 1.6 riastrad pmemend = PCI_BRIDGE_PREFETCHMEM_LIMIT_ADDR(res); 559 1.1 jmcneill if (PCI_BRIDGE_PREFETCHMEM_64BITS(res)) { 560 1.1 jmcneill reshigh = pci_conf_read(pc, tag, 561 1.1 jmcneill PCI_BRIDGE_PREFETCHBASEUP32_REG); 562 1.6 riastrad pmemstart |= (uint64_t)reshigh << 32; 563 1.1 jmcneill reshigh = pci_conf_read(pc, tag, 564 1.1 jmcneill PCI_BRIDGE_PREFETCHLIMITUP32_REG); 565 1.6 riastrad pmemend |= (uint64_t)reshigh << 32; 566 1.1 jmcneill } 567 1.6 riastrad if (pmemstart < pmemend) { 568 1.6 riastrad pci_resource_arena_add_range(pd->pd_bridge.ranges, 569 1.6 riastrad PCI_RANGE_PMEM, pmemstart, pmemend); 570 1.1 jmcneill } 571 1.1 jmcneill } 572 1.1 jmcneill 573 1.1 jmcneill /* 574 1.1 jmcneill * pci_resource_scan_device -- 575 1.1 jmcneill * 576 1.1 jmcneill * Determine the current configuration of a PCI device. 577 1.1 jmcneill */ 578 1.1 jmcneill static bool 579 1.1 jmcneill pci_resource_scan_device(struct pci_resources *pr, 580 1.1 jmcneill struct pci_bus *parent_bus, uint8_t devno, uint8_t funcno) 581 1.1 jmcneill { 582 1.1 jmcneill struct pci_device *pd; 583 1.1 jmcneill pcitag_t tag; 584 1.1 jmcneill pcireg_t id, bridge_bus; 585 1.1 jmcneill uint8_t sec_bus; 586 1.1 jmcneill 587 1.1 jmcneill tag = pci_make_tag(pr->pr_pc, parent_bus->pb_busno, devno, funcno); 588 1.1 jmcneill id = pci_conf_read(pr->pr_pc, tag, PCI_ID_REG); 589 1.1 jmcneill if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) { 590 1.1 jmcneill return false; 591 1.1 jmcneill } 592 1.1 jmcneill 593 1.1 jmcneill pd = PCICONF_BUS_DEVICE(parent_bus, devno, funcno); 594 1.1 jmcneill pd->pd_present = true; 595 1.1 jmcneill pd->pd_bus = parent_bus; 596 1.1 jmcneill pd->pd_tag = tag; 597 1.1 jmcneill pd->pd_devno = devno; 598 1.1 jmcneill pd->pd_funcno = funcno; 599 1.1 jmcneill pd->pd_id = id; 600 1.1 jmcneill pd->pd_class = pci_conf_read(pr->pr_pc, tag, PCI_CLASS_REG); 601 1.1 jmcneill pd->pd_bhlc = pci_conf_read(pr->pr_pc, tag, PCI_BHLC_REG); 602 1.1 jmcneill 603 1.1 jmcneill switch (PCI_HDRTYPE_TYPE(pd->pd_bhlc)) { 604 1.1 jmcneill case PCI_HDRTYPE_DEVICE: 605 1.1 jmcneill pci_resource_scan_bar(pr, pd, PCI_MAPREG_START, 606 1.1 jmcneill PCI_MAPREG_END, false); 607 1.1 jmcneill break; 608 1.1 jmcneill case PCI_HDRTYPE_PPB: 609 1.1 jmcneill pci_resource_scan_bar(pr, pd, PCI_MAPREG_START, 610 1.1 jmcneill PCI_MAPREG_PPB_END, true); 611 1.1 jmcneill pci_resource_scan_bridge(pr, pd); 612 1.1 jmcneill break; 613 1.1 jmcneill } 614 1.1 jmcneill 615 1.1 jmcneill pci_resource_device_print(pr, pd); 616 1.1 jmcneill 617 1.1 jmcneill if (PCI_HDRTYPE_TYPE(pd->pd_bhlc) == PCI_HDRTYPE_PPB && 618 1.1 jmcneill PCI_CLASS(pd->pd_class) == PCI_CLASS_BRIDGE && 619 1.1 jmcneill PCI_SUBCLASS(pd->pd_class) == PCI_SUBCLASS_BRIDGE_PCI) { 620 1.1 jmcneill bridge_bus = pci_conf_read(pr->pr_pc, tag, PCI_BRIDGE_BUS_REG); 621 1.1 jmcneill sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(bridge_bus); 622 1.7 riastrad if (pci_bus_in_range(pr, sec_bus)) { 623 1.5 jmcneill if (pci_resource_scan_bus(pr, pd, sec_bus) != 0) { 624 1.5 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " bus %u " 625 1.5 jmcneill "already scanned (firmware bug!)\n", 626 1.5 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), sec_bus); 627 1.5 jmcneill } 628 1.7 riastrad } else { 629 1.7 riastrad DPRINT("PCI: " PCI_SBDF_FMT " bus %u " 630 1.7 riastrad "out of range (firmware bug!)\n", 631 1.7 riastrad PCI_SBDF_FMT_ARGS(pr, pd), sec_bus); 632 1.1 jmcneill } 633 1.1 jmcneill } 634 1.1 jmcneill 635 1.1 jmcneill return true; 636 1.1 jmcneill } 637 1.1 jmcneill 638 1.1 jmcneill /* 639 1.1 jmcneill * pci_resource_scan_bus -- 640 1.1 jmcneill * 641 1.1 jmcneill * Enumerate devices on a bus, recursively. 642 1.1 jmcneill */ 643 1.5 jmcneill static int 644 1.1 jmcneill pci_resource_scan_bus(struct pci_resources *pr, 645 1.1 jmcneill struct pci_device *bridge_dev, uint8_t busno) 646 1.1 jmcneill { 647 1.1 jmcneill struct pci_bus *pb; 648 1.1 jmcneill uint8_t devno, funcno; 649 1.1 jmcneill uint8_t nfunc; 650 1.1 jmcneill 651 1.1 jmcneill KASSERT(busno >= pr->pr_startbus); 652 1.7 riastrad KASSERT(pci_bus_in_range(pr, busno)); 653 1.1 jmcneill 654 1.1 jmcneill if (PCICONF_RES_BUS(pr, busno) != NULL) { 655 1.1 jmcneill /* 656 1.1 jmcneill * Firmware has configured more than one bridge with the 657 1.1 jmcneill * same secondary bus number. 658 1.1 jmcneill */ 659 1.5 jmcneill return EINVAL; 660 1.1 jmcneill } 661 1.1 jmcneill 662 1.1 jmcneill pb = pci_new_bus(pr, busno, bridge_dev); 663 1.1 jmcneill PCICONF_RES_BUS(pr, busno) = pb; 664 1.1 jmcneill 665 1.1 jmcneill for (devno = 0; devno < PCI_MAX_DEVICE; devno++) { 666 1.1 jmcneill if (!pci_resource_scan_device(pr, pb, devno, 0)) { 667 1.1 jmcneill continue; 668 1.1 jmcneill } 669 1.1 jmcneill pb->pb_lastdevno = devno; 670 1.1 jmcneill 671 1.1 jmcneill nfunc = pci_resource_device_functions(pr, busno, devno); 672 1.1 jmcneill for (funcno = 1; funcno < nfunc; funcno++) { 673 1.1 jmcneill pci_resource_scan_device(pr, pb, devno, funcno); 674 1.1 jmcneill } 675 1.1 jmcneill } 676 1.5 jmcneill 677 1.5 jmcneill return 0; 678 1.1 jmcneill } 679 1.1 jmcneill 680 1.1 jmcneill /* 681 1.1 jmcneill * pci_resource_claim -- 682 1.1 jmcneill * 683 1.1 jmcneill * Claim a resource from a vmem arena. This is called to inform the 684 1.1 jmcneill * resource manager about resources already configured by system firmware. 685 1.1 jmcneill */ 686 1.1 jmcneill static int 687 1.6 riastrad pci_resource_claim(struct pci_resource_arena *arena, 688 1.6 riastrad vmem_addr_t start, vmem_addr_t end) 689 1.1 jmcneill { 690 1.1 jmcneill KASSERT(end >= start); 691 1.1 jmcneill 692 1.6 riastrad return vmem_xalloc(arena->vmem, end - start + 1, 0, 0, 0, start, end, 693 1.1 jmcneill VM_BESTFIT | VM_NOSLEEP, NULL); 694 1.1 jmcneill } 695 1.1 jmcneill 696 1.1 jmcneill /* 697 1.1 jmcneill * pci_resource_alloc -- 698 1.1 jmcneill * 699 1.1 jmcneill * Allocate a resource from a vmem arena. This is called when configuring 700 1.1 jmcneill * devices that were not already configured by system firmware. 701 1.1 jmcneill */ 702 1.3 riastrad static int 703 1.6 riastrad pci_resource_alloc(struct pci_resource_arena *arena, vmem_size_t size, 704 1.6 riastrad vmem_size_t align, 705 1.1 jmcneill uint64_t *base) 706 1.1 jmcneill { 707 1.1 jmcneill vmem_addr_t addr; 708 1.1 jmcneill int error; 709 1.1 jmcneill 710 1.1 jmcneill KASSERT(size != 0); 711 1.1 jmcneill 712 1.6 riastrad error = vmem_xalloc(arena->vmem, size, align, 0, 0, VMEM_ADDR_MIN, 713 1.1 jmcneill VMEM_ADDR_MAX, VM_BESTFIT | VM_NOSLEEP, &addr); 714 1.1 jmcneill if (error == 0) { 715 1.1 jmcneill *base = (uint64_t)addr; 716 1.1 jmcneill } 717 1.1 jmcneill 718 1.1 jmcneill return error; 719 1.1 jmcneill } 720 1.1 jmcneill 721 1.1 jmcneill /* 722 1.1 jmcneill * pci_resource_init_device -- 723 1.1 jmcneill * 724 1.1 jmcneill * Discover resources assigned by system firmware, notify the resource 725 1.1 jmcneill * manager of these ranges, and determine if the device has additional 726 1.1 jmcneill * resources that need to be allocated. 727 1.1 jmcneill */ 728 1.1 jmcneill static void 729 1.1 jmcneill pci_resource_init_device(struct pci_resources *pr, 730 1.1 jmcneill struct pci_device *pd) 731 1.1 jmcneill { 732 1.1 jmcneill struct pci_iores *pi; 733 1.1 jmcneill struct pci_bus *pb = pd->pd_bus; 734 1.6 riastrad struct pci_resource_arena *res_io = pb->pb_res[PCI_RANGE_IO]; 735 1.6 riastrad struct pci_resource_arena *res_mem = pb->pb_res[PCI_RANGE_MEM]; 736 1.6 riastrad struct pci_resource_arena *res_pmem = pb->pb_res[PCI_RANGE_PMEM]; 737 1.1 jmcneill pcireg_t cmd; 738 1.1 jmcneill u_int enabled, required; 739 1.1 jmcneill u_int iores; 740 1.1 jmcneill int error; 741 1.1 jmcneill 742 1.1 jmcneill KASSERT(pd->pd_present); 743 1.1 jmcneill 744 1.1 jmcneill if (IS_TEST_DEVICE(pd)) { 745 1.1 jmcneill cmd = pci_conf_read(pr->pr_pc, pd->pd_tag, 746 1.1 jmcneill PCI_COMMAND_STATUS_REG); 747 1.1 jmcneill cmd &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE| 748 1.1 jmcneill PCI_COMMAND_MASTER_ENABLE); 749 1.1 jmcneill pci_conf_write(pr->pr_pc, pd->pd_tag, PCI_COMMAND_STATUS_REG, 750 1.1 jmcneill cmd); 751 1.1 jmcneill } 752 1.1 jmcneill 753 1.1 jmcneill enabled = required = 0; 754 1.1 jmcneill cmd = pci_conf_read(pr->pr_pc, pd->pd_tag, PCI_COMMAND_STATUS_REG); 755 1.1 jmcneill if ((cmd & PCI_COMMAND_MEM_ENABLE) != 0) { 756 1.1 jmcneill enabled |= __BIT(PCI_MAPREG_TYPE_MEM); 757 1.1 jmcneill } 758 1.1 jmcneill if ((cmd & PCI_COMMAND_IO_ENABLE) != 0) { 759 1.1 jmcneill enabled |= __BIT(PCI_MAPREG_TYPE_IO); 760 1.1 jmcneill } 761 1.1 jmcneill 762 1.1 jmcneill for (iores = 0; iores < pd->pd_niores; iores++) { 763 1.1 jmcneill pi = &pd->pd_iores[iores]; 764 1.1 jmcneill 765 1.1 jmcneill required |= __BIT(pi->pi_type); 766 1.1 jmcneill 767 1.1 jmcneill if (IS_TEST_DEVICE(pd)) { 768 1.1 jmcneill pci_conf_write(pr->pr_pc, pd->pd_tag, 769 1.1 jmcneill PCI_BAR(pi->pi_bar), 0); 770 1.1 jmcneill continue; 771 1.1 jmcneill } 772 1.1 jmcneill if ((enabled & __BIT(pi->pi_type)) == 0) { 773 1.1 jmcneill continue; 774 1.1 jmcneill } 775 1.1 jmcneill 776 1.1 jmcneill if (pi->pi_type == PCI_MAPREG_TYPE_IO) { 777 1.1 jmcneill error = res_io == NULL ? ERANGE : 778 1.1 jmcneill pci_resource_claim(res_io, pi->pi_base, 779 1.1 jmcneill pi->pi_base + pi->pi_size - 1); 780 1.1 jmcneill if (error) { 781 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " [device] io " 782 1.1 jmcneill " %#" PRIx64 "-%#" PRIx64 783 1.1 jmcneill " invalid (%d)\n", 784 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 785 1.1 jmcneill pi->pi_base, 786 1.1 jmcneill pi->pi_base + pi->pi_size - 1, 787 1.1 jmcneill error); 788 1.1 jmcneill } 789 1.1 jmcneill continue; 790 1.1 jmcneill } 791 1.1 jmcneill 792 1.1 jmcneill KASSERT(pi->pi_type == PCI_MAPREG_TYPE_MEM); 793 1.1 jmcneill error = ERANGE; 794 1.4 jmcneill if (pi->pi_mem.prefetch) { 795 1.4 jmcneill /* 796 1.4 jmcneill * Prefetchable memory must be allocated from the 797 1.4 jmcneill * bridge's prefetchable region. 798 1.4 jmcneill */ 799 1.4 jmcneill if (res_pmem != NULL) { 800 1.4 jmcneill error = pci_resource_claim(res_pmem, pi->pi_base, 801 1.4 jmcneill pi->pi_base + pi->pi_size - 1); 802 1.4 jmcneill } 803 1.4 jmcneill } else if (pi->pi_mem.memtype == PCI_MAPREG_MEM_TYPE_64BIT) { 804 1.4 jmcneill /* 805 1.4 jmcneill * Non-prefetchable 64-bit memory can be allocated from 806 1.4 jmcneill * any range. Prefer allocations from the prefetchable 807 1.4 jmcneill * region to save 32-bit only resources for 32-bit BARs. 808 1.4 jmcneill */ 809 1.4 jmcneill if (res_pmem != NULL) { 810 1.4 jmcneill error = pci_resource_claim(res_pmem, pi->pi_base, 811 1.4 jmcneill pi->pi_base + pi->pi_size - 1); 812 1.4 jmcneill } 813 1.4 jmcneill if (error && res_mem != NULL) { 814 1.4 jmcneill error = pci_resource_claim(res_mem, pi->pi_base, 815 1.4 jmcneill pi->pi_base + pi->pi_size - 1); 816 1.4 jmcneill } 817 1.4 jmcneill } else { 818 1.4 jmcneill /* 819 1.4 jmcneill * Non-prefetchable 32-bit memory can be allocated from 820 1.4 jmcneill * any range, provided that the range is below 4GB. Try 821 1.4 jmcneill * the non-prefetchable range first, and if that fails, 822 1.4 jmcneill * make one last attempt at allocating from the 823 1.4 jmcneill * prefetchable range in case the platform provides 824 1.4 jmcneill * memory below 4GB. 825 1.4 jmcneill */ 826 1.4 jmcneill if (res_mem != NULL) { 827 1.4 jmcneill error = pci_resource_claim(res_mem, pi->pi_base, 828 1.4 jmcneill pi->pi_base + pi->pi_size - 1); 829 1.4 jmcneill } 830 1.4 jmcneill if (error && res_pmem != NULL) { 831 1.4 jmcneill error = pci_resource_claim(res_pmem, pi->pi_base, 832 1.4 jmcneill pi->pi_base + pi->pi_size - 1); 833 1.4 jmcneill } 834 1.1 jmcneill } 835 1.1 jmcneill if (error) { 836 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " [device] mem" 837 1.1 jmcneill " (%sprefetchable)" 838 1.1 jmcneill " %#" PRIx64 "-%#" PRIx64 839 1.1 jmcneill " invalid (%d)\n", 840 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 841 1.1 jmcneill pi->pi_mem.prefetch ? "" : "non-", 842 1.1 jmcneill pi->pi_base, 843 1.1 jmcneill pi->pi_base + pi->pi_size - 1, 844 1.1 jmcneill error); 845 1.1 jmcneill } 846 1.1 jmcneill } 847 1.1 jmcneill 848 1.1 jmcneill pd->pd_configured = (enabled & required) == required; 849 1.1 jmcneill 850 1.1 jmcneill if (!pd->pd_configured) { 851 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " [device] " 852 1.1 jmcneill "not configured by firmware\n", 853 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd)); 854 1.1 jmcneill } 855 1.1 jmcneill } 856 1.1 jmcneill 857 1.1 jmcneill /* 858 1.1 jmcneill * pci_resource_init_bus -- 859 1.1 jmcneill * 860 1.1 jmcneill * Discover resources in use on a given bus, recursively. 861 1.1 jmcneill */ 862 1.1 jmcneill static void 863 1.1 jmcneill pci_resource_init_bus(struct pci_resources *pr, uint8_t busno) 864 1.1 jmcneill { 865 1.1 jmcneill struct pci_bus *pb, *parent_bus; 866 1.1 jmcneill struct pci_device *pd, *bridge; 867 1.1 jmcneill uint8_t devno, funcno; 868 1.1 jmcneill uint8_t nfunc; 869 1.1 jmcneill int error; 870 1.1 jmcneill 871 1.1 jmcneill KASSERT(busno >= pr->pr_startbus); 872 1.7 riastrad KASSERT(pci_bus_in_range(pr, busno)); 873 1.1 jmcneill 874 1.1 jmcneill pb = PCICONF_RES_BUS(pr, busno); 875 1.1 jmcneill bridge = pb->pb_bridge; 876 1.1 jmcneill 877 1.1 jmcneill KASSERT(pb != NULL); 878 1.1 jmcneill KASSERT((busno == pr->pr_startbus) == (bridge == NULL)); 879 1.1 jmcneill 880 1.1 jmcneill if (bridge == NULL) { 881 1.1 jmcneill /* Use resources provided by firmware. */ 882 1.1 jmcneill PCI_RANGE_FOREACH(prtype) { 883 1.6 riastrad pb->pb_res[prtype] = pr->pr_ranges[prtype]; 884 1.6 riastrad pr->pr_ranges[prtype] = NULL; 885 1.1 jmcneill } 886 1.1 jmcneill } else { 887 1.1 jmcneill /* 888 1.1 jmcneill * Using the resources configured in to the bridge by 889 1.1 jmcneill * firmware, claim the resources on the parent bus and 890 1.1 jmcneill * create a new vmem arena for the secondary bus. 891 1.1 jmcneill */ 892 1.1 jmcneill KASSERT(bridge->pd_bus != NULL); 893 1.1 jmcneill parent_bus = bridge->pd_bus; 894 1.1 jmcneill PCI_RANGE_FOREACH(prtype) { 895 1.6 riastrad struct pci_resource_range *range; 896 1.6 riastrad 897 1.1 jmcneill if (parent_bus->pb_res[prtype] == NULL || 898 1.6 riastrad bridge->pd_bridge.ranges[prtype] == NULL) { 899 1.1 jmcneill continue; 900 1.1 jmcneill } 901 1.7 riastrad SIMPLEQ_FOREACH(range, 902 1.6 riastrad &bridge->pd_bridge.ranges[prtype]->list, 903 1.6 riastrad entry) { 904 1.6 riastrad error = pci_resource_claim( 905 1.6 riastrad parent_bus->pb_res[prtype], 906 1.6 riastrad range->start, range->end); 907 1.6 riastrad if (error) { 908 1.6 riastrad DPRINT("PCI: " PCI_SBDF_FMT 909 1.6 riastrad " bridge (bus %u)" 910 1.6 riastrad " %-4s %#" PRIx64 "-%#" PRIx64 911 1.6 riastrad " invalid\n", 912 1.6 riastrad PCI_SBDF_FMT_ARGS(pr, bridge), 913 1.6 riastrad busno, 914 1.6 riastrad pci_resource_typename(prtype), 915 1.6 riastrad range->start, range->end); 916 1.6 riastrad continue; 917 1.6 riastrad } 918 1.6 riastrad pci_resource_arena_add_range( 919 1.6 riastrad pb->pb_res, prtype, 920 1.6 riastrad range->start, range->end); 921 1.1 jmcneill KASSERT(pb->pb_res[prtype] != NULL); 922 1.1 jmcneill } 923 1.1 jmcneill } 924 1.1 jmcneill } 925 1.1 jmcneill 926 1.1 jmcneill for (devno = 0; devno <= pb->pb_lastdevno; devno++) { 927 1.1 jmcneill KASSERT(devno < PCI_MAX_DEVICE); 928 1.1 jmcneill nfunc = pci_resource_device_functions(pr, busno, devno); 929 1.1 jmcneill for (funcno = 0; funcno < nfunc; funcno++) { 930 1.1 jmcneill pd = PCICONF_BUS_DEVICE(pb, devno, funcno); 931 1.1 jmcneill if (!pd->pd_present) { 932 1.1 jmcneill continue; 933 1.1 jmcneill } 934 1.1 jmcneill if (pd->pd_ppb) { 935 1.1 jmcneill uint8_t sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY( 936 1.1 jmcneill pd->pd_bridge.bridge_bus); 937 1.7 riastrad KASSERT(pci_bus_in_range(pr, sec_bus)); 938 1.1 jmcneill pci_resource_init_bus(pr, sec_bus); 939 1.1 jmcneill } 940 1.1 jmcneill pci_resource_init_device(pr, pd); 941 1.1 jmcneill } 942 1.1 jmcneill } 943 1.1 jmcneill } 944 1.1 jmcneill 945 1.1 jmcneill /* 946 1.1 jmcneill * pci_resource_probe -- 947 1.1 jmcneill * 948 1.1 jmcneill * Scan for PCI devices and initialize the resource manager. 949 1.1 jmcneill */ 950 1.1 jmcneill static void 951 1.1 jmcneill pci_resource_probe(struct pci_resources *pr, 952 1.1 jmcneill const struct pci_resource_info *info) 953 1.1 jmcneill { 954 1.6 riastrad struct pci_resource_arena *busarena = info->ranges[PCI_RANGE_BUS]; 955 1.7 riastrad uint8_t startbus = SIMPLEQ_FIRST(&busarena->list)->start; 956 1.7 riastrad uint8_t endbus = SIMPLEQ_LAST(&busarena->list, pci_resource_range, 957 1.7 riastrad entry)->end; 958 1.1 jmcneill u_int nbus; 959 1.1 jmcneill 960 1.1 jmcneill KASSERT(startbus <= endbus); 961 1.1 jmcneill KASSERT(pr->pr_bus == NULL); 962 1.1 jmcneill 963 1.1 jmcneill nbus = endbus - startbus + 1; 964 1.1 jmcneill 965 1.1 jmcneill pr->pr_pc = info->pc; 966 1.1 jmcneill pr->pr_startbus = startbus; 967 1.7 riastrad pr->pr_busranges = busarena; 968 1.7 riastrad pr->pr_bus = kmem_zalloc(nbus * sizeof(pr->pr_bus[0]), KM_SLEEP); 969 1.1 jmcneill memcpy(pr->pr_ranges, info->ranges, sizeof(pr->pr_ranges)); 970 1.1 jmcneill 971 1.1 jmcneill /* Scan devices */ 972 1.1 jmcneill pci_resource_scan_bus(pr, NULL, pr->pr_startbus); 973 1.1 jmcneill 974 1.1 jmcneill /* 975 1.1 jmcneill * Create per-bus resource pools and remove ranges that are already 976 1.1 jmcneill * in use by devices and downstream bridges. 977 1.1 jmcneill */ 978 1.1 jmcneill pci_resource_init_bus(pr, pr->pr_startbus); 979 1.1 jmcneill } 980 1.1 jmcneill 981 1.1 jmcneill /* 982 1.1 jmcneill * pci_resource_alloc_device -- 983 1.1 jmcneill * 984 1.1 jmcneill * Attempt to allocate resources for a given device. 985 1.1 jmcneill */ 986 1.1 jmcneill static void 987 1.1 jmcneill pci_resource_alloc_device(struct pci_resources *pr, struct pci_device *pd) 988 1.1 jmcneill { 989 1.1 jmcneill struct pci_iores *pi; 990 1.6 riastrad struct pci_resource_arena *arena; 991 1.1 jmcneill pcireg_t cmd, ocmd, base; 992 1.1 jmcneill uint64_t addr; 993 1.1 jmcneill u_int enabled; 994 1.1 jmcneill u_int res; 995 1.1 jmcneill u_int align; 996 1.1 jmcneill int error; 997 1.1 jmcneill 998 1.1 jmcneill enabled = 0; 999 1.1 jmcneill ocmd = cmd = pci_conf_read(pr->pr_pc, pd->pd_tag, 1000 1.1 jmcneill PCI_COMMAND_STATUS_REG); 1001 1.1 jmcneill if ((cmd & PCI_COMMAND_MEM_ENABLE) != 0) { 1002 1.1 jmcneill enabled |= __BIT(PCI_MAPREG_TYPE_MEM); 1003 1.1 jmcneill } 1004 1.1 jmcneill if ((cmd & PCI_COMMAND_IO_ENABLE) != 0) { 1005 1.1 jmcneill enabled |= __BIT(PCI_MAPREG_TYPE_IO); 1006 1.1 jmcneill } 1007 1.1 jmcneill 1008 1.1 jmcneill for (res = 0; res < pd->pd_niores; res++) { 1009 1.1 jmcneill pi = &pd->pd_iores[res]; 1010 1.1 jmcneill 1011 1.1 jmcneill if ((enabled & __BIT(pi->pi_type)) != 0) { 1012 1.1 jmcneill continue; 1013 1.1 jmcneill } 1014 1.1 jmcneill 1015 1.1 jmcneill if (pi->pi_type == PCI_MAPREG_TYPE_IO) { 1016 1.1 jmcneill arena = pd->pd_bus->pb_res[PCI_RANGE_IO]; 1017 1.1 jmcneill align = uimax(pi->pi_size, 4); 1018 1.1 jmcneill } else { 1019 1.1 jmcneill KASSERT(pi->pi_type == PCI_MAPREG_TYPE_MEM); 1020 1.1 jmcneill arena = NULL; 1021 1.1 jmcneill align = uimax(pi->pi_size, 16); 1022 1.1 jmcneill if (pi->pi_mem.prefetch) { 1023 1.1 jmcneill arena = pd->pd_bus->pb_res[PCI_RANGE_PMEM]; 1024 1.1 jmcneill } 1025 1.1 jmcneill if (arena == NULL) { 1026 1.1 jmcneill arena = pd->pd_bus->pb_res[PCI_RANGE_MEM]; 1027 1.1 jmcneill } 1028 1.1 jmcneill } 1029 1.1 jmcneill if (arena == NULL) { 1030 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " BAR%u failed to" 1031 1.1 jmcneill " allocate %#" PRIx64 " bytes (no arena)\n", 1032 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 1033 1.1 jmcneill pi->pi_bar, pi->pi_size); 1034 1.1 jmcneill return; 1035 1.1 jmcneill } 1036 1.1 jmcneill error = pci_resource_alloc(arena, pi->pi_size, align, &addr); 1037 1.1 jmcneill if (error != 0) { 1038 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " BAR%u failed to" 1039 1.1 jmcneill " allocate %#" PRIx64 " bytes (no space)\n", 1040 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 1041 1.1 jmcneill pi->pi_bar, pi->pi_size); 1042 1.1 jmcneill return; 1043 1.1 jmcneill } 1044 1.1 jmcneill DPRINT("PCI: " PCI_SBDF_FMT " BAR%u assigned range" 1045 1.6 riastrad " %#" PRIx64 "-%#" PRIx64 "\n", 1046 1.1 jmcneill PCI_SBDF_FMT_ARGS(pr, pd), 1047 1.1 jmcneill pi->pi_bar, addr, addr + pi->pi_size - 1); 1048 1.1 jmcneill 1049 1.1 jmcneill if (pi->pi_type == PCI_MAPREG_TYPE_IO) { 1050 1.1 jmcneill cmd |= PCI_COMMAND_IO_ENABLE; 1051 1.1 jmcneill pci_conf_write(pr->pr_pc, pd->pd_tag, 1052 1.1 jmcneill PCI_BAR(pi->pi_bar), 1053 1.1 jmcneill PCI_MAPREG_IO_ADDR(addr) | PCI_MAPREG_TYPE_IO); 1054 1.1 jmcneill } else { 1055 1.1 jmcneill cmd |= PCI_COMMAND_MEM_ENABLE; 1056 1.1 jmcneill base = pci_conf_read(pr->pr_pc, pd->pd_tag, 1057 1.1 jmcneill PCI_BAR(pi->pi_bar)); 1058 1.1 jmcneill base = PCI_MAPREG_MEM_ADDR(addr) | 1059 1.1 jmcneill PCI_MAPREG_MEM_TYPE(base); 1060 1.1 jmcneill pci_conf_write(pr->pr_pc, pd->pd_tag, 1061 1.1 jmcneill PCI_BAR(pi->pi_bar), base); 1062 1.1 jmcneill if (pi->pi_mem.memtype == PCI_MAPREG_MEM_TYPE_64BIT) { 1063 1.3 riastrad base = (pcireg_t) 1064 1.3 riastrad (PCI_MAPREG_MEM64_ADDR(addr) >> 32); 1065 1.3 riastrad pci_conf_write(pr->pr_pc, pd->pd_tag, 1066 1.1 jmcneill PCI_BAR(pi->pi_bar + 1), base); 1067 1.1 jmcneill } 1068 1.1 jmcneill } 1069 1.1 jmcneill } 1070 1.1 jmcneill 1071 1.1 jmcneill if (ocmd != cmd) { 1072 1.1 jmcneill pci_conf_write(pr->pr_pc, pd->pd_tag, 1073 1.1 jmcneill PCI_COMMAND_STATUS_REG, cmd); 1074 1.1 jmcneill } 1075 1.1 jmcneill } 1076 1.1 jmcneill 1077 1.1 jmcneill /* 1078 1.1 jmcneill * pci_resource_alloc_bus -- 1079 1.1 jmcneill * 1080 1.1 jmcneill * Attempt to assign resources to all devices on a given bus, recursively. 1081 1.1 jmcneill */ 1082 1.1 jmcneill static void 1083 1.1 jmcneill pci_resource_alloc_bus(struct pci_resources *pr, uint8_t busno) 1084 1.1 jmcneill { 1085 1.1 jmcneill struct pci_bus *pb = PCICONF_RES_BUS(pr, busno); 1086 1.1 jmcneill struct pci_device *pd; 1087 1.1 jmcneill uint8_t devno, funcno; 1088 1.1 jmcneill 1089 1.1 jmcneill for (devno = 0; devno <= pb->pb_lastdevno; devno++) { 1090 1.1 jmcneill for (funcno = 0; funcno < 8; funcno++) { 1091 1.1 jmcneill pd = PCICONF_BUS_DEVICE(pb, devno, funcno); 1092 1.1 jmcneill if (!pd->pd_present) { 1093 1.1 jmcneill if (funcno == 0) { 1094 1.1 jmcneill break; 1095 1.1 jmcneill } 1096 1.1 jmcneill continue; 1097 1.1 jmcneill } 1098 1.1 jmcneill if (!pd->pd_configured) { 1099 1.1 jmcneill pci_resource_alloc_device(pr, pd); 1100 1.1 jmcneill } 1101 1.1 jmcneill if (pd->pd_ppb) { 1102 1.1 jmcneill uint8_t sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY( 1103 1.1 jmcneill pd->pd_bridge.bridge_bus); 1104 1.1 jmcneill pci_resource_alloc_bus(pr, sec_bus); 1105 1.1 jmcneill } 1106 1.1 jmcneill } 1107 1.1 jmcneill } 1108 1.1 jmcneill } 1109 1.1 jmcneill 1110 1.1 jmcneill /* 1111 1.1 jmcneill * pci_resource_init -- 1112 1.1 jmcneill * 1113 1.1 jmcneill * Public interface to PCI resource manager. Scans for available devices 1114 1.1 jmcneill * and assigns resources. 1115 1.1 jmcneill */ 1116 1.1 jmcneill void 1117 1.1 jmcneill pci_resource_init(const struct pci_resource_info *info) 1118 1.1 jmcneill { 1119 1.1 jmcneill struct pci_resources pr = {}; 1120 1.1 jmcneill 1121 1.6 riastrad if (info->ranges[PCI_RANGE_BUS] == NULL) { 1122 1.6 riastrad aprint_error("PCI: no buses\n"); 1123 1.6 riastrad return; 1124 1.6 riastrad } 1125 1.7 riastrad KASSERT(!SIMPLEQ_EMPTY(&info->ranges[PCI_RANGE_BUS]->list)); 1126 1.1 jmcneill pci_resource_probe(&pr, info); 1127 1.1 jmcneill pci_resource_alloc_bus(&pr, pr.pr_startbus); 1128 1.1 jmcneill } 1129 1.1 jmcneill 1130 1.1 jmcneill /* 1131 1.1 jmcneill * pci_resource_typename -- 1132 1.1 jmcneill * 1133 1.1 jmcneill * Return a string description of a PCI range type. 1134 1.1 jmcneill */ 1135 1.1 jmcneill const char * 1136 1.1 jmcneill pci_resource_typename(enum pci_range_type prtype) 1137 1.1 jmcneill { 1138 1.1 jmcneill KASSERT(prtype < NUM_PCI_RANGES); 1139 1.1 jmcneill return pci_range_typenames[prtype]; 1140 1.1 jmcneill } 1141