xref: /netbsd-src/sys/arch/x86/pci/pci_ranges.c (revision 6b5045cd66becdc075c8b0448426183de0e5b7e0)
1*6b5045cdSchristos /*	$NetBSD: pci_ranges.c,v 1.9 2021/06/21 03:01:23 christos Exp $	*/
2cfc495a0Sdyoung 
3cfc495a0Sdyoung /*-
4cfc495a0Sdyoung  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5cfc495a0Sdyoung  * All rights reserved.
6cfc495a0Sdyoung  *
7cfc495a0Sdyoung  * This code is derived from software contributed to The NetBSD Foundation
8cfc495a0Sdyoung  * by David Young <dyoung@NetBSD.org>.
9cfc495a0Sdyoung  *
10cfc495a0Sdyoung  * Redistribution and use in source and binary forms, with or without
11cfc495a0Sdyoung  * modification, are permitted provided that the following conditions
12cfc495a0Sdyoung  * are met:
13cfc495a0Sdyoung  * 1. Redistributions of source code must retain the above copyright
14cfc495a0Sdyoung  *    notice, this list of conditions and the following disclaimer.
15cfc495a0Sdyoung  * 2. Redistributions in binary form must reproduce the above copyright
16cfc495a0Sdyoung  *    notice, this list of conditions and the following disclaimer in the
17cfc495a0Sdyoung  *    documentation and/or other materials provided with the distribution.
18cfc495a0Sdyoung  *
19cfc495a0Sdyoung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20cfc495a0Sdyoung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21cfc495a0Sdyoung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22cfc495a0Sdyoung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23cfc495a0Sdyoung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24cfc495a0Sdyoung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25cfc495a0Sdyoung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26cfc495a0Sdyoung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27cfc495a0Sdyoung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28cfc495a0Sdyoung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29cfc495a0Sdyoung  * POSSIBILITY OF SUCH DAMAGE.
30cfc495a0Sdyoung  */
31cfc495a0Sdyoung 
32cfc495a0Sdyoung 
33cfc495a0Sdyoung #include <sys/cdefs.h>
34*6b5045cdSchristos __KERNEL_RCSID(0, "$NetBSD: pci_ranges.c,v 1.9 2021/06/21 03:01:23 christos Exp $");
35cfc495a0Sdyoung 
36cfc495a0Sdyoung #include <sys/types.h>
37cfc495a0Sdyoung #include <sys/param.h>
38cfc495a0Sdyoung #include <sys/systm.h>
39cfc495a0Sdyoung #include <sys/errno.h>
40cfc495a0Sdyoung #include <sys/bus.h>
41cfc495a0Sdyoung #include <sys/kmem.h>
42cfc495a0Sdyoung 
43cfc495a0Sdyoung #include <prop/proplib.h>
44cfc495a0Sdyoung #include <ppath/ppath.h>
45cfc495a0Sdyoung 
46cfc495a0Sdyoung #include <dev/pci/pcivar.h>
47cfc495a0Sdyoung #include <dev/pci/pcireg.h>
48cfc495a0Sdyoung #include <dev/pci/pccbbreg.h>
49cfc495a0Sdyoung 
508295eb1bSdyoung #include <machine/autoconf.h>
518295eb1bSdyoung 
52cfc495a0Sdyoung typedef enum pci_alloc_regtype {
53cfc495a0Sdyoung 	  PCI_ALLOC_REGTYPE_NONE = 0
54cfc495a0Sdyoung 	, PCI_ALLOC_REGTYPE_BAR = 1
55cfc495a0Sdyoung 	, PCI_ALLOC_REGTYPE_WIN = 2
56cfc495a0Sdyoung 	, PCI_ALLOC_REGTYPE_CBWIN = 3
57cfc495a0Sdyoung 	, PCI_ALLOC_REGTYPE_VGA_EN = 4
58cfc495a0Sdyoung } pci_alloc_regtype_t;
59cfc495a0Sdyoung 
60cfc495a0Sdyoung typedef enum pci_alloc_space {
61cfc495a0Sdyoung 	  PCI_ALLOC_SPACE_IO = 0
62cfc495a0Sdyoung 	, PCI_ALLOC_SPACE_MEM = 1
63cfc495a0Sdyoung } pci_alloc_space_t;
64cfc495a0Sdyoung 
65cfc495a0Sdyoung typedef enum pci_alloc_flags {
66cfc495a0Sdyoung 	  PCI_ALLOC_F_PREFETCHABLE = 0x1
67cfc495a0Sdyoung } pci_alloc_flags_t;
68cfc495a0Sdyoung 
69cfc495a0Sdyoung typedef struct pci_alloc {
70cfc495a0Sdyoung 	TAILQ_ENTRY(pci_alloc)		pal_link;
71cfc495a0Sdyoung 	pcitag_t			pal_tag;
72cfc495a0Sdyoung 	uint64_t			pal_addr;
73cfc495a0Sdyoung 	uint64_t			pal_size;
74cfc495a0Sdyoung 	pci_alloc_regtype_t		pal_type;
75cfc495a0Sdyoung 	struct pci_alloc_reg {
76cfc495a0Sdyoung 		int			r_ofs;
77cfc495a0Sdyoung 		pcireg_t		r_val;
78cfc495a0Sdyoung 		pcireg_t		r_mask;
79cfc495a0Sdyoung 	}				pal_reg[3];
80cfc495a0Sdyoung 	pci_alloc_space_t		pal_space;
81cfc495a0Sdyoung 	pci_alloc_flags_t		pal_flags;
82cfc495a0Sdyoung } pci_alloc_t;
83cfc495a0Sdyoung 
84cfc495a0Sdyoung typedef struct pci_alloc_reg pci_alloc_reg_t;
85cfc495a0Sdyoung 
86cfc495a0Sdyoung TAILQ_HEAD(pci_alloc_list, pci_alloc);
87cfc495a0Sdyoung 
88cfc495a0Sdyoung typedef struct pci_alloc_list pci_alloc_list_t;
89cfc495a0Sdyoung 
90cfc495a0Sdyoung static pci_alloc_t *
pci_alloc_dup(const pci_alloc_t * pal)91cfc495a0Sdyoung pci_alloc_dup(const pci_alloc_t *pal)
92cfc495a0Sdyoung {
93cfc495a0Sdyoung 	pci_alloc_t *npal;
94cfc495a0Sdyoung 
95fd34ea77Schs 	npal = kmem_alloc(sizeof(*npal), KM_SLEEP);
96cfc495a0Sdyoung 	*npal = *pal;
97cfc495a0Sdyoung 	return npal;
98cfc495a0Sdyoung }
99cfc495a0Sdyoung 
100cfc495a0Sdyoung static bool
pci_alloc_linkdup(pci_alloc_list_t * pals,const pci_alloc_t * pal)101cfc495a0Sdyoung pci_alloc_linkdup(pci_alloc_list_t *pals, const pci_alloc_t *pal)
102cfc495a0Sdyoung {
103cfc495a0Sdyoung 	pci_alloc_t *npal;
104cfc495a0Sdyoung 
105cfc495a0Sdyoung 	if ((npal = pci_alloc_dup(pal)) == NULL)
106cfc495a0Sdyoung 		return false;
107cfc495a0Sdyoung 
108cfc495a0Sdyoung 	TAILQ_INSERT_TAIL(pals, npal, pal_link);
109cfc495a0Sdyoung 
110cfc495a0Sdyoung 	return true;
111cfc495a0Sdyoung }
112cfc495a0Sdyoung 
113cfc495a0Sdyoung struct range_infer_ctx {
114cfc495a0Sdyoung 	pci_chipset_tag_t	ric_pc;
115cfc495a0Sdyoung 	pci_alloc_list_t	ric_pals;
116cfc495a0Sdyoung 	bus_addr_t		ric_mmio_bottom;
117cfc495a0Sdyoung 	bus_addr_t		ric_mmio_top;
118cfc495a0Sdyoung 	bus_addr_t		ric_io_bottom;
119cfc495a0Sdyoung 	bus_addr_t		ric_io_top;
120cfc495a0Sdyoung };
121cfc495a0Sdyoung 
122cfc495a0Sdyoung static bool
io_range_extend(struct range_infer_ctx * ric,const pci_alloc_t * pal)123cfc495a0Sdyoung io_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
124cfc495a0Sdyoung {
125cfc495a0Sdyoung 	if (ric->ric_io_bottom > pal->pal_addr)
126cfc495a0Sdyoung 		ric->ric_io_bottom = pal->pal_addr;
127cfc495a0Sdyoung 	if (ric->ric_io_top < pal->pal_addr + pal->pal_size)
128cfc495a0Sdyoung 		ric->ric_io_top = pal->pal_addr + pal->pal_size;
129cfc495a0Sdyoung 
130cfc495a0Sdyoung 	return pci_alloc_linkdup(&ric->ric_pals, pal);
131cfc495a0Sdyoung }
132cfc495a0Sdyoung 
133cfc495a0Sdyoung static bool
io_range_extend_by_bar(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t curbar,pcireg_t sizebar)134cfc495a0Sdyoung io_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun,
135cfc495a0Sdyoung     int ofs, pcireg_t curbar, pcireg_t sizebar)
136cfc495a0Sdyoung {
137cfc495a0Sdyoung 	pci_alloc_reg_t *r;
138cfc495a0Sdyoung 	pci_alloc_t pal = {
139cfc495a0Sdyoung 		  .pal_flags = 0
140cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_IO
141cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_BAR
142cfc495a0Sdyoung 		, .pal_reg = {{
143cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
144cfc495a0Sdyoung 		  }}
145cfc495a0Sdyoung 	};
146cfc495a0Sdyoung 
147cfc495a0Sdyoung 	r = &pal.pal_reg[0];
148cfc495a0Sdyoung 
149cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
150cfc495a0Sdyoung 	r->r_ofs = ofs;
151cfc495a0Sdyoung 	r->r_val = curbar;
152cfc495a0Sdyoung 
153cfc495a0Sdyoung 	pal.pal_addr = PCI_MAPREG_IO_ADDR(curbar);
154cfc495a0Sdyoung 	pal.pal_size = PCI_MAPREG_IO_SIZE(sizebar);
155cfc495a0Sdyoung 
156cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
157cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
158cfc495a0Sdyoung 
159cfc495a0Sdyoung 	return (pal.pal_size == 0) || io_range_extend(ric, &pal);
160cfc495a0Sdyoung }
161cfc495a0Sdyoung 
162cfc495a0Sdyoung static bool
io_range_extend_by_vga_enable(struct range_infer_ctx * ric,int bus,int dev,int fun,pcireg_t csr,pcireg_t bcr)163cfc495a0Sdyoung io_range_extend_by_vga_enable(struct range_infer_ctx *ric,
164cfc495a0Sdyoung     int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
165cfc495a0Sdyoung {
166cfc495a0Sdyoung 	pci_alloc_reg_t *r;
167cfc495a0Sdyoung 	pci_alloc_t tpal = {
168cfc495a0Sdyoung 		  .pal_flags = 0
169cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_IO
170cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
171cfc495a0Sdyoung 		, .pal_reg = {{
172cfc495a0Sdyoung 			  .r_ofs = PCI_COMMAND_STATUS_REG
173cfc495a0Sdyoung 			, .r_mask = PCI_COMMAND_IO_ENABLE
174cfc495a0Sdyoung 		  }, {
175cfc495a0Sdyoung 			  .r_ofs = PCI_BRIDGE_CONTROL_REG
17679770474Smsaitoh 			, .r_mask = PCI_BRIDGE_CONTROL_VGA;
177cfc495a0Sdyoung 		  }}
178cfc495a0Sdyoung 	}, pal[2];
179cfc495a0Sdyoung 
180cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
181cfc495a0Sdyoung 
182cfc495a0Sdyoung 	if ((csr & PCI_COMMAND_IO_ENABLE) == 0 ||
18379770474Smsaitoh 	    (bcr & PCI_BRIDGE_CONTROL_VGA) == 0) {
184cfc495a0Sdyoung 		aprint_debug("%s: %d.%d.%d I/O or VGA disabled\n",
185cfc495a0Sdyoung 		    __func__, bus, dev, fun);
186cfc495a0Sdyoung 		return true;
187cfc495a0Sdyoung 	}
188cfc495a0Sdyoung 
189cfc495a0Sdyoung 	r = &tpal.pal_reg[0];
190cfc495a0Sdyoung 	tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
191cfc495a0Sdyoung 	r[0].r_val = csr;
192cfc495a0Sdyoung 	r[1].r_val = bcr;
193cfc495a0Sdyoung 
194cfc495a0Sdyoung 	pal[0] = pal[1] = tpal;
195cfc495a0Sdyoung 
196cfc495a0Sdyoung 	pal[0].pal_addr = 0x3b0;
197cfc495a0Sdyoung 	pal[0].pal_size = 0x3bb - 0x3b0 + 1;
198cfc495a0Sdyoung 
199cfc495a0Sdyoung 	pal[1].pal_addr = 0x3c0;
200cfc495a0Sdyoung 	pal[1].pal_size = 0x3df - 0x3c0 + 1;
201cfc495a0Sdyoung 
202cfc495a0Sdyoung 	/* XXX add aliases for pal[0..1] */
203cfc495a0Sdyoung 
204cfc495a0Sdyoung 	return io_range_extend(ric, &pal[0]) && io_range_extend(ric, &pal[1]);
205cfc495a0Sdyoung }
206cfc495a0Sdyoung 
207cfc495a0Sdyoung static bool
io_range_extend_by_win(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,int ofshigh,pcireg_t io,pcireg_t iohigh)208cfc495a0Sdyoung io_range_extend_by_win(struct range_infer_ctx *ric,
209cfc495a0Sdyoung     int bus, int dev, int fun, int ofs, int ofshigh,
210cfc495a0Sdyoung     pcireg_t io, pcireg_t iohigh)
211cfc495a0Sdyoung {
212cfc495a0Sdyoung 	const int fourkb = 4 * 1024;
213cfc495a0Sdyoung 	pcireg_t baser, limitr;
214cfc495a0Sdyoung 	pci_alloc_reg_t *r;
215cfc495a0Sdyoung 	pci_alloc_t pal = {
216cfc495a0Sdyoung 		  .pal_flags = 0
217cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_IO
218cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_WIN
219cfc495a0Sdyoung 		, .pal_reg = {{
220cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
221cfc495a0Sdyoung 		  }}
222cfc495a0Sdyoung 	};
223cfc495a0Sdyoung 
224cfc495a0Sdyoung 	r = &pal.pal_reg[0];
225cfc495a0Sdyoung 
226cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
227cfc495a0Sdyoung 	r[0].r_ofs = ofs;
228cfc495a0Sdyoung 	r[0].r_val = io;
229cfc495a0Sdyoung 
23079770474Smsaitoh 	baser = __SHIFTOUT(io, PCI_BRIDGE_STATIO_IOBASE) >> 4;
23179770474Smsaitoh 	limitr = __SHIFTOUT(io, PCI_BRIDGE_STATIO_IOLIMIT) >> 4;
232cfc495a0Sdyoung 
233cfc495a0Sdyoung 	if (PCI_BRIDGE_IO_32BITS(io)) {
234cfc495a0Sdyoung 		pcireg_t baseh, limith;
235cfc495a0Sdyoung 
236cfc495a0Sdyoung 		r[1].r_mask = ~(pcireg_t)0;
237cfc495a0Sdyoung 		r[1].r_ofs = ofshigh;
238cfc495a0Sdyoung 		r[1].r_val = iohigh;
239cfc495a0Sdyoung 
24079770474Smsaitoh 		baseh = __SHIFTOUT(iohigh, PCI_BRIDGE_IOHIGH_BASE);
24179770474Smsaitoh 		limith = __SHIFTOUT(iohigh, PCI_BRIDGE_IOHIGH_LIMIT);
242cfc495a0Sdyoung 
243cfc495a0Sdyoung 		baser |= baseh << 4;
244cfc495a0Sdyoung 		limitr |= limith << 4;
245cfc495a0Sdyoung 	}
246cfc495a0Sdyoung 
247cfc495a0Sdyoung 	/* XXX check with the PCI standard */
248cfc495a0Sdyoung 	if (baser > limitr)
249cfc495a0Sdyoung 		return true;
250cfc495a0Sdyoung 
251cfc495a0Sdyoung 	pal.pal_addr = baser * fourkb;
252cfc495a0Sdyoung 	pal.pal_size = (limitr - baser + 1) * fourkb;
253cfc495a0Sdyoung 
254cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
255cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
256cfc495a0Sdyoung 
257cfc495a0Sdyoung 	return io_range_extend(ric, &pal);
258cfc495a0Sdyoung }
259cfc495a0Sdyoung 
260cfc495a0Sdyoung static bool
io_range_extend_by_cbwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t base0,pcireg_t limit0)261cfc495a0Sdyoung io_range_extend_by_cbwin(struct range_infer_ctx *ric,
262cfc495a0Sdyoung     int bus, int dev, int fun, int ofs, pcireg_t base0, pcireg_t limit0)
263cfc495a0Sdyoung {
264cfc495a0Sdyoung 	pcireg_t base, limit;
265cfc495a0Sdyoung 	pci_alloc_reg_t *r;
266cfc495a0Sdyoung 	pci_alloc_t pal = {
267cfc495a0Sdyoung 		  .pal_flags = 0
268cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_IO
269cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_CBWIN
270cfc495a0Sdyoung 		, .pal_reg = {{
271cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
272cfc495a0Sdyoung 		  }, {
273cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
274cfc495a0Sdyoung 		  }}
275cfc495a0Sdyoung 	};
276cfc495a0Sdyoung 
277cfc495a0Sdyoung 	r = &pal.pal_reg[0];
278cfc495a0Sdyoung 
279cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
280cfc495a0Sdyoung 	r[0].r_ofs = ofs;
281cfc495a0Sdyoung 	r[0].r_val = base0;
282cfc495a0Sdyoung 	r[1].r_ofs = ofs + 4;
283cfc495a0Sdyoung 	r[1].r_val = limit0;
284cfc495a0Sdyoung 
285cfc495a0Sdyoung 	base = base0 & __BITS(31, 2);
286cfc495a0Sdyoung 	limit = limit0 & __BITS(31, 2);
287cfc495a0Sdyoung 
288cfc495a0Sdyoung 	if (base > limit)
289cfc495a0Sdyoung 		return true;
290cfc495a0Sdyoung 
291cfc495a0Sdyoung 	pal.pal_addr = base;
292cfc495a0Sdyoung 	pal.pal_size = limit - base + 4;	/* XXX */
293cfc495a0Sdyoung 
294cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
295cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
296cfc495a0Sdyoung 
297cfc495a0Sdyoung 	return io_range_extend(ric, &pal);
298cfc495a0Sdyoung }
299cfc495a0Sdyoung 
300cfc495a0Sdyoung static void
io_range_infer(pci_chipset_tag_t pc,pcitag_t tag,void * ctx)301cfc495a0Sdyoung io_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
302cfc495a0Sdyoung {
303cfc495a0Sdyoung 	struct range_infer_ctx *ric = ctx;
304cfc495a0Sdyoung 	pcireg_t bhlcr, limit, io;
305cfc495a0Sdyoung 	int bar, bus, dev, fun, hdrtype, nbar;
306cfc495a0Sdyoung 	bool ok = true;
307cfc495a0Sdyoung 
308cfc495a0Sdyoung 	bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
309cfc495a0Sdyoung 
310cfc495a0Sdyoung 	hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
311cfc495a0Sdyoung 
312cfc495a0Sdyoung 	pci_decompose_tag(pc, tag, &bus, &dev, &fun);
313cfc495a0Sdyoung 
314cfc495a0Sdyoung 	switch (hdrtype) {
315cfc495a0Sdyoung 	case PCI_HDRTYPE_PPB:
316cfc495a0Sdyoung 		nbar = 2;
317cfc495a0Sdyoung 		/* Extract I/O windows */
318cfc495a0Sdyoung 		ok = ok && io_range_extend_by_win(ric, bus, dev, fun,
319cfc495a0Sdyoung 		    PCI_BRIDGE_STATIO_REG,
320cfc495a0Sdyoung 		    PCI_BRIDGE_IOHIGH_REG,
321cfc495a0Sdyoung 		    pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG),
322cfc495a0Sdyoung 		    pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG));
323cfc495a0Sdyoung 		ok = ok && io_range_extend_by_vga_enable(ric, bus, dev, fun,
324cfc495a0Sdyoung 		    pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
325cfc495a0Sdyoung 		    pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
326cfc495a0Sdyoung 		break;
327cfc495a0Sdyoung 	case PCI_HDRTYPE_PCB:
328cfc495a0Sdyoung 		/* Extract I/O windows */
329cfc495a0Sdyoung 		io = pci_conf_read(pc, tag, PCI_CB_IOBASE0);
330cfc495a0Sdyoung 		limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT0);
331cfc495a0Sdyoung 		ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
332cfc495a0Sdyoung 		    PCI_CB_IOBASE0, io, limit);
333cfc495a0Sdyoung 		io = pci_conf_read(pc, tag, PCI_CB_IOBASE1);
334cfc495a0Sdyoung 		limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT1);
335cfc495a0Sdyoung 		ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
336cfc495a0Sdyoung 		    PCI_CB_IOBASE1, io, limit);
337cfc495a0Sdyoung 		nbar = 1;
338cfc495a0Sdyoung 		break;
339cfc495a0Sdyoung 	case PCI_HDRTYPE_DEVICE:
340cfc495a0Sdyoung 		nbar = 6;
341cfc495a0Sdyoung 		break;
342cfc495a0Sdyoung 	default:
343cfc495a0Sdyoung 		aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
344cfc495a0Sdyoung 		    __func__, hdrtype, bus, dev, fun);
345cfc495a0Sdyoung 		return;
346cfc495a0Sdyoung 	}
347cfc495a0Sdyoung 
348cfc495a0Sdyoung 	for (bar = 0; bar < nbar; bar++) {
349cfc495a0Sdyoung 		pcireg_t basebar, sizebar;
350cfc495a0Sdyoung 
351cfc495a0Sdyoung 		basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
352cfc495a0Sdyoung 		pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
353cfc495a0Sdyoung 		sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
354cfc495a0Sdyoung 		pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
355cfc495a0Sdyoung 
356cfc495a0Sdyoung 		if (sizebar == 0)
357cfc495a0Sdyoung 			continue;
358cfc495a0Sdyoung 		if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_IO)
359cfc495a0Sdyoung 			continue;
360cfc495a0Sdyoung 
361cfc495a0Sdyoung 		ok = ok && io_range_extend_by_bar(ric, bus, dev, fun,
362cfc495a0Sdyoung 		    PCI_BAR(bar), basebar, sizebar);
363cfc495a0Sdyoung 	}
364cfc495a0Sdyoung 	if (!ok) {
365cfc495a0Sdyoung 		aprint_verbose("I/O range inference failed at PCI %d.%d.%d\n",
366cfc495a0Sdyoung 		    bus, dev, fun);
367cfc495a0Sdyoung 	}
368cfc495a0Sdyoung }
369cfc495a0Sdyoung 
370cfc495a0Sdyoung static bool
mmio_range_extend(struct range_infer_ctx * ric,const pci_alloc_t * pal)371cfc495a0Sdyoung mmio_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
372cfc495a0Sdyoung {
373cfc495a0Sdyoung 	if (ric->ric_mmio_bottom > pal->pal_addr)
374cfc495a0Sdyoung 		ric->ric_mmio_bottom = pal->pal_addr;
375cfc495a0Sdyoung 	if (ric->ric_mmio_top < pal->pal_addr + pal->pal_size)
376cfc495a0Sdyoung 		ric->ric_mmio_top = pal->pal_addr + pal->pal_size;
377cfc495a0Sdyoung 
378cfc495a0Sdyoung 	return pci_alloc_linkdup(&ric->ric_pals, pal);
379cfc495a0Sdyoung }
380cfc495a0Sdyoung 
381cfc495a0Sdyoung static bool
mmio_range_extend_by_bar(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t curbar,pcireg_t sizebar)382766e6e09Smsaitoh mmio_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev,
383766e6e09Smsaitoh     int fun, int ofs, pcireg_t curbar, pcireg_t sizebar)
384cfc495a0Sdyoung {
385cfc495a0Sdyoung 	int type;
386cfc495a0Sdyoung 	bool prefetchable;
387cfc495a0Sdyoung 	pci_alloc_reg_t *r;
388cfc495a0Sdyoung 	pci_alloc_t pal = {
389cfc495a0Sdyoung 		  .pal_flags = 0
390cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_MEM
391cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_BAR
392cfc495a0Sdyoung 		, .pal_reg = {{
393cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
394cfc495a0Sdyoung 		  }}
395cfc495a0Sdyoung 	};
396cfc495a0Sdyoung 
397cfc495a0Sdyoung 	r = &pal.pal_reg[0];
398cfc495a0Sdyoung 
399cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
400cfc495a0Sdyoung 	r->r_ofs = ofs;
401cfc495a0Sdyoung 	r->r_val = curbar;
402cfc495a0Sdyoung 
403cfc495a0Sdyoung 	pal.pal_addr = PCI_MAPREG_MEM_ADDR(curbar);
404cfc495a0Sdyoung 
405cfc495a0Sdyoung 	type = PCI_MAPREG_MEM_TYPE(curbar);
406cfc495a0Sdyoung 	prefetchable = PCI_MAPREG_MEM_PREFETCHABLE(curbar);
407cfc495a0Sdyoung 
408cfc495a0Sdyoung 	if (prefetchable)
409cfc495a0Sdyoung 		pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
410cfc495a0Sdyoung 
411cfc495a0Sdyoung 	switch (type) {
412cfc495a0Sdyoung 	case PCI_MAPREG_MEM_TYPE_32BIT:
413cfc495a0Sdyoung 		pal.pal_size = PCI_MAPREG_MEM_SIZE(sizebar);
414cfc495a0Sdyoung 		break;
415cfc495a0Sdyoung 	case PCI_MAPREG_MEM_TYPE_64BIT:
416cfc495a0Sdyoung 		pal.pal_size = PCI_MAPREG_MEM64_SIZE(sizebar);
417cfc495a0Sdyoung 		break;
418cfc495a0Sdyoung 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
419cfc495a0Sdyoung 	default:
420cfc495a0Sdyoung 		aprint_debug("%s: ignored memory type %d at %d.%d.%d\n",
421cfc495a0Sdyoung 		    __func__, type, bus, dev, fun);
422cfc495a0Sdyoung 		return false;
423cfc495a0Sdyoung 	}
424cfc495a0Sdyoung 
425cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
426cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
427cfc495a0Sdyoung 
428cfc495a0Sdyoung 	return (pal.pal_size == 0) || mmio_range_extend(ric, &pal);
429cfc495a0Sdyoung }
430cfc495a0Sdyoung 
431cfc495a0Sdyoung static bool
mmio_range_extend_by_vga_enable(struct range_infer_ctx * ric,int bus,int dev,int fun,pcireg_t csr,pcireg_t bcr)432cfc495a0Sdyoung mmio_range_extend_by_vga_enable(struct range_infer_ctx *ric,
433cfc495a0Sdyoung     int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
434cfc495a0Sdyoung {
435cfc495a0Sdyoung 	pci_alloc_reg_t *r;
436cfc495a0Sdyoung 	pci_alloc_t tpal = {
437cfc495a0Sdyoung 		  .pal_flags = PCI_ALLOC_F_PREFETCHABLE	/* XXX a guess */
438cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_MEM
439cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
440cfc495a0Sdyoung 		, .pal_reg = {{
441cfc495a0Sdyoung 			  .r_ofs = PCI_COMMAND_STATUS_REG
442cfc495a0Sdyoung 			, .r_mask = PCI_COMMAND_MEM_ENABLE
443cfc495a0Sdyoung 		  }, {
444cfc495a0Sdyoung 			  .r_ofs = PCI_BRIDGE_CONTROL_REG
44579770474Smsaitoh 			, .r_mask = PCI_BRIDGE_CONTROL_VGA
446cfc495a0Sdyoung 		  }}
447cfc495a0Sdyoung 	}, pal;
448cfc495a0Sdyoung 
449cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
450cfc495a0Sdyoung 
451cfc495a0Sdyoung 	if ((csr & PCI_COMMAND_MEM_ENABLE) == 0 ||
45279770474Smsaitoh 	    (bcr & PCI_BRIDGE_CONTROL_VGA) == 0) {
453cfc495a0Sdyoung 		aprint_debug("%s: %d.%d.%d memory or VGA disabled\n",
454cfc495a0Sdyoung 		    __func__, bus, dev, fun);
455cfc495a0Sdyoung 		return true;
456cfc495a0Sdyoung 	}
457cfc495a0Sdyoung 
458cfc495a0Sdyoung 	r = &tpal.pal_reg[0];
459cfc495a0Sdyoung 	tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
460cfc495a0Sdyoung 	r[0].r_val = csr;
461cfc495a0Sdyoung 	r[1].r_val = bcr;
462cfc495a0Sdyoung 
463cfc495a0Sdyoung 	pal = tpal;
464cfc495a0Sdyoung 
465cfc495a0Sdyoung 	pal.pal_addr = 0xa0000;
466cfc495a0Sdyoung 	pal.pal_size = 0xbffff - 0xa0000 + 1;
467cfc495a0Sdyoung 
468cfc495a0Sdyoung 	return mmio_range_extend(ric, &pal);
469cfc495a0Sdyoung }
470cfc495a0Sdyoung 
471cfc495a0Sdyoung static bool
mmio_range_extend_by_win(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t mem)472cfc495a0Sdyoung mmio_range_extend_by_win(struct range_infer_ctx *ric,
473cfc495a0Sdyoung     int bus, int dev, int fun, int ofs, pcireg_t mem)
474cfc495a0Sdyoung {
475cfc495a0Sdyoung 	const int onemeg = 1024 * 1024;
476cfc495a0Sdyoung 	pcireg_t baser, limitr;
477cfc495a0Sdyoung 	pci_alloc_reg_t *r;
478cfc495a0Sdyoung 	pci_alloc_t pal = {
479cfc495a0Sdyoung 		  .pal_flags = 0
480cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_MEM
481cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_WIN
482cfc495a0Sdyoung 		, .pal_reg = {{
483cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
484cfc495a0Sdyoung 		  }}
485cfc495a0Sdyoung 	};
486cfc495a0Sdyoung 
487cfc495a0Sdyoung 	r = &pal.pal_reg[0];
488cfc495a0Sdyoung 
489cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
490cfc495a0Sdyoung 	r->r_ofs = ofs;
491cfc495a0Sdyoung 	r->r_val = mem;
492cfc495a0Sdyoung 
493cfc495a0Sdyoung 	baser = (mem >> PCI_BRIDGE_MEMORY_BASE_SHIFT) &
494cfc495a0Sdyoung 	    PCI_BRIDGE_MEMORY_BASE_MASK;
495cfc495a0Sdyoung 	limitr = (mem >> PCI_BRIDGE_MEMORY_LIMIT_SHIFT) &
496cfc495a0Sdyoung 	    PCI_BRIDGE_MEMORY_LIMIT_MASK;
497cfc495a0Sdyoung 
498cfc495a0Sdyoung 	/* XXX check with the PCI standard */
499cfc495a0Sdyoung 	if (baser > limitr || limitr == 0)
500cfc495a0Sdyoung 		return true;
501cfc495a0Sdyoung 
502cfc495a0Sdyoung 	pal.pal_addr = baser * onemeg;
503cfc495a0Sdyoung 	pal.pal_size = (limitr - baser + 1) * onemeg;
504cfc495a0Sdyoung 
505cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
506cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
507cfc495a0Sdyoung 
508cfc495a0Sdyoung 	return mmio_range_extend(ric, &pal);
509cfc495a0Sdyoung }
510cfc495a0Sdyoung 
511cfc495a0Sdyoung static bool
mmio_range_extend_by_prememwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t mem,int hibaseofs,pcireg_t hibase,int hilimitofs,pcireg_t hilimit)512cfc495a0Sdyoung mmio_range_extend_by_prememwin(struct range_infer_ctx *ric,
513cfc495a0Sdyoung     int bus, int dev, int fun, int ofs, pcireg_t mem,
514cfc495a0Sdyoung     int hibaseofs, pcireg_t hibase,
515cfc495a0Sdyoung     int hilimitofs, pcireg_t hilimit)
516cfc495a0Sdyoung {
517cfc495a0Sdyoung 	const int onemeg = 1024 * 1024;
518cfc495a0Sdyoung 	uint64_t baser, limitr;
519cfc495a0Sdyoung 	pci_alloc_reg_t *r;
520cfc495a0Sdyoung 	pci_alloc_t pal = {
521cfc495a0Sdyoung 		  .pal_flags = PCI_ALLOC_F_PREFETCHABLE
522cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_MEM
523cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_WIN
524cfc495a0Sdyoung 		, .pal_reg = {{
525cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
526cfc495a0Sdyoung 		  }}
527cfc495a0Sdyoung 	};
528cfc495a0Sdyoung 
529cfc495a0Sdyoung 	r = &pal.pal_reg[0];
530cfc495a0Sdyoung 
531cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
532cfc495a0Sdyoung 	r[0].r_ofs = ofs;
533cfc495a0Sdyoung 	r[0].r_val = mem;
534cfc495a0Sdyoung 
535cfc495a0Sdyoung 	baser = (mem >> PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT) &
536cfc495a0Sdyoung 	    PCI_BRIDGE_PREFETCHMEM_BASE_MASK;
537cfc495a0Sdyoung 	limitr = (mem >> PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT) &
538cfc495a0Sdyoung 	    PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK;
539cfc495a0Sdyoung 
540cfc495a0Sdyoung 	if (PCI_BRIDGE_PREFETCHMEM_64BITS(mem)) {
541cfc495a0Sdyoung 		r[1].r_mask = r[2].r_mask = ~(pcireg_t)0;
542cfc495a0Sdyoung 		r[1].r_ofs = hibaseofs;
543cfc495a0Sdyoung 		r[1].r_val = hibase;
544cfc495a0Sdyoung 		r[2].r_ofs = hilimitofs;
545cfc495a0Sdyoung 		r[2].r_val = hilimit;
546cfc495a0Sdyoung 
547cfc495a0Sdyoung 		baser |= hibase << 12;
548cfc495a0Sdyoung 		limitr |= hibase << 12;
549cfc495a0Sdyoung 	}
550cfc495a0Sdyoung 
551cfc495a0Sdyoung 	/* XXX check with the PCI standard */
552cfc495a0Sdyoung 	if (baser > limitr || limitr == 0)
553cfc495a0Sdyoung 		return true;
554cfc495a0Sdyoung 
555cfc495a0Sdyoung 	pal.pal_addr = baser * onemeg;
556cfc495a0Sdyoung 	pal.pal_size = (limitr - baser + 1) * onemeg;
557cfc495a0Sdyoung 
558cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
559cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
560cfc495a0Sdyoung 
561cfc495a0Sdyoung 	return mmio_range_extend(ric, &pal);
562cfc495a0Sdyoung }
563cfc495a0Sdyoung 
564cfc495a0Sdyoung static bool
mmio_range_extend_by_cbwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t base,pcireg_t limit,bool prefetchable)565cfc495a0Sdyoung mmio_range_extend_by_cbwin(struct range_infer_ctx *ric,
566cfc495a0Sdyoung     int bus, int dev, int fun, int ofs, pcireg_t base, pcireg_t limit,
567cfc495a0Sdyoung     bool prefetchable)
568cfc495a0Sdyoung {
569cfc495a0Sdyoung 	pci_alloc_reg_t *r;
570cfc495a0Sdyoung 	pci_alloc_t pal = {
571cfc495a0Sdyoung 		  .pal_flags = 0
572cfc495a0Sdyoung 		, .pal_space = PCI_ALLOC_SPACE_MEM
573cfc495a0Sdyoung 		, .pal_type = PCI_ALLOC_REGTYPE_CBWIN
574cfc495a0Sdyoung 		, .pal_reg = {{
575cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
576cfc495a0Sdyoung 		  }, {
577cfc495a0Sdyoung 			  .r_mask = ~(pcireg_t)0
578cfc495a0Sdyoung 		  }}
579cfc495a0Sdyoung 	};
580cfc495a0Sdyoung 
581cfc495a0Sdyoung 	r = &pal.pal_reg[0];
582cfc495a0Sdyoung 
583cfc495a0Sdyoung 	if (prefetchable)
584cfc495a0Sdyoung 		pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
585cfc495a0Sdyoung 
586cfc495a0Sdyoung 	pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
587cfc495a0Sdyoung 	r[0].r_ofs = ofs;
588cfc495a0Sdyoung 	r[0].r_val = base;
589cfc495a0Sdyoung 	r[1].r_ofs = ofs + 4;
590cfc495a0Sdyoung 	r[1].r_val = limit;
591cfc495a0Sdyoung 
592cfc495a0Sdyoung 	if (base > limit)
593cfc495a0Sdyoung 		return true;
594cfc495a0Sdyoung 
595cfc495a0Sdyoung 	if (limit == 0)
596cfc495a0Sdyoung 		return true;
597cfc495a0Sdyoung 
598cfc495a0Sdyoung 	pal.pal_addr = base;
599cfc495a0Sdyoung 	pal.pal_size = limit - base + 4096;
600cfc495a0Sdyoung 
601cfc495a0Sdyoung 	aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
602cfc495a0Sdyoung 	    __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
603cfc495a0Sdyoung 
604cfc495a0Sdyoung 	return mmio_range_extend(ric, &pal);
605cfc495a0Sdyoung }
606cfc495a0Sdyoung 
607cfc495a0Sdyoung static void
mmio_range_infer(pci_chipset_tag_t pc,pcitag_t tag,void * ctx)608cfc495a0Sdyoung mmio_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
609cfc495a0Sdyoung {
610cfc495a0Sdyoung 	struct range_infer_ctx *ric = ctx;
611cfc495a0Sdyoung 	pcireg_t bcr, bhlcr, limit, mem, premem, hiprebase, hiprelimit;
612cfc495a0Sdyoung 	int bar, bus, dev, fun, hdrtype, nbar;
613cfc495a0Sdyoung 	bool ok = true;
614cfc495a0Sdyoung 
615cfc495a0Sdyoung 	bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
616cfc495a0Sdyoung 
617cfc495a0Sdyoung 	hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
618cfc495a0Sdyoung 
619cfc495a0Sdyoung 	pci_decompose_tag(pc, tag, &bus, &dev, &fun);
620cfc495a0Sdyoung 
621cfc495a0Sdyoung 	switch (hdrtype) {
622cfc495a0Sdyoung 	case PCI_HDRTYPE_PPB:
623cfc495a0Sdyoung 		nbar = 2;
624cfc495a0Sdyoung 		/* Extract memory windows */
625cfc495a0Sdyoung 		ok = ok && mmio_range_extend_by_win(ric, bus, dev, fun,
626cfc495a0Sdyoung 		    PCI_BRIDGE_MEMORY_REG,
627cfc495a0Sdyoung 		    pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG));
628cfc495a0Sdyoung 		premem = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG);
629cfc495a0Sdyoung 		if (PCI_BRIDGE_PREFETCHMEM_64BITS(premem)) {
630cfc495a0Sdyoung 			aprint_debug("%s: 64-bit prefetchable memory window "
631cfc495a0Sdyoung 			    "at %d.%d.%d\n", __func__, bus, dev, fun);
632cfc495a0Sdyoung 			hiprebase = pci_conf_read(pc, tag,
633cfc495a0Sdyoung 			    PCI_BRIDGE_PREFETCHBASE32_REG);
634cfc495a0Sdyoung 			hiprelimit = pci_conf_read(pc, tag,
635cfc495a0Sdyoung 			    PCI_BRIDGE_PREFETCHLIMIT32_REG);
636cfc495a0Sdyoung 		} else
637cfc495a0Sdyoung 			hiprebase = hiprelimit = 0;
638cfc495a0Sdyoung 		ok = ok &&
639cfc495a0Sdyoung 		    mmio_range_extend_by_prememwin(ric, bus, dev, fun,
640cfc495a0Sdyoung 		        PCI_BRIDGE_PREFETCHMEM_REG, premem,
641cfc495a0Sdyoung 		        PCI_BRIDGE_PREFETCHBASE32_REG, hiprebase,
642cfc495a0Sdyoung 		        PCI_BRIDGE_PREFETCHLIMIT32_REG, hiprelimit) &&
643cfc495a0Sdyoung 		    mmio_range_extend_by_vga_enable(ric, bus, dev, fun,
644cfc495a0Sdyoung 		        pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
645cfc495a0Sdyoung 		        pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
646cfc495a0Sdyoung 		break;
647cfc495a0Sdyoung 	case PCI_HDRTYPE_PCB:
648cfc495a0Sdyoung 		/* Extract memory windows */
649cfc495a0Sdyoung 		bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG);
650cfc495a0Sdyoung 		mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE0);
651cfc495a0Sdyoung 		limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT0);
652cfc495a0Sdyoung 		ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
653cfc495a0Sdyoung 		    PCI_CB_MEMBASE0, mem, limit,
654cfc495a0Sdyoung 		    (bcr & CB_BCR_PREFETCH_MEMWIN0) != 0);
655cfc495a0Sdyoung 		mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE1);
656cfc495a0Sdyoung 		limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT1);
657cfc495a0Sdyoung 		ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
658cfc495a0Sdyoung 		    PCI_CB_MEMBASE1, mem, limit,
659cfc495a0Sdyoung 		    (bcr & CB_BCR_PREFETCH_MEMWIN1) != 0);
660cfc495a0Sdyoung 		nbar = 1;
661cfc495a0Sdyoung 		break;
662cfc495a0Sdyoung 	case PCI_HDRTYPE_DEVICE:
663cfc495a0Sdyoung 		nbar = 6;
664cfc495a0Sdyoung 		break;
665cfc495a0Sdyoung 	default:
666cfc495a0Sdyoung 		aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
667cfc495a0Sdyoung 		    __func__, hdrtype, bus, dev, fun);
668cfc495a0Sdyoung 		return;
669cfc495a0Sdyoung 	}
670cfc495a0Sdyoung 
671cfc495a0Sdyoung 	for (bar = 0; bar < nbar; bar++) {
672cfc495a0Sdyoung 		pcireg_t basebar, sizebar;
673cfc495a0Sdyoung 
674cfc495a0Sdyoung 		basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
675cfc495a0Sdyoung 		pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
676cfc495a0Sdyoung 		sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
677cfc495a0Sdyoung 		pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
678cfc495a0Sdyoung 
679cfc495a0Sdyoung 		if (sizebar == 0)
680cfc495a0Sdyoung 			continue;
681cfc495a0Sdyoung 		if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_MEM)
682cfc495a0Sdyoung 			continue;
683cfc495a0Sdyoung 
684cfc495a0Sdyoung 		ok = ok && mmio_range_extend_by_bar(ric, bus, dev, fun,
685cfc495a0Sdyoung 		    PCI_BAR(bar), basebar, sizebar);
686cfc495a0Sdyoung 	}
687cfc495a0Sdyoung 	if (!ok) {
688cfc495a0Sdyoung 		aprint_verbose("MMIO range inference failed at PCI %d.%d.%d\n",
689cfc495a0Sdyoung 		    bus, dev, fun);
690cfc495a0Sdyoung 	}
691cfc495a0Sdyoung }
692cfc495a0Sdyoung 
693cfc495a0Sdyoung static const char *
pci_alloc_regtype_string(const pci_alloc_regtype_t t)694cfc495a0Sdyoung pci_alloc_regtype_string(const pci_alloc_regtype_t t)
695cfc495a0Sdyoung {
696cfc495a0Sdyoung 	switch (t) {
697cfc495a0Sdyoung 	case PCI_ALLOC_REGTYPE_BAR:
698cfc495a0Sdyoung 		return "bar";
699cfc495a0Sdyoung 	case PCI_ALLOC_REGTYPE_WIN:
700cfc495a0Sdyoung 	case PCI_ALLOC_REGTYPE_CBWIN:
701cfc495a0Sdyoung 		return "window";
702cfc495a0Sdyoung 	case PCI_ALLOC_REGTYPE_VGA_EN:
703cfc495a0Sdyoung 		return "vga-enable";
704cfc495a0Sdyoung 	default:
705cfc495a0Sdyoung 		return "<unknown>";
706cfc495a0Sdyoung 	}
707cfc495a0Sdyoung }
708cfc495a0Sdyoung 
709cfc495a0Sdyoung static void
pci_alloc_print(pci_chipset_tag_t pc,const pci_alloc_t * pal)710cfc495a0Sdyoung pci_alloc_print(pci_chipset_tag_t pc, const pci_alloc_t *pal)
711cfc495a0Sdyoung {
712cfc495a0Sdyoung 	int bus, dev, fun;
713cfc495a0Sdyoung 	const pci_alloc_reg_t *r;
714cfc495a0Sdyoung 
715cfc495a0Sdyoung 	pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
716cfc495a0Sdyoung 	r = &pal->pal_reg[0];
717cfc495a0Sdyoung 
718cfc495a0Sdyoung 	aprint_normal("%s range [0x%08" PRIx64 ", 0x%08" PRIx64 ")"
719cfc495a0Sdyoung 	    " at %d.%d.%d %s%s 0x%02x\n",
720cfc495a0Sdyoung 	    (pal->pal_space == PCI_ALLOC_SPACE_IO) ? "IO" : "MMIO",
721cfc495a0Sdyoung 	    pal->pal_addr, pal->pal_addr + pal->pal_size,
722cfc495a0Sdyoung 	    bus, dev, fun,
723cfc495a0Sdyoung 	    (pal->pal_flags & PCI_ALLOC_F_PREFETCHABLE) ? "prefetchable " : "",
724cfc495a0Sdyoung 	    pci_alloc_regtype_string(pal->pal_type),
725cfc495a0Sdyoung 	    r->r_ofs);
726cfc495a0Sdyoung }
727cfc495a0Sdyoung 
728cfc495a0Sdyoung prop_dictionary_t pci_rsrc_dict = NULL;
729cfc495a0Sdyoung 
730cfc495a0Sdyoung static bool
pci_range_record(pci_chipset_tag_t pc,prop_array_t rsvns,pci_alloc_list_t * pals,pci_alloc_space_t space)731cfc495a0Sdyoung pci_range_record(pci_chipset_tag_t pc, prop_array_t rsvns,
732cfc495a0Sdyoung     pci_alloc_list_t *pals, pci_alloc_space_t space)
733cfc495a0Sdyoung {
734cfc495a0Sdyoung 	int bus, dev, fun, i;
735cfc495a0Sdyoung 	prop_array_t regs;
736cfc495a0Sdyoung 	prop_dictionary_t reg;
737cfc495a0Sdyoung 	const pci_alloc_t *pal;
738cfc495a0Sdyoung 	const pci_alloc_reg_t *r;
739cfc495a0Sdyoung 	prop_dictionary_t rsvn;
740cfc495a0Sdyoung 
741cfc495a0Sdyoung 	TAILQ_FOREACH(pal, pals, pal_link) {
742cfc495a0Sdyoung 		bool ok = true;
743cfc495a0Sdyoung 
744cfc495a0Sdyoung 		r = &pal->pal_reg[0];
745cfc495a0Sdyoung 
746cfc495a0Sdyoung 		if (pal->pal_space != space)
747cfc495a0Sdyoung 			continue;
748cfc495a0Sdyoung 
749cfc495a0Sdyoung 		if ((rsvn = prop_dictionary_create()) == NULL)
750cfc495a0Sdyoung 			return false;
751cfc495a0Sdyoung 
752cfc495a0Sdyoung 		if ((regs = prop_array_create()) == NULL) {
753cfc495a0Sdyoung 			prop_object_release(rsvn);
754cfc495a0Sdyoung 			return false;
755cfc495a0Sdyoung 		}
756cfc495a0Sdyoung 
757cfc495a0Sdyoung 		if (!prop_dictionary_set(rsvn, "regs", regs)) {
758cfc495a0Sdyoung 			prop_object_release(rsvn);
759cfc495a0Sdyoung 			prop_object_release(regs);
760cfc495a0Sdyoung 			return false;
761cfc495a0Sdyoung 		}
762cfc495a0Sdyoung 
763cfc495a0Sdyoung 		for (i = 0; i < __arraycount(pal->pal_reg); i++) {
764cfc495a0Sdyoung 			r = &pal->pal_reg[i];
765cfc495a0Sdyoung 
766cfc495a0Sdyoung 			if (r->r_mask == 0)
767cfc495a0Sdyoung 				break;
768cfc495a0Sdyoung 
769cfc495a0Sdyoung 			ok = (reg = prop_dictionary_create()) != NULL;
770cfc495a0Sdyoung 			if (!ok)
771cfc495a0Sdyoung 				break;
772cfc495a0Sdyoung 
773cfc495a0Sdyoung 			ok = prop_dictionary_set_uint16(reg, "offset",
774cfc495a0Sdyoung 			        r->r_ofs) &&
775cfc495a0Sdyoung 			    prop_dictionary_set_uint32(reg, "val", r->r_val) &&
776cfc495a0Sdyoung 			    prop_dictionary_set_uint32(reg, "mask",
777cfc495a0Sdyoung 			        r->r_mask) && prop_array_add(regs, reg);
778cfc495a0Sdyoung 			if (!ok) {
779cfc495a0Sdyoung 				prop_object_release(reg);
780cfc495a0Sdyoung 				break;
781cfc495a0Sdyoung 			}
782cfc495a0Sdyoung 		}
783cfc495a0Sdyoung 
784cfc495a0Sdyoung 		pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
785cfc495a0Sdyoung 
786cfc495a0Sdyoung 		ok = ok &&
787*6b5045cdSchristos 		    prop_dictionary_set_string_nocopy(rsvn, "type",
788cfc495a0Sdyoung 		        pci_alloc_regtype_string(pal->pal_type)) &&
789cfc495a0Sdyoung 		    prop_dictionary_set_uint64(rsvn, "address",
790cfc495a0Sdyoung 		        pal->pal_addr) &&
791cfc495a0Sdyoung 		    prop_dictionary_set_uint64(rsvn, "size", pal->pal_size) &&
792cfc495a0Sdyoung 		    prop_dictionary_set_uint8(rsvn, "bus", bus) &&
793cfc495a0Sdyoung 		    prop_dictionary_set_uint8(rsvn, "device", dev) &&
794cfc495a0Sdyoung 		    prop_dictionary_set_uint8(rsvn, "function", fun) &&
795cfc495a0Sdyoung 		    prop_array_add(rsvns, rsvn);
796cfc495a0Sdyoung 		prop_object_release(rsvn);
797cfc495a0Sdyoung 		if (!ok)
798cfc495a0Sdyoung 			return false;
799cfc495a0Sdyoung 	}
800cfc495a0Sdyoung 	return true;
801cfc495a0Sdyoung }
802cfc495a0Sdyoung 
803cfc495a0Sdyoung prop_dictionary_t
pci_rsrc_filter(prop_dictionary_t rsrcs0,bool (* predicate)(void *,prop_dictionary_t),void * arg)804cfc495a0Sdyoung pci_rsrc_filter(prop_dictionary_t rsrcs0,
805cfc495a0Sdyoung     bool (*predicate)(void *, prop_dictionary_t), void *arg)
806cfc495a0Sdyoung {
807cfc495a0Sdyoung 	int i, space;
808cfc495a0Sdyoung 	prop_dictionary_t rsrcs;
809cfc495a0Sdyoung 	prop_array_t rsvns;
810cfc495a0Sdyoung 	ppath_t *op, *p;
811cfc495a0Sdyoung 
812cfc495a0Sdyoung 	if ((rsrcs = prop_dictionary_copy(rsrcs0)) == NULL)
813cfc495a0Sdyoung 		return NULL;
814cfc495a0Sdyoung 
815cfc495a0Sdyoung 	for (space = 0; space < 2; space++) {
816cfc495a0Sdyoung 		op = p = ppath_create();
817cfc495a0Sdyoung 		p = ppath_push_key(p, (space == 0) ? "memory" : "io");
818cfc495a0Sdyoung 		p = ppath_push_key(p, "bios-reservations");
819cfc495a0Sdyoung 		if (p == NULL) {
820cfc495a0Sdyoung 			ppath_release(op);
821cfc495a0Sdyoung 			return NULL;
822cfc495a0Sdyoung 		}
823cfc495a0Sdyoung 		if ((rsvns = ppath_lookup(rsrcs0, p)) == NULL) {
824cfc495a0Sdyoung 			printf("%s: reservations not found\n", __func__);
825cfc495a0Sdyoung 			ppath_release(p);
826cfc495a0Sdyoung 			return NULL;
827cfc495a0Sdyoung 		}
828cfc495a0Sdyoung 		for (i = prop_array_count(rsvns); --i >= 0; ) {
829cfc495a0Sdyoung 			prop_dictionary_t rsvn;
830cfc495a0Sdyoung 
831cfc495a0Sdyoung 			if ((p = ppath_push_idx(p, i)) == NULL) {
832cfc495a0Sdyoung 				printf("%s: ppath_push_idx\n", __func__);
833cfc495a0Sdyoung 				ppath_release(op);
834cfc495a0Sdyoung 				prop_object_release(rsrcs);
835cfc495a0Sdyoung 				return NULL;
836cfc495a0Sdyoung 			}
837cfc495a0Sdyoung 
838cfc495a0Sdyoung 			rsvn = ppath_lookup(rsrcs0, p);
839cfc495a0Sdyoung 
840cfc495a0Sdyoung 			KASSERT(rsvn != NULL);
841cfc495a0Sdyoung 
842cfc495a0Sdyoung 			if (!(*predicate)(arg, rsvn)) {
843cfc495a0Sdyoung 				ppath_copydel_object((prop_object_t)rsrcs0,
844cfc495a0Sdyoung 				    (prop_object_t *)&rsrcs, p);
845cfc495a0Sdyoung 			}
846cfc495a0Sdyoung 
847cfc495a0Sdyoung 			if ((p = ppath_pop(p, NULL)) == NULL) {
848cfc495a0Sdyoung 				printf("%s: ppath_pop\n", __func__);
849cfc495a0Sdyoung 				ppath_release(p);
850cfc495a0Sdyoung 				prop_object_release(rsrcs);
851cfc495a0Sdyoung 				return NULL;
852cfc495a0Sdyoung 			}
853cfc495a0Sdyoung 		}
854cfc495a0Sdyoung 		ppath_release(op);
855cfc495a0Sdyoung 	}
856cfc495a0Sdyoung 	return rsrcs;
857cfc495a0Sdyoung }
858cfc495a0Sdyoung 
859cfc495a0Sdyoung void
pci_ranges_infer(pci_chipset_tag_t pc,int minbus,int maxbus,bus_addr_t * iobasep,bus_size_t * iosizep,bus_addr_t * membasep,bus_size_t * memsizep)860cfc495a0Sdyoung pci_ranges_infer(pci_chipset_tag_t pc, int minbus, int maxbus,
861cfc495a0Sdyoung     bus_addr_t *iobasep, bus_size_t *iosizep,
862cfc495a0Sdyoung     bus_addr_t *membasep, bus_size_t *memsizep)
863cfc495a0Sdyoung {
864cfc495a0Sdyoung 	prop_dictionary_t iodict = NULL, memdict = NULL;
865cfc495a0Sdyoung 	prop_array_t iorsvns, memrsvns;
866cfc495a0Sdyoung 	struct range_infer_ctx ric = {
867cfc495a0Sdyoung 		  .ric_io_bottom = ~((bus_addr_t)0)
868cfc495a0Sdyoung 		, .ric_io_top = 0
869cfc495a0Sdyoung 		, .ric_mmio_bottom = ~((bus_addr_t)0)
870cfc495a0Sdyoung 		, .ric_mmio_top = 0
871cfc495a0Sdyoung 		, .ric_pals = TAILQ_HEAD_INITIALIZER(ric.ric_pals)
872cfc495a0Sdyoung 	};
873cfc495a0Sdyoung 	const pci_alloc_t *pal;
874cfc495a0Sdyoung 
875cfc495a0Sdyoung 	ric.ric_pc = pc;
876cfc495a0Sdyoung 	pci_device_foreach_min(pc, minbus, maxbus, mmio_range_infer, &ric);
877cfc495a0Sdyoung 	pci_device_foreach_min(pc, minbus, maxbus, io_range_infer, &ric);
878cfc495a0Sdyoung 	if (membasep != NULL)
879cfc495a0Sdyoung 		*membasep = ric.ric_mmio_bottom;
880cfc495a0Sdyoung 	if (memsizep != NULL)
881cfc495a0Sdyoung 		*memsizep = ric.ric_mmio_top - ric.ric_mmio_bottom;
882cfc495a0Sdyoung 	if (iobasep != NULL)
883cfc495a0Sdyoung 		*iobasep = ric.ric_io_bottom;
884cfc495a0Sdyoung 	if (iosizep != NULL)
885cfc495a0Sdyoung 		*iosizep = ric.ric_io_top - ric.ric_io_bottom;
886cfc495a0Sdyoung 	aprint_verbose("%s: inferred %" PRIuMAX
887cfc495a0Sdyoung 	    " bytes of memory-mapped PCI space at 0x%" PRIxMAX "\n", __func__,
888cfc495a0Sdyoung 	    (uintmax_t)(ric.ric_mmio_top - ric.ric_mmio_bottom),
889cfc495a0Sdyoung 	    (uintmax_t)ric.ric_mmio_bottom);
890cfc495a0Sdyoung 	aprint_verbose("%s: inferred %" PRIuMAX
891cfc495a0Sdyoung 	    " bytes of PCI I/O space at 0x%" PRIxMAX "\n", __func__,
892cfc495a0Sdyoung 	    (uintmax_t)(ric.ric_io_top - ric.ric_io_bottom),
893cfc495a0Sdyoung 	    (uintmax_t)ric.ric_io_bottom);
894cfc495a0Sdyoung 	TAILQ_FOREACH(pal, &ric.ric_pals, pal_link)
895cfc495a0Sdyoung 		pci_alloc_print(pc, pal);
896cfc495a0Sdyoung 
897cfc495a0Sdyoung 	if ((memdict = prop_dictionary_create()) == NULL) {
898cfc495a0Sdyoung 		aprint_error("%s: could not create PCI MMIO "
899cfc495a0Sdyoung 		    "resources dictionary\n", __func__);
900cfc495a0Sdyoung 	} else if ((memrsvns = prop_array_create()) == NULL) {
901cfc495a0Sdyoung 		aprint_error("%s: could not create PCI BIOS memory "
902cfc495a0Sdyoung 		    "reservations array\n", __func__);
903cfc495a0Sdyoung 	} else if (!prop_dictionary_set(memdict, "bios-reservations",
904cfc495a0Sdyoung 	    memrsvns)) {
905cfc495a0Sdyoung 		aprint_error("%s: could not record PCI BIOS memory "
906cfc495a0Sdyoung 		    "reservations array\n", __func__);
907cfc495a0Sdyoung 	} else if (!pci_range_record(pc, memrsvns, &ric.ric_pals,
908cfc495a0Sdyoung 	    PCI_ALLOC_SPACE_MEM)) {
909cfc495a0Sdyoung 		aprint_error("%s: could not record PCI BIOS memory "
910cfc495a0Sdyoung 		    "reservations\n", __func__);
911cfc495a0Sdyoung 	} else if (!prop_dictionary_set_uint64(memdict,
912cfc495a0Sdyoung 	    "start", ric.ric_mmio_bottom) ||
913cfc495a0Sdyoung 	    !prop_dictionary_set_uint64(memdict, "size",
914cfc495a0Sdyoung 	     ric.ric_mmio_top - ric.ric_mmio_bottom)) {
915cfc495a0Sdyoung 		aprint_error("%s: could not record PCI memory min & max\n",
916cfc495a0Sdyoung 		    __func__);
917cfc495a0Sdyoung 	} else if ((iodict = prop_dictionary_create()) == NULL) {
918cfc495a0Sdyoung 		aprint_error("%s: could not create PCI I/O "
919cfc495a0Sdyoung 		    "resources dictionary\n", __func__);
920cfc495a0Sdyoung 	} else if ((iorsvns = prop_array_create()) == NULL) {
921cfc495a0Sdyoung 		aprint_error("%s: could not create PCI BIOS I/O "
922cfc495a0Sdyoung 		    "reservations array\n", __func__);
923cfc495a0Sdyoung 	} else if (!prop_dictionary_set(iodict, "bios-reservations",
924cfc495a0Sdyoung 	    iorsvns)) {
925cfc495a0Sdyoung 		aprint_error("%s: could not record PCI BIOS I/O "
926cfc495a0Sdyoung 		    "reservations array\n", __func__);
927cfc495a0Sdyoung 	} else if (!pci_range_record(pc, iorsvns, &ric.ric_pals,
928cfc495a0Sdyoung 	    PCI_ALLOC_SPACE_IO)) {
929cfc495a0Sdyoung 		aprint_error("%s: could not record PCI BIOS I/O "
930cfc495a0Sdyoung 		    "reservations\n", __func__);
931cfc495a0Sdyoung 	} else if (!prop_dictionary_set_uint64(iodict,
932cfc495a0Sdyoung 	    "start", ric.ric_io_bottom) ||
933cfc495a0Sdyoung 	    !prop_dictionary_set_uint64(iodict, "size",
934cfc495a0Sdyoung 	     ric.ric_io_top - ric.ric_io_bottom)) {
935cfc495a0Sdyoung 		aprint_error("%s: could not record PCI I/O min & max\n",
936cfc495a0Sdyoung 		    __func__);
937cfc495a0Sdyoung 	} else if ((pci_rsrc_dict = prop_dictionary_create()) == NULL) {
938cfc495a0Sdyoung 		aprint_error("%s: could not create PCI resources dictionary\n",
939cfc495a0Sdyoung 		    __func__);
940cfc495a0Sdyoung 	} else if (!prop_dictionary_set(pci_rsrc_dict, "memory", memdict) ||
941cfc495a0Sdyoung 	           !prop_dictionary_set(pci_rsrc_dict, "io", iodict)) {
942cfc495a0Sdyoung 		aprint_error("%s: could not record PCI memory- or I/O-"
943cfc495a0Sdyoung 		    "resources dictionary\n", __func__);
944cfc495a0Sdyoung 		prop_object_release(pci_rsrc_dict);
945cfc495a0Sdyoung 		pci_rsrc_dict = NULL;
946cfc495a0Sdyoung 	}
947cfc495a0Sdyoung 
948cfc495a0Sdyoung 	if (iodict != NULL)
949cfc495a0Sdyoung 		prop_object_release(iodict);
950cfc495a0Sdyoung 	if (memdict != NULL)
951cfc495a0Sdyoung 		prop_object_release(memdict);
952cfc495a0Sdyoung 	/* XXX release iorsvns, memrsvns */
953cfc495a0Sdyoung }
9548295eb1bSdyoung 
9558295eb1bSdyoung static bool
pcibus_rsvn_predicate(void * arg,prop_dictionary_t rsvn)9568295eb1bSdyoung pcibus_rsvn_predicate(void *arg, prop_dictionary_t rsvn)
9578295eb1bSdyoung {
9588295eb1bSdyoung 	struct pcibus_attach_args *pba = arg;
9598295eb1bSdyoung 	uint8_t bus;
9608295eb1bSdyoung 
9618295eb1bSdyoung 	if (!prop_dictionary_get_uint8(rsvn, "bus", &bus))
9628295eb1bSdyoung 		return false;
9638295eb1bSdyoung 
9648295eb1bSdyoung 	return pba->pba_bus <= bus && bus <= pba->pba_sub;
9658295eb1bSdyoung }
9668295eb1bSdyoung 
9678295eb1bSdyoung static bool
pci_rsvn_predicate(void * arg,prop_dictionary_t rsvn)9688295eb1bSdyoung pci_rsvn_predicate(void *arg, prop_dictionary_t rsvn)
9698295eb1bSdyoung {
9708295eb1bSdyoung 	struct pci_attach_args *pa = arg;
9718295eb1bSdyoung 	uint8_t bus, device, function;
9728295eb1bSdyoung 	bool rc;
9738295eb1bSdyoung 
9748295eb1bSdyoung 	rc = prop_dictionary_get_uint8(rsvn, "bus", &bus) &&
9758295eb1bSdyoung 	    prop_dictionary_get_uint8(rsvn, "device", &device) &&
9768295eb1bSdyoung 	    prop_dictionary_get_uint8(rsvn, "function", &function);
9778295eb1bSdyoung 
9788295eb1bSdyoung 	if (!rc)
9798295eb1bSdyoung 		return false;
9808295eb1bSdyoung 
9818295eb1bSdyoung 	return pa->pa_bus == bus && pa->pa_device == device &&
9828295eb1bSdyoung 	    pa->pa_function == function;
9838295eb1bSdyoung }
9848295eb1bSdyoung 
9858295eb1bSdyoung void
device_pci_props_register(device_t dev,void * aux)9868295eb1bSdyoung device_pci_props_register(device_t dev, void *aux)
9878295eb1bSdyoung {
9888295eb1bSdyoung 	cfdata_t cf;
9898295eb1bSdyoung 	prop_dictionary_t dict;
9908295eb1bSdyoung 
9918295eb1bSdyoung 	cf = (device_parent(dev) != NULL) ? device_cfdata(dev) : NULL;
9928295eb1bSdyoung #if 0
9938295eb1bSdyoung 	aprint_normal_dev(dev, "is%s a pci, parent %p, cf %p, ifattr %s\n",
9948295eb1bSdyoung 	    device_is_a(dev, "pci") ? "" : " not",
995cbab9cadSchs 	    device_parent(dev),
9968295eb1bSdyoung 	    cf,
9978295eb1bSdyoung 	    cf != NULL ? cfdata_ifattr(cf) : "");
9988295eb1bSdyoung #endif
9998295eb1bSdyoung 	if (pci_rsrc_dict == NULL)
10008295eb1bSdyoung 		return;
10018295eb1bSdyoung 
10028295eb1bSdyoung 	if (!device_is_a(dev, "pci") &&
10038295eb1bSdyoung 	    (cf == NULL || strcmp(cfdata_ifattr(cf), "pci") != 0))
10048295eb1bSdyoung 		return;
10058295eb1bSdyoung 
10068295eb1bSdyoung 	dict = pci_rsrc_filter(pci_rsrc_dict,
10078295eb1bSdyoung 	    device_is_a(dev, "pci") ? &pcibus_rsvn_predicate
10088295eb1bSdyoung 				    : &pci_rsvn_predicate, aux);
10098295eb1bSdyoung 	if (dict == NULL)
10108295eb1bSdyoung 		return;
10118295eb1bSdyoung 	(void)prop_dictionary_set(device_properties(dev),
10128295eb1bSdyoung 	    "pci-resources", dict);
10138295eb1bSdyoung }
1014