Module Name:    src
Committed By:   riastradh
Date:           Mon Mar  3 19:02:31 UTC 2025

Modified Files:
        src/sys/dev/acpi: acpi_mcfg.c
        src/sys/dev/pci: pci_resource.c pci_resource.h

Log Message:
pci_resource(9): Handle multiple ranges of the same type.

Rather than having the caller fill in an array indexed by range type
of a single start/end pair for each type, the caller will now do:

        struct pci_resource_info info;

        memset(&info, 0, sizeof(info));

        pci_resource_add_range(&info, PCI_RANGE_MEM, mstart1, mend1);
        pci_resource_add_range(&info, PCI_RANGE_MEM, mstart2, mend2);
        pci_resource_add_range(&info, PCI_RANGE_MEM, mstart3, mend3);
        pci_resource_add_range(&info, PCI_RANGE_PMEM, pstart1, pend1);
        pci_resource_add_range(&info, PCI_RANGE_IO, iostart1, ioend1);
        ...

While here, fix a format string -- 0x% or %# is enough to say that
the output is hexadecimal; we don't need to belabour the point by
printing a `0x0x' prefix!

XXX While this handles multiple io/mem/prefetchable-mem ranges, it
doesn't yet handle multiple bus ranges, which we have seen in
practice, e.g. on orion o6.  TBD.

ok jmcneill@

PR port-amd64/59118: Thinkpad T495s - iwm PCI BAR is zero


To generate a diff of this commit:
cvs rdiff -u -r1.30 -r1.31 src/sys/dev/acpi/acpi_mcfg.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pci/pci_resource.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/pci_resource.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_mcfg.c
diff -u src/sys/dev/acpi/acpi_mcfg.c:1.30 src/sys/dev/acpi/acpi_mcfg.c:1.31
--- src/sys/dev/acpi/acpi_mcfg.c:1.30	Sun Nov 10 10:45:37 2024
+++ src/sys/dev/acpi/acpi_mcfg.c	Mon Mar  3 19:02:30 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: acpi_mcfg.c,v 1.30 2024/11/10 10:45:37 mlelstv Exp $	*/
+/*	$NetBSD: acpi_mcfg.c,v 1.31 2025/03/03 19:02:30 riastradh Exp $	*/
 
 /*-
  * Copyright (C) 2015 NONAKA Kimihiro <non...@netbsd.org>
@@ -28,7 +28,7 @@
 #include "opt_pci.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.30 2024/11/10 10:45:37 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.31 2025/03/03 19:02:30 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -755,8 +755,7 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE 
 	}
 
 	if (size > 0) {
-		pciinfo->ranges[type].start = addr;
-		pciinfo->ranges[type].end = addr + size - 1;
+		pci_resource_add_range(pciinfo, type, addr, addr + size - 1);
 	}
 
 	return AE_OK;
@@ -824,8 +823,7 @@ acpimcfg_configure_bus(device_t self, pc
 
 	memset(&pciinfo, 0, sizeof(pciinfo));
 	pciinfo.pc = pc;
-	pciinfo.ranges[PCI_RANGE_BUS].start = bus;
-	pciinfo.ranges[PCI_RANGE_BUS].end = endbus;
+	pci_resource_add_range(&pciinfo, PCI_RANGE_BUS, bus, endbus);
 	rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb,
 	    &pciinfo);
 	if (ACPI_FAILURE(rv)) {

Index: src/sys/dev/pci/pci_resource.c
diff -u src/sys/dev/pci/pci_resource.c:1.5 src/sys/dev/pci/pci_resource.c:1.6
--- src/sys/dev/pci/pci_resource.c:1.5	Sun Jun 30 09:30:45 2024
+++ src/sys/dev/pci/pci_resource.c	Mon Mar  3 19:02:30 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_resource.c,v 1.5 2024/06/30 09:30:45 jmcneill Exp $ */
+/* $NetBSD: pci_resource.c,v 1.6 2025/03/03 19:02:30 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2022 Jared McNeill <jmcne...@invisible.ca>
@@ -35,12 +35,15 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_resource.c,v 1.5 2024/06/30 09:30:45 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_resource.c,v 1.6 2025/03/03 19:02:30 riastradh Exp $");
 
 #include <sys/param.h>
+#include <sys/types.h>
+
 #include <sys/bus.h>
-#include <sys/systm.h>
 #include <sys/kmem.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
 #include <sys/vmem.h>
 
 #include <dev/pci/pcireg.h>
@@ -109,7 +112,7 @@ struct pci_device {
 	union {
 		struct {
 			pcireg_t	bridge_bus;
-			struct pci_resource_range ranges[NUM_PCI_RANGES];
+			struct pci_resource_arena *ranges[NUM_PCI_RANGES];
 		} pd_bridge;
 	};
 };
@@ -122,8 +125,9 @@ struct pci_bus {
 					/* Devices on bus */
 	u_int		pb_lastdevno;	/* Last device found */
 
-	struct pci_resource_range pb_ranges[NUM_PCI_RANGES];
-	vmem_t		*pb_res[NUM_PCI_RANGES];
+	/* XXX Nothing seems to use pb_ranges? */
+	struct pci_resource_arena *pb_ranges[NUM_PCI_RANGES];
+	struct pci_resource_arena *pb_res[NUM_PCI_RANGES];
 };
 
 struct pci_resources {
@@ -132,8 +136,18 @@ struct pci_resources {
 	uint8_t		pr_startbus;	/* First bus number */
 	uint8_t		pr_endbus;	/* Last bus number */
 
-	struct pci_resource_range pr_ranges[NUM_PCI_RANGES];
-	vmem_t		*pr_res[NUM_PCI_RANGES];
+	struct pci_resource_arena *pr_ranges[NUM_PCI_RANGES];
+};
+
+struct pci_resource_arena {
+	vmem_t					*vmem;
+	SLIST_HEAD(, pci_resource_range)	list;
+};
+
+struct pci_resource_range {
+	uint64_t			start;
+	uint64_t			end;
+	SLIST_ENTRY(pci_resource_range)	entry;
 };
 
 static int	pci_resource_scan_bus(struct pci_resources *,
@@ -151,24 +165,90 @@ static int	pci_resource_scan_bus(struct 
 #define	PCICONF_BUS_DEVICE(_pb, _devno, _funcno)		\
 	(&(_pb)->pb_device[(_devno) * PCI_MAX_FUNC + (_funcno)])
 
+static void
+pci_resource_arena_add_range(struct pci_resource_arena **arenas,
+    enum pci_range_type type, uint64_t start, uint64_t end)
+{
+	struct pci_resource_arena *arena;
+	struct pci_resource_range *new, *range, *prev;
+	int error;
+
+	/*
+	 * Create an arena if we haven't already.
+	 */
+	if ((arena = arenas[type]) == NULL) {
+		arena = arenas[type] = kmem_zalloc(sizeof(*arenas[type]),
+		    KM_SLEEP);
+		arena->vmem = vmem_create(pci_resource_typename(type),
+		    0, 0, 1, NULL, NULL, NULL, 0, VM_SLEEP, IPL_NONE);
+		SLIST_INIT(&arena->list);
+	}
+
+	/*
+	 * Warn if this is a bus range and there already is a bus
+	 * range, or if the start/end are bad.  The other types of
+	 * ranges can have more than one range and larger addresses.
+	 *
+	 * XXX Not accurate: some machines do have multiple bus ranges.
+	 * But currently this logic can't handle that -- requires some
+	 * extra work to iterate over all the bus ranges.  TBD.
+	 */
+	if (type == PCI_RANGE_BUS &&
+	    (start > UINT8_MAX || end > UINT8_MAX ||
+		!SLIST_EMPTY(&arena->list))) {
+		aprint_error("PCI: unexpected bus range"
+		    " %" PRIu64 "-%" PRIu64 ", ignoring\n",
+		    start, end);
+		return;
+	}
+
+	/*
+	 * Reserve the range in the vmem for allocation.  If there's
+	 * already an overlapping range, just drop this one.
+	 */
+	error = vmem_add(arena->vmem, start, end - start + 1, VM_SLEEP);
+	if (error) {
+		/* XXX show some more context */
+		aprint_error("overlapping %s range: %#" PRIx64 "-%#" PRIx64 ","
+		    " discarding\n",
+		    pci_resource_typename(type), start, end);
+		return;
+	}
+
+	/*
+	 * Add an entry to the list so we can iterate over them, in
+	 * ascending address order for the sake of legible printing.
+	 * (We don't expect to have so many entries that the linear
+	 * time of insertion will cause trouble.)
+	 */
+	new = kmem_zalloc(sizeof(*new), KM_SLEEP);
+	new->start = start;
+	new->end = end;
+	prev = NULL;
+	SLIST_FOREACH(range, &arena->list, entry) {
+		if (new->start < range->start)
+			break;
+		prev = range;
+	}
+	if (prev) {
+		SLIST_INSERT_AFTER(prev, new, entry);
+	} else {
+		SLIST_INSERT_HEAD(&arena->list, new, entry);
+	}
+}
+
 /*
- * pci_create_vmem --
+ * pci_resource_add_range --
  *
- *   Create a vmem arena covering the specified range, used for tracking
- *   PCI resources.
+ *   Add a contiguous range of addresses (inclusive of both bounds) for
+ *   the specified type of resource.
  */
-static vmem_t *
-pci_create_vmem(const char *name, bus_addr_t start, bus_addr_t end)
+void
+pci_resource_add_range(struct pci_resource_info *info,
+    enum pci_range_type type, uint64_t start, uint64_t end)
 {
-	vmem_t *arena;
-	int error __diagused;
 
-	arena = vmem_create(name, 0, 0, 1, NULL, NULL, NULL, 0, VM_SLEEP,
-	    IPL_NONE);
-	error = vmem_add(arena, start, end - start + 1, VM_SLEEP);
-	KASSERTMSG(error == 0, "error=%d", error);
-
-	return arena;
+	pci_resource_arena_add_range(info->ranges, type, start, end);
 }
 
 /*
@@ -180,7 +260,7 @@ static struct pci_bus *
 pci_new_bus(struct pci_resources *pr, uint8_t busno, struct pci_device *bridge)
 {
 	struct pci_bus *pb;
-	struct pci_resource_range *ranges;
+	struct pci_resource_arena **ranges;
 
 	pb = kmem_zalloc(sizeof(*pb), KM_SLEEP);
 	pb->pb_busno = busno;
@@ -234,6 +314,7 @@ pci_resource_device_print(struct pci_res
     struct pci_device *pd)
 {
 	struct pci_iores *pi;
+	struct pci_resource_range *range;
 	u_int res;
 
 	DPRINT("PCI: " PCI_SBDF_FMT " %04x:%04x %02x 0x%06x",
@@ -251,29 +332,44 @@ pci_resource_device_print(struct pci_res
 		    PCI_BRIDGE_BUS_NUM_SECONDARY(pd->pd_bridge.bridge_bus),
 		    PCI_BRIDGE_BUS_NUM_SUBORDINATE(pd->pd_bridge.bridge_bus));
 
-		if (pd->pd_bridge.ranges[PCI_RANGE_IO].end) {
-			DPRINT("PCI: " PCI_SBDF_FMT
-			       " [bridge] window io  %#" PRIx64 "-%#" PRIx64
-			       "\n",
-			       PCI_SBDF_FMT_ARGS(pr, pd),
-			       pd->pd_bridge.ranges[PCI_RANGE_IO].start,
-			       pd->pd_bridge.ranges[PCI_RANGE_IO].end);
-		}
-		if (pd->pd_bridge.ranges[PCI_RANGE_MEM].end) {
-			DPRINT("PCI: " PCI_SBDF_FMT
-			       " [bridge] window mem %#" PRIx64 "-%#" PRIx64
-			       " (non-prefetchable)\n",
-			       PCI_SBDF_FMT_ARGS(pr, pd),
-			       pd->pd_bridge.ranges[PCI_RANGE_MEM].start,
-			       pd->pd_bridge.ranges[PCI_RANGE_MEM].end);
-		}
-		if (pd->pd_bridge.ranges[PCI_RANGE_PMEM].end) {
-			DPRINT("PCI: " PCI_SBDF_FMT
-			       " [bridge] window mem %#" PRIx64 "-%#" PRIx64
-			       " (prefetchable)\n",
-			       PCI_SBDF_FMT_ARGS(pr, pd),
-			       pd->pd_bridge.ranges[PCI_RANGE_PMEM].start,
-			       pd->pd_bridge.ranges[PCI_RANGE_PMEM].end);
+		if (pd->pd_bridge.ranges[PCI_RANGE_IO]) {
+			SLIST_FOREACH(range,
+			    &pd->pd_bridge.ranges[PCI_RANGE_IO]->list,
+			    entry) {
+				DPRINT("PCI: " PCI_SBDF_FMT
+				    " [bridge] window io "
+				    " %#" PRIx64 "-%#" PRIx64
+				    "\n",
+				    PCI_SBDF_FMT_ARGS(pr, pd),
+				    range->start,
+				    range->end);
+			}
+		}
+		if (pd->pd_bridge.ranges[PCI_RANGE_MEM]) {
+			SLIST_FOREACH(range,
+			    &pd->pd_bridge.ranges[PCI_RANGE_MEM]->list,
+			    entry) {
+				DPRINT("PCI: " PCI_SBDF_FMT
+				    " [bridge] window mem"
+				    " %#" PRIx64 "-%#" PRIx64
+				    " (non-prefetchable)\n",
+				    PCI_SBDF_FMT_ARGS(pr, pd),
+				    range->start,
+				    range->end);
+			}
+		}
+		if (pd->pd_bridge.ranges[PCI_RANGE_PMEM]) {
+			SLIST_FOREACH(range,
+			    &pd->pd_bridge.ranges[PCI_RANGE_PMEM]->list,
+			    entry) {
+				DPRINT("PCI: " PCI_SBDF_FMT
+				    " [bridge] window mem"
+				    " %#" PRIx64 "-%#" PRIx64
+				    " (prefetchable)\n",
+				    PCI_SBDF_FMT_ARGS(pr, pd),
+				    range->start,
+				    range->end);
+			}
 		}
 
 		break;
@@ -413,64 +509,54 @@ pci_resource_scan_bridge(struct pci_reso
 	pci_chipset_tag_t pc = pr->pr_pc;
 	pcitag_t tag = pd->pd_tag;
 	pcireg_t res, reshigh;
+	uint64_t iostart, ioend;
+	uint64_t memstart, memend;
+	uint64_t pmemstart, pmemend;
 
 	pd->pd_ppb = true;
 
 	res = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG);
 	pd->pd_bridge.bridge_bus = res;
-	pd->pd_bridge.ranges[PCI_RANGE_BUS].start =
-	    PCI_BRIDGE_BUS_NUM_SECONDARY(res);
-	pd->pd_bridge.ranges[PCI_RANGE_BUS].end =
-	    PCI_BRIDGE_BUS_NUM_SUBORDINATE(res);
+	pci_resource_arena_add_range(pd->pd_bridge.ranges,
+	    PCI_RANGE_BUS,
+	    PCI_BRIDGE_BUS_NUM_SECONDARY(res),
+	    PCI_BRIDGE_BUS_NUM_SUBORDINATE(res));
 
 	res = pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG);
-	pd->pd_bridge.ranges[PCI_RANGE_IO].start =
-	    PCI_BRIDGE_STATIO_IOBASE_ADDR(res);
-	pd->pd_bridge.ranges[PCI_RANGE_IO].end =
-	    PCI_BRIDGE_STATIO_IOLIMIT_ADDR(res);
+	iostart = PCI_BRIDGE_STATIO_IOBASE_ADDR(res);
+	ioend = PCI_BRIDGE_STATIO_IOLIMIT_ADDR(res);
 	if (PCI_BRIDGE_IO_32BITS(res)) {
 		reshigh = pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG);
-		pd->pd_bridge.ranges[PCI_RANGE_IO].start |=
-		    __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_BASE) << 16;
-		pd->pd_bridge.ranges[PCI_RANGE_IO].end |=
-		    __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_LIMIT) << 16;
-	}
-	if (pd->pd_bridge.ranges[PCI_RANGE_IO].start >=
-	    pd->pd_bridge.ranges[PCI_RANGE_IO].end) {
-		pd->pd_bridge.ranges[PCI_RANGE_IO].start = 0;
-		pd->pd_bridge.ranges[PCI_RANGE_IO].end = 0;
+		iostart |= __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_BASE) << 16;
+		ioend |= __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_LIMIT) << 16;
+	}
+	if (iostart < ioend) {
+		pci_resource_arena_add_range(pd->pd_bridge.ranges,
+		    PCI_RANGE_IO, iostart, ioend);
 	}
 
 	res = pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG);
-	pd->pd_bridge.ranges[PCI_RANGE_MEM].start =
-	    PCI_BRIDGE_MEMORY_BASE_ADDR(res);
-	pd->pd_bridge.ranges[PCI_RANGE_MEM].end =
-	    PCI_BRIDGE_MEMORY_LIMIT_ADDR(res);
-	if (pd->pd_bridge.ranges[PCI_RANGE_MEM].start >=
-	    pd->pd_bridge.ranges[PCI_RANGE_MEM].end) {
-		pd->pd_bridge.ranges[PCI_RANGE_MEM].start = 0;
-		pd->pd_bridge.ranges[PCI_RANGE_MEM].end = 0;
+	memstart = PCI_BRIDGE_MEMORY_BASE_ADDR(res);
+	memend = PCI_BRIDGE_MEMORY_LIMIT_ADDR(res);
+	if (memstart < memend) {
+		pci_resource_arena_add_range(pd->pd_bridge.ranges,
+		    PCI_RANGE_MEM, memstart, memend);
 	}
 
 	res = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG);
-	pd->pd_bridge.ranges[PCI_RANGE_PMEM].start =
-	    PCI_BRIDGE_PREFETCHMEM_BASE_ADDR(res);
-	pd->pd_bridge.ranges[PCI_RANGE_PMEM].end =
-	    PCI_BRIDGE_PREFETCHMEM_LIMIT_ADDR(res);
+	pmemstart = PCI_BRIDGE_PREFETCHMEM_BASE_ADDR(res);
+	pmemend = PCI_BRIDGE_PREFETCHMEM_LIMIT_ADDR(res);
 	if (PCI_BRIDGE_PREFETCHMEM_64BITS(res)) {
 		reshigh = pci_conf_read(pc, tag,
 		    PCI_BRIDGE_PREFETCHBASEUP32_REG);
-		pd->pd_bridge.ranges[PCI_RANGE_PMEM].start |=
-		    (uint64_t)reshigh << 32;
+		pmemstart |= (uint64_t)reshigh << 32;
 		reshigh = pci_conf_read(pc, tag,
 		    PCI_BRIDGE_PREFETCHLIMITUP32_REG);
-		pd->pd_bridge.ranges[PCI_RANGE_PMEM].end |=
-		    (uint64_t)reshigh << 32;
+		pmemend |= (uint64_t)reshigh << 32;
 	}
-	if (pd->pd_bridge.ranges[PCI_RANGE_PMEM].start >=
-	    pd->pd_bridge.ranges[PCI_RANGE_PMEM].end) {
-		pd->pd_bridge.ranges[PCI_RANGE_PMEM].start = 0;
-		pd->pd_bridge.ranges[PCI_RANGE_PMEM].end = 0;
+	if (pmemstart < pmemend) {
+		pci_resource_arena_add_range(pd->pd_bridge.ranges,
+		    PCI_RANGE_PMEM, pmemstart, pmemend);
 	}
 }
 
@@ -584,11 +670,12 @@ pci_resource_scan_bus(struct pci_resourc
  *   resource manager about resources already configured by system firmware.
  */
 static int
-pci_resource_claim(vmem_t *arena, vmem_addr_t start, vmem_addr_t end)
+pci_resource_claim(struct pci_resource_arena *arena,
+    vmem_addr_t start, vmem_addr_t end)
 {
 	KASSERT(end >= start);
 
-	return vmem_xalloc(arena, end - start + 1, 0, 0, 0, start, end,
+	return vmem_xalloc(arena->vmem, end - start + 1, 0, 0, 0, start, end,
 	    VM_BESTFIT | VM_NOSLEEP, NULL);
 }
 
@@ -599,7 +686,8 @@ pci_resource_claim(vmem_t *arena, vmem_a
  *   devices that were not already configured by system firmware.
  */
 static int
-pci_resource_alloc(vmem_t *arena, vmem_size_t size, vmem_size_t align,
+pci_resource_alloc(struct pci_resource_arena *arena, vmem_size_t size,
+    vmem_size_t align,
     uint64_t *base)
 {
 	vmem_addr_t addr;
@@ -607,7 +695,7 @@ pci_resource_alloc(vmem_t *arena, vmem_s
 
 	KASSERT(size != 0);
 
-	error = vmem_xalloc(arena, size, align, 0, 0, VMEM_ADDR_MIN,
+	error = vmem_xalloc(arena->vmem, size, align, 0, 0, VMEM_ADDR_MIN,
 	    VMEM_ADDR_MAX, VM_BESTFIT | VM_NOSLEEP, &addr);
 	if (error == 0) {
 		*base = (uint64_t)addr;
@@ -629,9 +717,9 @@ pci_resource_init_device(struct pci_reso
 {
 	struct pci_iores *pi;
 	struct pci_bus *pb = pd->pd_bus;
-	vmem_t *res_io = pb->pb_res[PCI_RANGE_IO];
-	vmem_t *res_mem = pb->pb_res[PCI_RANGE_MEM];
-	vmem_t *res_pmem = pb->pb_res[PCI_RANGE_PMEM];
+	struct pci_resource_arena *res_io = pb->pb_res[PCI_RANGE_IO];
+	struct pci_resource_arena *res_mem = pb->pb_res[PCI_RANGE_MEM];
+	struct pci_resource_arena *res_pmem = pb->pb_res[PCI_RANGE_PMEM];
 	pcireg_t cmd;
 	u_int enabled, required;
 	u_int iores;
@@ -778,8 +866,8 @@ pci_resource_init_bus(struct pci_resourc
 	if (bridge == NULL) {
 		/* Use resources provided by firmware. */
 		PCI_RANGE_FOREACH(prtype) {
-			pb->pb_res[prtype] = pr->pr_res[prtype];
-			pr->pr_res[prtype] = NULL;
+			pb->pb_res[prtype] = pr->pr_ranges[prtype];
+			pr->pr_ranges[prtype] = NULL;
 		}
 	} else {
 		/*
@@ -790,28 +878,33 @@ pci_resource_init_bus(struct pci_resourc
 		KASSERT(bridge->pd_bus != NULL);
 		parent_bus = bridge->pd_bus;
 		PCI_RANGE_FOREACH(prtype) {
+			struct pci_resource_range *range;
+
 			if (parent_bus->pb_res[prtype] == NULL ||
-			    !bridge->pd_bridge.ranges[prtype].end) {
+			    bridge->pd_bridge.ranges[prtype] == NULL) {
 				continue;
 			}
-			error = pci_resource_claim(
-			    parent_bus->pb_res[prtype],
-			    bridge->pd_bridge.ranges[prtype].start,
-			    bridge->pd_bridge.ranges[prtype].end);
-			if (error == 0) {
-				pb->pb_res[prtype] = pci_create_vmem(
-				    pci_resource_typename(prtype),
-				    bridge->pd_bridge.ranges[prtype].start,
-				    bridge->pd_bridge.ranges[prtype].end);
+			SLIST_FOREACH(range,
+			    &bridge->pd_bridge.ranges[prtype]->list,
+			    entry) {
+				error = pci_resource_claim(
+				    parent_bus->pb_res[prtype],
+				    range->start, range->end);
+				if (error) {
+					DPRINT("PCI: " PCI_SBDF_FMT
+					    " bridge (bus %u)"
+					    " %-4s %#" PRIx64 "-%#" PRIx64
+					    " invalid\n",
+					    PCI_SBDF_FMT_ARGS(pr, bridge),
+					    busno,
+					    pci_resource_typename(prtype),
+					    range->start, range->end);
+					continue;
+				}
+				pci_resource_arena_add_range(
+				    pb->pb_res, prtype,
+				    range->start, range->end);
 				KASSERT(pb->pb_res[prtype] != NULL);
-			} else {
-				DPRINT("PCI: " PCI_SBDF_FMT " bridge (bus %u)"
-				       " %-4s %#" PRIx64 "-%#" PRIx64
-				       " invalid\n",
-				       PCI_SBDF_FMT_ARGS(pr, bridge), busno,
-				       pci_resource_typename(prtype),
-				       bridge->pd_bridge.ranges[prtype].start,
-				       bridge->pd_bridge.ranges[prtype].end);
 			}
 		}
 	}
@@ -843,8 +936,10 @@ static void
 pci_resource_probe(struct pci_resources *pr,
     const struct pci_resource_info *info)
 {
-	uint8_t startbus = (uint8_t)info->ranges[PCI_RANGE_BUS].start;
-	uint8_t endbus = (uint8_t)info->ranges[PCI_RANGE_BUS].end;
+	struct pci_resource_arena *busarena = info->ranges[PCI_RANGE_BUS];
+	struct pci_resource_range *busrange = SLIST_FIRST(&busarena->list);
+	uint8_t startbus = (uint8_t)busrange->start;
+	uint8_t endbus = (uint8_t)busrange->end;
 	u_int nbus;
 
 	KASSERT(startbus <= endbus);
@@ -857,15 +952,6 @@ pci_resource_probe(struct pci_resources 
 	pr->pr_endbus = endbus;
 	pr->pr_bus = kmem_zalloc(nbus * sizeof(struct pci_bus *), KM_SLEEP);
 	memcpy(pr->pr_ranges, info->ranges, sizeof(pr->pr_ranges));
-	PCI_RANGE_FOREACH(prtype) {
-		if (prtype == PCI_RANGE_BUS || info->ranges[prtype].end) {
-			pr->pr_res[prtype] = pci_create_vmem(
-			    pci_resource_typename(prtype),
-			    info->ranges[prtype].start,
-			    info->ranges[prtype].end);
-			KASSERT(pr->pr_res[prtype] != NULL);
-		}
-	}
 
 	/* Scan devices */
 	pci_resource_scan_bus(pr, NULL, pr->pr_startbus);
@@ -886,7 +972,7 @@ static void
 pci_resource_alloc_device(struct pci_resources *pr, struct pci_device *pd)
 {
 	struct pci_iores *pi;
-	vmem_t *arena;
+	struct pci_resource_arena *arena;
 	pcireg_t cmd, ocmd, base;
 	uint64_t addr;
 	u_int enabled;
@@ -941,7 +1027,7 @@ pci_resource_alloc_device(struct pci_res
 			return;
 		}
 		DPRINT("PCI: " PCI_SBDF_FMT " BAR%u assigned range"
-		       " 0x%#" PRIx64 "-0x%#" PRIx64 "\n",
+		       " %#" PRIx64 "-%#" PRIx64 "\n",
 		       PCI_SBDF_FMT_ARGS(pr, pd),
 		       pi->pi_bar, addr, addr + pi->pi_size - 1);
 
@@ -1017,6 +1103,11 @@ pci_resource_init(const struct pci_resou
 {
 	struct pci_resources pr = {};
 
+	if (info->ranges[PCI_RANGE_BUS] == NULL) {
+		aprint_error("PCI: no buses\n");
+		return;
+	}
+	KASSERT(!SLIST_EMPTY(&info->ranges[PCI_RANGE_BUS]->list));
 	pci_resource_probe(&pr, info);
 	pci_resource_alloc_bus(&pr, pr.pr_startbus);
 }

Index: src/sys/dev/pci/pci_resource.h
diff -u src/sys/dev/pci/pci_resource.h:1.1 src/sys/dev/pci/pci_resource.h:1.2
--- src/sys/dev/pci/pci_resource.h:1.1	Fri Oct 14 22:10:15 2022
+++ src/sys/dev/pci/pci_resource.h	Mon Mar  3 19:02:30 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_resource.h,v 1.1 2022/10/14 22:10:15 jmcneill Exp $ */
+/* $NetBSD: pci_resource.h,v 1.2 2025/03/03 19:02:30 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2022 Jared McNeill <jmcne...@invisible.ca>
@@ -26,7 +26,10 @@
  * SUCH DAMAGE.
  */
 
-#pragma once
+#ifndef	_DEV_PCI_PCI_RESOURCE_H_
+#define	_DEV_PCI_PCI_RESOURCE_H_
+
+#include <sys/types.h>
 
 enum pci_range_type {
 	PCI_RANGE_BUS,
@@ -36,15 +39,14 @@ enum pci_range_type {
 	NUM_PCI_RANGES
 };
 
-struct pci_resource_range {
-	uint64_t	start;
-	uint64_t	end;
-};
-
 struct pci_resource_info {
 	pci_chipset_tag_t		pc;
-	struct pci_resource_range	ranges[NUM_PCI_RANGES];
+	struct pci_resource_arena	*ranges[NUM_PCI_RANGES];
 };
 
+void		pci_resource_add_range(struct pci_resource_info *,
+		    enum pci_range_type, uint64_t, uint64_t);
 void		pci_resource_init(const struct pci_resource_info *);
 const char *	pci_resource_typename(enum pci_range_type);
+
+#endif	/* _DEV_PCI_PCI_RESOURCE_H_ */

Reply via email to