10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #if defined(DEBUG) 300Sstevel@tonic-gate #define BUSRA_DEBUG 310Sstevel@tonic-gate #endif 320Sstevel@tonic-gate 330Sstevel@tonic-gate /* 340Sstevel@tonic-gate * This module provides a set of resource management interfaces 350Sstevel@tonic-gate * to manage bus resources globally in the system. 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * The bus nexus drivers are typically responsible to setup resource 380Sstevel@tonic-gate * maps for the bus resources available for a bus instance. However 390Sstevel@tonic-gate * this module also provides resource setup functions for PCI bus 400Sstevel@tonic-gate * (used by both SPARC and X86 platforms) and ISA bus instances (used 410Sstevel@tonic-gate * only for X86 platforms). 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <sys/types.h> 450Sstevel@tonic-gate #include <sys/systm.h> 460Sstevel@tonic-gate #include <sys/ddi.h> 470Sstevel@tonic-gate #include <sys/sunddi.h> 480Sstevel@tonic-gate #include <sys/sunndi.h> 490Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 500Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 510Sstevel@tonic-gate #include <sys/kmem.h> 520Sstevel@tonic-gate #include <sys/pctypes.h> 530Sstevel@tonic-gate #include <sys/modctl.h> 540Sstevel@tonic-gate #include <sys/debug.h> 550Sstevel@tonic-gate #include <sys/spl.h> 560Sstevel@tonic-gate #include <sys/pci.h> 570Sstevel@tonic-gate #include <sys/autoconf.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #if defined(BUSRA_DEBUG) 600Sstevel@tonic-gate int busra_debug = 0; 610Sstevel@tonic-gate #define DEBUGPRT \ 620Sstevel@tonic-gate if (busra_debug) cmn_err 630Sstevel@tonic-gate 640Sstevel@tonic-gate #else 650Sstevel@tonic-gate #define DEBUGPRT \ 660Sstevel@tonic-gate if (0) cmn_err 670Sstevel@tonic-gate #endif 680Sstevel@tonic-gate 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * global mutex that protects the global list of resource maps. 720Sstevel@tonic-gate */ 730Sstevel@tonic-gate kmutex_t ra_lock; 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * basic resource element 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate struct ra_resource { 790Sstevel@tonic-gate struct ra_resource *ra_next; 800Sstevel@tonic-gate uint64_t ra_base; 810Sstevel@tonic-gate uint64_t ra_len; 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* 850Sstevel@tonic-gate * link list element for the list of dips (and their resource ranges) 860Sstevel@tonic-gate * for a particular resource type. 870Sstevel@tonic-gate * ra_rangeset points to the list of resources available 880Sstevel@tonic-gate * for this type and this dip. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate struct ra_dip_type { 910Sstevel@tonic-gate struct ra_dip_type *ra_next; 920Sstevel@tonic-gate struct ra_resource *ra_rangeset; 930Sstevel@tonic-gate dev_info_t *ra_dip; 940Sstevel@tonic-gate }; 950Sstevel@tonic-gate 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * link list element for list of types resources. Each element 990Sstevel@tonic-gate * has all resources for a particular type. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate struct ra_type_map { 1020Sstevel@tonic-gate struct ra_type_map *ra_next; 1030Sstevel@tonic-gate struct ra_dip_type *ra_dip_list; 1040Sstevel@tonic-gate char *type; 1050Sstevel@tonic-gate }; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* 1090Sstevel@tonic-gate * place holder to keep the head of the whole global list. 1100Sstevel@tonic-gate * the address of the first typemap would be stored in it. 1110Sstevel@tonic-gate */ 1120Sstevel@tonic-gate static struct ra_type_map *ra_map_list_head = NULL; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * This is the loadable module wrapper. 1170Sstevel@tonic-gate * It is essentially boilerplate so isn't documented 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate extern struct mod_ops mod_miscops; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate #ifdef BUSRA_DEBUG 1220Sstevel@tonic-gate void ra_dump_all(); 1230Sstevel@tonic-gate #endif 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* internal function prototypes */ 1260Sstevel@tonic-gate static struct ra_dip_type *find_dip_map_resources(dev_info_t *dip, char *type, 1270Sstevel@tonic-gate struct ra_dip_type ***backdip, struct ra_type_map ***backtype, 1280Sstevel@tonic-gate uint32_t flag); 1290Sstevel@tonic-gate static int isnot_pow2(uint64_t value); 1300Sstevel@tonic-gate static int claim_pci_busnum(dev_info_t *dip, void *arg); 1310Sstevel@tonic-gate static int ra_map_exist(dev_info_t *dip, char *type); 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate #define RA_INSERT(prev, el) \ 1350Sstevel@tonic-gate el->ra_next = *prev; \ 1360Sstevel@tonic-gate *prev = el; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate #define RA_REMOVE(prev, el) \ 1390Sstevel@tonic-gate *prev = el->ra_next; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate static struct modlmisc modlmisc = { 1430Sstevel@tonic-gate &mod_miscops, /* Type of module. This one is a module */ 1440Sstevel@tonic-gate "Bus Resource Allocator (BUSRA) %I%", /* Name of the module. */ 1450Sstevel@tonic-gate }; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate static struct modlinkage modlinkage = { 1480Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 1490Sstevel@tonic-gate }; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate int 1520Sstevel@tonic-gate _init() 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate int ret; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate mutex_init(&ra_lock, NULL, MUTEX_DRIVER, 1570Sstevel@tonic-gate (void *)(intptr_t)__ipltospl(SPL7 - 1)); 1580Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) { 1590Sstevel@tonic-gate mutex_destroy(&ra_lock); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate return (ret); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate int 1650Sstevel@tonic-gate _fini() 1660Sstevel@tonic-gate { 1670Sstevel@tonic-gate int ret; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate mutex_enter(&ra_lock); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate if (ra_map_list_head != NULL) { 1720Sstevel@tonic-gate mutex_exit(&ra_lock); 1730Sstevel@tonic-gate return (EBUSY); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate ret = mod_remove(&modlinkage); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate mutex_exit(&ra_lock); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (ret == 0) 1810Sstevel@tonic-gate mutex_destroy(&ra_lock); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate return (ret); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate int 1870Sstevel@tonic-gate _info(struct modinfo *modinfop) 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate { 1900Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* 1940Sstevel@tonic-gate * set up an empty resource map for a given type and dip 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate int 1970Sstevel@tonic-gate ndi_ra_map_setup(dev_info_t *dip, char *type) 1980Sstevel@tonic-gate { 1990Sstevel@tonic-gate struct ra_type_map *typemapp; 2000Sstevel@tonic-gate struct ra_dip_type *dipmap; 2010Sstevel@tonic-gate struct ra_dip_type **backdip; 2020Sstevel@tonic-gate struct ra_type_map **backtype; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate mutex_enter(&ra_lock); 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0); 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (dipmap == NULL) { 2100Sstevel@tonic-gate if (backtype == NULL) { 2110Sstevel@tonic-gate typemapp = (struct ra_type_map *) 2120Sstevel@tonic-gate kmem_zalloc(sizeof (*typemapp), KM_SLEEP); 2130Sstevel@tonic-gate typemapp->type = (char *)kmem_zalloc(strlen(type) + 1, 2140Sstevel@tonic-gate KM_SLEEP); 2150Sstevel@tonic-gate (void) strcpy(typemapp->type, type); 2160Sstevel@tonic-gate RA_INSERT(&ra_map_list_head, typemapp); 2170Sstevel@tonic-gate } else { 2180Sstevel@tonic-gate typemapp = *backtype; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate if (backdip == NULL) { 2210Sstevel@tonic-gate /* allocate and insert in list of dips for this type */ 2220Sstevel@tonic-gate dipmap = (struct ra_dip_type *) 2230Sstevel@tonic-gate kmem_zalloc(sizeof (*dipmap), KM_SLEEP); 2240Sstevel@tonic-gate dipmap->ra_dip = dip; 2250Sstevel@tonic-gate RA_INSERT(&typemapp->ra_dip_list, dipmap); 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate mutex_exit(&ra_lock); 2300Sstevel@tonic-gate return (NDI_SUCCESS); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * destroys a resource map for a given dip and type 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate int 2370Sstevel@tonic-gate ndi_ra_map_destroy(dev_info_t *dip, char *type) 2380Sstevel@tonic-gate { 2390Sstevel@tonic-gate struct ra_dip_type *dipmap; 2400Sstevel@tonic-gate struct ra_dip_type **backdip; 2410Sstevel@tonic-gate struct ra_type_map **backtype, *typemap; 2420Sstevel@tonic-gate struct ra_resource *range; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate mutex_enter(&ra_lock); 2450Sstevel@tonic-gate dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate if (dipmap == NULL) { 2480Sstevel@tonic-gate mutex_exit(&ra_lock); 2490Sstevel@tonic-gate return (NDI_FAILURE); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * destroy all resources for this dip 2540Sstevel@tonic-gate * remove dip from type list 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate ASSERT((backdip != NULL) && (backtype != NULL)); 2570Sstevel@tonic-gate while (dipmap->ra_rangeset != NULL) { 2580Sstevel@tonic-gate range = dipmap->ra_rangeset; 2590Sstevel@tonic-gate RA_REMOVE(&dipmap->ra_rangeset, range); 2600Sstevel@tonic-gate kmem_free((caddr_t)range, sizeof (*range)); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate /* remove from dip list */ 2630Sstevel@tonic-gate RA_REMOVE(backdip, dipmap); 2640Sstevel@tonic-gate kmem_free((caddr_t)dipmap, sizeof (*dipmap)); 2650Sstevel@tonic-gate if ((*backtype)->ra_dip_list == NULL) { 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * This was the last dip with this resource type. 2680Sstevel@tonic-gate * Remove the type from the global list. 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate typemap = *backtype; 2710Sstevel@tonic-gate RA_REMOVE(backtype, (*backtype)); 2720Sstevel@tonic-gate kmem_free((caddr_t)typemap->type, strlen(typemap->type) + 1); 2730Sstevel@tonic-gate kmem_free((caddr_t)typemap, sizeof (*typemap)); 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate mutex_exit(&ra_lock); 2770Sstevel@tonic-gate return (NDI_SUCCESS); 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate static int 2810Sstevel@tonic-gate ra_map_exist(dev_info_t *dip, char *type) 2820Sstevel@tonic-gate { 2830Sstevel@tonic-gate struct ra_dip_type **backdip; 2840Sstevel@tonic-gate struct ra_type_map **backtype; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate mutex_enter(&ra_lock); 2870Sstevel@tonic-gate if (find_dip_map_resources(dip, type, &backdip, &backtype, 0) == NULL) { 2880Sstevel@tonic-gate mutex_exit(&ra_lock); 2890Sstevel@tonic-gate return (NDI_FAILURE); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate mutex_exit(&ra_lock); 2930Sstevel@tonic-gate return (NDI_SUCCESS); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * Find a dip map for the specified type, if NDI_RA_PASS will go up on dev tree 2970Sstevel@tonic-gate * if found, backdip and backtype will be updated to point to the previous 2980Sstevel@tonic-gate * dip in the list and previous type for this dip in the list. 2990Sstevel@tonic-gate * If no such type at all in the resource list both backdip and backtype 3000Sstevel@tonic-gate * will be null. If the type found but no dip, back dip will be null. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate static struct ra_dip_type * 3040Sstevel@tonic-gate find_dip_map_resources(dev_info_t *dip, char *type, 3050Sstevel@tonic-gate struct ra_dip_type ***backdip, struct ra_type_map ***backtype, 3060Sstevel@tonic-gate uint32_t flag) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate struct ra_type_map **prevmap; 3090Sstevel@tonic-gate struct ra_dip_type *dipmap, **prevdip; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate ASSERT(mutex_owned(&ra_lock)); 3120Sstevel@tonic-gate prevdip = NULL; 3130Sstevel@tonic-gate dipmap = NULL; 3140Sstevel@tonic-gate prevmap = &ra_map_list_head; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate while (*prevmap) { 3170Sstevel@tonic-gate if (strcmp((*prevmap)->type, type) == 0) 3180Sstevel@tonic-gate break; 3190Sstevel@tonic-gate prevmap = &(*prevmap)->ra_next; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if (*prevmap) { 3230Sstevel@tonic-gate for (; dip != NULL; dip = ddi_get_parent(dip)) { 3240Sstevel@tonic-gate prevdip = &(*prevmap)->ra_dip_list; 3250Sstevel@tonic-gate dipmap = *prevdip; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate while (dipmap) { 3280Sstevel@tonic-gate if (dipmap->ra_dip == dip) 3290Sstevel@tonic-gate break; 3300Sstevel@tonic-gate prevdip = &dipmap->ra_next; 3310Sstevel@tonic-gate dipmap = dipmap->ra_next; 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (dipmap != NULL) { 3350Sstevel@tonic-gate /* found it */ 3360Sstevel@tonic-gate break; 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if (!(flag & NDI_RA_PASS)) { 3400Sstevel@tonic-gate break; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate *backtype = (*prevmap == NULL) ? NULL: prevmap; 3460Sstevel@tonic-gate *backdip = (dipmap == NULL) ? NULL: prevdip; 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate return (dipmap); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate int 3520Sstevel@tonic-gate ndi_ra_free(dev_info_t *dip, uint64_t base, uint64_t len, char *type, 3530Sstevel@tonic-gate uint32_t flag) 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate struct ra_dip_type *dipmap; 3560Sstevel@tonic-gate struct ra_resource *newmap, *overlapmap, *oldmap = NULL; 3570Sstevel@tonic-gate struct ra_resource *mapp, **backp; 3580Sstevel@tonic-gate uint64_t newend, mapend; 3590Sstevel@tonic-gate struct ra_dip_type **backdip; 3600Sstevel@tonic-gate struct ra_type_map **backtype; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (len == 0) { 3630Sstevel@tonic-gate return (NDI_SUCCESS); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate mutex_enter(&ra_lock); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if ((dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 3690Sstevel@tonic-gate flag)) == NULL) { 3700Sstevel@tonic-gate mutex_exit(&ra_lock); 3710Sstevel@tonic-gate return (NDI_FAILURE); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate mapp = dipmap->ra_rangeset; 3750Sstevel@tonic-gate backp = &dipmap->ra_rangeset; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate /* now find where range lies and fix things up */ 3780Sstevel@tonic-gate newend = base + len; 3790Sstevel@tonic-gate for (; mapp != NULL; backp = &(mapp->ra_next), mapp = mapp->ra_next) { 3800Sstevel@tonic-gate mapend = mapp->ra_base + mapp->ra_len; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* check for overlap first */ 3830Sstevel@tonic-gate if ((base <= mapp->ra_base && newend > mapp->ra_base) || 3840Sstevel@tonic-gate (base > mapp->ra_base && base < mapend)) { 3850Sstevel@tonic-gate /* overlap with mapp */ 3860Sstevel@tonic-gate overlapmap = mapp; 3870Sstevel@tonic-gate goto overlap; 3880Sstevel@tonic-gate } else if ((base == mapend && mapp->ra_next) && 3890Sstevel@tonic-gate (newend > mapp->ra_next->ra_base)) { 3900Sstevel@tonic-gate /* overlap with mapp->ra_next */ 3910Sstevel@tonic-gate overlapmap = mapp->ra_next; 3920Sstevel@tonic-gate goto overlap; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (newend == mapp->ra_base) { 3960Sstevel@tonic-gate /* simple - on front */ 3970Sstevel@tonic-gate mapp->ra_base = base; 3980Sstevel@tonic-gate mapp->ra_len += len; 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * don't need to check if it merges with 4010Sstevel@tonic-gate * previous since that would match on on end 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate break; 4040Sstevel@tonic-gate } else if (base == mapend) { 4050Sstevel@tonic-gate /* simple - on end */ 4060Sstevel@tonic-gate mapp->ra_len += len; 4070Sstevel@tonic-gate if (mapp->ra_next && 4080Sstevel@tonic-gate (newend == mapp->ra_next->ra_base)) { 4090Sstevel@tonic-gate /* merge with next node */ 4100Sstevel@tonic-gate oldmap = mapp->ra_next; 4110Sstevel@tonic-gate mapp->ra_len += oldmap->ra_len; 4120Sstevel@tonic-gate RA_REMOVE(&mapp->ra_next, oldmap); 4130Sstevel@tonic-gate kmem_free((caddr_t)oldmap, sizeof (*oldmap)); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate break; 4160Sstevel@tonic-gate } else if (base < mapp->ra_base) { 4170Sstevel@tonic-gate /* somewhere in between so just an insert */ 4180Sstevel@tonic-gate newmap = (struct ra_resource *) 4190Sstevel@tonic-gate kmem_zalloc(sizeof (*newmap), KM_SLEEP); 4200Sstevel@tonic-gate newmap->ra_base = base; 4210Sstevel@tonic-gate newmap->ra_len = len; 4220Sstevel@tonic-gate RA_INSERT(backp, newmap); 4230Sstevel@tonic-gate break; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate if (mapp == NULL) { 4270Sstevel@tonic-gate /* stick on end */ 4280Sstevel@tonic-gate newmap = (struct ra_resource *) 4290Sstevel@tonic-gate kmem_zalloc(sizeof (*newmap), KM_SLEEP); 4300Sstevel@tonic-gate newmap->ra_base = base; 4310Sstevel@tonic-gate newmap->ra_len = len; 4320Sstevel@tonic-gate RA_INSERT(backp, newmap); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate mutex_exit(&ra_lock); 4360Sstevel@tonic-gate return (NDI_SUCCESS); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate overlap: 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Bad free may happen on some x86 platforms with BIOS exporting 4410Sstevel@tonic-gate * incorrect resource maps. The system is otherwise functioning 4420Sstevel@tonic-gate * normally. We send such messages to syslog only. 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate cmn_err(CE_NOTE, "!ndi_ra_free: bad free, dip %p, resource type %s \n", 4450Sstevel@tonic-gate (void *)dip, type); 4460Sstevel@tonic-gate cmn_err(CE_NOTE, "!ndi_ra_free: freeing base 0x%" PRIx64 ", len 0x%" 4470Sstevel@tonic-gate PRIX64 " overlaps with existing resource base 0x%" PRIx64 4480Sstevel@tonic-gate ", len 0x%" PRIx64 "\n", base, len, overlapmap->ra_base, 4490Sstevel@tonic-gate overlapmap->ra_len); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate mutex_exit(&ra_lock); 4520Sstevel@tonic-gate return (NDI_FAILURE); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* check to see if value is power of 2 or not. */ 4560Sstevel@tonic-gate static int 4570Sstevel@tonic-gate isnot_pow2(uint64_t value) 4580Sstevel@tonic-gate { 4590Sstevel@tonic-gate uint32_t low; 4600Sstevel@tonic-gate uint32_t hi; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate low = value & 0xffffffff; 4630Sstevel@tonic-gate hi = value >> 32; 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * ddi_ffs and ddi_fls gets long values, so in 32bit environment 4670Sstevel@tonic-gate * won't work correctly for 64bit values 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate if ((ddi_ffs(low) == ddi_fls(low)) && 4700Sstevel@tonic-gate (ddi_ffs(hi) == ddi_fls(hi))) 4710Sstevel@tonic-gate return (0); 4720Sstevel@tonic-gate return (1); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate static void 4760Sstevel@tonic-gate adjust_link(struct ra_resource **backp, struct ra_resource *mapp, 4770Sstevel@tonic-gate uint64_t base, uint64_t len) 4780Sstevel@tonic-gate { 4790Sstevel@tonic-gate struct ra_resource *newmap; 4800Sstevel@tonic-gate uint64_t newlen; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (base != mapp->ra_base) { 4830Sstevel@tonic-gate /* in the middle or end */ 4840Sstevel@tonic-gate newlen = base - mapp->ra_base; 4850Sstevel@tonic-gate if ((mapp->ra_len - newlen) == len) { 4860Sstevel@tonic-gate /* on the end */ 4870Sstevel@tonic-gate mapp->ra_len = newlen; 4880Sstevel@tonic-gate } else { 4890Sstevel@tonic-gate /* in the middle */ 4900Sstevel@tonic-gate newmap = (struct ra_resource *) 4910Sstevel@tonic-gate kmem_zalloc(sizeof (*newmap), KM_SLEEP); 4920Sstevel@tonic-gate newmap->ra_base = base + len; 4930Sstevel@tonic-gate newmap->ra_len = mapp->ra_len - 4940Sstevel@tonic-gate (len + newlen); 4950Sstevel@tonic-gate mapp->ra_len = newlen; 4960Sstevel@tonic-gate RA_INSERT(&(mapp->ra_next), newmap); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate } else { 4990Sstevel@tonic-gate /* at the beginning */ 5000Sstevel@tonic-gate mapp->ra_base += len; 5010Sstevel@tonic-gate mapp->ra_len -= len; 5020Sstevel@tonic-gate if (mapp->ra_len == 0) { 5030Sstevel@tonic-gate /* remove the whole node */ 5040Sstevel@tonic-gate RA_REMOVE(backp, mapp); 5050Sstevel@tonic-gate kmem_free((caddr_t)mapp, sizeof (*mapp)); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate int 5110Sstevel@tonic-gate ndi_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, uint64_t *retbasep, 5120Sstevel@tonic-gate uint64_t *retlenp, char *type, uint32_t flag) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate struct ra_dip_type *dipmap; 5150Sstevel@tonic-gate struct ra_resource *mapp, **backp, **backlargestp; 5160Sstevel@tonic-gate uint64_t mask = 0; 5170Sstevel@tonic-gate uint64_t len, remlen, largestbase, largestlen; 5180Sstevel@tonic-gate uint64_t base, oldbase, lower, upper; 5190Sstevel@tonic-gate struct ra_dip_type **backdip; 5200Sstevel@tonic-gate struct ra_type_map **backtype; 5210Sstevel@tonic-gate int rval = NDI_FAILURE; 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate len = req->ra_len; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate if (req->ra_flags & NDI_RA_ALIGN_SIZE) { 5270Sstevel@tonic-gate if (isnot_pow2(req->ra_len)) { 5280Sstevel@tonic-gate DEBUGPRT(CE_WARN, "ndi_ra_alloc: bad length(pow2) 0x%" 5290Sstevel@tonic-gate PRIx64, req->ra_len); 5300Sstevel@tonic-gate *retbasep = 0; 5310Sstevel@tonic-gate *retlenp = 0; 5320Sstevel@tonic-gate return (NDI_FAILURE); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate mask = (req->ra_flags & NDI_RA_ALIGN_SIZE) ? (len - 1) : 5370Sstevel@tonic-gate req->ra_align_mask; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate mutex_enter(&ra_lock); 5410Sstevel@tonic-gate dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, flag); 5420Sstevel@tonic-gate if ((dipmap == NULL) || ((mapp = dipmap->ra_rangeset) == NULL)) { 5430Sstevel@tonic-gate mutex_exit(&ra_lock); 5440Sstevel@tonic-gate DEBUGPRT(CE_CONT, "ndi_ra_alloc no map found for this type\n"); 5450Sstevel@tonic-gate return (NDI_FAILURE); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate DEBUGPRT(CE_CONT, "ndi_ra_alloc: mapp = %p len=%" PRIx64 ", mask=%" 5490Sstevel@tonic-gate PRIx64 "\n", (void *)mapp, len, mask); 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate backp = &(dipmap->ra_rangeset); 5520Sstevel@tonic-gate backlargestp = NULL; 5530Sstevel@tonic-gate largestbase = 0; 5540Sstevel@tonic-gate largestlen = 0; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate lower = 0; 5570Sstevel@tonic-gate upper = ~(uint64_t)0; 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate if (req->ra_flags & NDI_RA_ALLOC_BOUNDED) { 5600Sstevel@tonic-gate /* bounded so skip to first possible */ 5610Sstevel@tonic-gate lower = req->ra_boundbase; 5620Sstevel@tonic-gate upper = req->ra_boundlen + lower; 5630Sstevel@tonic-gate if ((upper == 0) || (upper < req->ra_boundlen)) 5640Sstevel@tonic-gate upper = ~(uint64_t)0; 5650Sstevel@tonic-gate DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 ", len = %" 5660Sstevel@tonic-gate PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64 5670Sstevel@tonic-gate "\n", mapp->ra_len, len, mapp->ra_base, mask); 5680Sstevel@tonic-gate for (; mapp != NULL && 5690Sstevel@tonic-gate (mapp->ra_base + mapp->ra_len) < lower; 5700Sstevel@tonic-gate backp = &(mapp->ra_next), mapp = mapp->ra_next) { 5710Sstevel@tonic-gate if (((mapp->ra_len + mapp->ra_base) == 0) || 5720Sstevel@tonic-gate ((mapp->ra_len + mapp->ra_base) < mapp->ra_len)) 5730Sstevel@tonic-gate /* 5740Sstevel@tonic-gate * This elements end goes beyond max uint64_t. 5750Sstevel@tonic-gate * potential candidate, check end against lower 5760Sstevel@tonic-gate * would not be precise. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate break; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate DEBUGPRT(CE_CONT, " ra_len = %" PRIx64 ", ra_base=%" 5810Sstevel@tonic-gate PRIx64 "\n", mapp->ra_len, mapp->ra_base); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (!(req->ra_flags & NDI_RA_ALLOC_SPECIFIED)) { 5870Sstevel@tonic-gate /* first fit - not user specified */ 5880Sstevel@tonic-gate DEBUGPRT(CE_CONT, "ndi_ra_alloc(unspecified request)" 5890Sstevel@tonic-gate "lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper); 5900Sstevel@tonic-gate for (; mapp != NULL && mapp->ra_base <= upper; 5910Sstevel@tonic-gate backp = &(mapp->ra_next), mapp = mapp->ra_next) { 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 5940Sstevel@tonic-gate ", len = %" PRIx64 "", mapp->ra_len, len); 5950Sstevel@tonic-gate base = mapp->ra_base; 5960Sstevel@tonic-gate if (base < lower) { 5970Sstevel@tonic-gate base = lower; 5980Sstevel@tonic-gate DEBUGPRT(CE_CONT, "\tbase=%" PRIx64 5990Sstevel@tonic-gate ", ra_base=%" PRIx64 ", mask=%" PRIx64, 6000Sstevel@tonic-gate base, mapp->ra_base, mask); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if ((base & mask) != 0) { 6040Sstevel@tonic-gate oldbase = base; 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * failed a critical constraint 6070Sstevel@tonic-gate * adjust and see if it still fits 6080Sstevel@tonic-gate */ 6090Sstevel@tonic-gate base = base & ~mask; 6100Sstevel@tonic-gate base += (mask + 1); 6110Sstevel@tonic-gate DEBUGPRT(CE_CONT, "\tnew base=%" PRIx64 "\n", 6120Sstevel@tonic-gate base); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * Check to see if the new base is past 6160Sstevel@tonic-gate * the end of the resource. 6170Sstevel@tonic-gate */ 6180Sstevel@tonic-gate if (base >= (oldbase + mapp->ra_len + 1)) { 6190Sstevel@tonic-gate continue; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) { 6240Sstevel@tonic-gate if ((upper - mapp->ra_base) < mapp->ra_len) 6250Sstevel@tonic-gate remlen = upper - base; 6260Sstevel@tonic-gate else 6270Sstevel@tonic-gate remlen = mapp->ra_len - 6280Sstevel@tonic-gate (base - mapp->ra_base); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if ((backlargestp == NULL) || 6310Sstevel@tonic-gate (largestlen < remlen)) { 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate backlargestp = backp; 6340Sstevel@tonic-gate largestbase = base; 6350Sstevel@tonic-gate largestlen = remlen; 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate if (mapp->ra_len >= len) { 6400Sstevel@tonic-gate /* a candidate -- apply constraints */ 6410Sstevel@tonic-gate if ((len > (mapp->ra_len - 6420Sstevel@tonic-gate (base - mapp->ra_base))) || 6430Sstevel@tonic-gate ((len - 1 + base) > upper)) { 6440Sstevel@tonic-gate continue; 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* we have a fit */ 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate DEBUGPRT(CE_CONT, "\thave a fit\n"); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate adjust_link(backp, mapp, base, len); 6520Sstevel@tonic-gate rval = NDI_SUCCESS; 6530Sstevel@tonic-gate break; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } else { 6580Sstevel@tonic-gate /* want an exact value/fit */ 6590Sstevel@tonic-gate base = req->ra_addr; 6600Sstevel@tonic-gate len = req->ra_len; 6610Sstevel@tonic-gate for (; mapp != NULL && mapp->ra_base <= upper; 6620Sstevel@tonic-gate backp = &(mapp->ra_next), mapp = mapp->ra_next) { 6630Sstevel@tonic-gate if (base >= mapp->ra_base && 6640Sstevel@tonic-gate ((base - mapp->ra_base) < mapp->ra_len)) { 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * This is the node with he requested base in 6670Sstevel@tonic-gate * its range 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate if ((len > mapp->ra_len) || 6700Sstevel@tonic-gate (base - mapp->ra_base > 6710Sstevel@tonic-gate mapp->ra_len - len)) { 6720Sstevel@tonic-gate /* length requirement not satisfied */ 6730Sstevel@tonic-gate if (req->ra_flags & 6740Sstevel@tonic-gate NDI_RA_ALLOC_PARTIAL_OK) { 6750Sstevel@tonic-gate if ((upper - mapp->ra_base) 6760Sstevel@tonic-gate < mapp->ra_len) 6770Sstevel@tonic-gate remlen = upper - base; 6780Sstevel@tonic-gate else 6790Sstevel@tonic-gate remlen = 6800Sstevel@tonic-gate mapp->ra_len - 6810Sstevel@tonic-gate (base - 6820Sstevel@tonic-gate mapp->ra_base); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate backlargestp = backp; 6850Sstevel@tonic-gate largestbase = base; 6860Sstevel@tonic-gate largestlen = remlen; 6870Sstevel@tonic-gate base = 0; 6880Sstevel@tonic-gate } else { 6890Sstevel@tonic-gate /* We have a match */ 6900Sstevel@tonic-gate adjust_link(backp, mapp, base, len); 6910Sstevel@tonic-gate rval = NDI_SUCCESS; 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate break; 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate if ((rval != NDI_SUCCESS) && 6990Sstevel@tonic-gate (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) && 7000Sstevel@tonic-gate (backlargestp != NULL)) { 7010Sstevel@tonic-gate adjust_link(backlargestp, *backlargestp, largestbase, 7020Sstevel@tonic-gate largestlen); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate base = largestbase; 7050Sstevel@tonic-gate len = largestlen; 7060Sstevel@tonic-gate rval = NDI_RA_PARTIAL_REQ; 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate mutex_exit(&ra_lock); 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (rval == NDI_FAILURE) { 7120Sstevel@tonic-gate *retbasep = 0; 7130Sstevel@tonic-gate *retlenp = 0; 7140Sstevel@tonic-gate } else { 7150Sstevel@tonic-gate *retbasep = base; 7160Sstevel@tonic-gate *retlenp = len; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate return (rval); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * isa_resource_setup 7230Sstevel@tonic-gate * check for /used-resources and initialize 7240Sstevel@tonic-gate * based on info there. If no /used-resources, 7250Sstevel@tonic-gate * fail. 7260Sstevel@tonic-gate */ 7270Sstevel@tonic-gate int 7280Sstevel@tonic-gate isa_resource_setup() 7290Sstevel@tonic-gate { 7300Sstevel@tonic-gate dev_info_t *used, *usedpdip; 7310Sstevel@tonic-gate /* 7320Sstevel@tonic-gate * note that at this time bootconf creates 32 bit properties for 7330Sstevel@tonic-gate * io-space and device-memory 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate struct iorange { 7360Sstevel@tonic-gate uint32_t base; 7370Sstevel@tonic-gate uint32_t len; 7380Sstevel@tonic-gate } *iorange; 7390Sstevel@tonic-gate struct memrange { 7400Sstevel@tonic-gate uint32_t base; 7410Sstevel@tonic-gate uint32_t len; 7420Sstevel@tonic-gate } *memrange; 7430Sstevel@tonic-gate uint32_t *irq; 7440Sstevel@tonic-gate int proplen; 7450Sstevel@tonic-gate int i, len; 7460Sstevel@tonic-gate int maxrange; 7470Sstevel@tonic-gate ndi_ra_request_t req; 7480Sstevel@tonic-gate uint64_t retbase; 7490Sstevel@tonic-gate uint64_t retlen; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate used = ddi_find_devinfo("used-resources", -1, 0); 7520Sstevel@tonic-gate if (used == NULL) { 7530Sstevel@tonic-gate DEBUGPRT(CE_CONT, 7540Sstevel@tonic-gate "isa_resource_setup: used-resources not found"); 7550Sstevel@tonic-gate return (NDI_FAILURE); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate /* 7590Sstevel@tonic-gate * initialize to all resources being present 7600Sstevel@tonic-gate * and then remove the ones in use. 7610Sstevel@tonic-gate */ 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate usedpdip = ddi_root_node(); 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate DEBUGPRT(CE_CONT, "isa_resource_setup: used = %p usedpdip = %p\n", 7660Sstevel@tonic-gate (void *)used, (void *)usedpdip); 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 7690Sstevel@tonic-gate return (NDI_FAILURE); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* initialize io space, highest end base is 0xffff */ 7730Sstevel@tonic-gate /* note that length is highest addr + 1 since starts from 0 */ 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate (void) ndi_ra_free(usedpdip, 0, 0xffff + 1, NDI_RA_TYPE_IO, 0); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, used, DDI_PROP_DONTPASS, 7780Sstevel@tonic-gate "io-space", (caddr_t)&iorange, &proplen) == DDI_SUCCESS) { 7790Sstevel@tonic-gate maxrange = proplen / sizeof (struct iorange); 7800Sstevel@tonic-gate /* remove the "used" I/O resources */ 7810Sstevel@tonic-gate for (i = 0; i < maxrange; i++) { 7820Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (req)); 7830Sstevel@tonic-gate req.ra_addr = (uint64_t)iorange[i].base; 7840Sstevel@tonic-gate req.ra_len = (uint64_t)iorange[i].len; 7850Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 7860Sstevel@tonic-gate (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen, 7870Sstevel@tonic-gate NDI_RA_TYPE_IO, 0); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate kmem_free((caddr_t)iorange, proplen); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 7940Sstevel@tonic-gate return (NDI_FAILURE); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate /* initialize memory space where highest end base is 0xffffffff */ 7970Sstevel@tonic-gate /* note that length is highest addr + 1 since starts from 0 */ 7980Sstevel@tonic-gate (void) ndi_ra_free(usedpdip, 0, ((uint64_t)((uint32_t)~0)) + 1, 7990Sstevel@tonic-gate NDI_RA_TYPE_MEM, 0); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, used, DDI_PROP_DONTPASS, 8020Sstevel@tonic-gate "device-memory", (caddr_t)&memrange, &proplen) == DDI_SUCCESS) { 8030Sstevel@tonic-gate maxrange = proplen / sizeof (struct memrange); 8040Sstevel@tonic-gate /* remove the "used" memory resources */ 8050Sstevel@tonic-gate for (i = 0; i < maxrange; i++) { 8060Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (req)); 8070Sstevel@tonic-gate req.ra_addr = (uint64_t)memrange[i].base; 8080Sstevel@tonic-gate req.ra_len = (uint64_t)memrange[i].len; 8090Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 8100Sstevel@tonic-gate (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen, 8110Sstevel@tonic-gate NDI_RA_TYPE_MEM, 0); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate kmem_free((caddr_t)memrange, proplen); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_INTR) == NDI_FAILURE) { 8180Sstevel@tonic-gate return (NDI_FAILURE); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* initialize the interrupt space */ 8220Sstevel@tonic-gate (void) ndi_ra_free(usedpdip, 0, 16, NDI_RA_TYPE_INTR, 0); 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 8250Sstevel@tonic-gate bzero(&req, sizeof (req)); 8260Sstevel@tonic-gate req.ra_addr = 2; /* 2 == 9 so never allow */ 8270Sstevel@tonic-gate req.ra_len = 1; 8280Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 8290Sstevel@tonic-gate (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen, 8300Sstevel@tonic-gate NDI_RA_TYPE_INTR, 0); 8310Sstevel@tonic-gate #endif 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, used, DDI_PROP_DONTPASS, 8340Sstevel@tonic-gate "interrupts", (caddr_t)&irq, &proplen) == DDI_SUCCESS) { 8350Sstevel@tonic-gate /* Initialize available interrupts by negating the used */ 8360Sstevel@tonic-gate len = (proplen / sizeof (uint32_t)); 8370Sstevel@tonic-gate for (i = 0; i < len; i++) { 8380Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (req)); 8390Sstevel@tonic-gate req.ra_addr = (uint64_t)irq[i]; 8400Sstevel@tonic-gate req.ra_len = 1; 8410Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 8420Sstevel@tonic-gate (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen, 8430Sstevel@tonic-gate NDI_RA_TYPE_INTR, 0); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate kmem_free((caddr_t)irq, proplen); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate #ifdef BUSRA_DEBUG 8490Sstevel@tonic-gate if (busra_debug) { 8500Sstevel@tonic-gate (void) ra_dump_all(NULL, usedpdip); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate #endif 8530Sstevel@tonic-gate return (NDI_SUCCESS); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate #ifdef BUSRA_DEBUG 8580Sstevel@tonic-gate void 8590Sstevel@tonic-gate ra_dump_all(char *type, dev_info_t *dip) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate struct ra_type_map *typemap; 8630Sstevel@tonic-gate struct ra_dip_type *dipmap; 8640Sstevel@tonic-gate struct ra_resource *res; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate typemap = (struct ra_type_map *)ra_map_list_head; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate for (; typemap != NULL; typemap = typemap->ra_next) { 8690Sstevel@tonic-gate if (type != NULL) { 8700Sstevel@tonic-gate if (strcmp(typemap->type, type) != 0) 8710Sstevel@tonic-gate continue; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate cmn_err(CE_CONT, "type is %s\n", typemap->type); 8740Sstevel@tonic-gate for (dipmap = typemap->ra_dip_list; dipmap != NULL; 8750Sstevel@tonic-gate dipmap = dipmap->ra_next) { 8760Sstevel@tonic-gate if (dip != NULL) { 8770Sstevel@tonic-gate if ((dipmap->ra_dip) != dip) 8780Sstevel@tonic-gate continue; 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate cmn_err(CE_CONT, " dip is %p\n", 8810Sstevel@tonic-gate (void *)dipmap->ra_dip); 8820Sstevel@tonic-gate for (res = dipmap->ra_rangeset; res != NULL; 8830Sstevel@tonic-gate res = res->ra_next) { 8840Sstevel@tonic-gate cmn_err(CE_CONT, "\t range is %" PRIx64 8850Sstevel@tonic-gate " %" PRIx64 "\n", res->ra_base, 8860Sstevel@tonic-gate res->ra_len); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate if (dip != NULL) 8890Sstevel@tonic-gate break; 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate if (type != NULL) 8920Sstevel@tonic-gate break; 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate #endif 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate struct bus_range { /* 1275 "bus-range" property definition */ 8980Sstevel@tonic-gate uint32_t lo; 8990Sstevel@tonic-gate uint32_t hi; 9000Sstevel@tonic-gate } pci_bus_range; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate struct busnum_ctrl { 9030Sstevel@tonic-gate int rv; 9040Sstevel@tonic-gate dev_info_t *dip; 9050Sstevel@tonic-gate struct bus_range *range; 9060Sstevel@tonic-gate }; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * Setup resource map for the pci bus node based on the "available" 9110Sstevel@tonic-gate * property and "bus-range" property. 9120Sstevel@tonic-gate */ 9130Sstevel@tonic-gate int 9140Sstevel@tonic-gate pci_resource_setup(dev_info_t *dip) 9150Sstevel@tonic-gate { 9160Sstevel@tonic-gate pci_regspec_t *regs; 9170Sstevel@tonic-gate int rlen, rcount, i; 9180Sstevel@tonic-gate char bus_type[16] = "(unknown)"; 9190Sstevel@tonic-gate int len; 9200Sstevel@tonic-gate struct busnum_ctrl ctrl; 9210Sstevel@tonic-gate int circular_count; 9220Sstevel@tonic-gate int rval = NDI_SUCCESS; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* 9250Sstevel@tonic-gate * If this is a pci bus node then look for "available" property 9260Sstevel@tonic-gate * to find the available resources on this bus. 9270Sstevel@tonic-gate */ 9280Sstevel@tonic-gate len = sizeof (bus_type); 9290Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 9300Sstevel@tonic-gate DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type", 9310Sstevel@tonic-gate (caddr_t)&bus_type, &len) != DDI_SUCCESS) 9320Sstevel@tonic-gate return (NDI_FAILURE); 9330Sstevel@tonic-gate 934*226Set142600 /* it is not a pci bus type */ 935*226Set142600 if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0)) 9360Sstevel@tonic-gate return (NDI_FAILURE); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* read the "available" property if it is available */ 9390Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 9400Sstevel@tonic-gate "available", (caddr_t)®s, &rlen) != DDI_SUCCESS) 9410Sstevel@tonic-gate return (NDI_FAILURE); 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /* 9450Sstevel@tonic-gate * The pci-hotplug project addresses adding the call 9460Sstevel@tonic-gate * to pci_resource_setup from pci nexus driver. 9470Sstevel@tonic-gate * However that project would initially be only for x86, 9480Sstevel@tonic-gate * so for sparc pcmcia-pci support we still need to call 9490Sstevel@tonic-gate * pci_resource_setup in pcic driver. Once all pci nexus drivers 9500Sstevel@tonic-gate * are updated to call pci_resource_setup this portion of the 9510Sstevel@tonic-gate * code would really become an assert to make sure this 9520Sstevel@tonic-gate * function is not called for the same dip twice. 9530Sstevel@tonic-gate */ 9540Sstevel@tonic-gate { 9550Sstevel@tonic-gate if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) { 9560Sstevel@tonic-gate return (NDI_FAILURE); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { 9620Sstevel@tonic-gate return (NDI_FAILURE); 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { 9660Sstevel@tonic-gate return (NDI_FAILURE); 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM) == NDI_FAILURE) { 9700Sstevel@tonic-gate return (NDI_FAILURE); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == 9740Sstevel@tonic-gate NDI_FAILURE) { 9750Sstevel@tonic-gate return (NDI_FAILURE); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /* create the available resource list for both memory and io space */ 9800Sstevel@tonic-gate rcount = rlen / sizeof (pci_regspec_t); 9810Sstevel@tonic-gate for (i = 0; i < rcount; i++) { 9820Sstevel@tonic-gate switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) { 9830Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 9840Sstevel@tonic-gate (void) ndi_ra_free(dip, 9850Sstevel@tonic-gate (uint64_t)regs[i].pci_phys_low, 9860Sstevel@tonic-gate (uint64_t)regs[i].pci_size_low, 9870Sstevel@tonic-gate (regs[i].pci_phys_hi & PCI_REG_PF_M) ? 9880Sstevel@tonic-gate NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM, 9890Sstevel@tonic-gate 0); 9900Sstevel@tonic-gate break; 9910Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 9920Sstevel@tonic-gate (void) ndi_ra_free(dip, 9930Sstevel@tonic-gate ((uint64_t)(regs[i].pci_phys_mid) << 32) | 9940Sstevel@tonic-gate ((uint64_t)(regs[i].pci_phys_low)), 9950Sstevel@tonic-gate ((uint64_t)(regs[i].pci_size_hi) << 32) | 9960Sstevel@tonic-gate ((uint64_t)(regs[i].pci_size_low)), 9970Sstevel@tonic-gate (regs[i].pci_phys_hi & PCI_REG_PF_M) ? 9980Sstevel@tonic-gate NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM, 9990Sstevel@tonic-gate 0); 10000Sstevel@tonic-gate break; 10010Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 10020Sstevel@tonic-gate (void) ndi_ra_free(dip, 10030Sstevel@tonic-gate (uint64_t)regs[i].pci_phys_low, 10040Sstevel@tonic-gate (uint64_t)regs[i].pci_size_low, 10050Sstevel@tonic-gate NDI_RA_TYPE_IO, 10060Sstevel@tonic-gate 0); 10070Sstevel@tonic-gate break; 10080Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_CONFIG): 10090Sstevel@tonic-gate break; 10100Sstevel@tonic-gate default: 10110Sstevel@tonic-gate cmn_err(CE_WARN, 10120Sstevel@tonic-gate "pci_resource_setup: bad addr type: %x\n", 10130Sstevel@tonic-gate PCI_REG_ADDR_G(regs[i].pci_phys_hi)); 10140Sstevel@tonic-gate break; 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate } 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate kmem_free((caddr_t)regs, rlen); 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate /* 10210Sstevel@tonic-gate * Create resource map for available bus numbers if the node 10220Sstevel@tonic-gate * has available-bus-range or bus-range property. 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate len = sizeof (struct bus_range); 10250Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 10260Sstevel@tonic-gate "available-bus-range", (caddr_t)&pci_bus_range, &len) == 10270Sstevel@tonic-gate DDI_SUCCESS) { 10280Sstevel@tonic-gate /* 10290Sstevel@tonic-gate * Add bus numbers in the range to the free list. 10300Sstevel@tonic-gate */ 10310Sstevel@tonic-gate (void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo, 10320Sstevel@tonic-gate (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo + 10330Sstevel@tonic-gate 1, NDI_RA_TYPE_PCI_BUSNUM, 0); 10340Sstevel@tonic-gate } else { 10350Sstevel@tonic-gate /* 10360Sstevel@tonic-gate * We don't have an available-bus-range property. If, instead, 10370Sstevel@tonic-gate * we have a bus-range property we add all the bus numbers 10380Sstevel@tonic-gate * in that range to the free list but we must then scan 10390Sstevel@tonic-gate * for pci-pci bridges on this bus to find out the if there 10400Sstevel@tonic-gate * are any of those bus numbers already in use. If so, we can 10410Sstevel@tonic-gate * reclaim them. 10420Sstevel@tonic-gate */ 10430Sstevel@tonic-gate len = sizeof (struct bus_range); 10440Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, 10450Sstevel@tonic-gate DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range, 10460Sstevel@tonic-gate &len) == DDI_SUCCESS) { 10470Sstevel@tonic-gate if (pci_bus_range.lo != pci_bus_range.hi) { 10480Sstevel@tonic-gate /* 10490Sstevel@tonic-gate * Add bus numbers other than the secondary 10500Sstevel@tonic-gate * bus number to the free list. 10510Sstevel@tonic-gate */ 10520Sstevel@tonic-gate (void) ndi_ra_free(dip, 10530Sstevel@tonic-gate (uint64_t)pci_bus_range.lo + 1, 10540Sstevel@tonic-gate (uint64_t)pci_bus_range.hi - 10550Sstevel@tonic-gate (uint64_t)pci_bus_range.lo, 10560Sstevel@tonic-gate NDI_RA_TYPE_PCI_BUSNUM, 0); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* scan for pci-pci bridges */ 10590Sstevel@tonic-gate ctrl.rv = DDI_SUCCESS; 10600Sstevel@tonic-gate ctrl.dip = dip; 10610Sstevel@tonic-gate ctrl.range = &pci_bus_range; 10620Sstevel@tonic-gate ndi_devi_enter(dip, &circular_count); 10630Sstevel@tonic-gate ddi_walk_devs(ddi_get_child(dip), 10640Sstevel@tonic-gate claim_pci_busnum, (void *)&ctrl); 10650Sstevel@tonic-gate ndi_devi_exit(dip, circular_count); 10660Sstevel@tonic-gate if (ctrl.rv != DDI_SUCCESS) { 10670Sstevel@tonic-gate /* failed to create the map */ 10680Sstevel@tonic-gate (void) ndi_ra_map_destroy(dip, 10690Sstevel@tonic-gate NDI_RA_TYPE_PCI_BUSNUM); 10700Sstevel@tonic-gate rval = NDI_FAILURE; 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate #ifdef BUSRA_DEBUG 10770Sstevel@tonic-gate if (busra_debug) { 10780Sstevel@tonic-gate (void) ra_dump_all(NULL, dip); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate #endif 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate return (rval); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * If the device is a PCI bus device (i.e bus-range property exists) then 10870Sstevel@tonic-gate * claim the bus numbers used by the device from the specified bus 10880Sstevel@tonic-gate * resource map. 10890Sstevel@tonic-gate */ 10900Sstevel@tonic-gate static int 10910Sstevel@tonic-gate claim_pci_busnum(dev_info_t *dip, void *arg) 10920Sstevel@tonic-gate { 10930Sstevel@tonic-gate struct bus_range pci_bus_range; 10940Sstevel@tonic-gate struct busnum_ctrl *ctrl; 10950Sstevel@tonic-gate ndi_ra_request_t req; 10960Sstevel@tonic-gate char bus_type[16] = "(unknown)"; 10970Sstevel@tonic-gate int len; 10980Sstevel@tonic-gate uint64_t base; 10990Sstevel@tonic-gate uint64_t retlen; 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate ctrl = (struct busnum_ctrl *)arg; 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate /* check if this is a PCI bus node */ 11040Sstevel@tonic-gate len = sizeof (bus_type); 11050Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 11060Sstevel@tonic-gate DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type", 11070Sstevel@tonic-gate (caddr_t)&bus_type, &len) != DDI_SUCCESS) 11080Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 11090Sstevel@tonic-gate 1110*226Set142600 /* it is not a pci bus type */ 1111*226Set142600 if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0)) 11120Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* look for the bus-range property */ 11150Sstevel@tonic-gate len = sizeof (struct bus_range); 11160Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 11170Sstevel@tonic-gate "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) { 11180Sstevel@tonic-gate if ((pci_bus_range.lo >= ctrl->range->lo) && 11190Sstevel@tonic-gate (pci_bus_range.hi <= ctrl->range->hi)) { 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /* claim the bus range from the bus resource map */ 11220Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (req)); 11230Sstevel@tonic-gate req.ra_addr = (uint64_t)pci_bus_range.lo; 11240Sstevel@tonic-gate req.ra_flags |= NDI_RA_ALLOC_SPECIFIED; 11250Sstevel@tonic-gate req.ra_len = (uint64_t)pci_bus_range.hi - 11260Sstevel@tonic-gate (uint64_t)pci_bus_range.lo + 1; 11270Sstevel@tonic-gate if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen, 11280Sstevel@tonic-gate NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS) 11290Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate /* 11340Sstevel@tonic-gate * Error return. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate ctrl->rv = DDI_FAILURE; 11370Sstevel@tonic-gate return (DDI_WALK_TERMINATE); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate void 11410Sstevel@tonic-gate pci_resource_destroy(dev_info_t *dip) 11420Sstevel@tonic-gate { 11430Sstevel@tonic-gate (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO); 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM); 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate pci_resource_setup_avail(dev_info_t *dip, pci_regspec_t *avail_p, int entries) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate int i; 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) 11590Sstevel@tonic-gate return (NDI_FAILURE); 11600Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) 11610Sstevel@tonic-gate return (NDI_FAILURE); 11620Sstevel@tonic-gate if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == NDI_FAILURE) 11630Sstevel@tonic-gate return (NDI_FAILURE); 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate /* for each entry in the PCI "available" property */ 11660Sstevel@tonic-gate for (i = 0; i < entries; i++, avail_p++) { 11670Sstevel@tonic-gate if (avail_p->pci_phys_hi == -1u) 11680Sstevel@tonic-gate goto err; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate switch (PCI_REG_ADDR_G(avail_p->pci_phys_hi)) { 11710Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): { 11720Sstevel@tonic-gate (void) ndi_ra_free(dip, 11730Sstevel@tonic-gate (uint64_t)avail_p->pci_phys_low, 11740Sstevel@tonic-gate (uint64_t)avail_p->pci_size_low, 11750Sstevel@tonic-gate (avail_p->pci_phys_hi & 11760Sstevel@tonic-gate PCI_REG_PF_M) ? 11770Sstevel@tonic-gate NDI_RA_TYPE_PCI_PREFETCH_MEM : 11780Sstevel@tonic-gate NDI_RA_TYPE_MEM, 11790Sstevel@tonic-gate 0); 11800Sstevel@tonic-gate } 11810Sstevel@tonic-gate break; 11820Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 11830Sstevel@tonic-gate (void) ndi_ra_free(dip, 11840Sstevel@tonic-gate (uint64_t)avail_p->pci_phys_low, 11850Sstevel@tonic-gate (uint64_t)avail_p->pci_size_low, 11860Sstevel@tonic-gate NDI_RA_TYPE_IO, 11870Sstevel@tonic-gate 0); 11880Sstevel@tonic-gate break; 11890Sstevel@tonic-gate default: 11900Sstevel@tonic-gate goto err; 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate #ifdef BUSRA_DEBUG 11940Sstevel@tonic-gate if (busra_debug) { 11950Sstevel@tonic-gate (void) ra_dump_all(NULL, dip); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate #endif 11980Sstevel@tonic-gate return (NDI_SUCCESS); 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate err: 12010Sstevel@tonic-gate cmn_err(CE_WARN, "pci_resource_setup_avail: bad entry[%d]=%x\n", 12020Sstevel@tonic-gate i, avail_p->pci_phys_hi); 12030Sstevel@tonic-gate return (NDI_FAILURE); 12040Sstevel@tonic-gate } 1205