xref: /netbsd-src/sys/dev/pci/pci_resource.c (revision 408f62c9058b5c65ed70382216931f6f110cc88a)
1*408f62c9Sjmcneill /* $NetBSD: pci_resource.c,v 1.5 2024/06/30 09:30:45 jmcneill Exp $ */
21099f047Sjmcneill 
31099f047Sjmcneill /*-
41099f047Sjmcneill  * Copyright (c) 2022 Jared McNeill <jmcneill@invisible.ca>
51099f047Sjmcneill  * All rights reserved.
61099f047Sjmcneill  *
71099f047Sjmcneill  * Redistribution and use in source and binary forms, with or without
81099f047Sjmcneill  * modification, are permitted provided that the following conditions
91099f047Sjmcneill  * are met:
101099f047Sjmcneill  * 1. Redistributions of source code must retain the above copyright
111099f047Sjmcneill  *    notice, this list of conditions and the following disclaimer.
121099f047Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
131099f047Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
141099f047Sjmcneill  *    documentation and/or other materials provided with the distribution.
151099f047Sjmcneill  *
161099f047Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171099f047Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181099f047Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191099f047Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201099f047Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211099f047Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221099f047Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231099f047Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241099f047Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251099f047Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261099f047Sjmcneill  * SUCH DAMAGE.
271099f047Sjmcneill  */
281099f047Sjmcneill 
291099f047Sjmcneill /*
301099f047Sjmcneill  * pci_resource.c --
311099f047Sjmcneill  *
321099f047Sjmcneill  * Scan current PCI resource allocations and attempt to assign resources
331099f047Sjmcneill  * to devices that are not configured WITHOUT changing any configuration
341099f047Sjmcneill  * performed by system firmware.
351099f047Sjmcneill  */
361099f047Sjmcneill 
371099f047Sjmcneill #include <sys/cdefs.h>
38*408f62c9Sjmcneill __KERNEL_RCSID(0, "$NetBSD: pci_resource.c,v 1.5 2024/06/30 09:30:45 jmcneill Exp $");
391099f047Sjmcneill 
401099f047Sjmcneill #include <sys/param.h>
411099f047Sjmcneill #include <sys/bus.h>
421099f047Sjmcneill #include <sys/systm.h>
431099f047Sjmcneill #include <sys/kmem.h>
441099f047Sjmcneill #include <sys/vmem.h>
451099f047Sjmcneill 
461099f047Sjmcneill #include <dev/pci/pcireg.h>
471099f047Sjmcneill #include <dev/pci/pcivar.h>
481099f047Sjmcneill #include <dev/pci/pcidevs.h>
491099f047Sjmcneill #include <dev/pci/pci_resource.h>
501099f047Sjmcneill 
511099f047Sjmcneill #define	DPRINT		aprint_debug
521099f047Sjmcneill 
531099f047Sjmcneill #if defined(PCI_RESOURCE_TEST_VENDOR_ID) && \
541099f047Sjmcneill     defined(PCI_RESOURCE_TEST_PRODUCT_ID)
551099f047Sjmcneill #define IS_TEST_DEVICE(_pd)						      \
561099f047Sjmcneill 	(PCI_VENDOR(pd->pd_id) == PCI_RESOURCE_TEST_VENDOR_ID &&	      \
571099f047Sjmcneill 	 PCI_PRODUCT(pd->pd_id) == PCI_RESOURCE_TEST_PRODUCT_ID)
581099f047Sjmcneill #else
591099f047Sjmcneill #define IS_TEST_DEVICE(_pd)	0
601099f047Sjmcneill #endif
611099f047Sjmcneill 
621099f047Sjmcneill #define	PCI_MAX_DEVICE	32
631099f047Sjmcneill #define	PCI_MAX_FUNC	8
641099f047Sjmcneill 
651099f047Sjmcneill #define	PCI_MAX_IORES	6
661099f047Sjmcneill 
671099f047Sjmcneill #define	PCI_RANGE_FOREACH(_type)					      \
681099f047Sjmcneill 	for (u_int _type = PCI_RANGE_BUS; _type < NUM_PCI_RANGES; _type++)
691099f047Sjmcneill 
701099f047Sjmcneill static const char *pci_range_typenames[NUM_PCI_RANGES] = {
711099f047Sjmcneill 	[PCI_RANGE_BUS]  = "bus",
721099f047Sjmcneill 	[PCI_RANGE_IO]   = "io",
731099f047Sjmcneill 	[PCI_RANGE_MEM]  = "mem",
741099f047Sjmcneill 	[PCI_RANGE_PMEM] = "pmem",
751099f047Sjmcneill };
761099f047Sjmcneill 
771099f047Sjmcneill struct pci_bus;
781099f047Sjmcneill 
791099f047Sjmcneill struct pci_iores {
801099f047Sjmcneill 	uint64_t	pi_base;	/* Base address */
811099f047Sjmcneill 	uint64_t	pi_size;	/* Resource size */
821099f047Sjmcneill 	uint8_t		pi_type;	/* PCI_MAPREG_TYPE_* */
831099f047Sjmcneill 	u_int		pi_bar;		/* PCI bar number */
841099f047Sjmcneill 	union {
851099f047Sjmcneill 		struct {
861099f047Sjmcneill 			uint8_t		memtype;
871099f047Sjmcneill 			bool		prefetch;
881099f047Sjmcneill 		} pi_mem;
891099f047Sjmcneill 	};
901099f047Sjmcneill };
911099f047Sjmcneill 
921099f047Sjmcneill struct pci_device {
931099f047Sjmcneill 	bool		pd_present;	/* Device is present */
941099f047Sjmcneill 	bool		pd_configured;	/* Device is configured */
951099f047Sjmcneill 	struct pci_bus *pd_bus;	/* Parent bus */
961099f047Sjmcneill 	uint8_t		pd_devno;	/* Device number */
971099f047Sjmcneill 	uint8_t		pd_funcno;	/* Function number */
981099f047Sjmcneill 	pcitag_t	pd_tag;		/* PCI tag */
991099f047Sjmcneill 
1001099f047Sjmcneill 	pcireg_t	pd_id;		/* Vendor ID, Device ID */
1011099f047Sjmcneill 	pcireg_t	pd_class;	/* Revision ID, Class Code */
1021099f047Sjmcneill 	pcireg_t	pd_bhlc;	/* BIST, Header Type, Primary Latency
1031099f047Sjmcneill 					 * Timer, Cache Line Size */
1041099f047Sjmcneill 
1051099f047Sjmcneill 	struct pci_iores pd_iores[PCI_MAX_IORES];
1061099f047Sjmcneill 	u_int		pd_niores;
1071099f047Sjmcneill 
1081099f047Sjmcneill 	bool		pd_ppb;		/* PCI-PCI bridge */
1091099f047Sjmcneill 	union {
1101099f047Sjmcneill 		struct {
1111099f047Sjmcneill 			pcireg_t	bridge_bus;
1121099f047Sjmcneill 			struct pci_resource_range ranges[NUM_PCI_RANGES];
1131099f047Sjmcneill 		} pd_bridge;
1141099f047Sjmcneill 	};
1151099f047Sjmcneill };
1161099f047Sjmcneill 
1171099f047Sjmcneill struct pci_bus {
1181099f047Sjmcneill 	uint8_t		pb_busno;	/* Bus number */
1191099f047Sjmcneill 	struct pci_device *pb_bridge; /* Parent bridge, or NULL */
1201099f047Sjmcneill 
1211099f047Sjmcneill 	struct pci_device pb_device[PCI_MAX_DEVICE * PCI_MAX_FUNC];
1221099f047Sjmcneill 					/* Devices on bus */
1231099f047Sjmcneill 	u_int		pb_lastdevno;	/* Last device found */
1241099f047Sjmcneill 
1251099f047Sjmcneill 	struct pci_resource_range pb_ranges[NUM_PCI_RANGES];
1261099f047Sjmcneill 	vmem_t		*pb_res[NUM_PCI_RANGES];
1271099f047Sjmcneill };
1281099f047Sjmcneill 
1291099f047Sjmcneill struct pci_resources {
1301099f047Sjmcneill 	struct pci_bus **pr_bus;	/* Bus list */
1311099f047Sjmcneill 	pci_chipset_tag_t pr_pc;	/* Chipset tag */
1321099f047Sjmcneill 	uint8_t		pr_startbus;	/* First bus number */
1331099f047Sjmcneill 	uint8_t		pr_endbus;	/* Last bus number */
1341099f047Sjmcneill 
1351099f047Sjmcneill 	struct pci_resource_range pr_ranges[NUM_PCI_RANGES];
1361099f047Sjmcneill 	vmem_t		*pr_res[NUM_PCI_RANGES];
1371099f047Sjmcneill };
1381099f047Sjmcneill 
139*408f62c9Sjmcneill static int	pci_resource_scan_bus(struct pci_resources *,
1401099f047Sjmcneill 		    struct pci_device *, uint8_t);
1411099f047Sjmcneill 
1421099f047Sjmcneill #define	PCI_SBDF_FMT			"%04x:%02x:%02x.%u"
1431099f047Sjmcneill #define	PCI_SBDF_FMT_ARGS(_pr, _pd)	\
1441099f047Sjmcneill 	pci_get_segment((_pr)->pr_pc),	\
1451099f047Sjmcneill 	(_pd)->pd_bus->pb_busno,	\
1461099f047Sjmcneill 	(_pd)->pd_devno,		\
1471099f047Sjmcneill 	(_pd)->pd_funcno
1481099f047Sjmcneill 
1491099f047Sjmcneill #define	PCICONF_RES_BUS(_pr, _busno)				\
1501099f047Sjmcneill 	((_pr)->pr_bus[(_busno) - (_pr)->pr_startbus])
1511099f047Sjmcneill #define	PCICONF_BUS_DEVICE(_pb, _devno, _funcno)		\
1521099f047Sjmcneill 	(&(_pb)->pb_device[(_devno) * PCI_MAX_FUNC + (_funcno)])
1531099f047Sjmcneill 
1541099f047Sjmcneill /*
1551099f047Sjmcneill  * pci_create_vmem --
1561099f047Sjmcneill  *
1571099f047Sjmcneill  *   Create a vmem arena covering the specified range, used for tracking
1581099f047Sjmcneill  *   PCI resources.
1591099f047Sjmcneill  */
1601099f047Sjmcneill static vmem_t *
pci_create_vmem(const char * name,bus_addr_t start,bus_addr_t end)1611099f047Sjmcneill pci_create_vmem(const char *name, bus_addr_t start, bus_addr_t end)
1621099f047Sjmcneill {
1631099f047Sjmcneill 	vmem_t *arena;
164ddd4c7f7Sriastradh 	int error __diagused;
1651099f047Sjmcneill 
1661099f047Sjmcneill 	arena = vmem_create(name, 0, 0, 1, NULL, NULL, NULL, 0, VM_SLEEP,
1671099f047Sjmcneill 	    IPL_NONE);
168ddd4c7f7Sriastradh 	error = vmem_add(arena, start, end - start + 1, VM_SLEEP);
169ddd4c7f7Sriastradh 	KASSERTMSG(error == 0, "error=%d", error);
1701099f047Sjmcneill 
1711099f047Sjmcneill 	return arena;
1721099f047Sjmcneill }
1731099f047Sjmcneill 
1741099f047Sjmcneill /*
1751099f047Sjmcneill  * pci_new_bus --
1761099f047Sjmcneill  *
1771099f047Sjmcneill  *   Create a new PCI bus and initialize its resource ranges.
1781099f047Sjmcneill  */
1791099f047Sjmcneill static struct pci_bus *
pci_new_bus(struct pci_resources * pr,uint8_t busno,struct pci_device * bridge)1801099f047Sjmcneill pci_new_bus(struct pci_resources *pr, uint8_t busno, struct pci_device *bridge)
1811099f047Sjmcneill {
1821099f047Sjmcneill 	struct pci_bus *pb;
1831099f047Sjmcneill 	struct pci_resource_range *ranges;
1841099f047Sjmcneill 
1851099f047Sjmcneill 	pb = kmem_zalloc(sizeof(*pb), KM_SLEEP);
1861099f047Sjmcneill 	pb->pb_busno = busno;
1871099f047Sjmcneill 	pb->pb_bridge = bridge;
1881099f047Sjmcneill 	if (bridge == NULL) {
1891099f047Sjmcneill 		/*
1901099f047Sjmcneill 		 * No additional constraints on resource allocations for
1911099f047Sjmcneill 		 * the root bus.
1921099f047Sjmcneill 		 */
1931099f047Sjmcneill 		ranges = pr->pr_ranges;
1941099f047Sjmcneill 	} else {
1951099f047Sjmcneill 		/*
1961099f047Sjmcneill 		 * Resource allocations for this bus are constrained by the
1971099f047Sjmcneill 		 * bridge forwarding settings.
1981099f047Sjmcneill 		 */
1991099f047Sjmcneill 		ranges = bridge->pd_bridge.ranges;
2001099f047Sjmcneill 	}
2011099f047Sjmcneill 	memcpy(pb->pb_ranges, ranges, sizeof(pb->pb_ranges));
2021099f047Sjmcneill 
2031099f047Sjmcneill 	return pb;
2041099f047Sjmcneill }
2051099f047Sjmcneill 
2061099f047Sjmcneill /*
2071099f047Sjmcneill  * pci_resource_device_functions --
2081099f047Sjmcneill  *
2091099f047Sjmcneill  *   Returns the number of PCI functions for a a given bus and device.
2101099f047Sjmcneill  */
2111099f047Sjmcneill static uint8_t
pci_resource_device_functions(struct pci_resources * pr,uint8_t busno,uint8_t devno)2121099f047Sjmcneill pci_resource_device_functions(struct pci_resources *pr,
2131099f047Sjmcneill     uint8_t busno, uint8_t devno)
2141099f047Sjmcneill {
2151099f047Sjmcneill 	struct pci_bus *pb;
2161099f047Sjmcneill 	struct pci_device *pd;
2171099f047Sjmcneill 
2181099f047Sjmcneill 	pb = PCICONF_RES_BUS(pr, busno);
2191099f047Sjmcneill 	pd = PCICONF_BUS_DEVICE(pb, devno, 0);
2201099f047Sjmcneill 	if (!pd->pd_present) {
2211099f047Sjmcneill 		return 0;
2221099f047Sjmcneill 	}
2231099f047Sjmcneill 
2241099f047Sjmcneill 	return PCI_HDRTYPE_MULTIFN(pd->pd_bhlc) ? 8 : 1;
2251099f047Sjmcneill }
2261099f047Sjmcneill 
2271099f047Sjmcneill /*
2281099f047Sjmcneill  * pci_resource_device_print --
2291099f047Sjmcneill  *
2301099f047Sjmcneill  *   Log details about a device.
2311099f047Sjmcneill  */
2321099f047Sjmcneill static void
pci_resource_device_print(struct pci_resources * pr,struct pci_device * pd)2331099f047Sjmcneill pci_resource_device_print(struct pci_resources *pr,
2341099f047Sjmcneill     struct pci_device *pd)
2351099f047Sjmcneill {
2361099f047Sjmcneill 	struct pci_iores *pi;
2371099f047Sjmcneill 	u_int res;
2381099f047Sjmcneill 
2391099f047Sjmcneill 	DPRINT("PCI: " PCI_SBDF_FMT " %04x:%04x %02x 0x%06x",
2401099f047Sjmcneill 	       PCI_SBDF_FMT_ARGS(pr, pd),
2411099f047Sjmcneill 	       PCI_VENDOR(pd->pd_id), PCI_PRODUCT(pd->pd_id),
2421099f047Sjmcneill 	       PCI_REVISION(pd->pd_class), (pd->pd_class >> 8) & 0xffffff);
2431099f047Sjmcneill 
2441099f047Sjmcneill 	switch (PCI_HDRTYPE_TYPE(pd->pd_bhlc)) {
2451099f047Sjmcneill 	case PCI_HDRTYPE_DEVICE:
2461099f047Sjmcneill 		DPRINT(" (device)\n");
2471099f047Sjmcneill 		break;
2481099f047Sjmcneill 	case PCI_HDRTYPE_PPB:
2491099f047Sjmcneill 		DPRINT(" (bridge %u -> %u-%u)\n",
2501099f047Sjmcneill 		    PCI_BRIDGE_BUS_NUM_PRIMARY(pd->pd_bridge.bridge_bus),
2511099f047Sjmcneill 		    PCI_BRIDGE_BUS_NUM_SECONDARY(pd->pd_bridge.bridge_bus),
2521099f047Sjmcneill 		    PCI_BRIDGE_BUS_NUM_SUBORDINATE(pd->pd_bridge.bridge_bus));
2531099f047Sjmcneill 
2541099f047Sjmcneill 		if (pd->pd_bridge.ranges[PCI_RANGE_IO].end) {
2551099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT
2561099f047Sjmcneill 			       " [bridge] window io  %#" PRIx64 "-%#" PRIx64
2571099f047Sjmcneill 			       "\n",
2581099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
2591099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_IO].start,
2601099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_IO].end);
2611099f047Sjmcneill 		}
2621099f047Sjmcneill 		if (pd->pd_bridge.ranges[PCI_RANGE_MEM].end) {
2631099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT
2641099f047Sjmcneill 			       " [bridge] window mem %#" PRIx64 "-%#" PRIx64
2651099f047Sjmcneill 			       " (non-prefetchable)\n",
2661099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
2671099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_MEM].start,
2681099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_MEM].end);
2691099f047Sjmcneill 		}
2701099f047Sjmcneill 		if (pd->pd_bridge.ranges[PCI_RANGE_PMEM].end) {
2711099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT
2721099f047Sjmcneill 			       " [bridge] window mem %#" PRIx64 "-%#" PRIx64
2731099f047Sjmcneill 			       " (prefetchable)\n",
2741099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
2751099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_PMEM].start,
2761099f047Sjmcneill 			       pd->pd_bridge.ranges[PCI_RANGE_PMEM].end);
2771099f047Sjmcneill 		}
2781099f047Sjmcneill 
2791099f047Sjmcneill 		break;
2801099f047Sjmcneill 	default:
2811099f047Sjmcneill 		DPRINT(" (0x%02x)\n", PCI_HDRTYPE_TYPE(pd->pd_bhlc));
2821099f047Sjmcneill 	}
2831099f047Sjmcneill 
2841099f047Sjmcneill 	for (res = 0; res < pd->pd_niores; res++) {
2851099f047Sjmcneill 		pi = &pd->pd_iores[res];
2861099f047Sjmcneill 
2871099f047Sjmcneill 		DPRINT("PCI: " PCI_SBDF_FMT
2881099f047Sjmcneill 		       " [device] resource BAR%u: %s @ %#" PRIx64 " size %#"
2891099f047Sjmcneill 		       PRIx64,
2901099f047Sjmcneill 		       PCI_SBDF_FMT_ARGS(pr, pd), pi->pi_bar,
2911099f047Sjmcneill 		       pi->pi_type == PCI_MAPREG_TYPE_MEM ? "mem" : "io ",
2921099f047Sjmcneill 		       pi->pi_base, pi->pi_size);
2931099f047Sjmcneill 
2941099f047Sjmcneill 		if (pi->pi_type == PCI_MAPREG_TYPE_MEM) {
2951099f047Sjmcneill 			switch (pi->pi_mem.memtype) {
2961099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_32BIT:
2971099f047Sjmcneill 				DPRINT(", 32-bit");
2981099f047Sjmcneill 				break;
2991099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
3001099f047Sjmcneill 				DPRINT(", 32-bit (1M)");
3011099f047Sjmcneill 				break;
3021099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_64BIT:
3031099f047Sjmcneill 				DPRINT(", 64-bit");
3041099f047Sjmcneill 				break;
3051099f047Sjmcneill 			}
3061099f047Sjmcneill 			DPRINT(" %sprefetchable",
3071099f047Sjmcneill 			    pi->pi_mem.prefetch ? "" : "non-");
3081099f047Sjmcneill 		}
3091099f047Sjmcneill 		DPRINT("\n");
3101099f047Sjmcneill 	}
3111099f047Sjmcneill }
3121099f047Sjmcneill 
3131099f047Sjmcneill /*
3141099f047Sjmcneill  * pci_resource_scan_bar --
3151099f047Sjmcneill  *
3161099f047Sjmcneill  *   Determine the current BAR configuration for a given device.
3171099f047Sjmcneill  */
3181099f047Sjmcneill static void
pci_resource_scan_bar(struct pci_resources * pr,struct pci_device * pd,pcireg_t mapreg_start,pcireg_t mapreg_end,bool is_ppb)3191099f047Sjmcneill pci_resource_scan_bar(struct pci_resources *pr,
3201099f047Sjmcneill     struct pci_device *pd, pcireg_t mapreg_start, pcireg_t mapreg_end,
3211099f047Sjmcneill     bool is_ppb)
3221099f047Sjmcneill {
3231099f047Sjmcneill 	pci_chipset_tag_t pc = pr->pr_pc;
3241099f047Sjmcneill 	pcitag_t tag = pd->pd_tag;
3251099f047Sjmcneill 	pcireg_t mapreg = mapreg_start;
3261099f047Sjmcneill 	pcireg_t ocmd, cmd, bar[2], mask[2];
3271099f047Sjmcneill 	uint64_t addr, size;
3281099f047Sjmcneill 	struct pci_iores *pi;
3291099f047Sjmcneill 
3301099f047Sjmcneill 	if (!is_ppb) {
3311099f047Sjmcneill 		ocmd = cmd = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
3321099f047Sjmcneill 		cmd &= ~(PCI_COMMAND_MASTER_ENABLE |
3331099f047Sjmcneill 			 PCI_COMMAND_MEM_ENABLE |
3341099f047Sjmcneill 			 PCI_COMMAND_IO_ENABLE);
3351099f047Sjmcneill 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, cmd);
3361099f047Sjmcneill 	}
3371099f047Sjmcneill 
3381099f047Sjmcneill 	while (mapreg < mapreg_end) {
3391099f047Sjmcneill 		u_int width = 4;
3401099f047Sjmcneill 
3411099f047Sjmcneill 		bar[0] = pci_conf_read(pc, tag, mapreg);
3421099f047Sjmcneill 		pci_conf_write(pc, tag, mapreg, 0xffffffff);
3431099f047Sjmcneill 		mask[0] = pci_conf_read(pc, tag, mapreg);
3441099f047Sjmcneill 		pci_conf_write(pc, tag, mapreg, bar[0]);
3451099f047Sjmcneill 
3461099f047Sjmcneill 		switch (PCI_MAPREG_TYPE(mask[0])) {
3471099f047Sjmcneill 		case PCI_MAPREG_TYPE_MEM:
3481099f047Sjmcneill 			switch (PCI_MAPREG_MEM_TYPE(mask[0])) {
3491099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_32BIT:
3501099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
3511099f047Sjmcneill 				size = PCI_MAPREG_MEM_SIZE(mask[0]);
3521099f047Sjmcneill 				addr = PCI_MAPREG_MEM_ADDR(bar[0]);
3531099f047Sjmcneill 				break;
3541099f047Sjmcneill 			case PCI_MAPREG_MEM_TYPE_64BIT:
3551099f047Sjmcneill 				bar[1] = pci_conf_read(pc, tag, mapreg + 4);
3561099f047Sjmcneill 				pci_conf_write(pc, tag, mapreg + 4, 0xffffffff);
3571099f047Sjmcneill 				mask[1] = pci_conf_read(pc, tag, mapreg + 4);
3581099f047Sjmcneill 				pci_conf_write(pc, tag, mapreg + 4, bar[1]);
3591099f047Sjmcneill 
3601099f047Sjmcneill 				size = PCI_MAPREG_MEM64_SIZE(
3611099f047Sjmcneill 				    ((uint64_t)mask[1] << 32) | mask[0]);
3621099f047Sjmcneill 				addr = PCI_MAPREG_MEM64_ADDR(
3631099f047Sjmcneill 				    ((uint64_t)bar[1] << 32) | bar[0]);
3641099f047Sjmcneill 				width = 8;
3651099f047Sjmcneill 				break;
3661099f047Sjmcneill 			default:
3671099f047Sjmcneill 				size = 0;
3681099f047Sjmcneill 			}
3691099f047Sjmcneill 			if (size > 0) {
3701099f047Sjmcneill 				pi = &pd->pd_iores[pd->pd_niores++];
3711099f047Sjmcneill 				pi->pi_type = PCI_MAPREG_TYPE_MEM;
3721099f047Sjmcneill 				pi->pi_base = addr;
3731099f047Sjmcneill 				pi->pi_size = size;
3741099f047Sjmcneill 				pi->pi_bar = (mapreg - mapreg_start) / 4;
3751099f047Sjmcneill 				pi->pi_mem.memtype =
3761099f047Sjmcneill 				    PCI_MAPREG_MEM_TYPE(mask[0]);
3771099f047Sjmcneill 				pi->pi_mem.prefetch =
3781099f047Sjmcneill 				    PCI_MAPREG_MEM_PREFETCHABLE(mask[0]);
3791099f047Sjmcneill 			}
3801099f047Sjmcneill 			break;
3811099f047Sjmcneill 		case PCI_MAPREG_TYPE_IO:
3821099f047Sjmcneill 			size = PCI_MAPREG_IO_SIZE(mask[0] | 0xffff0000);
3831099f047Sjmcneill 			addr = PCI_MAPREG_IO_ADDR(bar[0]);
3841099f047Sjmcneill 			if (size > 0) {
3851099f047Sjmcneill 				pi = &pd->pd_iores[pd->pd_niores++];
3861099f047Sjmcneill 				pi->pi_type = PCI_MAPREG_TYPE_IO;
3871099f047Sjmcneill 				pi->pi_base = addr;
3881099f047Sjmcneill 				pi->pi_size = size;
3891099f047Sjmcneill 				pi->pi_bar = (mapreg - mapreg_start) / 4;
3901099f047Sjmcneill 			}
3911099f047Sjmcneill 			break;
3921099f047Sjmcneill 		}
3931099f047Sjmcneill 
3941099f047Sjmcneill 		KASSERT(pd->pd_niores <= PCI_MAX_IORES);
3951099f047Sjmcneill 
3961099f047Sjmcneill 		mapreg += width;
3971099f047Sjmcneill 	}
3981099f047Sjmcneill 
3991099f047Sjmcneill 	if (!is_ppb) {
4001099f047Sjmcneill 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, ocmd);
4011099f047Sjmcneill 	}
4021099f047Sjmcneill }
4031099f047Sjmcneill 
4041099f047Sjmcneill /*
4051099f047Sjmcneill  * pci_resource_scan_bridge --
4061099f047Sjmcneill  *
4071099f047Sjmcneill  *   Determine the current configuration of a PCI-PCI bridge.
4081099f047Sjmcneill  */
4091099f047Sjmcneill static void
pci_resource_scan_bridge(struct pci_resources * pr,struct pci_device * pd)4101099f047Sjmcneill pci_resource_scan_bridge(struct pci_resources *pr,
4111099f047Sjmcneill     struct pci_device *pd)
4121099f047Sjmcneill {
4131099f047Sjmcneill 	pci_chipset_tag_t pc = pr->pr_pc;
4141099f047Sjmcneill 	pcitag_t tag = pd->pd_tag;
4151099f047Sjmcneill 	pcireg_t res, reshigh;
4161099f047Sjmcneill 
4171099f047Sjmcneill 	pd->pd_ppb = true;
4181099f047Sjmcneill 
4191099f047Sjmcneill 	res = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG);
4201099f047Sjmcneill 	pd->pd_bridge.bridge_bus = res;
4211099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_BUS].start =
4221099f047Sjmcneill 	    PCI_BRIDGE_BUS_NUM_SECONDARY(res);
4231099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_BUS].end =
4241099f047Sjmcneill 	    PCI_BRIDGE_BUS_NUM_SUBORDINATE(res);
4251099f047Sjmcneill 
4261099f047Sjmcneill 	res = pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG);
4271099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_IO].start =
4281099f047Sjmcneill 	    PCI_BRIDGE_STATIO_IOBASE_ADDR(res);
4291099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_IO].end =
4301099f047Sjmcneill 	    PCI_BRIDGE_STATIO_IOLIMIT_ADDR(res);
4311099f047Sjmcneill 	if (PCI_BRIDGE_IO_32BITS(res)) {
4321099f047Sjmcneill 		reshigh = pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG);
4331099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_IO].start |=
4341099f047Sjmcneill 		    __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_BASE) << 16;
4351099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_IO].end |=
4361099f047Sjmcneill 		    __SHIFTOUT(reshigh, PCI_BRIDGE_IOHIGH_LIMIT) << 16;
4371099f047Sjmcneill 	}
4381099f047Sjmcneill 	if (pd->pd_bridge.ranges[PCI_RANGE_IO].start >=
4391099f047Sjmcneill 	    pd->pd_bridge.ranges[PCI_RANGE_IO].end) {
4401099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_IO].start = 0;
4411099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_IO].end = 0;
4421099f047Sjmcneill 	}
4431099f047Sjmcneill 
4441099f047Sjmcneill 	res = pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG);
4451099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_MEM].start =
4461099f047Sjmcneill 	    PCI_BRIDGE_MEMORY_BASE_ADDR(res);
4471099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_MEM].end =
4481099f047Sjmcneill 	    PCI_BRIDGE_MEMORY_LIMIT_ADDR(res);
4491099f047Sjmcneill 	if (pd->pd_bridge.ranges[PCI_RANGE_MEM].start >=
4501099f047Sjmcneill 	    pd->pd_bridge.ranges[PCI_RANGE_MEM].end) {
4511099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_MEM].start = 0;
4521099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_MEM].end = 0;
4531099f047Sjmcneill 	}
4541099f047Sjmcneill 
4551099f047Sjmcneill 	res = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG);
4561099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_PMEM].start =
4571099f047Sjmcneill 	    PCI_BRIDGE_PREFETCHMEM_BASE_ADDR(res);
4581099f047Sjmcneill 	pd->pd_bridge.ranges[PCI_RANGE_PMEM].end =
4591099f047Sjmcneill 	    PCI_BRIDGE_PREFETCHMEM_LIMIT_ADDR(res);
4601099f047Sjmcneill 	if (PCI_BRIDGE_PREFETCHMEM_64BITS(res)) {
4611099f047Sjmcneill 		reshigh = pci_conf_read(pc, tag,
4621099f047Sjmcneill 		    PCI_BRIDGE_PREFETCHBASEUP32_REG);
4631099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_PMEM].start |=
4641099f047Sjmcneill 		    (uint64_t)reshigh << 32;
4651099f047Sjmcneill 		reshigh = pci_conf_read(pc, tag,
4661099f047Sjmcneill 		    PCI_BRIDGE_PREFETCHLIMITUP32_REG);
4671099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_PMEM].end |=
4681099f047Sjmcneill 		    (uint64_t)reshigh << 32;
4691099f047Sjmcneill 	}
4701099f047Sjmcneill 	if (pd->pd_bridge.ranges[PCI_RANGE_PMEM].start >=
4711099f047Sjmcneill 	    pd->pd_bridge.ranges[PCI_RANGE_PMEM].end) {
4721099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_PMEM].start = 0;
4731099f047Sjmcneill 		pd->pd_bridge.ranges[PCI_RANGE_PMEM].end = 0;
4741099f047Sjmcneill 	}
4751099f047Sjmcneill }
4761099f047Sjmcneill 
4771099f047Sjmcneill /*
4781099f047Sjmcneill  * pci_resource_scan_device --
4791099f047Sjmcneill  *
4801099f047Sjmcneill  *   Determine the current configuration of a PCI device.
4811099f047Sjmcneill  */
4821099f047Sjmcneill static bool
pci_resource_scan_device(struct pci_resources * pr,struct pci_bus * parent_bus,uint8_t devno,uint8_t funcno)4831099f047Sjmcneill pci_resource_scan_device(struct pci_resources *pr,
4841099f047Sjmcneill     struct pci_bus *parent_bus, uint8_t devno, uint8_t funcno)
4851099f047Sjmcneill {
4861099f047Sjmcneill 	struct pci_device *pd;
4871099f047Sjmcneill 	pcitag_t tag;
4881099f047Sjmcneill 	pcireg_t id, bridge_bus;
4891099f047Sjmcneill 	uint8_t sec_bus;
4901099f047Sjmcneill 
4911099f047Sjmcneill 	tag = pci_make_tag(pr->pr_pc, parent_bus->pb_busno, devno, funcno);
4921099f047Sjmcneill 	id = pci_conf_read(pr->pr_pc, tag, PCI_ID_REG);
4931099f047Sjmcneill 	if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) {
4941099f047Sjmcneill 		return false;
4951099f047Sjmcneill 	}
4961099f047Sjmcneill 
4971099f047Sjmcneill 	pd = PCICONF_BUS_DEVICE(parent_bus, devno, funcno);
4981099f047Sjmcneill 	pd->pd_present = true;
4991099f047Sjmcneill 	pd->pd_bus = parent_bus;
5001099f047Sjmcneill 	pd->pd_tag = tag;
5011099f047Sjmcneill 	pd->pd_devno = devno;
5021099f047Sjmcneill 	pd->pd_funcno = funcno;
5031099f047Sjmcneill 	pd->pd_id = id;
5041099f047Sjmcneill 	pd->pd_class = pci_conf_read(pr->pr_pc, tag, PCI_CLASS_REG);
5051099f047Sjmcneill 	pd->pd_bhlc = pci_conf_read(pr->pr_pc, tag, PCI_BHLC_REG);
5061099f047Sjmcneill 
5071099f047Sjmcneill 	switch (PCI_HDRTYPE_TYPE(pd->pd_bhlc)) {
5081099f047Sjmcneill 	case PCI_HDRTYPE_DEVICE:
5091099f047Sjmcneill 		pci_resource_scan_bar(pr, pd, PCI_MAPREG_START,
5101099f047Sjmcneill 		    PCI_MAPREG_END, false);
5111099f047Sjmcneill 		break;
5121099f047Sjmcneill 	case PCI_HDRTYPE_PPB:
5131099f047Sjmcneill 		pci_resource_scan_bar(pr, pd, PCI_MAPREG_START,
5141099f047Sjmcneill 		    PCI_MAPREG_PPB_END, true);
5151099f047Sjmcneill 		pci_resource_scan_bridge(pr, pd);
5161099f047Sjmcneill 		break;
5171099f047Sjmcneill 	}
5181099f047Sjmcneill 
5191099f047Sjmcneill 	pci_resource_device_print(pr, pd);
5201099f047Sjmcneill 
5211099f047Sjmcneill 	if (PCI_HDRTYPE_TYPE(pd->pd_bhlc) == PCI_HDRTYPE_PPB &&
5221099f047Sjmcneill 	    PCI_CLASS(pd->pd_class) == PCI_CLASS_BRIDGE &&
5231099f047Sjmcneill 	    PCI_SUBCLASS(pd->pd_class) == PCI_SUBCLASS_BRIDGE_PCI) {
5241099f047Sjmcneill 		bridge_bus = pci_conf_read(pr->pr_pc, tag, PCI_BRIDGE_BUS_REG);
5251099f047Sjmcneill 		sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(bridge_bus);
5261099f047Sjmcneill 		if (sec_bus <= pr->pr_endbus) {
527*408f62c9Sjmcneill 			if (pci_resource_scan_bus(pr, pd, sec_bus) != 0) {
528*408f62c9Sjmcneill 				DPRINT("PCI: " PCI_SBDF_FMT " bus %u "
529*408f62c9Sjmcneill 				       "already scanned (firmware bug!)\n",
530*408f62c9Sjmcneill 				       PCI_SBDF_FMT_ARGS(pr, pd), sec_bus);
531*408f62c9Sjmcneill 			}
5321099f047Sjmcneill 		}
5331099f047Sjmcneill 	}
5341099f047Sjmcneill 
5351099f047Sjmcneill 	return true;
5361099f047Sjmcneill }
5371099f047Sjmcneill 
5381099f047Sjmcneill /*
5391099f047Sjmcneill  * pci_resource_scan_bus --
5401099f047Sjmcneill  *
5411099f047Sjmcneill  *   Enumerate devices on a bus, recursively.
5421099f047Sjmcneill  */
543*408f62c9Sjmcneill static int
pci_resource_scan_bus(struct pci_resources * pr,struct pci_device * bridge_dev,uint8_t busno)5441099f047Sjmcneill pci_resource_scan_bus(struct pci_resources *pr,
5451099f047Sjmcneill     struct pci_device *bridge_dev, uint8_t busno)
5461099f047Sjmcneill {
5471099f047Sjmcneill 	struct pci_bus *pb;
5481099f047Sjmcneill 	uint8_t devno, funcno;
5491099f047Sjmcneill 	uint8_t nfunc;
5501099f047Sjmcneill 
5511099f047Sjmcneill 	KASSERT(busno >= pr->pr_startbus);
5521099f047Sjmcneill 	KASSERT(busno <= pr->pr_endbus);
5531099f047Sjmcneill 
5541099f047Sjmcneill 	if (PCICONF_RES_BUS(pr, busno) != NULL) {
5551099f047Sjmcneill 		/*
5561099f047Sjmcneill 		 * Firmware has configured more than one bridge with the
5571099f047Sjmcneill 		 * same secondary bus number.
5581099f047Sjmcneill 		 */
559*408f62c9Sjmcneill 		return EINVAL;
5601099f047Sjmcneill 	}
5611099f047Sjmcneill 
5621099f047Sjmcneill 	pb = pci_new_bus(pr, busno, bridge_dev);
5631099f047Sjmcneill 	PCICONF_RES_BUS(pr, busno) = pb;
5641099f047Sjmcneill 
5651099f047Sjmcneill 	for (devno = 0; devno < PCI_MAX_DEVICE; devno++) {
5661099f047Sjmcneill 		if (!pci_resource_scan_device(pr, pb, devno, 0)) {
5671099f047Sjmcneill 			continue;
5681099f047Sjmcneill 		}
5691099f047Sjmcneill 		pb->pb_lastdevno = devno;
5701099f047Sjmcneill 
5711099f047Sjmcneill 		nfunc = pci_resource_device_functions(pr, busno, devno);
5721099f047Sjmcneill 		for (funcno = 1; funcno < nfunc; funcno++) {
5731099f047Sjmcneill 			pci_resource_scan_device(pr, pb, devno, funcno);
5741099f047Sjmcneill 		}
5751099f047Sjmcneill 	}
576*408f62c9Sjmcneill 
577*408f62c9Sjmcneill 	return 0;
5781099f047Sjmcneill }
5791099f047Sjmcneill 
5801099f047Sjmcneill /*
5811099f047Sjmcneill  * pci_resource_claim --
5821099f047Sjmcneill  *
5831099f047Sjmcneill  *   Claim a resource from a vmem arena. This is called to inform the
5841099f047Sjmcneill  *   resource manager about resources already configured by system firmware.
5851099f047Sjmcneill  */
5861099f047Sjmcneill static int
pci_resource_claim(vmem_t * arena,vmem_addr_t start,vmem_addr_t end)5871099f047Sjmcneill pci_resource_claim(vmem_t *arena, vmem_addr_t start, vmem_addr_t end)
5881099f047Sjmcneill {
5891099f047Sjmcneill 	KASSERT(end >= start);
5901099f047Sjmcneill 
5911099f047Sjmcneill 	return vmem_xalloc(arena, end - start + 1, 0, 0, 0, start, end,
5921099f047Sjmcneill 	    VM_BESTFIT | VM_NOSLEEP, NULL);
5931099f047Sjmcneill }
5941099f047Sjmcneill 
5951099f047Sjmcneill /*
5961099f047Sjmcneill  * pci_resource_alloc --
5971099f047Sjmcneill  *
5981099f047Sjmcneill  *   Allocate a resource from a vmem arena. This is called when configuring
5991099f047Sjmcneill  *   devices that were not already configured by system firmware.
6001099f047Sjmcneill  */
6011099f047Sjmcneill static int
pci_resource_alloc(vmem_t * arena,vmem_size_t size,vmem_size_t align,uint64_t * base)6021099f047Sjmcneill pci_resource_alloc(vmem_t *arena, vmem_size_t size, vmem_size_t align,
6031099f047Sjmcneill     uint64_t *base)
6041099f047Sjmcneill {
6051099f047Sjmcneill 	vmem_addr_t addr;
6061099f047Sjmcneill 	int error;
6071099f047Sjmcneill 
6081099f047Sjmcneill 	KASSERT(size != 0);
6091099f047Sjmcneill 
6101099f047Sjmcneill 	error = vmem_xalloc(arena, size, align, 0, 0, VMEM_ADDR_MIN,
6111099f047Sjmcneill 	    VMEM_ADDR_MAX, VM_BESTFIT | VM_NOSLEEP, &addr);
6121099f047Sjmcneill 	if (error == 0) {
6131099f047Sjmcneill 		*base = (uint64_t)addr;
6141099f047Sjmcneill 	}
6151099f047Sjmcneill 
6161099f047Sjmcneill 	return error;
6171099f047Sjmcneill }
6181099f047Sjmcneill 
6191099f047Sjmcneill /*
6201099f047Sjmcneill  * pci_resource_init_device --
6211099f047Sjmcneill  *
6221099f047Sjmcneill  *   Discover resources assigned by system firmware, notify the resource
6231099f047Sjmcneill  *   manager of these ranges, and determine if the device has additional
6241099f047Sjmcneill  *   resources that need to be allocated.
6251099f047Sjmcneill  */
6261099f047Sjmcneill static void
pci_resource_init_device(struct pci_resources * pr,struct pci_device * pd)6271099f047Sjmcneill pci_resource_init_device(struct pci_resources *pr,
6281099f047Sjmcneill     struct pci_device *pd)
6291099f047Sjmcneill {
6301099f047Sjmcneill 	struct pci_iores *pi;
6311099f047Sjmcneill 	struct pci_bus *pb = pd->pd_bus;
6321099f047Sjmcneill 	vmem_t *res_io = pb->pb_res[PCI_RANGE_IO];
6331099f047Sjmcneill 	vmem_t *res_mem = pb->pb_res[PCI_RANGE_MEM];
6341099f047Sjmcneill 	vmem_t *res_pmem = pb->pb_res[PCI_RANGE_PMEM];
6351099f047Sjmcneill 	pcireg_t cmd;
6361099f047Sjmcneill 	u_int enabled, required;
6371099f047Sjmcneill 	u_int iores;
6381099f047Sjmcneill 	int error;
6391099f047Sjmcneill 
6401099f047Sjmcneill 	KASSERT(pd->pd_present);
6411099f047Sjmcneill 
6421099f047Sjmcneill 	if (IS_TEST_DEVICE(pd)) {
6431099f047Sjmcneill 		cmd = pci_conf_read(pr->pr_pc, pd->pd_tag,
6441099f047Sjmcneill 		    PCI_COMMAND_STATUS_REG);
6451099f047Sjmcneill 		cmd &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE|
6461099f047Sjmcneill 			 PCI_COMMAND_MASTER_ENABLE);
6471099f047Sjmcneill 		pci_conf_write(pr->pr_pc, pd->pd_tag, PCI_COMMAND_STATUS_REG,
6481099f047Sjmcneill 		    cmd);
6491099f047Sjmcneill 	}
6501099f047Sjmcneill 
6511099f047Sjmcneill 	enabled = required = 0;
6521099f047Sjmcneill 	cmd = pci_conf_read(pr->pr_pc, pd->pd_tag, PCI_COMMAND_STATUS_REG);
6531099f047Sjmcneill 	if ((cmd & PCI_COMMAND_MEM_ENABLE) != 0) {
6541099f047Sjmcneill 		enabled |= __BIT(PCI_MAPREG_TYPE_MEM);
6551099f047Sjmcneill 	}
6561099f047Sjmcneill 	if ((cmd & PCI_COMMAND_IO_ENABLE) != 0) {
6571099f047Sjmcneill 		enabled |= __BIT(PCI_MAPREG_TYPE_IO);
6581099f047Sjmcneill 	}
6591099f047Sjmcneill 
6601099f047Sjmcneill 	for (iores = 0; iores < pd->pd_niores; iores++) {
6611099f047Sjmcneill 		pi = &pd->pd_iores[iores];
6621099f047Sjmcneill 
6631099f047Sjmcneill 		required |= __BIT(pi->pi_type);
6641099f047Sjmcneill 
6651099f047Sjmcneill 		if (IS_TEST_DEVICE(pd)) {
6661099f047Sjmcneill 			pci_conf_write(pr->pr_pc, pd->pd_tag,
6671099f047Sjmcneill 			    PCI_BAR(pi->pi_bar), 0);
6681099f047Sjmcneill 			continue;
6691099f047Sjmcneill 		}
6701099f047Sjmcneill 		if ((enabled & __BIT(pi->pi_type)) == 0) {
6711099f047Sjmcneill 			continue;
6721099f047Sjmcneill 		}
6731099f047Sjmcneill 
6741099f047Sjmcneill 		if (pi->pi_type == PCI_MAPREG_TYPE_IO) {
6751099f047Sjmcneill 			error = res_io == NULL ? ERANGE :
6761099f047Sjmcneill 			    pci_resource_claim(res_io, pi->pi_base,
6771099f047Sjmcneill 				pi->pi_base + pi->pi_size - 1);
6781099f047Sjmcneill 			if (error) {
6791099f047Sjmcneill 				DPRINT("PCI: " PCI_SBDF_FMT " [device] io "
6801099f047Sjmcneill 				       " %#" PRIx64 "-%#" PRIx64
6811099f047Sjmcneill 				       " invalid (%d)\n",
6821099f047Sjmcneill 				       PCI_SBDF_FMT_ARGS(pr, pd),
6831099f047Sjmcneill 				       pi->pi_base,
6841099f047Sjmcneill 				       pi->pi_base + pi->pi_size - 1,
6851099f047Sjmcneill 				       error);
6861099f047Sjmcneill 			}
6871099f047Sjmcneill 			continue;
6881099f047Sjmcneill 		}
6891099f047Sjmcneill 
6901099f047Sjmcneill 		KASSERT(pi->pi_type == PCI_MAPREG_TYPE_MEM);
6911099f047Sjmcneill 		error = ERANGE;
69272a3412dSjmcneill 		if (pi->pi_mem.prefetch) {
69372a3412dSjmcneill 			/*
69472a3412dSjmcneill 			 * Prefetchable memory must be allocated from the
69572a3412dSjmcneill 			 * bridge's prefetchable region.
69672a3412dSjmcneill 			 */
69772a3412dSjmcneill 			if (res_pmem != NULL) {
69872a3412dSjmcneill 				error = pci_resource_claim(res_pmem, pi->pi_base,
69972a3412dSjmcneill 				    pi->pi_base + pi->pi_size - 1);
70072a3412dSjmcneill 			}
70172a3412dSjmcneill 		} else if (pi->pi_mem.memtype == PCI_MAPREG_MEM_TYPE_64BIT) {
70272a3412dSjmcneill 			/*
70372a3412dSjmcneill 			 * Non-prefetchable 64-bit memory can be allocated from
70472a3412dSjmcneill 			 * any range. Prefer allocations from the prefetchable
70572a3412dSjmcneill 			 * region to save 32-bit only resources for 32-bit BARs.
70672a3412dSjmcneill 			 */
70772a3412dSjmcneill 			if (res_pmem != NULL) {
7081099f047Sjmcneill 				error = pci_resource_claim(res_pmem, pi->pi_base,
7091099f047Sjmcneill 				    pi->pi_base + pi->pi_size - 1);
7101099f047Sjmcneill 			}
7111099f047Sjmcneill 			if (error && res_mem != NULL) {
7121099f047Sjmcneill 				error = pci_resource_claim(res_mem, pi->pi_base,
7131099f047Sjmcneill 				    pi->pi_base + pi->pi_size - 1);
7141099f047Sjmcneill 			}
71572a3412dSjmcneill 		} else {
71672a3412dSjmcneill 			/*
71772a3412dSjmcneill 			 * Non-prefetchable 32-bit memory can be allocated from
71872a3412dSjmcneill 			 * any range, provided that the range is below 4GB. Try
71972a3412dSjmcneill 			 * the non-prefetchable range first, and if that fails,
72072a3412dSjmcneill 			 * make one last attempt at allocating from the
72172a3412dSjmcneill 			 * prefetchable range in case the platform provides
72272a3412dSjmcneill 			 * memory below 4GB.
72372a3412dSjmcneill 			 */
72472a3412dSjmcneill 			if (res_mem != NULL) {
72572a3412dSjmcneill 				error = pci_resource_claim(res_mem, pi->pi_base,
72672a3412dSjmcneill 				    pi->pi_base + pi->pi_size - 1);
72772a3412dSjmcneill 			}
72872a3412dSjmcneill 			if (error && res_pmem != NULL) {
72972a3412dSjmcneill 				error = pci_resource_claim(res_pmem, pi->pi_base,
73072a3412dSjmcneill 				    pi->pi_base + pi->pi_size - 1);
73172a3412dSjmcneill 			}
73272a3412dSjmcneill 		}
7331099f047Sjmcneill 		if (error) {
7341099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT " [device] mem"
7351099f047Sjmcneill 			       " (%sprefetchable)"
7361099f047Sjmcneill 			       " %#" PRIx64 "-%#" PRIx64
7371099f047Sjmcneill 			       " invalid (%d)\n",
7381099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
7391099f047Sjmcneill 			       pi->pi_mem.prefetch ? "" : "non-",
7401099f047Sjmcneill 			       pi->pi_base,
7411099f047Sjmcneill 			       pi->pi_base + pi->pi_size - 1,
7421099f047Sjmcneill 			       error);
7431099f047Sjmcneill 		}
7441099f047Sjmcneill 	}
7451099f047Sjmcneill 
7461099f047Sjmcneill 	pd->pd_configured = (enabled & required) == required;
7471099f047Sjmcneill 
7481099f047Sjmcneill 	if (!pd->pd_configured) {
7491099f047Sjmcneill 		DPRINT("PCI: " PCI_SBDF_FMT " [device] "
7501099f047Sjmcneill 		       "not configured by firmware\n",
7511099f047Sjmcneill 		       PCI_SBDF_FMT_ARGS(pr, pd));
7521099f047Sjmcneill 	}
7531099f047Sjmcneill }
7541099f047Sjmcneill 
7551099f047Sjmcneill /*
7561099f047Sjmcneill  * pci_resource_init_bus --
7571099f047Sjmcneill  *
7581099f047Sjmcneill  *   Discover resources in use on a given bus, recursively.
7591099f047Sjmcneill  */
7601099f047Sjmcneill static void
pci_resource_init_bus(struct pci_resources * pr,uint8_t busno)7611099f047Sjmcneill pci_resource_init_bus(struct pci_resources *pr, uint8_t busno)
7621099f047Sjmcneill {
7631099f047Sjmcneill 	struct pci_bus *pb, *parent_bus;
7641099f047Sjmcneill 	struct pci_device *pd, *bridge;
7651099f047Sjmcneill 	uint8_t devno, funcno;
7661099f047Sjmcneill 	uint8_t nfunc;
7671099f047Sjmcneill 	int error;
7681099f047Sjmcneill 
7691099f047Sjmcneill 	KASSERT(busno >= pr->pr_startbus);
7701099f047Sjmcneill 	KASSERT(busno <= pr->pr_endbus);
7711099f047Sjmcneill 
7721099f047Sjmcneill 	pb = PCICONF_RES_BUS(pr, busno);
7731099f047Sjmcneill 	bridge = pb->pb_bridge;
7741099f047Sjmcneill 
7751099f047Sjmcneill 	KASSERT(pb != NULL);
7761099f047Sjmcneill 	KASSERT((busno == pr->pr_startbus) == (bridge == NULL));
7771099f047Sjmcneill 
7781099f047Sjmcneill 	if (bridge == NULL) {
7791099f047Sjmcneill 		/* Use resources provided by firmware. */
7801099f047Sjmcneill 		PCI_RANGE_FOREACH(prtype) {
7811099f047Sjmcneill 			pb->pb_res[prtype] = pr->pr_res[prtype];
7821099f047Sjmcneill 			pr->pr_res[prtype] = NULL;
7831099f047Sjmcneill 		}
7841099f047Sjmcneill 	} else {
7851099f047Sjmcneill 		/*
7861099f047Sjmcneill 		 * Using the resources configured in to the bridge by
7871099f047Sjmcneill 		 * firmware, claim the resources on the parent bus and
7881099f047Sjmcneill 		 * create a new vmem arena for the secondary bus.
7891099f047Sjmcneill 		 */
7901099f047Sjmcneill 		KASSERT(bridge->pd_bus != NULL);
7911099f047Sjmcneill 		parent_bus = bridge->pd_bus;
7921099f047Sjmcneill 		PCI_RANGE_FOREACH(prtype) {
7931099f047Sjmcneill 			if (parent_bus->pb_res[prtype] == NULL ||
7941099f047Sjmcneill 			    !bridge->pd_bridge.ranges[prtype].end) {
7951099f047Sjmcneill 				continue;
7961099f047Sjmcneill 			}
7971099f047Sjmcneill 			error = pci_resource_claim(
7981099f047Sjmcneill 			    parent_bus->pb_res[prtype],
7991099f047Sjmcneill 			    bridge->pd_bridge.ranges[prtype].start,
8001099f047Sjmcneill 			    bridge->pd_bridge.ranges[prtype].end);
8011099f047Sjmcneill 			if (error == 0) {
8021099f047Sjmcneill 				pb->pb_res[prtype] = pci_create_vmem(
8031099f047Sjmcneill 				    pci_resource_typename(prtype),
8041099f047Sjmcneill 				    bridge->pd_bridge.ranges[prtype].start,
8051099f047Sjmcneill 				    bridge->pd_bridge.ranges[prtype].end);
8061099f047Sjmcneill 				KASSERT(pb->pb_res[prtype] != NULL);
8071099f047Sjmcneill 			} else {
8081099f047Sjmcneill 				DPRINT("PCI: " PCI_SBDF_FMT " bridge (bus %u)"
8091099f047Sjmcneill 				       " %-4s %#" PRIx64 "-%#" PRIx64
8101099f047Sjmcneill 				       " invalid\n",
8111099f047Sjmcneill 				       PCI_SBDF_FMT_ARGS(pr, bridge), busno,
8121099f047Sjmcneill 				       pci_resource_typename(prtype),
8131099f047Sjmcneill 				       bridge->pd_bridge.ranges[prtype].start,
8141099f047Sjmcneill 				       bridge->pd_bridge.ranges[prtype].end);
8151099f047Sjmcneill 			}
8161099f047Sjmcneill 		}
8171099f047Sjmcneill 	}
8181099f047Sjmcneill 
8191099f047Sjmcneill 	for (devno = 0; devno <= pb->pb_lastdevno; devno++) {
8201099f047Sjmcneill 		KASSERT(devno < PCI_MAX_DEVICE);
8211099f047Sjmcneill 		nfunc = pci_resource_device_functions(pr, busno, devno);
8221099f047Sjmcneill 		for (funcno = 0; funcno < nfunc; funcno++) {
8231099f047Sjmcneill 			pd = PCICONF_BUS_DEVICE(pb, devno, funcno);
8241099f047Sjmcneill 			if (!pd->pd_present) {
8251099f047Sjmcneill 				continue;
8261099f047Sjmcneill 			}
8271099f047Sjmcneill 			if (pd->pd_ppb) {
8281099f047Sjmcneill 				uint8_t sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(
8291099f047Sjmcneill 				    pd->pd_bridge.bridge_bus);
8301099f047Sjmcneill 				pci_resource_init_bus(pr, sec_bus);
8311099f047Sjmcneill 			}
8321099f047Sjmcneill 			pci_resource_init_device(pr, pd);
8331099f047Sjmcneill 		}
8341099f047Sjmcneill 	}
8351099f047Sjmcneill }
8361099f047Sjmcneill 
8371099f047Sjmcneill /*
8381099f047Sjmcneill  * pci_resource_probe --
8391099f047Sjmcneill  *
8401099f047Sjmcneill  *   Scan for PCI devices and initialize the resource manager.
8411099f047Sjmcneill  */
8421099f047Sjmcneill static void
pci_resource_probe(struct pci_resources * pr,const struct pci_resource_info * info)8431099f047Sjmcneill pci_resource_probe(struct pci_resources *pr,
8441099f047Sjmcneill     const struct pci_resource_info *info)
8451099f047Sjmcneill {
8461099f047Sjmcneill 	uint8_t startbus = (uint8_t)info->ranges[PCI_RANGE_BUS].start;
8471099f047Sjmcneill 	uint8_t endbus = (uint8_t)info->ranges[PCI_RANGE_BUS].end;
8481099f047Sjmcneill 	u_int nbus;
8491099f047Sjmcneill 
8501099f047Sjmcneill 	KASSERT(startbus <= endbus);
8511099f047Sjmcneill 	KASSERT(pr->pr_bus == NULL);
8521099f047Sjmcneill 
8531099f047Sjmcneill 	nbus = endbus - startbus + 1;
8541099f047Sjmcneill 
8551099f047Sjmcneill 	pr->pr_pc = info->pc;
8561099f047Sjmcneill 	pr->pr_startbus = startbus;
8571099f047Sjmcneill 	pr->pr_endbus = endbus;
8581099f047Sjmcneill 	pr->pr_bus = kmem_zalloc(nbus * sizeof(struct pci_bus *), KM_SLEEP);
8591099f047Sjmcneill 	memcpy(pr->pr_ranges, info->ranges, sizeof(pr->pr_ranges));
8601099f047Sjmcneill 	PCI_RANGE_FOREACH(prtype) {
8611099f047Sjmcneill 		if (prtype == PCI_RANGE_BUS || info->ranges[prtype].end) {
8621099f047Sjmcneill 			pr->pr_res[prtype] = pci_create_vmem(
8631099f047Sjmcneill 			    pci_resource_typename(prtype),
8641099f047Sjmcneill 			    info->ranges[prtype].start,
8651099f047Sjmcneill 			    info->ranges[prtype].end);
8661099f047Sjmcneill 			KASSERT(pr->pr_res[prtype] != NULL);
8671099f047Sjmcneill 		}
8681099f047Sjmcneill 	}
8691099f047Sjmcneill 
8701099f047Sjmcneill 	/* Scan devices */
8711099f047Sjmcneill 	pci_resource_scan_bus(pr, NULL, pr->pr_startbus);
8721099f047Sjmcneill 
8731099f047Sjmcneill 	/*
8741099f047Sjmcneill 	 * Create per-bus resource pools and remove ranges that are already
8751099f047Sjmcneill 	 * in use by devices and downstream bridges.
8761099f047Sjmcneill 	 */
8771099f047Sjmcneill 	pci_resource_init_bus(pr, pr->pr_startbus);
8781099f047Sjmcneill }
8791099f047Sjmcneill 
8801099f047Sjmcneill /*
8811099f047Sjmcneill  * pci_resource_alloc_device --
8821099f047Sjmcneill  *
8831099f047Sjmcneill  *   Attempt to allocate resources for a given device.
8841099f047Sjmcneill  */
8851099f047Sjmcneill static void
pci_resource_alloc_device(struct pci_resources * pr,struct pci_device * pd)8861099f047Sjmcneill pci_resource_alloc_device(struct pci_resources *pr, struct pci_device *pd)
8871099f047Sjmcneill {
8881099f047Sjmcneill 	struct pci_iores *pi;
8891099f047Sjmcneill 	vmem_t *arena;
8901099f047Sjmcneill 	pcireg_t cmd, ocmd, base;
8911099f047Sjmcneill 	uint64_t addr;
8921099f047Sjmcneill 	u_int enabled;
8931099f047Sjmcneill 	u_int res;
8941099f047Sjmcneill 	u_int align;
8951099f047Sjmcneill 	int error;
8961099f047Sjmcneill 
8971099f047Sjmcneill 	enabled = 0;
8981099f047Sjmcneill 	ocmd = cmd = pci_conf_read(pr->pr_pc, pd->pd_tag,
8991099f047Sjmcneill 	    PCI_COMMAND_STATUS_REG);
9001099f047Sjmcneill 	if ((cmd & PCI_COMMAND_MEM_ENABLE) != 0) {
9011099f047Sjmcneill 		enabled |= __BIT(PCI_MAPREG_TYPE_MEM);
9021099f047Sjmcneill 	}
9031099f047Sjmcneill 	if ((cmd & PCI_COMMAND_IO_ENABLE) != 0) {
9041099f047Sjmcneill 		enabled |= __BIT(PCI_MAPREG_TYPE_IO);
9051099f047Sjmcneill 	}
9061099f047Sjmcneill 
9071099f047Sjmcneill 	for (res = 0; res < pd->pd_niores; res++) {
9081099f047Sjmcneill 		pi = &pd->pd_iores[res];
9091099f047Sjmcneill 
9101099f047Sjmcneill 		if ((enabled & __BIT(pi->pi_type)) != 0) {
9111099f047Sjmcneill 			continue;
9121099f047Sjmcneill 		}
9131099f047Sjmcneill 
9141099f047Sjmcneill 		if (pi->pi_type == PCI_MAPREG_TYPE_IO) {
9151099f047Sjmcneill 			arena = pd->pd_bus->pb_res[PCI_RANGE_IO];
9161099f047Sjmcneill 			align = uimax(pi->pi_size, 4);
9171099f047Sjmcneill 		} else {
9181099f047Sjmcneill 			KASSERT(pi->pi_type == PCI_MAPREG_TYPE_MEM);
9191099f047Sjmcneill 			arena = NULL;
9201099f047Sjmcneill 			align = uimax(pi->pi_size, 16);
9211099f047Sjmcneill 			if (pi->pi_mem.prefetch) {
9221099f047Sjmcneill 				arena = pd->pd_bus->pb_res[PCI_RANGE_PMEM];
9231099f047Sjmcneill 			}
9241099f047Sjmcneill 			if (arena == NULL) {
9251099f047Sjmcneill 				arena = pd->pd_bus->pb_res[PCI_RANGE_MEM];
9261099f047Sjmcneill 			}
9271099f047Sjmcneill 		}
9281099f047Sjmcneill 		if (arena == NULL) {
9291099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT " BAR%u failed to"
9301099f047Sjmcneill 			       " allocate %#" PRIx64 " bytes (no arena)\n",
9311099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
9321099f047Sjmcneill 			       pi->pi_bar, pi->pi_size);
9331099f047Sjmcneill 			return;
9341099f047Sjmcneill 		}
9351099f047Sjmcneill 		error = pci_resource_alloc(arena, pi->pi_size, align, &addr);
9361099f047Sjmcneill 		if (error != 0) {
9371099f047Sjmcneill 			DPRINT("PCI: " PCI_SBDF_FMT " BAR%u failed to"
9381099f047Sjmcneill 			       " allocate %#" PRIx64 " bytes (no space)\n",
9391099f047Sjmcneill 			       PCI_SBDF_FMT_ARGS(pr, pd),
9401099f047Sjmcneill 			       pi->pi_bar, pi->pi_size);
9411099f047Sjmcneill 			return;
9421099f047Sjmcneill 		}
9431099f047Sjmcneill 		DPRINT("PCI: " PCI_SBDF_FMT " BAR%u assigned range"
9441099f047Sjmcneill 		       " 0x%#" PRIx64 "-0x%#" PRIx64 "\n",
9451099f047Sjmcneill 		       PCI_SBDF_FMT_ARGS(pr, pd),
9461099f047Sjmcneill 		       pi->pi_bar, addr, addr + pi->pi_size - 1);
9471099f047Sjmcneill 
9481099f047Sjmcneill 		if (pi->pi_type == PCI_MAPREG_TYPE_IO) {
9491099f047Sjmcneill 			cmd |= PCI_COMMAND_IO_ENABLE;
9501099f047Sjmcneill 			pci_conf_write(pr->pr_pc, pd->pd_tag,
9511099f047Sjmcneill 			    PCI_BAR(pi->pi_bar),
9521099f047Sjmcneill 			    PCI_MAPREG_IO_ADDR(addr) | PCI_MAPREG_TYPE_IO);
9531099f047Sjmcneill 		} else {
9541099f047Sjmcneill 			cmd |= PCI_COMMAND_MEM_ENABLE;
9551099f047Sjmcneill 			base = pci_conf_read(pr->pr_pc, pd->pd_tag,
9561099f047Sjmcneill 			    PCI_BAR(pi->pi_bar));
9571099f047Sjmcneill 			base = PCI_MAPREG_MEM_ADDR(addr) |
9581099f047Sjmcneill 			    PCI_MAPREG_MEM_TYPE(base);
9591099f047Sjmcneill 			pci_conf_write(pr->pr_pc, pd->pd_tag,
9601099f047Sjmcneill 			    PCI_BAR(pi->pi_bar), base);
9611099f047Sjmcneill 			if (pi->pi_mem.memtype == PCI_MAPREG_MEM_TYPE_64BIT) {
9621099f047Sjmcneill 				base = (pcireg_t)
9631099f047Sjmcneill 				    (PCI_MAPREG_MEM64_ADDR(addr) >> 32);
9641099f047Sjmcneill 				pci_conf_write(pr->pr_pc, pd->pd_tag,
9651099f047Sjmcneill 				    PCI_BAR(pi->pi_bar + 1), base);
9661099f047Sjmcneill 			}
9671099f047Sjmcneill 		}
9681099f047Sjmcneill 	}
9691099f047Sjmcneill 
9701099f047Sjmcneill 	if (ocmd != cmd) {
9711099f047Sjmcneill 		pci_conf_write(pr->pr_pc, pd->pd_tag,
9721099f047Sjmcneill 		    PCI_COMMAND_STATUS_REG, cmd);
9731099f047Sjmcneill 	}
9741099f047Sjmcneill }
9751099f047Sjmcneill 
9761099f047Sjmcneill /*
9771099f047Sjmcneill  * pci_resource_alloc_bus --
9781099f047Sjmcneill  *
9791099f047Sjmcneill  *   Attempt to assign resources to all devices on a given bus, recursively.
9801099f047Sjmcneill  */
9811099f047Sjmcneill static void
pci_resource_alloc_bus(struct pci_resources * pr,uint8_t busno)9821099f047Sjmcneill pci_resource_alloc_bus(struct pci_resources *pr, uint8_t busno)
9831099f047Sjmcneill {
9841099f047Sjmcneill 	struct pci_bus *pb = PCICONF_RES_BUS(pr, busno);
9851099f047Sjmcneill 	struct pci_device *pd;
9861099f047Sjmcneill 	uint8_t devno, funcno;
9871099f047Sjmcneill 
9881099f047Sjmcneill 	for (devno = 0; devno <= pb->pb_lastdevno; devno++) {
9891099f047Sjmcneill 		for (funcno = 0; funcno < 8; funcno++) {
9901099f047Sjmcneill 			pd = PCICONF_BUS_DEVICE(pb, devno, funcno);
9911099f047Sjmcneill 			if (!pd->pd_present) {
9921099f047Sjmcneill 				if (funcno == 0) {
9931099f047Sjmcneill 					break;
9941099f047Sjmcneill 				}
9951099f047Sjmcneill 				continue;
9961099f047Sjmcneill 			}
9971099f047Sjmcneill 			if (!pd->pd_configured) {
9981099f047Sjmcneill 				pci_resource_alloc_device(pr, pd);
9991099f047Sjmcneill 			}
10001099f047Sjmcneill 			if (pd->pd_ppb) {
10011099f047Sjmcneill 				uint8_t sec_bus = PCI_BRIDGE_BUS_NUM_SECONDARY(
10021099f047Sjmcneill 				    pd->pd_bridge.bridge_bus);
10031099f047Sjmcneill 				pci_resource_alloc_bus(pr, sec_bus);
10041099f047Sjmcneill 			}
10051099f047Sjmcneill 		}
10061099f047Sjmcneill 	}
10071099f047Sjmcneill }
10081099f047Sjmcneill 
10091099f047Sjmcneill /*
10101099f047Sjmcneill  * pci_resource_init --
10111099f047Sjmcneill  *
10121099f047Sjmcneill  *   Public interface to PCI resource manager. Scans for available devices
10131099f047Sjmcneill  *   and assigns resources.
10141099f047Sjmcneill  */
10151099f047Sjmcneill void
pci_resource_init(const struct pci_resource_info * info)10161099f047Sjmcneill pci_resource_init(const struct pci_resource_info *info)
10171099f047Sjmcneill {
10181099f047Sjmcneill 	struct pci_resources pr = {};
10191099f047Sjmcneill 
10201099f047Sjmcneill 	pci_resource_probe(&pr, info);
10211099f047Sjmcneill 	pci_resource_alloc_bus(&pr, pr.pr_startbus);
10221099f047Sjmcneill }
10231099f047Sjmcneill 
10241099f047Sjmcneill /*
10251099f047Sjmcneill  * pci_resource_typename --
10261099f047Sjmcneill  *
10271099f047Sjmcneill  *   Return a string description of a PCI range type.
10281099f047Sjmcneill  */
10291099f047Sjmcneill const char *
pci_resource_typename(enum pci_range_type prtype)10301099f047Sjmcneill pci_resource_typename(enum pci_range_type prtype)
10311099f047Sjmcneill {
10321099f047Sjmcneill 	KASSERT(prtype < NUM_PCI_RANGES);
10331099f047Sjmcneill 	return pci_range_typenames[prtype];
10341099f047Sjmcneill }
1035