Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #if defined(DEBUG)
     27 #define	BUSRA_DEBUG
     28 #endif
     29 
     30 /*
     31  * This module provides a set of resource management interfaces
     32  * to manage bus resources globally in the system.
     33  *
     34  * The bus nexus drivers are typically responsible to setup resource
     35  * maps for the bus resources available for a bus instance. However
     36  * this module also provides resource setup functions for PCI bus
     37  * (used by both SPARC and X86 platforms) and ISA bus instances (used
     38  * only for X86 platforms).
     39  */
     40 
     41 #include <sys/types.h>
     42 #include <sys/systm.h>
     43 #include <sys/ddi.h>
     44 #include <sys/sunddi.h>
     45 #include <sys/sunndi.h>
     46 #include <sys/ddi_impldefs.h>
     47 #include <sys/ndi_impldefs.h>
     48 #include <sys/kmem.h>
     49 #include <sys/pctypes.h>
     50 #include <sys/modctl.h>
     51 #include <sys/debug.h>
     52 #include <sys/spl.h>
     53 #include <sys/pci.h>
     54 #include <sys/autoconf.h>
     55 
     56 #if defined(BUSRA_DEBUG)
     57 int busra_debug = 0;
     58 #define	DEBUGPRT \
     59 	if (busra_debug) cmn_err
     60 
     61 #else
     62 #define	DEBUGPRT \
     63 	if (0) cmn_err
     64 #endif
     65 
     66 
     67 /*
     68  * global mutex that protects the global list of resource maps.
     69  */
     70 kmutex_t ra_lock;
     71 
     72 /*
     73  * basic resource element
     74  */
     75 struct ra_resource {
     76 	struct ra_resource *ra_next;
     77 	uint64_t	ra_base;
     78 	uint64_t 	ra_len;
     79 };
     80 
     81 /*
     82  * link list element for the list of dips (and their resource ranges)
     83  * for a particular resource type.
     84  * ra_rangeset points to the list of resources available
     85  * for this type and this dip.
     86  */
     87 struct ra_dip_type  {
     88 	struct ra_dip_type *ra_next;
     89 	struct ra_resource  *ra_rangeset;
     90 	dev_info_t *ra_dip;
     91 };
     92 
     93 
     94 /*
     95  * link list element for list of types resources. Each element
     96  * has all resources for a particular type.
     97  */
     98 struct ra_type_map {
     99 	struct ra_type_map *ra_next;
    100 	struct ra_dip_type *ra_dip_list;
    101 	char *type;
    102 };
    103 
    104 
    105 /*
    106  * place holder to keep the head of the whole global list.
    107  * the address of the first typemap would be stored in it.
    108  */
    109 static struct ra_type_map	*ra_map_list_head = NULL;
    110 
    111 
    112 /*
    113  * This is the loadable module wrapper.
    114  * It is essentially boilerplate so isn't documented
    115  */
    116 extern struct mod_ops mod_miscops;
    117 
    118 #ifdef BUSRA_DEBUG
    119 void ra_dump_all();
    120 #endif
    121 
    122 /* internal function prototypes */
    123 static struct ra_dip_type *find_dip_map_resources(dev_info_t *dip, char *type,
    124     struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
    125     uint32_t flag);
    126 static int isnot_pow2(uint64_t value);
    127 static int claim_pci_busnum(dev_info_t *dip, void *arg);
    128 static int ra_map_exist(dev_info_t *dip, char *type);
    129 
    130 static int pci_get_available_prop(dev_info_t *dip, uint64_t base,
    131     uint64_t len, char *busra_type);
    132 static int pci_put_available_prop(dev_info_t *dip, uint64_t base,
    133     uint64_t len, char *busra_type);
    134 static uint32_t pci_type_ra2pci(char *type);
    135 static boolean_t is_pcie_fabric(dev_info_t *dip);
    136 
    137 #define	PCI_ADDR_TYPE_MASK	(PCI_REG_ADDR_M | PCI_REG_PF_M)
    138 #define	PCI_ADDR_TYPE_INVAL	0xffffffff
    139 
    140 #define	RA_INSERT(prev, el) \
    141 	el->ra_next = *prev; \
    142 	*prev = el;
    143 
    144 #define	RA_REMOVE(prev, el) \
    145 	*prev = el->ra_next;
    146 
    147 
    148 static struct modlmisc modlmisc = {
    149 	&mod_miscops,		/* Type of module. This one is a module */
    150 	"Bus Resource Allocator (BUSRA)",	/* Name of the module. */
    151 };
    152 
    153 static struct modlinkage modlinkage = {
    154 	MODREV_1, (void *)&modlmisc, NULL
    155 };
    156 
    157 int
    158 _init()
    159 {
    160 	int	ret;
    161 
    162 	mutex_init(&ra_lock, NULL, MUTEX_DRIVER,
    163 	    (void *)(intptr_t)__ipltospl(SPL7 - 1));
    164 	if ((ret = mod_install(&modlinkage)) != 0) {
    165 		mutex_destroy(&ra_lock);
    166 	}
    167 	return (ret);
    168 }
    169 
    170 int
    171 _fini()
    172 {
    173 	int	ret;
    174 
    175 	mutex_enter(&ra_lock);
    176 
    177 	if (ra_map_list_head != NULL) {
    178 		mutex_exit(&ra_lock);
    179 		return (EBUSY);
    180 	}
    181 
    182 	ret = mod_remove(&modlinkage);
    183 
    184 	mutex_exit(&ra_lock);
    185 
    186 	if (ret == 0)
    187 		mutex_destroy(&ra_lock);
    188 
    189 	return (ret);
    190 }
    191 
    192 int
    193 _info(struct modinfo *modinfop)
    194 
    195 {
    196 	return (mod_info(&modlinkage, modinfop));
    197 }
    198 
    199 /*
    200  * set up an empty resource map for a given type and dip
    201  */
    202 int
    203 ndi_ra_map_setup(dev_info_t *dip, char *type)
    204 {
    205 	struct ra_type_map  *typemapp;
    206 	struct ra_dip_type  *dipmap;
    207 	struct ra_dip_type  **backdip;
    208 	struct ra_type_map  **backtype;
    209 
    210 
    211 	mutex_enter(&ra_lock);
    212 
    213 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
    214 
    215 	if (dipmap == NULL) {
    216 		if (backtype == NULL) {
    217 			typemapp = (struct ra_type_map *)
    218 			    kmem_zalloc(sizeof (*typemapp), KM_SLEEP);
    219 			typemapp->type = (char *)kmem_zalloc(strlen(type) + 1,
    220 			    KM_SLEEP);
    221 			(void) strcpy(typemapp->type, type);
    222 			RA_INSERT(&ra_map_list_head, typemapp);
    223 		} else {
    224 			typemapp = *backtype;
    225 		}
    226 		if (backdip == NULL) {
    227 			/* allocate and insert in list of dips for this type */
    228 			dipmap = (struct ra_dip_type *)
    229 			    kmem_zalloc(sizeof (*dipmap), KM_SLEEP);
    230 			dipmap->ra_dip = dip;
    231 			RA_INSERT(&typemapp->ra_dip_list, dipmap);
    232 		}
    233 	}
    234 
    235 	mutex_exit(&ra_lock);
    236 	return (NDI_SUCCESS);
    237 }
    238 
    239 /*
    240  * destroys a resource map for a given dip and type
    241  */
    242 int
    243 ndi_ra_map_destroy(dev_info_t *dip, char *type)
    244 {
    245 	struct ra_dip_type	*dipmap;
    246 	struct ra_dip_type	**backdip;
    247 	struct ra_type_map  	**backtype, *typemap;
    248 	struct ra_resource	*range;
    249 
    250 	mutex_enter(&ra_lock);
    251 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
    252 
    253 	if (dipmap == NULL) {
    254 		mutex_exit(&ra_lock);
    255 		return (NDI_FAILURE);
    256 	}
    257 
    258 	/*
    259 	 * destroy all resources for this dip
    260 	 * remove dip from type list
    261 	 */
    262 	ASSERT((backdip != NULL) && (backtype != NULL));
    263 	while (dipmap->ra_rangeset != NULL) {
    264 		range = dipmap->ra_rangeset;
    265 		RA_REMOVE(&dipmap->ra_rangeset, range);
    266 		kmem_free((caddr_t)range, sizeof (*range));
    267 	}
    268 	/* remove from dip list */
    269 	RA_REMOVE(backdip, dipmap);
    270 	kmem_free((caddr_t)dipmap, sizeof (*dipmap));
    271 	if ((*backtype)->ra_dip_list == NULL) {
    272 		/*
    273 		 * This was the last dip with this resource type.
    274 		 * Remove the type from the global list.
    275 		 */
    276 		typemap = *backtype;
    277 		RA_REMOVE(backtype, (*backtype));
    278 		kmem_free((caddr_t)typemap->type, strlen(typemap->type) + 1);
    279 		kmem_free((caddr_t)typemap, sizeof (*typemap));
    280 	}
    281 
    282 	mutex_exit(&ra_lock);
    283 	return (NDI_SUCCESS);
    284 }
    285 
    286 static int
    287 ra_map_exist(dev_info_t *dip, char *type)
    288 {
    289 	struct ra_dip_type  **backdip;
    290 	struct ra_type_map  **backtype;
    291 
    292 	mutex_enter(&ra_lock);
    293 	if (find_dip_map_resources(dip, type, &backdip, &backtype, 0) == NULL) {
    294 		mutex_exit(&ra_lock);
    295 		return (NDI_FAILURE);
    296 	}
    297 
    298 	mutex_exit(&ra_lock);
    299 	return (NDI_SUCCESS);
    300 }
    301 /*
    302  * Find a dip map for the specified type, if NDI_RA_PASS will go up on dev tree
    303  * if found, backdip and backtype will be updated to point to the previous
    304  * dip in the list and previous type for this dip in the list.
    305  * If no such type at all in the resource list both backdip and backtype
    306  * will be null. If the type found but no dip, back dip will be null.
    307  */
    308 
    309 static struct ra_dip_type *
    310 find_dip_map_resources(dev_info_t *dip, char *type,
    311     struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
    312     uint32_t flag)
    313 {
    314 	struct ra_type_map **prevmap;
    315 	struct ra_dip_type *dipmap, **prevdip;
    316 
    317 	ASSERT(mutex_owned(&ra_lock));
    318 	prevdip = NULL;
    319 	dipmap = NULL;
    320 	prevmap = &ra_map_list_head;
    321 
    322 	while (*prevmap) {
    323 		if (strcmp((*prevmap)->type, type) == 0)
    324 			break;
    325 		prevmap = &(*prevmap)->ra_next;
    326 	}
    327 
    328 	if (*prevmap) {
    329 		for (; dip != NULL; dip = ddi_get_parent(dip)) {
    330 			prevdip = &(*prevmap)->ra_dip_list;
    331 			dipmap = *prevdip;
    332 
    333 			while (dipmap) {
    334 				if (dipmap->ra_dip == dip)
    335 					break;
    336 				prevdip =  &dipmap->ra_next;
    337 				dipmap = dipmap->ra_next;
    338 			}
    339 
    340 			if (dipmap != NULL) {
    341 				/* found it */
    342 				break;
    343 			}
    344 
    345 			if (!(flag & NDI_RA_PASS)) {
    346 				break;
    347 			}
    348 		}
    349 	}
    350 
    351 	*backtype = (*prevmap == NULL) ?  NULL: prevmap;
    352 	*backdip = (dipmap == NULL) ?  NULL: prevdip;
    353 
    354 	return (dipmap);
    355 }
    356 
    357 int
    358 ndi_ra_free(dev_info_t *dip, uint64_t base, uint64_t len, char *type,
    359     uint32_t flag)
    360 {
    361 	struct ra_dip_type *dipmap;
    362 	struct ra_resource *newmap, *overlapmap, *oldmap = NULL;
    363 	struct ra_resource  *mapp, **backp;
    364 	uint64_t newend, mapend;
    365 	struct ra_dip_type **backdip;
    366 	struct ra_type_map **backtype;
    367 
    368 	if (len == 0) {
    369 		return (NDI_SUCCESS);
    370 	}
    371 
    372 	mutex_enter(&ra_lock);
    373 
    374 	if ((dipmap = find_dip_map_resources(dip, type, &backdip, &backtype,
    375 	    flag)) == NULL) {
    376 		mutex_exit(&ra_lock);
    377 		return (NDI_FAILURE);
    378 	}
    379 
    380 	mapp = dipmap->ra_rangeset;
    381 	backp = &dipmap->ra_rangeset;
    382 
    383 	/* now find where range lies and fix things up */
    384 	newend = base + len;
    385 	for (; mapp != NULL; backp = &(mapp->ra_next), mapp = mapp->ra_next) {
    386 		mapend = mapp->ra_base + mapp->ra_len;
    387 
    388 		/* check for overlap first */
    389 		if ((base <= mapp->ra_base && newend > mapp->ra_base) ||
    390 		    (base > mapp->ra_base && base < mapend)) {
    391 			/* overlap with mapp */
    392 			overlapmap = mapp;
    393 			goto overlap;
    394 		} else if ((base == mapend && mapp->ra_next) &&
    395 		    (newend > mapp->ra_next->ra_base)) {
    396 			/* overlap with mapp->ra_next */
    397 			overlapmap = mapp->ra_next;
    398 			goto overlap;
    399 		}
    400 
    401 		if (newend == mapp->ra_base) {
    402 			/* simple - on front */
    403 			mapp->ra_base = base;
    404 			mapp->ra_len += len;
    405 			/*
    406 			 * don't need to check if it merges with
    407 			 * previous since that would match on on end
    408 			 */
    409 			break;
    410 		} else if (base == mapend) {
    411 			/* simple - on end */
    412 			mapp->ra_len += len;
    413 			if (mapp->ra_next &&
    414 			    (newend == mapp->ra_next->ra_base)) {
    415 				/* merge with next node */
    416 				oldmap = mapp->ra_next;
    417 				mapp->ra_len += oldmap->ra_len;
    418 				RA_REMOVE(&mapp->ra_next, oldmap);
    419 				kmem_free((caddr_t)oldmap, sizeof (*oldmap));
    420 			}
    421 			break;
    422 		} else if (base < mapp->ra_base) {
    423 			/* somewhere in between so just an insert */
    424 			newmap = (struct ra_resource *)
    425 			    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
    426 			newmap->ra_base = base;
    427 			newmap->ra_len = len;
    428 			RA_INSERT(backp, newmap);
    429 			break;
    430 		}
    431 	}
    432 	if (mapp == NULL) {
    433 		/* stick on end */
    434 		newmap = (struct ra_resource *)
    435 		    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
    436 		newmap->ra_base = base;
    437 		newmap->ra_len = len;
    438 		RA_INSERT(backp, newmap);
    439 	}
    440 
    441 	mutex_exit(&ra_lock);
    442 
    443 	/*
    444 	 * Update dip's "available" property, adding this piece of
    445 	 * resource to the pool.
    446 	 */
    447 	(void) pci_put_available_prop(dip, base, len, type);
    448 done:
    449 	return (NDI_SUCCESS);
    450 
    451 overlap:
    452 	/*
    453 	 * Bad free may happen on some x86 platforms with BIOS exporting
    454 	 * incorrect resource maps. The system is otherwise functioning
    455 	 * normally. We send such messages to syslog only.
    456 	 */
    457 	cmn_err(CE_NOTE, "!ndi_ra_free: bad free, dip %p, resource type %s \n",
    458 	    (void *)dip, type);
    459 	cmn_err(CE_NOTE, "!ndi_ra_free: freeing base 0x%" PRIx64 ", len 0x%"
    460 	    PRIX64 " overlaps with existing resource base 0x%" PRIx64
    461 	    ", len 0x%" PRIx64 "\n", base, len, overlapmap->ra_base,
    462 	    overlapmap->ra_len);
    463 
    464 	mutex_exit(&ra_lock);
    465 	return (NDI_FAILURE);
    466 }
    467 
    468 /* check to see if value is power of 2 or not. */
    469 static int
    470 isnot_pow2(uint64_t value)
    471 {
    472 	uint32_t low;
    473 	uint32_t hi;
    474 
    475 	low = value & 0xffffffff;
    476 	hi = value >> 32;
    477 
    478 	/*
    479 	 * ddi_ffs and ddi_fls gets long values, so in 32bit environment
    480 	 * won't work correctly for 64bit values
    481 	 */
    482 	if ((ddi_ffs(low) == ddi_fls(low)) &&
    483 	    (ddi_ffs(hi) == ddi_fls(hi)))
    484 		return (0);
    485 	return (1);
    486 }
    487 
    488 static  void
    489 adjust_link(struct ra_resource **backp, struct ra_resource *mapp,
    490 	    uint64_t base, uint64_t len)
    491 {
    492 	struct ra_resource *newmap;
    493 	uint64_t newlen;
    494 
    495 	if (base != mapp->ra_base) {
    496 		/* in the middle or end */
    497 		newlen = base - mapp->ra_base;
    498 		if ((mapp->ra_len - newlen) == len) {
    499 			/* on the end */
    500 			mapp->ra_len = newlen;
    501 		} else {
    502 			/* in the middle */
    503 			newmap = (struct ra_resource *)
    504 			    kmem_zalloc(sizeof (*newmap), KM_SLEEP);
    505 			newmap->ra_base = base + len;
    506 			newmap->ra_len = mapp->ra_len - (len + newlen);
    507 			mapp->ra_len = newlen;
    508 			RA_INSERT(&(mapp->ra_next), newmap);
    509 		}
    510 	} else {
    511 		/* at the beginning */
    512 		mapp->ra_base += len;
    513 		mapp->ra_len -= len;
    514 		if (mapp->ra_len == 0) {
    515 			/* remove the whole node */
    516 			RA_REMOVE(backp, mapp);
    517 			kmem_free((caddr_t)mapp, sizeof (*mapp));
    518 		}
    519 	}
    520 }
    521 
    522 int
    523 ndi_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, uint64_t *retbasep,
    524     uint64_t *retlenp, char *type, uint32_t flag)
    525 {
    526 	struct ra_dip_type *dipmap;
    527 	struct ra_resource *mapp, **backp, **backlargestp;
    528 	uint64_t mask = 0;
    529 	uint64_t len, remlen, largestbase, largestlen;
    530 	uint64_t base, oldbase, lower, upper;
    531 	struct ra_dip_type  **backdip;
    532 	struct ra_type_map  **backtype;
    533 	int  rval = NDI_FAILURE;
    534 
    535 
    536 	len = req->ra_len;
    537 
    538 	if (req->ra_flags & NDI_RA_ALIGN_SIZE) {
    539 		if (isnot_pow2(req->ra_len)) {
    540 			DEBUGPRT(CE_WARN, "ndi_ra_alloc: bad length(pow2) 0x%"
    541 			    PRIx64, req->ra_len);
    542 			*retbasep = 0;
    543 			*retlenp = 0;
    544 			return (NDI_FAILURE);
    545 		}
    546 	}
    547 
    548 	mask = (req->ra_flags & NDI_RA_ALIGN_SIZE) ? (len - 1) :
    549 	    req->ra_align_mask;
    550 
    551 
    552 	mutex_enter(&ra_lock);
    553 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, flag);
    554 	if ((dipmap == NULL) || ((mapp = dipmap->ra_rangeset) == NULL)) {
    555 		mutex_exit(&ra_lock);
    556 		DEBUGPRT(CE_CONT, "ndi_ra_alloc no map found for this type\n");
    557 		return (NDI_FAILURE);
    558 	}
    559 
    560 	DEBUGPRT(CE_CONT, "ndi_ra_alloc: mapp = %p len=%" PRIx64 ", mask=%"
    561 	    PRIx64 "\n", (void *)mapp, len, mask);
    562 
    563 	backp = &(dipmap->ra_rangeset);
    564 	backlargestp = NULL;
    565 	largestbase = 0;
    566 	largestlen = 0;
    567 
    568 	lower = 0;
    569 	upper = ~(uint64_t)0;
    570 
    571 	if (req->ra_flags & NDI_RA_ALLOC_BOUNDED) {
    572 		/* bounded so skip to first possible */
    573 		lower = req->ra_boundbase;
    574 		upper = req->ra_boundlen + lower;
    575 		if ((upper == 0) || (upper < req->ra_boundlen))
    576 			upper = ~(uint64_t)0;
    577 		DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 ", len = %"
    578 		    PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64
    579 		    "\n", mapp->ra_len, len, mapp->ra_base, mask);
    580 		for (; mapp != NULL && (mapp->ra_base + mapp->ra_len) < lower;
    581 		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
    582 			if (((mapp->ra_len + mapp->ra_base) == 0) ||
    583 			    ((mapp->ra_len + mapp->ra_base) < mapp->ra_len))
    584 				/*
    585 				 * This elements end goes beyond max uint64_t.
    586 				 * potential candidate, check end against lower
    587 				 * would not be precise.
    588 				 */
    589 				break;
    590 
    591 			DEBUGPRT(CE_CONT, " ra_len = %" PRIx64 ", ra_base=%"
    592 			    PRIx64 "\n", mapp->ra_len, mapp->ra_base);
    593 			}
    594 
    595 	}
    596 
    597 	if (!(req->ra_flags & NDI_RA_ALLOC_SPECIFIED)) {
    598 		/* first fit - not user specified */
    599 		DEBUGPRT(CE_CONT, "ndi_ra_alloc(unspecified request)"
    600 		    "lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper);
    601 		for (; mapp != NULL && mapp->ra_base <= upper;
    602 		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
    603 
    604 			DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64
    605 			    ", len = %" PRIx64 "", mapp->ra_len, len);
    606 			base = mapp->ra_base;
    607 			if (base < lower) {
    608 				base = lower;
    609 				DEBUGPRT(CE_CONT, "\tbase=%" PRIx64
    610 				    ", ra_base=%" PRIx64 ", mask=%" PRIx64,
    611 				    base, mapp->ra_base, mask);
    612 			}
    613 
    614 			if ((base & mask) != 0) {
    615 				oldbase = base;
    616 				/*
    617 				 * failed a critical constraint
    618 				 * adjust and see if it still fits
    619 				 */
    620 				base = base & ~mask;
    621 				base += (mask + 1);
    622 				DEBUGPRT(CE_CONT, "\tnew base=%" PRIx64 "\n",
    623 				    base);
    624 
    625 				/*
    626 				 * Check to see if the new base is past
    627 				 * the end of the resource.
    628 				 */
    629 				if (base >= (oldbase + mapp->ra_len + 1)) {
    630 					continue;
    631 				}
    632 			}
    633 
    634 			if (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) {
    635 				if ((upper - mapp->ra_base)  <  mapp->ra_len)
    636 					remlen = upper - base;
    637 				else
    638 					remlen = mapp->ra_len -
    639 					    (base - mapp->ra_base);
    640 
    641 				if ((backlargestp == NULL) ||
    642 				    (largestlen < remlen)) {
    643 
    644 					backlargestp = backp;
    645 					largestbase = base;
    646 					largestlen = remlen;
    647 				}
    648 			}
    649 
    650 			if (mapp->ra_len >= len) {
    651 				/* a candidate -- apply constraints */
    652 				if ((len > (mapp->ra_len -
    653 				    (base - mapp->ra_base))) ||
    654 				    ((len - 1 + base) > upper)) {
    655 					continue;
    656 				}
    657 
    658 				/* we have a fit */
    659 
    660 				DEBUGPRT(CE_CONT, "\thave a fit\n");
    661 
    662 				adjust_link(backp, mapp, base, len);
    663 				rval = NDI_SUCCESS;
    664 				break;
    665 
    666 			}
    667 		}
    668 	} else {
    669 		/* want an exact value/fit */
    670 		base = req->ra_addr;
    671 		len = req->ra_len;
    672 		for (; mapp != NULL && mapp->ra_base <= upper;
    673 		    backp = &(mapp->ra_next), mapp = mapp->ra_next) {
    674 			if (base >= mapp->ra_base &&
    675 			    ((base - mapp->ra_base) < mapp->ra_len)) {
    676 				/*
    677 				 * This is the node with he requested base in
    678 				 * its range
    679 				 */
    680 				if ((len > mapp->ra_len) ||
    681 				    (base - mapp->ra_base >
    682 				    mapp->ra_len - len)) {
    683 					/* length requirement not satisfied */
    684 					if (req->ra_flags &
    685 					    NDI_RA_ALLOC_PARTIAL_OK) {
    686 						if ((upper - mapp->ra_base)
    687 						    < mapp->ra_len)
    688 							remlen = upper - base;
    689 						else
    690 							remlen =
    691 							    mapp->ra_len -
    692 							    (base -
    693 							    mapp->ra_base);
    694 					}
    695 					backlargestp = backp;
    696 					largestbase = base;
    697 					largestlen = remlen;
    698 					base = 0;
    699 				} else {
    700 					/* We have a match */
    701 					adjust_link(backp, mapp, base, len);
    702 					rval = NDI_SUCCESS;
    703 				}
    704 				break;
    705 			}
    706 		}
    707 	}
    708 
    709 	if ((rval != NDI_SUCCESS) &&
    710 	    (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) &&
    711 	    (backlargestp != NULL)) {
    712 		adjust_link(backlargestp, *backlargestp, largestbase,
    713 		    largestlen);
    714 
    715 		base = largestbase;
    716 		len = largestlen;
    717 		rval = NDI_RA_PARTIAL_REQ;
    718 	}
    719 
    720 	mutex_exit(&ra_lock);
    721 
    722 	if (rval == NDI_FAILURE) {
    723 		*retbasep = 0;
    724 		*retlenp = 0;
    725 	} else {
    726 		*retbasep = base;
    727 		*retlenp = len;
    728 	}
    729 
    730 	/*
    731 	 * Update dip's "available" property, substract this piece of
    732 	 * resource from the pool.
    733 	 */
    734 	if ((rval == NDI_SUCCESS) || (rval == NDI_RA_PARTIAL_REQ))
    735 		(void) pci_get_available_prop(dip, *retbasep, *retlenp, type);
    736 
    737 	return (rval);
    738 }
    739 
    740 /*
    741  * isa_resource_setup
    742  *	check for /used-resources and initialize
    743  *	based on info there.  If no /used-resources,
    744  *	fail.
    745  */
    746 int
    747 isa_resource_setup()
    748 {
    749 	dev_info_t *used, *usedpdip;
    750 	/*
    751 	 * note that at this time bootconf creates 32 bit properties for
    752 	 * io-space and device-memory
    753 	 */
    754 	struct iorange {
    755 		uint32_t	base;
    756 		uint32_t	len;
    757 	} *iorange;
    758 	struct memrange {
    759 		uint32_t	base;
    760 		uint32_t	len;
    761 	} *memrange;
    762 	uint32_t *irq;
    763 	int proplen;
    764 	int i, len;
    765 	int maxrange;
    766 	ndi_ra_request_t req;
    767 	uint64_t retbase;
    768 	uint64_t retlen;
    769 
    770 	used = ddi_find_devinfo("used-resources", -1, 0);
    771 	if (used == NULL) {
    772 		DEBUGPRT(CE_CONT,
    773 		    "isa_resource_setup: used-resources not found");
    774 		return (NDI_FAILURE);
    775 	}
    776 
    777 	/*
    778 	 * initialize to all resources being present
    779 	 * and then remove the ones in use.
    780 	 */
    781 
    782 	usedpdip = ddi_root_node();
    783 
    784 	DEBUGPRT(CE_CONT, "isa_resource_setup: used = %p usedpdip = %p\n",
    785 	    (void *)used, (void *)usedpdip);
    786 
    787 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
    788 		return (NDI_FAILURE);
    789 	}
    790 
    791 	/* initialize io space, highest end base is 0xffff */
    792 	/* note that length is highest addr + 1 since starts from 0 */
    793 
    794 	(void) ndi_ra_free(usedpdip, 0, 0xffff + 1,  NDI_RA_TYPE_IO, 0);
    795 
    796 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
    797 	    "io-space", (caddr_t)&iorange, &proplen) == DDI_SUCCESS) {
    798 		maxrange = proplen / sizeof (struct iorange);
    799 		/* remove the "used" I/O resources */
    800 		for (i = 0; i < maxrange; i++) {
    801 			bzero((caddr_t)&req, sizeof (req));
    802 			req.ra_addr =  (uint64_t)iorange[i].base;
    803 			req.ra_len = (uint64_t)iorange[i].len;
    804 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
    805 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
    806 			    NDI_RA_TYPE_IO, 0);
    807 		}
    808 
    809 		kmem_free((caddr_t)iorange, proplen);
    810 	}
    811 
    812 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
    813 		return (NDI_FAILURE);
    814 	}
    815 	/* initialize memory space where highest end base is 0xffffffff */
    816 	/* note that length is highest addr + 1 since starts from 0 */
    817 	(void) ndi_ra_free(usedpdip, 0, ((uint64_t)((uint32_t)~0)) + 1,
    818 	    NDI_RA_TYPE_MEM, 0);
    819 
    820 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
    821 	    "device-memory", (caddr_t)&memrange, &proplen) == DDI_SUCCESS) {
    822 		maxrange = proplen / sizeof (struct memrange);
    823 		/* remove the "used" memory resources */
    824 		for (i = 0; i < maxrange; i++) {
    825 			bzero((caddr_t)&req, sizeof (req));
    826 			req.ra_addr = (uint64_t)memrange[i].base;
    827 			req.ra_len = (uint64_t)memrange[i].len;
    828 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
    829 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
    830 			    NDI_RA_TYPE_MEM, 0);
    831 		}
    832 
    833 		kmem_free((caddr_t)memrange, proplen);
    834 	}
    835 
    836 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_INTR) == NDI_FAILURE) {
    837 		return (NDI_FAILURE);
    838 	}
    839 
    840 	/* initialize the interrupt space */
    841 	(void) ndi_ra_free(usedpdip, 0, 16, NDI_RA_TYPE_INTR, 0);
    842 
    843 #if defined(__i386) || defined(__amd64)
    844 	bzero(&req, sizeof (req));
    845 	req.ra_addr = 2;	/* 2 == 9 so never allow */
    846 	req.ra_len = 1;
    847 	req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
    848 	(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
    849 	    NDI_RA_TYPE_INTR, 0);
    850 #endif
    851 
    852 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
    853 	    "interrupts", (caddr_t)&irq, &proplen) == DDI_SUCCESS) {
    854 		/* Initialize available interrupts by negating the used */
    855 		len = (proplen / sizeof (uint32_t));
    856 		for (i = 0; i < len; i++) {
    857 			bzero((caddr_t)&req, sizeof (req));
    858 			req.ra_addr = (uint64_t)irq[i];
    859 			req.ra_len = 1;
    860 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
    861 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
    862 			    NDI_RA_TYPE_INTR, 0);
    863 		}
    864 		kmem_free((caddr_t)irq, proplen);
    865 	}
    866 
    867 #ifdef BUSRA_DEBUG
    868 	if (busra_debug) {
    869 		(void) ra_dump_all(NULL, usedpdip);
    870 	}
    871 #endif
    872 	return (NDI_SUCCESS);
    873 
    874 }
    875 
    876 #ifdef BUSRA_DEBUG
    877 void
    878 ra_dump_all(char *type, dev_info_t *dip)
    879 {
    880 
    881 	struct ra_type_map *typemap;
    882 	struct ra_dip_type *dipmap;
    883 	struct ra_resource *res;
    884 
    885 	typemap =  (struct ra_type_map *)ra_map_list_head;
    886 
    887 	for (; typemap != NULL; typemap = typemap->ra_next) {
    888 		if (type != NULL) {
    889 			if (strcmp(typemap->type, type) != 0)
    890 				continue;
    891 		}
    892 		cmn_err(CE_CONT, "type is %s\n", typemap->type);
    893 		for (dipmap = typemap->ra_dip_list; dipmap != NULL;
    894 		    dipmap = dipmap->ra_next) {
    895 			if (dip != NULL) {
    896 				if ((dipmap->ra_dip) != dip)
    897 					continue;
    898 			}
    899 			cmn_err(CE_CONT, "  dip is %p\n",
    900 			    (void *)dipmap->ra_dip);
    901 			for (res = dipmap->ra_rangeset; res != NULL;
    902 			    res = res->ra_next) {
    903 				cmn_err(CE_CONT, "\t  range is %" PRIx64
    904 				    " %" PRIx64 "\n", res->ra_base,
    905 				    res->ra_len);
    906 			}
    907 			if (dip != NULL)
    908 				break;
    909 		}
    910 		if (type != NULL)
    911 			break;
    912 	}
    913 }
    914 #endif
    915 
    916 struct bus_range {	/* 1275 "bus-range" property definition */
    917 	uint32_t lo;
    918 	uint32_t hi;
    919 } pci_bus_range;
    920 
    921 struct busnum_ctrl {
    922 	int	rv;
    923 	dev_info_t *dip;
    924 	struct	bus_range *range;
    925 };
    926 
    927 
    928 /*
    929  * Setup resource map for the pci bus node based on the "available"
    930  * property and "bus-range" property.
    931  */
    932 int
    933 pci_resource_setup(dev_info_t *dip)
    934 {
    935 	pci_regspec_t *regs;
    936 	int rlen, rcount, i;
    937 	char bus_type[16] = "(unknown)";
    938 	int len;
    939 	struct busnum_ctrl ctrl;
    940 	int circular_count;
    941 	int rval = NDI_SUCCESS;
    942 
    943 	/*
    944 	 * If this is a pci bus node then look for "available" property
    945 	 * to find the available resources on this bus.
    946 	 */
    947 	len = sizeof (bus_type);
    948 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
    949 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
    950 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
    951 		return (NDI_FAILURE);
    952 
    953 	/* it is not a pci/pci-ex bus type */
    954 	if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
    955 		return (NDI_FAILURE);
    956 
    957 	/*
    958 	 * The pci-hotplug project addresses adding the call
    959 	 * to pci_resource_setup from pci nexus driver.
    960 	 * However that project would initially be only for x86,
    961 	 * so for sparc pcmcia-pci support we still need to call
    962 	 * pci_resource_setup in pcic driver. Once all pci nexus drivers
    963 	 * are updated to call pci_resource_setup this portion of the
    964 	 * code would really become an assert to make sure this
    965 	 * function is not called for the same dip twice.
    966 	 */
    967 	/*
    968 	 * Another user for the check below is hotplug PCI/PCIe bridges.
    969 	 *
    970 	 * For PCI/PCIE devices under a PCIE hierarchy, ndi_ra_alloc/free
    971 	 * will update the devinfo node's "available" property, to reflect
    972 	 * the fact that a piece of resource has been removed/added to
    973 	 * a devinfo node.
    974 	 * During probe of a new PCI bridge in the hotplug case, PCI
    975 	 * configurator firstly allocates maximum MEM/IO from its parent,
    976 	 * then calls ndi_ra_free() to use these resources to setup busra
    977 	 * pool for the new bridge, as well as adding these resources to
    978 	 * the "available" property of the new devinfo node. Then configu-
    979 	 * rator will attach driver for the bridge before probing its
    980 	 * children, and the bridge driver will then initialize its hotplug
    981 	 * contollers (if it supports hotplug) and HPC driver will call
    982 	 * this function to setup the busra pool, but the resource pool
    983 	 * has already been setup at the first of pcicfg_probe_bridge(),
    984 	 * thus we need the check below to return directly in this case.
    985 	 * Otherwise the ndi_ra_free() below will see overlapping resources.
    986 	 */
    987 	{
    988 		if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) {
    989 			return (NDI_FAILURE);
    990 		}
    991 	}
    992 
    993 
    994 	/*
    995 	 * Create empty resource maps first.
    996 	 *
    997 	 * NOTE: If all the allocated resources are already assigned to
    998 	 * device(s) in the hot plug slot then "available" property may not
    999 	 * be present. But, subsequent hot plug operation may unconfigure
   1000 	 * the device in the slot and try to free up it's resources. So,
   1001 	 * at the minimum we should create empty maps here.
   1002 	 */
   1003 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
   1004 		return (NDI_FAILURE);
   1005 	}
   1006 
   1007 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
   1008 		return (NDI_FAILURE);
   1009 	}
   1010 
   1011 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM) == NDI_FAILURE) {
   1012 		return (NDI_FAILURE);
   1013 	}
   1014 
   1015 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
   1016 	    NDI_FAILURE) {
   1017 		return (NDI_FAILURE);
   1018 	}
   1019 
   1020 	/* read the "available" property if it is available */
   1021 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
   1022 	    "available", (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
   1023 		/*
   1024 		 * Remove "available" property as the entries will be
   1025 		 * re-created in ndi_ra_free() below, note prom based
   1026 		 * property will not be removed. But in ndi_ra_free()
   1027 		 * we'll be creating non prom based property entries.
   1028 		 */
   1029 		(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
   1030 		/*
   1031 		 * create the available resource list for both memory and
   1032 		 * io space
   1033 		 */
   1034 		rcount = rlen / sizeof (pci_regspec_t);
   1035 		for (i = 0; i < rcount; i++) {
   1036 			switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) {
   1037 			case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
   1038 				(void) ndi_ra_free(dip,
   1039 				    (uint64_t)regs[i].pci_phys_low,
   1040 				    (uint64_t)regs[i].pci_size_low,
   1041 				    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
   1042 				    NDI_RA_TYPE_PCI_PREFETCH_MEM :
   1043 				    NDI_RA_TYPE_MEM,
   1044 				    0);
   1045 				break;
   1046 			case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
   1047 				(void) ndi_ra_free(dip,
   1048 				    ((uint64_t)(regs[i].pci_phys_mid) << 32) |
   1049 				    ((uint64_t)(regs[i].pci_phys_low)),
   1050 				    ((uint64_t)(regs[i].pci_size_hi) << 32) |
   1051 				    ((uint64_t)(regs[i].pci_size_low)),
   1052 				    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
   1053 				    NDI_RA_TYPE_PCI_PREFETCH_MEM :
   1054 				    NDI_RA_TYPE_MEM,
   1055 				    0);
   1056 				break;
   1057 			case PCI_REG_ADDR_G(PCI_ADDR_IO):
   1058 				(void) ndi_ra_free(dip,
   1059 				    (uint64_t)regs[i].pci_phys_low,
   1060 				    (uint64_t)regs[i].pci_size_low,
   1061 				    NDI_RA_TYPE_IO,
   1062 				    0);
   1063 				break;
   1064 			case PCI_REG_ADDR_G(PCI_ADDR_CONFIG):
   1065 				break;
   1066 			default:
   1067 				cmn_err(CE_WARN,
   1068 				    "pci_resource_setup: bad addr type: %x\n",
   1069 				    PCI_REG_ADDR_G(regs[i].pci_phys_hi));
   1070 				break;
   1071 			}
   1072 		}
   1073 		kmem_free(regs, rlen);
   1074 	}
   1075 
   1076 	/*
   1077 	 * update resource map for available bus numbers if the node
   1078 	 * has available-bus-range or bus-range property.
   1079 	 */
   1080 	len = sizeof (struct bus_range);
   1081 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
   1082 	    "available-bus-range", (caddr_t)&pci_bus_range, &len) ==
   1083 	    DDI_SUCCESS) {
   1084 		/*
   1085 		 * Add bus numbers in the range to the free list.
   1086 		 */
   1087 		(void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo,
   1088 		    (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo +
   1089 		    1, NDI_RA_TYPE_PCI_BUSNUM, 0);
   1090 	} else {
   1091 		/*
   1092 		 * We don't have an available-bus-range property. If, instead,
   1093 		 * we have a bus-range property we add all the bus numbers
   1094 		 * in that range to the free list but we must then scan
   1095 		 * for pci-pci bridges on this bus to find out the if there
   1096 		 * are any of those bus numbers already in use. If so, we can
   1097 		 * reclaim them.
   1098 		 */
   1099 		len = sizeof (struct bus_range);
   1100 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
   1101 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range,
   1102 		    &len) == DDI_SUCCESS) {
   1103 			if (pci_bus_range.lo != pci_bus_range.hi) {
   1104 				/*
   1105 				 * Add bus numbers other than the secondary
   1106 				 * bus number to the free list.
   1107 				 */
   1108 				(void) ndi_ra_free(dip,
   1109 				    (uint64_t)pci_bus_range.lo + 1,
   1110 				    (uint64_t)pci_bus_range.hi -
   1111 				    (uint64_t)pci_bus_range.lo,
   1112 				    NDI_RA_TYPE_PCI_BUSNUM, 0);
   1113 
   1114 				/* scan for pci-pci bridges */
   1115 				ctrl.rv = DDI_SUCCESS;
   1116 				ctrl.dip = dip;
   1117 				ctrl.range = &pci_bus_range;
   1118 				ndi_devi_enter(dip, &circular_count);
   1119 				ddi_walk_devs(ddi_get_child(dip),
   1120 				    claim_pci_busnum, (void *)&ctrl);
   1121 				ndi_devi_exit(dip, circular_count);
   1122 				if (ctrl.rv != DDI_SUCCESS) {
   1123 					/* failed to create the map */
   1124 					(void) ndi_ra_map_destroy(dip,
   1125 					    NDI_RA_TYPE_PCI_BUSNUM);
   1126 					rval = NDI_FAILURE;
   1127 				}
   1128 			}
   1129 		}
   1130 	}
   1131 
   1132 #ifdef BUSRA_DEBUG
   1133 	if (busra_debug) {
   1134 		(void) ra_dump_all(NULL, dip);
   1135 	}
   1136 #endif
   1137 
   1138 	return (rval);
   1139 }
   1140 
   1141 /*
   1142  * If the device is a PCI bus device (i.e bus-range property exists) then
   1143  * claim the bus numbers used by the device from the specified bus
   1144  * resource map.
   1145  */
   1146 static int
   1147 claim_pci_busnum(dev_info_t *dip, void *arg)
   1148 {
   1149 	struct bus_range pci_bus_range;
   1150 	struct busnum_ctrl *ctrl;
   1151 	ndi_ra_request_t req;
   1152 	char bus_type[16] = "(unknown)";
   1153 	int len;
   1154 	uint64_t base;
   1155 	uint64_t retlen;
   1156 
   1157 	ctrl = (struct busnum_ctrl *)arg;
   1158 
   1159 	/* check if this is a PCI bus node */
   1160 	len = sizeof (bus_type);
   1161 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
   1162 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
   1163 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
   1164 		return (DDI_WALK_PRUNECHILD);
   1165 
   1166 	/* it is not a pci/pci-ex bus type */
   1167 	if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
   1168 		return (DDI_WALK_PRUNECHILD);
   1169 
   1170 	/* look for the bus-range property */
   1171 	len = sizeof (struct bus_range);
   1172 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
   1173 	    "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
   1174 		if ((pci_bus_range.lo >= ctrl->range->lo) &&
   1175 		    (pci_bus_range.hi <= ctrl->range->hi)) {
   1176 
   1177 			/* claim the bus range from the bus resource map */
   1178 			bzero((caddr_t)&req, sizeof (req));
   1179 			req.ra_addr = (uint64_t)pci_bus_range.lo;
   1180 			req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
   1181 			req.ra_len = (uint64_t)pci_bus_range.hi -
   1182 			    (uint64_t)pci_bus_range.lo + 1;
   1183 			if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
   1184 			    NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
   1185 				return (DDI_WALK_PRUNECHILD);
   1186 		}
   1187 	}
   1188 
   1189 	/*
   1190 	 * Error return.
   1191 	 */
   1192 	ctrl->rv = DDI_FAILURE;
   1193 	return (DDI_WALK_TERMINATE);
   1194 }
   1195 
   1196 void
   1197 pci_resource_destroy(dev_info_t *dip)
   1198 {
   1199 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO);
   1200 
   1201 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM);
   1202 
   1203 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
   1204 
   1205 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM);
   1206 }
   1207 
   1208 
   1209 int
   1210 pci_resource_setup_avail(dev_info_t *dip, pci_regspec_t *avail_p, int entries)
   1211 {
   1212 	int i;
   1213 
   1214 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE)
   1215 		return (NDI_FAILURE);
   1216 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE)
   1217 		return (NDI_FAILURE);
   1218 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == NDI_FAILURE)
   1219 		return (NDI_FAILURE);
   1220 
   1221 	/* for each entry in the PCI "available" property */
   1222 	for (i = 0; i < entries; i++, avail_p++) {
   1223 		if (avail_p->pci_phys_hi == -1u)
   1224 			goto err;
   1225 
   1226 		switch (PCI_REG_ADDR_G(avail_p->pci_phys_hi)) {
   1227 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32): {
   1228 			(void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
   1229 			    (uint64_t)avail_p->pci_size_low,
   1230 			    (avail_p->pci_phys_hi & PCI_REG_PF_M) ?
   1231 			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
   1232 			    0);
   1233 			}
   1234 			break;
   1235 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
   1236 			(void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
   1237 			    (uint64_t)avail_p->pci_size_low, NDI_RA_TYPE_IO, 0);
   1238 			break;
   1239 		default:
   1240 			goto err;
   1241 		}
   1242 	}
   1243 #ifdef BUSRA_DEBUG
   1244 	if (busra_debug) {
   1245 		(void) ra_dump_all(NULL, dip);
   1246 	}
   1247 #endif
   1248 	return (NDI_SUCCESS);
   1249 
   1250 err:
   1251 	cmn_err(CE_WARN, "pci_resource_setup_avail: bad entry[%d]=%x\n",
   1252 	    i, avail_p->pci_phys_hi);
   1253 	return (NDI_FAILURE);
   1254 }
   1255 
   1256 /*
   1257  * Return true if the devinfo node resides on PCI or PCI Express bus,
   1258  * sitting in a PCI Express hierarchy.
   1259  */
   1260 static boolean_t
   1261 is_pcie_fabric(dev_info_t *dip)
   1262 {
   1263 	dev_info_t *root = ddi_root_node();
   1264 	dev_info_t *pdip;
   1265 	boolean_t found = B_FALSE;
   1266 	char *bus;
   1267 
   1268 	/*
   1269 	 * Is this pci/pcie ?
   1270 	 */
   1271 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
   1272 	    DDI_PROP_DONTPASS, "device_type", &bus) !=
   1273 	    DDI_PROP_SUCCESS) {
   1274 		DEBUGPRT(CE_WARN, "is_pcie_fabric: cannot find "
   1275 		    "\"device_type\" property for dip %p\n", (void *)dip);
   1276 		return (B_FALSE);
   1277 	}
   1278 
   1279 	if (strcmp(bus, "pciex") == 0) {
   1280 		/* pcie bus, done */
   1281 		ddi_prop_free(bus);
   1282 		return (B_TRUE);
   1283 	} else if (strcmp(bus, "pci") == 0) {
   1284 		/*
   1285 		 * pci bus, fall through to check if it resides in
   1286 		 * a pcie hierarchy.
   1287 		 */
   1288 		ddi_prop_free(bus);
   1289 	} else {
   1290 		/* other bus, return failure */
   1291 		ddi_prop_free(bus);
   1292 		return (B_FALSE);
   1293 	}
   1294 
   1295 	/*
   1296 	 * Does this device reside in a pcie fabric ?
   1297 	 */
   1298 	for (pdip = ddi_get_parent(dip); pdip && (pdip != root) &&
   1299 	    !found; pdip = ddi_get_parent(pdip)) {
   1300 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
   1301 		    DDI_PROP_DONTPASS, "device_type", &bus) !=
   1302 		    DDI_PROP_SUCCESS)
   1303 			break;
   1304 
   1305 		if (strcmp(bus, "pciex") == 0)
   1306 			found = B_TRUE;
   1307 
   1308 		ddi_prop_free(bus);
   1309 	}
   1310 
   1311 	return (found);
   1312 }
   1313 
   1314 /*
   1315  * Remove a piece of IO/MEM resource from "available" property of 'dip'.
   1316  */
   1317 static int
   1318 pci_get_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
   1319     char *busra_type)
   1320 {
   1321 	pci_regspec_t	*regs, *newregs;
   1322 	uint_t		status;
   1323 	int		rlen, rcount;
   1324 	int		i, j, k;
   1325 	uint64_t	dlen;
   1326 	boolean_t	found = B_FALSE;
   1327 	uint32_t	type;
   1328 
   1329 	/* check if we're manipulating MEM/IO resource */
   1330 	if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
   1331 		return (DDI_SUCCESS);
   1332 
   1333 	/* check if dip is a pci/pcie device resides in a pcie fabric */
   1334 	if (!is_pcie_fabric(dip))
   1335 		return (DDI_SUCCESS);
   1336 
   1337 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
   1338 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
   1339 	    "available", (caddr_t)&regs, &rlen);
   1340 
   1341 	ASSERT(status == DDI_SUCCESS);
   1342 	if (status != DDI_SUCCESS)
   1343 		return (status);
   1344 
   1345 	/*
   1346 	 * The updated "available" property will at most have one more entry
   1347 	 * than existing one (when the requested range is in the middle of
   1348 	 * the matched property entry)
   1349 	 */
   1350 	newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
   1351 
   1352 	rcount = rlen / sizeof (pci_regspec_t);
   1353 	for (i = 0, j = 0; i < rcount; i++) {
   1354 		if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
   1355 			uint64_t range_base, range_len;
   1356 
   1357 			range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
   1358 			    ((uint64_t)(regs[i].pci_phys_low));
   1359 			range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
   1360 			    ((uint64_t)(regs[i].pci_size_low));
   1361 
   1362 			if ((base < range_base) ||
   1363 			    (base + len > range_base + range_len)) {
   1364 				/*
   1365 				 * not a match, copy the entry
   1366 				 */
   1367 				goto copy_entry;
   1368 			}
   1369 
   1370 			/*
   1371 			 * range_base	base	base+len	range_base
   1372 			 *					+range_len
   1373 			 *   +------------+-----------+----------+
   1374 			 *   |		  |///////////|		 |
   1375 			 *   +------------+-----------+----------+
   1376 			 */
   1377 			/*
   1378 			 * Found a match, remove the range out of this entry.
   1379 			 */
   1380 			found = B_TRUE;
   1381 
   1382 			dlen = base - range_base;
   1383 			if (dlen != 0) {
   1384 				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
   1385 				newregs[j].pci_phys_mid =
   1386 				    (uint32_t)(range_base >> 32);
   1387 				newregs[j].pci_phys_low =
   1388 				    (uint32_t)(range_base);
   1389 				newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
   1390 				newregs[j].pci_size_low = (uint32_t)dlen;
   1391 				j++;
   1392 			}
   1393 
   1394 			dlen = (range_base + range_len) - (base + len);
   1395 			if (dlen != 0) {
   1396 				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
   1397 				newregs[j].pci_phys_mid =
   1398 				    (uint32_t)((base + len)>> 32);
   1399 				newregs[j].pci_phys_low =
   1400 				    (uint32_t)(base + len);
   1401 				newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
   1402 				newregs[j].pci_size_low = (uint32_t)dlen;
   1403 				j++;
   1404 			}
   1405 
   1406 			/*
   1407 			 * We've allocated the resource from the matched
   1408 			 * entry, almost finished but still need to copy
   1409 			 * the rest entries from the original property
   1410 			 * array.
   1411 			 */
   1412 			for (k = i + 1; k < rcount; k++) {
   1413 				newregs[j] = regs[k];
   1414 				j++;
   1415 			}
   1416 
   1417 			goto done;
   1418 
   1419 		} else {
   1420 copy_entry:
   1421 			newregs[j] = regs[i];
   1422 			j++;
   1423 		}
   1424 	}
   1425 
   1426 done:
   1427 	/*
   1428 	 * This should not fail so assert it. For non-debug kernel we don't
   1429 	 * want to panic thus only logging a warning message.
   1430 	 */
   1431 	ASSERT(found == B_TRUE);
   1432 	if (!found) {
   1433 		cmn_err(CE_WARN, "pci_get_available_prop: failed to remove "
   1434 		    "resource from dip %p : base 0x%" PRIx64 ", len 0x%" PRIX64
   1435 		    ", type 0x%x\n", (void *)dip, base, len, type);
   1436 		kmem_free(newregs, rlen + sizeof (pci_regspec_t));
   1437 		kmem_free(regs, rlen);
   1438 
   1439 		return (DDI_FAILURE);
   1440 	}
   1441 
   1442 	/*
   1443 	 * Found the resources from parent, update the "available"
   1444 	 * property.
   1445 	 */
   1446 	if (j == 0) {
   1447 		/* all the resources are consumed, remove the property */
   1448 		(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
   1449 	} else {
   1450 		/*
   1451 		 * There are still resource available in the parent dip,
   1452 		 * update with the remaining resources.
   1453 		 */
   1454 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
   1455 		    "available", (int *)newregs,
   1456 		    (j * sizeof (pci_regspec_t)) / sizeof (int));
   1457 	}
   1458 
   1459 	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
   1460 	kmem_free(regs, rlen);
   1461 
   1462 	return (DDI_SUCCESS);
   1463 }
   1464 
   1465 /*
   1466  * Add a piece of IO/MEM resource to "available" property of 'dip'.
   1467  */
   1468 static int
   1469 pci_put_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
   1470     char *busra_type)
   1471 {
   1472 	pci_regspec_t	*regs, *newregs;
   1473 	uint_t		status;
   1474 	int		rlen, rcount;
   1475 	int		i, j, k;
   1476 	int		matched = 0;
   1477 	uint64_t	orig_base = base;
   1478 	uint64_t	orig_len = len;
   1479 	uint32_t	type;
   1480 
   1481 	/* check if we're manipulating MEM/IO resource */
   1482 	if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
   1483 		return (DDI_SUCCESS);
   1484 
   1485 	/* check if dip is a pci/pcie device resides in a pcie fabric */
   1486 	if (!is_pcie_fabric(dip))
   1487 		return (DDI_SUCCESS);
   1488 
   1489 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
   1490 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
   1491 	    "available", (caddr_t)&regs, &rlen);
   1492 
   1493 	switch (status) {
   1494 		case DDI_PROP_NOT_FOUND:
   1495 			goto not_found;
   1496 
   1497 		case DDI_PROP_SUCCESS:
   1498 			break;
   1499 
   1500 		default:
   1501 			return (status);
   1502 	}
   1503 
   1504 	/*
   1505 	 * The "available" property exist on the node, try to put this
   1506 	 * resource back, merge if there are adjacent resources.
   1507 	 *
   1508 	 * The updated "available" property will at most have one more entry
   1509 	 * than existing one (when there is no adjacent entries thus the new
   1510 	 * resource is appended at the end)
   1511 	 */
   1512 	newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
   1513 
   1514 	rcount = rlen / sizeof (pci_regspec_t);
   1515 	for (i = 0, j = 0; i < rcount; i++) {
   1516 		if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
   1517 			uint64_t range_base, range_len;
   1518 
   1519 			range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
   1520 			    ((uint64_t)(regs[i].pci_phys_low));
   1521 			range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
   1522 			    ((uint64_t)(regs[i].pci_size_low));
   1523 
   1524 			if ((base + len < range_base) ||
   1525 			    (base > range_base + range_len)) {
   1526 				/*
   1527 				 * Not adjacent, copy the entry and contiue
   1528 				 */
   1529 				goto copy_entry;
   1530 			}
   1531 
   1532 			/*
   1533 			 * Adjacent or overlap?
   1534 			 *
   1535 			 * Should not have overlapping resources so assert it.
   1536 			 * For non-debug kernel we don't want to panic thus
   1537 			 * only logging a warning message.
   1538 			 */
   1539 #if 0
   1540 			ASSERT((base + len == range_base) ||
   1541 			    (base == range_base + range_len));
   1542 #endif
   1543 			if ((base + len != range_base) &&
   1544 			    (base != range_base + range_len)) {
   1545 				cmn_err(CE_WARN, "pci_put_available_prop: "
   1546 				    "failed to add resource to dip %p : "
   1547 				    "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
   1548 				    "overlaps with existing resource "
   1549 				    "base 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
   1550 				    (void *)dip, orig_base, orig_len,
   1551 				    range_base, range_len);
   1552 
   1553 				goto failure;
   1554 			}
   1555 
   1556 			/*
   1557 			 * On the left:
   1558 			 *
   1559 			 * base		range_base
   1560 			 *   +-------------+-------------+
   1561 			 *   |/////////////|		 |
   1562 			 *   +-------------+-------------+
   1563 			 *	len		range_len
   1564 			 *
   1565 			 * On the right:
   1566 			 *
   1567 			 * range_base	 base
   1568 			 *   +-------------+-------------+
   1569 			 *   |		   |/////////////|
   1570 			 *   +-------------+-------------+
   1571 			 *	range_len	len
   1572 			 */
   1573 			/*
   1574 			 * There are at most two piece of resources adjacent
   1575 			 * with this resource, assert it.
   1576 			 */
   1577 			ASSERT(matched < 2);
   1578 
   1579 			if (!(matched < 2)) {
   1580 				cmn_err(CE_WARN, "pci_put_available_prop: "
   1581 				    "failed to add resource to dip %p : "
   1582 				    "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
   1583 				    "found overlaps in existing resources\n",
   1584 				    (void *)dip, orig_base, orig_len);
   1585 
   1586 				goto failure;
   1587 			}
   1588 
   1589 			/* setup base & len to refer to the merged range */
   1590 			len += range_len;
   1591 			if (base == range_base + range_len)
   1592 				base = range_base;
   1593 
   1594 			if (matched == 0) {
   1595 				/*
   1596 				 * One adjacent entry, add this resource in
   1597 				 */
   1598 				newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
   1599 				newregs[j].pci_phys_mid =
   1600 				    (uint32_t)(base >> 32);
   1601 				newregs[j].pci_phys_low = (uint32_t)(base);
   1602 				newregs[j].pci_size_hi = (uint32_t)(len >> 32);
   1603 				newregs[j].pci_size_low = (uint32_t)len;
   1604 
   1605 				matched = 1;
   1606 				k = j;
   1607 				j++;
   1608 			} else { /* matched == 1 */
   1609 				/*
   1610 				 * Two adjacent entries, merge them together
   1611 				 */
   1612 				newregs[k].pci_phys_hi = regs[i].pci_phys_hi;
   1613 				newregs[k].pci_phys_mid =
   1614 				    (uint32_t)(base >> 32);
   1615 				newregs[k].pci_phys_low = (uint32_t)(base);
   1616 				newregs[k].pci_size_hi = (uint32_t)(len >> 32);
   1617 				newregs[k].pci_size_low = (uint32_t)len;
   1618 
   1619 				matched = 2;
   1620 			}
   1621 		} else {
   1622 copy_entry:
   1623 			newregs[j] = regs[i];
   1624 			j++;
   1625 		}
   1626 	}
   1627 
   1628 	if (matched == 0) {
   1629 		/* No adjacent entries, append at end */
   1630 		ASSERT(j == rcount);
   1631 
   1632 		/*
   1633 		 * According to page 15 of 1275 spec, bit "n" of "available"
   1634 		 * should be set to 1.
   1635 		 */
   1636 		newregs[j].pci_phys_hi = type;
   1637 		newregs[j].pci_phys_hi |= PCI_REG_REL_M;
   1638 
   1639 		newregs[j].pci_phys_mid = (uint32_t)(base >> 32);
   1640 		newregs[j].pci_phys_low = (uint32_t)base;
   1641 		newregs[j].pci_size_hi = (uint32_t)(len >> 32);
   1642 		newregs[j].pci_size_low = (uint32_t)len;
   1643 
   1644 		j++;
   1645 	}
   1646 
   1647 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
   1648 	    "available", (int *)newregs,
   1649 	    (j * sizeof (pci_regspec_t)) / sizeof (int));
   1650 
   1651 	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
   1652 	kmem_free(regs, rlen);
   1653 	return (DDI_SUCCESS);
   1654 
   1655 not_found:
   1656 	/*
   1657 	 * There is no "available" property on the parent node, create it.
   1658 	 */
   1659 	newregs = kmem_alloc(sizeof (pci_regspec_t), KM_SLEEP);
   1660 
   1661 	/*
   1662 	 * According to page 15 of 1275 spec, bit "n" of "available" should
   1663 	 * be set to 1.
   1664 	 */
   1665 	newregs[0].pci_phys_hi = type;
   1666 	newregs[0].pci_phys_hi |= PCI_REG_REL_M;
   1667 
   1668 	newregs[0].pci_phys_mid = (uint32_t)(base >> 32);
   1669 	newregs[0].pci_phys_low = (uint32_t)base;
   1670 	newregs[0].pci_size_hi = (uint32_t)(len >> 32);
   1671 	newregs[0].pci_size_low = (uint32_t)len;
   1672 
   1673 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
   1674 	    "available", (int *)newregs,
   1675 	    sizeof (pci_regspec_t) / sizeof (int));
   1676 	kmem_free(newregs, sizeof (pci_regspec_t));
   1677 	return (DDI_SUCCESS);
   1678 
   1679 failure:
   1680 	kmem_free(newregs, rlen + sizeof (pci_regspec_t));
   1681 	kmem_free(regs, rlen);
   1682 	return (DDI_FAILURE);
   1683 }
   1684 
   1685 static uint32_t
   1686 pci_type_ra2pci(char *type)
   1687 {
   1688 	uint32_t	pci_type = PCI_ADDR_TYPE_INVAL;
   1689 
   1690 	/*
   1691 	 * No 64 bit mem support for now
   1692 	 */
   1693 	if (strcmp(type, NDI_RA_TYPE_IO) == 0) {
   1694 		pci_type = PCI_ADDR_IO;
   1695 
   1696 	} else if (strcmp(type, NDI_RA_TYPE_MEM) == 0) {
   1697 		pci_type = PCI_ADDR_MEM32;
   1698 
   1699 	} else if (strcmp(type, NDI_RA_TYPE_PCI_PREFETCH_MEM)  == 0) {
   1700 		pci_type = PCI_ADDR_MEM32;
   1701 		pci_type |= PCI_REG_PF_M;
   1702 	}
   1703 
   1704 	return (pci_type);
   1705 }
   1706