xref: /illumos-gate/usr/src/uts/common/io/busra.c (revision ba2be53024c0b999e74ba9adcd7d80fec5df8c57)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #if defined(DEBUG)
29 #define	BUSRA_DEBUG
30 #endif
31 
32 /*
33  * This module provides a set of resource management interfaces
34  * to manage bus resources globally in the system.
35  *
36  * The bus nexus drivers are typically responsible to setup resource
37  * maps for the bus resources available for a bus instance. However
38  * this module also provides resource setup functions for PCI bus
39  * (used by both SPARC and X86 platforms) and ISA bus instances (used
40  * only for X86 platforms).
41  */
42 
43 #include <sys/types.h>
44 #include <sys/systm.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sunndi.h>
48 #include <sys/ddi_impldefs.h>
49 #include <sys/ndi_impldefs.h>
50 #include <sys/kmem.h>
51 #include <sys/pctypes.h>
52 #include <sys/modctl.h>
53 #include <sys/debug.h>
54 #include <sys/spl.h>
55 #include <sys/pci.h>
56 #include <sys/autoconf.h>
57 
58 #if defined(BUSRA_DEBUG)
59 int busra_debug = 0;
60 #define	DEBUGPRT \
61 	if (busra_debug) cmn_err
62 
63 #else
64 #define	DEBUGPRT \
65 	if (0) cmn_err
66 #endif
67 
68 
69 /*
70  * global mutex that protects the global list of resource maps.
71  */
72 kmutex_t ra_lock;
73 
74 /*
75  * basic resource element
76  */
77 struct ra_resource {
78 	struct ra_resource *ra_next;
79 	uint64_t	ra_base;
80 	uint64_t 	ra_len;
81 };
82 
83 /*
84  * link list element for the list of dips (and their resource ranges)
85  * for a particular resource type.
86  * ra_rangeset points to the list of resources available
87  * for this type and this dip.
88  */
89 struct ra_dip_type  {
90 	struct ra_dip_type *ra_next;
91 	struct ra_resource  *ra_rangeset;
92 	dev_info_t *ra_dip;
93 };
94 
95 
96 /*
97  * link list element for list of types resources. Each element
98  * has all resources for a particular type.
99  */
100 struct ra_type_map {
101 	struct ra_type_map *ra_next;
102 	struct ra_dip_type *ra_dip_list;
103 	char *type;
104 };
105 
106 
107 /*
108  * place holder to keep the head of the whole global list.
109  * the address of the first typemap would be stored in it.
110  */
111 static struct ra_type_map	*ra_map_list_head = NULL;
112 
113 
114 /*
115  * This is the loadable module wrapper.
116  * It is essentially boilerplate so isn't documented
117  */
118 extern struct mod_ops mod_miscops;
119 
120 #ifdef BUSRA_DEBUG
121 void ra_dump_all();
122 #endif
123 
124 /* internal function prototypes */
125 static struct ra_dip_type *find_dip_map_resources(dev_info_t *dip, char *type,
126     struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
127     uint32_t flag);
128 static int isnot_pow2(uint64_t value);
129 static int claim_pci_busnum(dev_info_t *dip, void *arg);
130 static int ra_map_exist(dev_info_t *dip, char *type);
131 
132 
133 #define	RA_INSERT(prev, el) \
134 	el->ra_next = *prev; \
135 	*prev = el;
136 
137 #define	RA_REMOVE(prev, el) \
138 	*prev = el->ra_next;
139 
140 
141 static struct modlmisc modlmisc = {
142 	&mod_miscops,		/* Type of module. This one is a module */
143 	"Bus Resource Allocator (BUSRA) %I%",	/* Name of the module. */
144 };
145 
146 static struct modlinkage modlinkage = {
147 	MODREV_1, (void *)&modlmisc, NULL
148 };
149 
150 int
151 _init()
152 {
153 	int	ret;
154 
155 	mutex_init(&ra_lock, NULL, MUTEX_DRIVER,
156 		(void *)(intptr_t)__ipltospl(SPL7 - 1));
157 	if ((ret = mod_install(&modlinkage)) != 0) {
158 		mutex_destroy(&ra_lock);
159 	}
160 	return (ret);
161 }
162 
163 int
164 _fini()
165 {
166 	int	ret;
167 
168 	mutex_enter(&ra_lock);
169 
170 	if (ra_map_list_head != NULL) {
171 		mutex_exit(&ra_lock);
172 		return (EBUSY);
173 	}
174 
175 	ret = mod_remove(&modlinkage);
176 
177 	mutex_exit(&ra_lock);
178 
179 	if (ret == 0)
180 		mutex_destroy(&ra_lock);
181 
182 	return (ret);
183 }
184 
185 int
186 _info(struct modinfo *modinfop)
187 
188 {
189 	return (mod_info(&modlinkage, modinfop));
190 }
191 
192 /*
193  * set up an empty resource map for a given type and dip
194  */
195 int
196 ndi_ra_map_setup(dev_info_t *dip, char *type)
197 {
198 	struct ra_type_map  *typemapp;
199 	struct ra_dip_type  *dipmap;
200 	struct ra_dip_type  **backdip;
201 	struct ra_type_map  **backtype;
202 
203 
204 	mutex_enter(&ra_lock);
205 
206 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
207 
208 	if (dipmap == NULL) {
209 		if (backtype == NULL) {
210 			typemapp = (struct ra_type_map *)
211 			kmem_zalloc(sizeof (*typemapp), KM_SLEEP);
212 			typemapp->type = (char *)kmem_zalloc(strlen(type) + 1,
213 				KM_SLEEP);
214 			(void) strcpy(typemapp->type, type);
215 			RA_INSERT(&ra_map_list_head, typemapp);
216 		} else {
217 			typemapp = *backtype;
218 		}
219 		if (backdip == NULL) {
220 			/* allocate and insert in list of dips for this type */
221 			dipmap = (struct ra_dip_type *)
222 			kmem_zalloc(sizeof (*dipmap), KM_SLEEP);
223 			dipmap->ra_dip = dip;
224 			RA_INSERT(&typemapp->ra_dip_list, dipmap);
225 		}
226 	}
227 
228 	mutex_exit(&ra_lock);
229 	return (NDI_SUCCESS);
230 }
231 
232 /*
233  * destroys a resource map for a given dip and type
234  */
235 int
236 ndi_ra_map_destroy(dev_info_t *dip, char *type)
237 {
238 	struct ra_dip_type	*dipmap;
239 	struct ra_dip_type	**backdip;
240 	struct ra_type_map  	**backtype, *typemap;
241 	struct ra_resource	*range;
242 
243 	mutex_enter(&ra_lock);
244 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
245 
246 	if (dipmap == NULL) {
247 		mutex_exit(&ra_lock);
248 		return (NDI_FAILURE);
249 	}
250 
251 	/*
252 	 * destroy all resources for this dip
253 	 * remove dip from type list
254 	 */
255 	ASSERT((backdip != NULL) && (backtype != NULL));
256 	while (dipmap->ra_rangeset != NULL) {
257 		range = dipmap->ra_rangeset;
258 		RA_REMOVE(&dipmap->ra_rangeset, range);
259 		kmem_free((caddr_t)range, sizeof (*range));
260 	}
261 	/* remove from dip list */
262 	RA_REMOVE(backdip, dipmap);
263 	kmem_free((caddr_t)dipmap, sizeof (*dipmap));
264 	if ((*backtype)->ra_dip_list == NULL) {
265 		/*
266 		 * This was the last dip with this resource type.
267 		 * Remove the type from the global list.
268 		 */
269 		typemap = *backtype;
270 		RA_REMOVE(backtype, (*backtype));
271 		kmem_free((caddr_t)typemap->type, strlen(typemap->type) + 1);
272 		kmem_free((caddr_t)typemap, sizeof (*typemap));
273 	}
274 
275 	mutex_exit(&ra_lock);
276 	return (NDI_SUCCESS);
277 }
278 
279 static int
280 ra_map_exist(dev_info_t *dip, char *type)
281 {
282 	struct ra_dip_type  **backdip;
283 	struct ra_type_map  **backtype;
284 
285 	mutex_enter(&ra_lock);
286 	if (find_dip_map_resources(dip, type, &backdip, &backtype, 0) == NULL) {
287 		mutex_exit(&ra_lock);
288 		return (NDI_FAILURE);
289 	}
290 
291 	mutex_exit(&ra_lock);
292 	return (NDI_SUCCESS);
293 }
294 /*
295  * Find a dip map for the specified type, if NDI_RA_PASS will go up on dev tree
296  * if found, backdip and backtype will be updated to point to the previous
297  * dip in the list and previous type for this dip in the list.
298  * If no such type at all in the resource list both backdip and backtype
299  * will be null. If the type found but no dip, back dip will be null.
300  */
301 
302 static struct ra_dip_type *
303 find_dip_map_resources(dev_info_t *dip, char *type,
304     struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
305     uint32_t flag)
306 {
307 	struct ra_type_map **prevmap;
308 	struct ra_dip_type *dipmap, **prevdip;
309 
310 	ASSERT(mutex_owned(&ra_lock));
311 	prevdip = NULL;
312 	dipmap = NULL;
313 	prevmap = &ra_map_list_head;
314 
315 	while (*prevmap) {
316 		if (strcmp((*prevmap)->type, type) == 0)
317 			break;
318 		prevmap = &(*prevmap)->ra_next;
319 	}
320 
321 	if (*prevmap) {
322 		for (; dip != NULL; dip = ddi_get_parent(dip)) {
323 			prevdip = &(*prevmap)->ra_dip_list;
324 			dipmap = *prevdip;
325 
326 			while (dipmap) {
327 				if (dipmap->ra_dip == dip)
328 					break;
329 				prevdip =  &dipmap->ra_next;
330 				dipmap = dipmap->ra_next;
331 			}
332 
333 			if (dipmap != NULL) {
334 				/* found it */
335 				break;
336 			}
337 
338 			if (!(flag & NDI_RA_PASS)) {
339 				break;
340 			}
341 		}
342 	}
343 
344 	*backtype = (*prevmap == NULL) ?  NULL: prevmap;
345 	*backdip = (dipmap == NULL) ?  NULL: prevdip;
346 
347 	return (dipmap);
348 }
349 
350 int
351 ndi_ra_free(dev_info_t *dip, uint64_t base, uint64_t len, char *type,
352     uint32_t flag)
353 {
354 	struct ra_dip_type *dipmap;
355 	struct ra_resource *newmap, *overlapmap, *oldmap = NULL;
356 	struct ra_resource  *mapp, **backp;
357 	uint64_t newend, mapend;
358 	struct ra_dip_type **backdip;
359 	struct ra_type_map **backtype;
360 
361 	if (len == 0) {
362 		return (NDI_SUCCESS);
363 	}
364 
365 	mutex_enter(&ra_lock);
366 
367 	if ((dipmap = find_dip_map_resources(dip, type, &backdip, &backtype,
368 	    flag)) == NULL) {
369 		mutex_exit(&ra_lock);
370 		return (NDI_FAILURE);
371 	}
372 
373 	mapp = dipmap->ra_rangeset;
374 	backp = &dipmap->ra_rangeset;
375 
376 	/* now find where range lies and fix things up */
377 	newend = base + len;
378 	for (; mapp != NULL; backp = &(mapp->ra_next), mapp = mapp->ra_next) {
379 		mapend = mapp->ra_base + mapp->ra_len;
380 
381 		/* check for overlap first */
382 		if ((base <= mapp->ra_base && newend > mapp->ra_base) ||
383 		    (base > mapp->ra_base && base < mapend)) {
384 			/* overlap with mapp */
385 			overlapmap = mapp;
386 			goto overlap;
387 		} else if ((base == mapend && mapp->ra_next) &&
388 		    (newend > mapp->ra_next->ra_base)) {
389 			/* overlap with mapp->ra_next */
390 			overlapmap = mapp->ra_next;
391 			goto overlap;
392 		}
393 
394 		if (newend == mapp->ra_base) {
395 			/* simple - on front */
396 			mapp->ra_base = base;
397 			mapp->ra_len += len;
398 			/*
399 			 * don't need to check if it merges with
400 			 * previous since that would match on on end
401 			 */
402 			break;
403 		} else if (base == mapend) {
404 			/* simple - on end */
405 			mapp->ra_len += len;
406 			if (mapp->ra_next &&
407 			    (newend == mapp->ra_next->ra_base)) {
408 				/* merge with next node */
409 				oldmap = mapp->ra_next;
410 				mapp->ra_len += oldmap->ra_len;
411 				RA_REMOVE(&mapp->ra_next, oldmap);
412 				kmem_free((caddr_t)oldmap, sizeof (*oldmap));
413 			}
414 			break;
415 		} else if (base < mapp->ra_base) {
416 			/* somewhere in between so just an insert */
417 			newmap = (struct ra_resource *)
418 				kmem_zalloc(sizeof (*newmap), KM_SLEEP);
419 			newmap->ra_base = base;
420 			newmap->ra_len = len;
421 			RA_INSERT(backp, newmap);
422 			break;
423 		}
424 	}
425 	if (mapp == NULL) {
426 		/* stick on end */
427 		newmap = (struct ra_resource *)
428 				kmem_zalloc(sizeof (*newmap), KM_SLEEP);
429 		newmap->ra_base = base;
430 		newmap->ra_len = len;
431 		RA_INSERT(backp, newmap);
432 	}
433 
434 	mutex_exit(&ra_lock);
435 	return (NDI_SUCCESS);
436 
437 overlap:
438 	/*
439 	 * Bad free may happen on some x86 platforms with BIOS exporting
440 	 * incorrect resource maps. The system is otherwise functioning
441 	 * normally. We send such messages to syslog only.
442 	 */
443 	cmn_err(CE_NOTE, "!ndi_ra_free: bad free, dip %p, resource type %s \n",
444 	    (void *)dip, type);
445 	cmn_err(CE_NOTE, "!ndi_ra_free: freeing base 0x%" PRIx64 ", len 0x%"
446 	    PRIX64 " overlaps with existing resource base 0x%" PRIx64
447 	    ", len 0x%" PRIx64 "\n", base, len, overlapmap->ra_base,
448 	    overlapmap->ra_len);
449 
450 	mutex_exit(&ra_lock);
451 	return (NDI_FAILURE);
452 }
453 
454 /* check to see if value is power of 2 or not. */
455 static int
456 isnot_pow2(uint64_t value)
457 {
458 	uint32_t low;
459 	uint32_t hi;
460 
461 	low = value & 0xffffffff;
462 	hi = value >> 32;
463 
464 	/*
465 	 * ddi_ffs and ddi_fls gets long values, so in 32bit environment
466 	 * won't work correctly for 64bit values
467 	 */
468 	if ((ddi_ffs(low) == ddi_fls(low)) &&
469 	    (ddi_ffs(hi) == ddi_fls(hi)))
470 		return (0);
471 	return (1);
472 }
473 
474 static  void
475 adjust_link(struct ra_resource **backp, struct ra_resource *mapp,
476 	    uint64_t base, uint64_t len)
477 {
478 	struct ra_resource *newmap;
479 	uint64_t newlen;
480 
481 	if (base != mapp->ra_base) {
482 		/* in the middle or end */
483 		newlen = base - mapp->ra_base;
484 		if ((mapp->ra_len - newlen) == len) {
485 			/* on the end */
486 			mapp->ra_len = newlen;
487 		} else {
488 			/* in the middle */
489 			newmap = (struct ra_resource *)
490 					kmem_zalloc(sizeof (*newmap), KM_SLEEP);
491 			newmap->ra_base = base + len;
492 			newmap->ra_len = mapp->ra_len -
493 				(len + newlen);
494 			mapp->ra_len = newlen;
495 			RA_INSERT(&(mapp->ra_next), newmap);
496 		}
497 	} else {
498 		/* at the beginning */
499 		mapp->ra_base += len;
500 		mapp->ra_len -= len;
501 		if (mapp->ra_len == 0) {
502 			/* remove the whole node */
503 			RA_REMOVE(backp, mapp);
504 			kmem_free((caddr_t)mapp, sizeof (*mapp));
505 		}
506 	}
507 }
508 
509 int
510 ndi_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, uint64_t *retbasep,
511     uint64_t *retlenp, char *type, uint32_t flag)
512 {
513 	struct ra_dip_type *dipmap;
514 	struct ra_resource *mapp, **backp, **backlargestp;
515 	uint64_t mask = 0;
516 	uint64_t len, remlen, largestbase, largestlen;
517 	uint64_t base, oldbase, lower, upper;
518 	struct ra_dip_type  **backdip;
519 	struct ra_type_map  **backtype;
520 	int  rval = NDI_FAILURE;
521 
522 
523 	len = req->ra_len;
524 
525 	if (req->ra_flags & NDI_RA_ALIGN_SIZE) {
526 		if (isnot_pow2(req->ra_len)) {
527 			DEBUGPRT(CE_WARN, "ndi_ra_alloc: bad length(pow2) 0x%"
528 				PRIx64, req->ra_len);
529 			*retbasep = 0;
530 			*retlenp = 0;
531 			return (NDI_FAILURE);
532 		}
533 	}
534 
535 	mask = (req->ra_flags & NDI_RA_ALIGN_SIZE) ? (len - 1) :
536 	    req->ra_align_mask;
537 
538 
539 	mutex_enter(&ra_lock);
540 	dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, flag);
541 	if ((dipmap == NULL) || ((mapp = dipmap->ra_rangeset) == NULL)) {
542 		mutex_exit(&ra_lock);
543 		DEBUGPRT(CE_CONT, "ndi_ra_alloc no map found for this type\n");
544 		return (NDI_FAILURE);
545 	}
546 
547 	DEBUGPRT(CE_CONT, "ndi_ra_alloc: mapp = %p len=%" PRIx64 ", mask=%"
548 			PRIx64 "\n", (void *)mapp, len, mask);
549 
550 	backp = &(dipmap->ra_rangeset);
551 	backlargestp = NULL;
552 	largestbase = 0;
553 	largestlen = 0;
554 
555 	lower = 0;
556 	upper = ~(uint64_t)0;
557 
558 	if (req->ra_flags & NDI_RA_ALLOC_BOUNDED) {
559 		/* bounded so skip to first possible */
560 		lower = req->ra_boundbase;
561 		upper = req->ra_boundlen + lower;
562 		if ((upper == 0) || (upper < req->ra_boundlen))
563 			upper = ~(uint64_t)0;
564 		DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 ", len = %"
565 				PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64
566 				"\n", mapp->ra_len, len, mapp->ra_base, mask);
567 		for (; mapp != NULL &&
568 			(mapp->ra_base + mapp->ra_len) < lower;
569 			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
570 			if (((mapp->ra_len + mapp->ra_base) == 0) ||
571 			    ((mapp->ra_len + mapp->ra_base) < mapp->ra_len))
572 				/*
573 				 * This elements end goes beyond max uint64_t.
574 				 * potential candidate, check end against lower
575 				 * would not be precise.
576 				 */
577 				break;
578 
579 			DEBUGPRT(CE_CONT, " ra_len = %" PRIx64 ", ra_base=%"
580 			    PRIx64 "\n", mapp->ra_len, mapp->ra_base);
581 			}
582 
583 	}
584 
585 	if (!(req->ra_flags & NDI_RA_ALLOC_SPECIFIED)) {
586 		/* first fit - not user specified */
587 		DEBUGPRT(CE_CONT, "ndi_ra_alloc(unspecified request)"
588 			"lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper);
589 		for (; mapp != NULL && mapp->ra_base <= upper;
590 			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
591 
592 			DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64
593 			    ", len = %" PRIx64 "", mapp->ra_len, len);
594 			base = mapp->ra_base;
595 			if (base < lower) {
596 				base = lower;
597 				DEBUGPRT(CE_CONT, "\tbase=%" PRIx64
598 				    ", ra_base=%" PRIx64 ", mask=%" PRIx64,
599 				    base, mapp->ra_base, mask);
600 			}
601 
602 			if ((base & mask) != 0) {
603 				oldbase = base;
604 				/*
605 				 * failed a critical constraint
606 				 * adjust and see if it still fits
607 				 */
608 				base = base & ~mask;
609 				base += (mask + 1);
610 				DEBUGPRT(CE_CONT, "\tnew base=%" PRIx64 "\n",
611 					base);
612 
613 				/*
614 				 * Check to see if the new base is past
615 				 * the end of the resource.
616 				 */
617 				if (base >= (oldbase + mapp->ra_len + 1)) {
618 					continue;
619 				}
620 			}
621 
622 			if (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) {
623 				if ((upper - mapp->ra_base)  <  mapp->ra_len)
624 					remlen = upper - base;
625 				else
626 					remlen = mapp->ra_len -
627 						(base - mapp->ra_base);
628 
629 				if ((backlargestp == NULL) ||
630 				    (largestlen < remlen)) {
631 
632 					backlargestp = backp;
633 					largestbase = base;
634 					largestlen = remlen;
635 				}
636 			}
637 
638 			if (mapp->ra_len >= len) {
639 				/* a candidate -- apply constraints */
640 				if ((len > (mapp->ra_len -
641 				    (base - mapp->ra_base))) ||
642 				    ((len - 1 + base) > upper)) {
643 					continue;
644 				}
645 
646 				/* we have a fit */
647 
648 				DEBUGPRT(CE_CONT, "\thave a fit\n");
649 
650 				adjust_link(backp, mapp, base, len);
651 				rval = NDI_SUCCESS;
652 				break;
653 
654 			}
655 		}
656 	} else {
657 		/* want an exact value/fit */
658 		base = req->ra_addr;
659 		len = req->ra_len;
660 		for (; mapp != NULL && mapp->ra_base <= upper;
661 			backp = &(mapp->ra_next), mapp = mapp->ra_next) {
662 			if (base >= mapp->ra_base &&
663 			    ((base - mapp->ra_base) < mapp->ra_len)) {
664 				/*
665 				 * This is the node with he requested base in
666 				 * its range
667 				 */
668 				if ((len > mapp->ra_len) ||
669 				    (base - mapp->ra_base >
670 				    mapp->ra_len - len)) {
671 					/* length requirement not satisfied */
672 					if (req->ra_flags &
673 					    NDI_RA_ALLOC_PARTIAL_OK) {
674 						if ((upper - mapp->ra_base)
675 						    < mapp->ra_len)
676 							remlen = upper - base;
677 						else
678 							remlen =
679 							    mapp->ra_len -
680 							    (base -
681 							    mapp->ra_base);
682 					}
683 					backlargestp = backp;
684 					largestbase = base;
685 					largestlen = remlen;
686 					base = 0;
687 				} else {
688 					/* We have a match */
689 					adjust_link(backp, mapp, base, len);
690 					rval = NDI_SUCCESS;
691 				}
692 				break;
693 			}
694 		}
695 	}
696 
697 	if ((rval != NDI_SUCCESS) &&
698 	    (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) &&
699 	    (backlargestp != NULL)) {
700 		adjust_link(backlargestp, *backlargestp, largestbase,
701 			largestlen);
702 
703 		base = largestbase;
704 		len = largestlen;
705 		rval = NDI_RA_PARTIAL_REQ;
706 	}
707 
708 	mutex_exit(&ra_lock);
709 
710 	if (rval == NDI_FAILURE) {
711 		*retbasep = 0;
712 		*retlenp = 0;
713 	} else {
714 		*retbasep = base;
715 		*retlenp = len;
716 	}
717 	return (rval);
718 }
719 
720 /*
721  * isa_resource_setup
722  *	check for /used-resources and initialize
723  *	based on info there.  If no /used-resources,
724  *	fail.
725  */
726 int
727 isa_resource_setup()
728 {
729 	dev_info_t *used, *usedpdip;
730 	/*
731 	 * note that at this time bootconf creates 32 bit properties for
732 	 * io-space and device-memory
733 	 */
734 	struct iorange {
735 		uint32_t	base;
736 		uint32_t	len;
737 	} *iorange;
738 	struct memrange {
739 		uint32_t	base;
740 		uint32_t	len;
741 	} *memrange;
742 	uint32_t *irq;
743 	int proplen;
744 	int i, len;
745 	int maxrange;
746 	ndi_ra_request_t req;
747 	uint64_t retbase;
748 	uint64_t retlen;
749 
750 	used = ddi_find_devinfo("used-resources", -1, 0);
751 	if (used == NULL) {
752 		DEBUGPRT(CE_CONT,
753 			"isa_resource_setup: used-resources not found");
754 		return (NDI_FAILURE);
755 	}
756 
757 	/*
758 	 * initialize to all resources being present
759 	 * and then remove the ones in use.
760 	 */
761 
762 	usedpdip = ddi_root_node();
763 
764 	DEBUGPRT(CE_CONT, "isa_resource_setup: used = %p usedpdip = %p\n",
765 	    (void *)used, (void *)usedpdip);
766 
767 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
768 		return (NDI_FAILURE);
769 	}
770 
771 	/* initialize io space, highest end base is 0xffff */
772 	/* note that length is highest addr + 1 since starts from 0 */
773 
774 	(void) ndi_ra_free(usedpdip, 0, 0xffff + 1,  NDI_RA_TYPE_IO, 0);
775 
776 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
777 	    "io-space", (caddr_t)&iorange, &proplen) == DDI_SUCCESS) {
778 		maxrange = proplen / sizeof (struct iorange);
779 		/* remove the "used" I/O resources */
780 		for (i = 0; i < maxrange; i++) {
781 			bzero((caddr_t)&req, sizeof (req));
782 			req.ra_addr =  (uint64_t)iorange[i].base;
783 			req.ra_len = (uint64_t)iorange[i].len;
784 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
785 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
786 			    NDI_RA_TYPE_IO, 0);
787 		}
788 
789 		kmem_free((caddr_t)iorange, proplen);
790 	}
791 
792 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
793 		return (NDI_FAILURE);
794 	}
795 	/* initialize memory space where highest end base is 0xffffffff */
796 	/* note that length is highest addr + 1 since starts from 0 */
797 	(void) ndi_ra_free(usedpdip, 0, ((uint64_t)((uint32_t)~0)) + 1,
798 	    NDI_RA_TYPE_MEM, 0);
799 
800 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
801 	    "device-memory", (caddr_t)&memrange, &proplen) == DDI_SUCCESS) {
802 		maxrange = proplen / sizeof (struct memrange);
803 		/* remove the "used" memory resources */
804 		for (i = 0; i < maxrange; i++) {
805 			bzero((caddr_t)&req, sizeof (req));
806 			req.ra_addr = (uint64_t)memrange[i].base;
807 			req.ra_len = (uint64_t)memrange[i].len;
808 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
809 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
810 			    NDI_RA_TYPE_MEM, 0);
811 		}
812 
813 		kmem_free((caddr_t)memrange, proplen);
814 	}
815 
816 	if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_INTR) == NDI_FAILURE) {
817 		return (NDI_FAILURE);
818 	}
819 
820 	/* initialize the interrupt space */
821 	(void) ndi_ra_free(usedpdip, 0, 16, NDI_RA_TYPE_INTR, 0);
822 
823 #if defined(__i386) || defined(__amd64)
824 	bzero(&req, sizeof (req));
825 	req.ra_addr = 2;	/* 2 == 9 so never allow */
826 	req.ra_len = 1;
827 	req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
828 	(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
829 	    NDI_RA_TYPE_INTR, 0);
830 #endif
831 
832 	if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
833 	    "interrupts", (caddr_t)&irq, &proplen) == DDI_SUCCESS) {
834 		/* Initialize available interrupts by negating the used */
835 		len = (proplen / sizeof (uint32_t));
836 		for (i = 0; i < len; i++) {
837 			bzero((caddr_t)&req, sizeof (req));
838 			req.ra_addr = (uint64_t)irq[i];
839 			req.ra_len = 1;
840 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
841 			(void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
842 			    NDI_RA_TYPE_INTR, 0);
843 		}
844 		kmem_free((caddr_t)irq, proplen);
845 	}
846 
847 #ifdef BUSRA_DEBUG
848 	if (busra_debug) {
849 		(void) ra_dump_all(NULL, usedpdip);
850 	}
851 #endif
852 	return (NDI_SUCCESS);
853 
854 }
855 
856 #ifdef BUSRA_DEBUG
857 void
858 ra_dump_all(char *type, dev_info_t *dip)
859 {
860 
861 	struct ra_type_map *typemap;
862 	struct ra_dip_type *dipmap;
863 	struct ra_resource *res;
864 
865 	typemap =  (struct ra_type_map *)ra_map_list_head;
866 
867 	for (; typemap != NULL; typemap = typemap->ra_next) {
868 		if (type != NULL) {
869 			if (strcmp(typemap->type, type) != 0)
870 				continue;
871 		}
872 		cmn_err(CE_CONT, "type is %s\n", typemap->type);
873 		for (dipmap = typemap->ra_dip_list; dipmap != NULL;
874 			dipmap = dipmap->ra_next) {
875 			if (dip != NULL) {
876 				if ((dipmap->ra_dip) != dip)
877 					continue;
878 			}
879 			cmn_err(CE_CONT, "  dip is %p\n",
880 			    (void *)dipmap->ra_dip);
881 			for (res = dipmap->ra_rangeset; res != NULL;
882 				res = res->ra_next) {
883 				cmn_err(CE_CONT, "\t  range is %" PRIx64
884 				    " %" PRIx64 "\n", res->ra_base,
885 				    res->ra_len);
886 			}
887 			if (dip != NULL)
888 				break;
889 		}
890 		if (type != NULL)
891 			break;
892 	}
893 }
894 #endif
895 
896 struct bus_range {	/* 1275 "bus-range" property definition */
897 	uint32_t lo;
898 	uint32_t hi;
899 } pci_bus_range;
900 
901 struct busnum_ctrl {
902 	int	rv;
903 	dev_info_t *dip;
904 	struct	bus_range *range;
905 };
906 
907 
908 /*
909  * Setup resource map for the pci bus node based on the "available"
910  * property and "bus-range" property.
911  */
912 int
913 pci_resource_setup(dev_info_t *dip)
914 {
915 	pci_regspec_t *regs;
916 	int rlen, rcount, i;
917 	char bus_type[16] = "(unknown)";
918 	int len;
919 	struct busnum_ctrl ctrl;
920 	int circular_count;
921 	int rval = NDI_SUCCESS;
922 
923 	/*
924 	 * If this is a pci bus node then look for "available" property
925 	 * to find the available resources on this bus.
926 	 */
927 	len = sizeof (bus_type);
928 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
929 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
930 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
931 		return (NDI_FAILURE);
932 
933 	/* it is not a pci/pci-ex bus type */
934 	if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
935 		return (NDI_FAILURE);
936 
937 	/*
938 	 * The pci-hotplug project addresses adding the call
939 	 * to pci_resource_setup from pci nexus driver.
940 	 * However that project would initially be only for x86,
941 	 * so for sparc pcmcia-pci support we still need to call
942 	 * pci_resource_setup in pcic driver. Once all pci nexus drivers
943 	 * are updated to call pci_resource_setup this portion of the
944 	 * code would really become an assert to make sure this
945 	 * function is not called for the same dip twice.
946 	 */
947 	{
948 		if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) {
949 			return (NDI_FAILURE);
950 		}
951 	}
952 
953 
954 	/*
955 	 * Create empty resource maps first.
956 	 *
957 	 * NOTE: If all the allocated resources are already assigned to
958 	 * device(s) in the hot plug slot then "available" property may not
959 	 * be present. But, subsequent hot plug operation may unconfigure
960 	 * the device in the slot and try to free up it's resources. So,
961 	 * at the minimum we should create empty maps here.
962 	 */
963 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
964 		return (NDI_FAILURE);
965 	}
966 
967 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
968 		return (NDI_FAILURE);
969 	}
970 
971 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM) == NDI_FAILURE) {
972 		return (NDI_FAILURE);
973 	}
974 
975 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
976 	    NDI_FAILURE) {
977 		return (NDI_FAILURE);
978 	}
979 
980 	/* read the "available" property if it is available */
981 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
982 	    "available", (caddr_t)&regs, &rlen) == DDI_SUCCESS) {
983 		/*
984 		 * create the available resource list for both memory and
985 		 * io space
986 		 */
987 		rcount = rlen / sizeof (pci_regspec_t);
988 		for (i = 0; i < rcount; i++) {
989 		    switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) {
990 		    case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
991 			(void) ndi_ra_free(dip,
992 			    (uint64_t)regs[i].pci_phys_low,
993 			    (uint64_t)regs[i].pci_size_low,
994 			    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
995 			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
996 			    0);
997 			break;
998 		    case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
999 			(void) ndi_ra_free(dip,
1000 			    ((uint64_t)(regs[i].pci_phys_mid) << 32) |
1001 			    ((uint64_t)(regs[i].pci_phys_low)),
1002 			    ((uint64_t)(regs[i].pci_size_hi) << 32) |
1003 			    ((uint64_t)(regs[i].pci_size_low)),
1004 			    (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
1005 			    NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
1006 			    0);
1007 			break;
1008 		    case PCI_REG_ADDR_G(PCI_ADDR_IO):
1009 			(void) ndi_ra_free(dip,
1010 			    (uint64_t)regs[i].pci_phys_low,
1011 			    (uint64_t)regs[i].pci_size_low,
1012 			    NDI_RA_TYPE_IO,
1013 			    0);
1014 			break;
1015 		    case PCI_REG_ADDR_G(PCI_ADDR_CONFIG):
1016 			break;
1017 		    default:
1018 			cmn_err(CE_WARN,
1019 			    "pci_resource_setup: bad addr type: %x\n",
1020 			    PCI_REG_ADDR_G(regs[i].pci_phys_hi));
1021 			break;
1022 		    }
1023 		}
1024 		kmem_free(regs, rlen);
1025 	}
1026 
1027 	/*
1028 	 * update resource map for available bus numbers if the node
1029 	 * has available-bus-range or bus-range property.
1030 	 */
1031 	len = sizeof (struct bus_range);
1032 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1033 	    "available-bus-range", (caddr_t)&pci_bus_range, &len) ==
1034 	    DDI_SUCCESS) {
1035 		/*
1036 		 * Add bus numbers in the range to the free list.
1037 		 */
1038 		(void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo,
1039 		    (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo +
1040 		    1, NDI_RA_TYPE_PCI_BUSNUM, 0);
1041 	} else {
1042 		/*
1043 		 * We don't have an available-bus-range property. If, instead,
1044 		 * we have a bus-range property we add all the bus numbers
1045 		 * in that range to the free list but we must then scan
1046 		 * for pci-pci bridges on this bus to find out the if there
1047 		 * are any of those bus numbers already in use. If so, we can
1048 		 * reclaim them.
1049 		 */
1050 		len = sizeof (struct bus_range);
1051 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
1052 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range,
1053 		    &len) == DDI_SUCCESS) {
1054 			if (pci_bus_range.lo != pci_bus_range.hi) {
1055 				/*
1056 				 * Add bus numbers other than the secondary
1057 				 * bus number to the free list.
1058 				 */
1059 				(void) ndi_ra_free(dip,
1060 				    (uint64_t)pci_bus_range.lo + 1,
1061 				    (uint64_t)pci_bus_range.hi -
1062 				    (uint64_t)pci_bus_range.lo,
1063 				    NDI_RA_TYPE_PCI_BUSNUM, 0);
1064 
1065 				/* scan for pci-pci bridges */
1066 				ctrl.rv = DDI_SUCCESS;
1067 				ctrl.dip = dip;
1068 				ctrl.range = &pci_bus_range;
1069 				ndi_devi_enter(dip, &circular_count);
1070 				ddi_walk_devs(ddi_get_child(dip),
1071 				    claim_pci_busnum, (void *)&ctrl);
1072 				ndi_devi_exit(dip, circular_count);
1073 				if (ctrl.rv != DDI_SUCCESS) {
1074 					/* failed to create the map */
1075 					(void) ndi_ra_map_destroy(dip,
1076 					    NDI_RA_TYPE_PCI_BUSNUM);
1077 					rval = NDI_FAILURE;
1078 				}
1079 			}
1080 		}
1081 	}
1082 
1083 #ifdef BUSRA_DEBUG
1084 	if (busra_debug) {
1085 		(void) ra_dump_all(NULL, dip);
1086 	}
1087 #endif
1088 
1089 	return (rval);
1090 }
1091 
1092 /*
1093  * If the device is a PCI bus device (i.e bus-range property exists) then
1094  * claim the bus numbers used by the device from the specified bus
1095  * resource map.
1096  */
1097 static int
1098 claim_pci_busnum(dev_info_t *dip, void *arg)
1099 {
1100 	struct bus_range pci_bus_range;
1101 	struct busnum_ctrl *ctrl;
1102 	ndi_ra_request_t req;
1103 	char bus_type[16] = "(unknown)";
1104 	int len;
1105 	uint64_t base;
1106 	uint64_t retlen;
1107 
1108 	ctrl = (struct busnum_ctrl *)arg;
1109 
1110 	/* check if this is a PCI bus node */
1111 	len = sizeof (bus_type);
1112 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
1113 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
1114 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
1115 		return (DDI_WALK_PRUNECHILD);
1116 
1117 	/* it is not a pci/pci-ex bus type */
1118 	if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
1119 		return (DDI_WALK_PRUNECHILD);
1120 
1121 	/* look for the bus-range property */
1122 	len = sizeof (struct bus_range);
1123 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1124 	    "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
1125 		if ((pci_bus_range.lo >= ctrl->range->lo) &&
1126 		    (pci_bus_range.hi <= ctrl->range->hi)) {
1127 
1128 			/* claim the bus range from the bus resource map */
1129 			bzero((caddr_t)&req, sizeof (req));
1130 			req.ra_addr = (uint64_t)pci_bus_range.lo;
1131 			req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
1132 			req.ra_len = (uint64_t)pci_bus_range.hi -
1133 			    (uint64_t)pci_bus_range.lo + 1;
1134 			if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
1135 			    NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
1136 				return (DDI_WALK_PRUNECHILD);
1137 		}
1138 	}
1139 
1140 	/*
1141 	 * Error return.
1142 	 */
1143 	ctrl->rv = DDI_FAILURE;
1144 	return (DDI_WALK_TERMINATE);
1145 }
1146 
1147 void
1148 pci_resource_destroy(dev_info_t *dip)
1149 {
1150 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO);
1151 
1152 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM);
1153 
1154 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
1155 
1156 	(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM);
1157 }
1158 
1159 
1160 int
1161 pci_resource_setup_avail(dev_info_t *dip, pci_regspec_t *avail_p, int entries)
1162 {
1163 	int i;
1164 
1165 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE)
1166 		return (NDI_FAILURE);
1167 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE)
1168 		return (NDI_FAILURE);
1169 	if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == NDI_FAILURE)
1170 		return (NDI_FAILURE);
1171 
1172 	/* for each entry in the PCI "available" property */
1173 	for (i = 0; i < entries; i++, avail_p++) {
1174 		if (avail_p->pci_phys_hi == -1u)
1175 			goto err;
1176 
1177 		switch (PCI_REG_ADDR_G(avail_p->pci_phys_hi)) {
1178 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32): {
1179 			(void) ndi_ra_free(dip,
1180 				(uint64_t)avail_p->pci_phys_low,
1181 				(uint64_t)avail_p->pci_size_low,
1182 				(avail_p->pci_phys_hi &
1183 					PCI_REG_PF_M) ?
1184 					NDI_RA_TYPE_PCI_PREFETCH_MEM :
1185 					NDI_RA_TYPE_MEM,
1186 				0);
1187 			}
1188 			break;
1189 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
1190 			(void) ndi_ra_free(dip,
1191 				(uint64_t)avail_p->pci_phys_low,
1192 				(uint64_t)avail_p->pci_size_low,
1193 				NDI_RA_TYPE_IO,
1194 				0);
1195 			break;
1196 		default:
1197 			goto err;
1198 		}
1199 	}
1200 #ifdef BUSRA_DEBUG
1201 	if (busra_debug) {
1202 		(void) ra_dump_all(NULL, dip);
1203 	}
1204 #endif
1205 	return (NDI_SUCCESS);
1206 
1207 err:
1208 	cmn_err(CE_WARN, "pci_resource_setup_avail: bad entry[%d]=%x\n",
1209 		i, avail_p->pci_phys_hi);
1210 	return (NDI_FAILURE);
1211 }
1212