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