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