1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * PC specific DDI implementation 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <sys/autoconf.h> 34*0Sstevel@tonic-gate #include <sys/avintr.h> 35*0Sstevel@tonic-gate #include <sys/bootconf.h> 36*0Sstevel@tonic-gate #include <sys/conf.h> 37*0Sstevel@tonic-gate #include <sys/cpuvar.h> 38*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 39*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 40*0Sstevel@tonic-gate #include <sys/ethernet.h> 41*0Sstevel@tonic-gate #include <sys/fp.h> 42*0Sstevel@tonic-gate #include <sys/instance.h> 43*0Sstevel@tonic-gate #include <sys/kmem.h> 44*0Sstevel@tonic-gate #include <sys/machsystm.h> 45*0Sstevel@tonic-gate #include <sys/modctl.h> 46*0Sstevel@tonic-gate #include <sys/promif.h> 47*0Sstevel@tonic-gate #include <sys/prom_plat.h> 48*0Sstevel@tonic-gate #include <sys/sunndi.h> 49*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 50*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 51*0Sstevel@tonic-gate #include <sys/sysmacros.h> 52*0Sstevel@tonic-gate #include <sys/systeminfo.h> 53*0Sstevel@tonic-gate #include <sys/utsname.h> 54*0Sstevel@tonic-gate #include <sys/atomic.h> 55*0Sstevel@tonic-gate #include <sys/spl.h> 56*0Sstevel@tonic-gate #include <sys/archsystm.h> 57*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 58*0Sstevel@tonic-gate #include <sys/ontrap.h> 59*0Sstevel@tonic-gate #include <sys/ramdisk.h> 60*0Sstevel@tonic-gate #include <sys/sunndi.h> 61*0Sstevel@tonic-gate #include <sys/vmem.h> 62*0Sstevel@tonic-gate #include <sys/pci_impl.h> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* 65*0Sstevel@tonic-gate * DDI Boot Configuration 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * No platform drivers on this platform 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate char *platform_module_list[] = { 72*0Sstevel@tonic-gate (char *)0 73*0Sstevel@tonic-gate }; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* pci bus resource maps */ 76*0Sstevel@tonic-gate struct pci_bus_resource *pci_bus_res; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate extern int root_is_svm; 79*0Sstevel@tonic-gate uint64_t ramdisk_start, ramdisk_end; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate /* 82*0Sstevel@tonic-gate * Forward declarations 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate static int getlongprop_buf(); 85*0Sstevel@tonic-gate static void get_boot_properties(void); 86*0Sstevel@tonic-gate static void impl_bus_initialprobe(void); 87*0Sstevel@tonic-gate static void impl_bus_reprobe(void); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate static int poke_mem(peekpoke_ctlops_t *in_args); 90*0Sstevel@tonic-gate static int peek_mem(peekpoke_ctlops_t *in_args); 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate #define CTGENTRIES 15 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate static struct ctgas { 95*0Sstevel@tonic-gate struct ctgas *ctg_next; 96*0Sstevel@tonic-gate int ctg_index; 97*0Sstevel@tonic-gate void *ctg_addr[CTGENTRIES]; 98*0Sstevel@tonic-gate size_t ctg_size[CTGENTRIES]; 99*0Sstevel@tonic-gate } ctglist; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate static kmutex_t ctgmutex; 102*0Sstevel@tonic-gate #define CTGLOCK() mutex_enter(&ctgmutex) 103*0Sstevel@tonic-gate #define CTGUNLOCK() mutex_exit(&ctgmutex) 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * Minimum pfn value of page_t's put on the free list. This is to simplify 107*0Sstevel@tonic-gate * support of ddi dma memory requests which specify small, non-zero addr_lo 108*0Sstevel@tonic-gate * values. 109*0Sstevel@tonic-gate * 110*0Sstevel@tonic-gate * The default value of 2, which corresponds to the only known non-zero addr_lo 111*0Sstevel@tonic-gate * value used, means a single page will be sacrificed (pfn typically starts 112*0Sstevel@tonic-gate * at 1). ddiphysmin can be set to 0 to disable. It cannot be set above 0x100 113*0Sstevel@tonic-gate * otherwise mp startup panics. 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate pfn_t ddiphysmin = 2; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate static void 118*0Sstevel@tonic-gate check_driver_disable(void) 119*0Sstevel@tonic-gate { 120*0Sstevel@tonic-gate int proplen = 128; 121*0Sstevel@tonic-gate char *prop_name; 122*0Sstevel@tonic-gate char *drv_name, *propval; 123*0Sstevel@tonic-gate major_t major; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate prop_name = kmem_alloc(proplen, KM_SLEEP); 126*0Sstevel@tonic-gate for (major = 0; major < devcnt; major++) { 127*0Sstevel@tonic-gate drv_name = ddi_major_to_name(major); 128*0Sstevel@tonic-gate if (drv_name == NULL) 129*0Sstevel@tonic-gate continue; 130*0Sstevel@tonic-gate (void) snprintf(prop_name, proplen, "disable-%s", drv_name); 131*0Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 132*0Sstevel@tonic-gate DDI_PROP_DONTPASS, prop_name, &propval) == DDI_SUCCESS) { 133*0Sstevel@tonic-gate if (strcmp(propval, "true") == 0) { 134*0Sstevel@tonic-gate devnamesp[major].dn_flags |= DN_DRIVER_REMOVED; 135*0Sstevel@tonic-gate cmn_err(CE_NOTE, "driver %s disabled", 136*0Sstevel@tonic-gate drv_name); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate ddi_prop_free(propval); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate kmem_free(prop_name, proplen); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * Configure the hardware on the system. 147*0Sstevel@tonic-gate * Called before the rootfs is mounted 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate void 150*0Sstevel@tonic-gate configure(void) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate extern void i_ddi_init_root(); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate #if defined(__i386) 155*0Sstevel@tonic-gate extern int fpu_pentium_fdivbug; 156*0Sstevel@tonic-gate #endif /* __i386 */ 157*0Sstevel@tonic-gate extern int fpu_ignored; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Determine if an FPU is attached 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate fpu_probe(); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate #if defined(__i386) 166*0Sstevel@tonic-gate if (fpu_pentium_fdivbug) { 167*0Sstevel@tonic-gate printf("\ 168*0Sstevel@tonic-gate FP hardware exhibits Pentium floating point divide problem\n"); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate #endif /* __i386 */ 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate if (fpu_ignored) { 173*0Sstevel@tonic-gate printf("FP hardware will not be used\n"); 174*0Sstevel@tonic-gate } else if (!fpu_exists) { 175*0Sstevel@tonic-gate printf("No FPU in configuration\n"); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Initialize devices on the machine. 180*0Sstevel@tonic-gate * Uses configuration tree built by the PROMs to determine what 181*0Sstevel@tonic-gate * is present, and builds a tree of prototype dev_info nodes 182*0Sstevel@tonic-gate * corresponding to the hardware which identified itself. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate #if !defined(SAS) && !defined(MPSAS) 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Check for disabled drivers and initialize root node. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate check_driver_disable(); 189*0Sstevel@tonic-gate i_ddi_init_root(); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * attach the isa nexus to get ACPI resource usage 193*0Sstevel@tonic-gate * isa is "kind of" a pseudo node 194*0Sstevel@tonic-gate */ 195*0Sstevel@tonic-gate (void) i_ddi_attach_pseudo_node("isa"); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* reprogram devices not set up by firmware (BIOS) */ 198*0Sstevel@tonic-gate impl_bus_reprobe(); 199*0Sstevel@tonic-gate #endif /* !SAS && !MPSAS */ 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * The "status" property indicates the operational status of a device. 204*0Sstevel@tonic-gate * If this property is present, the value is a string indicating the 205*0Sstevel@tonic-gate * status of the device as follows: 206*0Sstevel@tonic-gate * 207*0Sstevel@tonic-gate * "okay" operational. 208*0Sstevel@tonic-gate * "disabled" not operational, but might become operational. 209*0Sstevel@tonic-gate * "fail" not operational because a fault has been detected, 210*0Sstevel@tonic-gate * and it is unlikely that the device will become 211*0Sstevel@tonic-gate * operational without repair. no additional details 212*0Sstevel@tonic-gate * are available. 213*0Sstevel@tonic-gate * "fail-xxx" not operational because a fault has been detected, 214*0Sstevel@tonic-gate * and it is unlikely that the device will become 215*0Sstevel@tonic-gate * operational without repair. "xxx" is additional 216*0Sstevel@tonic-gate * human-readable information about the particular 217*0Sstevel@tonic-gate * fault condition that was detected. 218*0Sstevel@tonic-gate * 219*0Sstevel@tonic-gate * The absence of this property means that the operational status is 220*0Sstevel@tonic-gate * unknown or okay. 221*0Sstevel@tonic-gate * 222*0Sstevel@tonic-gate * This routine checks the status property of the specified device node 223*0Sstevel@tonic-gate * and returns 0 if the operational status indicates failure, and 1 otherwise. 224*0Sstevel@tonic-gate * 225*0Sstevel@tonic-gate * The property may exist on plug-in cards the existed before IEEE 1275-1994. 226*0Sstevel@tonic-gate * And, in that case, the property may not even be a string. So we carefully 227*0Sstevel@tonic-gate * check for the value "fail", in the beginning of the string, noting 228*0Sstevel@tonic-gate * the property length. 229*0Sstevel@tonic-gate */ 230*0Sstevel@tonic-gate int 231*0Sstevel@tonic-gate status_okay(int id, char *buf, int buflen) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate char status_buf[OBP_MAXPROPNAME]; 234*0Sstevel@tonic-gate char *bufp = buf; 235*0Sstevel@tonic-gate int len = buflen; 236*0Sstevel@tonic-gate int proplen; 237*0Sstevel@tonic-gate static const char *status = "status"; 238*0Sstevel@tonic-gate static const char *fail = "fail"; 239*0Sstevel@tonic-gate int fail_len = (int)strlen(fail); 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate /* 242*0Sstevel@tonic-gate * Get the proplen ... if it's smaller than "fail", 243*0Sstevel@tonic-gate * or doesn't exist ... then we don't care, since 244*0Sstevel@tonic-gate * the value can't begin with the char string "fail". 245*0Sstevel@tonic-gate * 246*0Sstevel@tonic-gate * NB: proplen, if it's a string, includes the NULL in the 247*0Sstevel@tonic-gate * the size of the property, and fail_len does not. 248*0Sstevel@tonic-gate */ 249*0Sstevel@tonic-gate proplen = prom_getproplen((dnode_t)id, (caddr_t)status); 250*0Sstevel@tonic-gate if (proplen <= fail_len) /* nonexistant or uninteresting len */ 251*0Sstevel@tonic-gate return (1); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * if a buffer was provided, use it 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate if ((buf == (char *)NULL) || (buflen <= 0)) { 257*0Sstevel@tonic-gate bufp = status_buf; 258*0Sstevel@tonic-gate len = sizeof (status_buf); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate *bufp = (char)0; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * Get the property into the buffer, to the extent of the buffer, 264*0Sstevel@tonic-gate * and in case the buffer is smaller than the property size, 265*0Sstevel@tonic-gate * NULL terminate the buffer. (This handles the case where 266*0Sstevel@tonic-gate * a buffer was passed in and the caller wants to print the 267*0Sstevel@tonic-gate * value, but the buffer was too small). 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate (void) prom_bounded_getprop((dnode_t)id, (caddr_t)status, 270*0Sstevel@tonic-gate (caddr_t)bufp, len); 271*0Sstevel@tonic-gate *(bufp + len - 1) = (char)0; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * If the value begins with the char string "fail", 275*0Sstevel@tonic-gate * then it means the node is failed. We don't care 276*0Sstevel@tonic-gate * about any other values. We assume the node is ok 277*0Sstevel@tonic-gate * although it might be 'disabled'. 278*0Sstevel@tonic-gate */ 279*0Sstevel@tonic-gate if (strncmp(bufp, fail, fail_len) == 0) 280*0Sstevel@tonic-gate return (0); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate return (1); 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate /* 286*0Sstevel@tonic-gate * Check the status of the device node passed as an argument. 287*0Sstevel@tonic-gate * 288*0Sstevel@tonic-gate * if ((status is OKAY) || (status is DISABLED)) 289*0Sstevel@tonic-gate * return DDI_SUCCESS 290*0Sstevel@tonic-gate * else 291*0Sstevel@tonic-gate * print a warning and return DDI_FAILURE 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate /*ARGSUSED1*/ 294*0Sstevel@tonic-gate int 295*0Sstevel@tonic-gate check_status(int id, char *name, dev_info_t *parent) 296*0Sstevel@tonic-gate { 297*0Sstevel@tonic-gate char status_buf[64]; 298*0Sstevel@tonic-gate char devtype_buf[OBP_MAXPROPNAME]; 299*0Sstevel@tonic-gate int retval = DDI_FAILURE; 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate /* 302*0Sstevel@tonic-gate * is the status okay? 303*0Sstevel@tonic-gate */ 304*0Sstevel@tonic-gate if (status_okay(id, status_buf, sizeof (status_buf))) 305*0Sstevel@tonic-gate return (DDI_SUCCESS); 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * a status property indicating bad memory will be associated 309*0Sstevel@tonic-gate * with a node which has a "device_type" property with a value of 310*0Sstevel@tonic-gate * "memory-controller". in this situation, return DDI_SUCCESS 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate if (getlongprop_buf(id, OBP_DEVICETYPE, devtype_buf, 313*0Sstevel@tonic-gate sizeof (devtype_buf)) > 0) { 314*0Sstevel@tonic-gate if (strcmp(devtype_buf, "memory-controller") == 0) 315*0Sstevel@tonic-gate retval = DDI_SUCCESS; 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate * print the status property information 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate cmn_err(CE_WARN, "status '%s' for '%s'", status_buf, name); 322*0Sstevel@tonic-gate return (retval); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /*ARGSUSED*/ 326*0Sstevel@tonic-gate uint_t 327*0Sstevel@tonic-gate softlevel1(caddr_t arg1, caddr_t arg2) 328*0Sstevel@tonic-gate { 329*0Sstevel@tonic-gate softint(); 330*0Sstevel@tonic-gate return (1); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Allow for implementation specific correction of PROM property values. 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /*ARGSUSED*/ 338*0Sstevel@tonic-gate void 339*0Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, 340*0Sstevel@tonic-gate caddr_t buffer) 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * There are no adjustments needed in this implementation. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate static int 348*0Sstevel@tonic-gate getlongprop_buf(int id, char *name, char *buf, int maxlen) 349*0Sstevel@tonic-gate { 350*0Sstevel@tonic-gate int size; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate size = prom_getproplen((dnode_t)id, name); 353*0Sstevel@tonic-gate if (size <= 0 || (size > maxlen - 1)) 354*0Sstevel@tonic-gate return (-1); 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate if (-1 == prom_getprop((dnode_t)id, name, buf)) 357*0Sstevel@tonic-gate return (-1); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (strcmp("name", name) == 0) { 360*0Sstevel@tonic-gate if (buf[size - 1] != '\0') { 361*0Sstevel@tonic-gate buf[size] = '\0'; 362*0Sstevel@tonic-gate size += 1; 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate return (size); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate static int 370*0Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen) 371*0Sstevel@tonic-gate { 372*0Sstevel@tonic-gate int ret; 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di, 375*0Sstevel@tonic-gate DDI_PROP_DONTPASS, pname, pval, plen)) 376*0Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 377*0Sstevel@tonic-gate *plen = (*plen) * (sizeof (int)); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate return (ret); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * Node Configuration 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate struct prop_ispec { 388*0Sstevel@tonic-gate uint_t pri, vec; 389*0Sstevel@tonic-gate }; 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Create a ddi_parent_private_data structure from the ddi properties of 393*0Sstevel@tonic-gate * the dev_info node. 394*0Sstevel@tonic-gate * 395*0Sstevel@tonic-gate * The "reg" and either an "intr" or "interrupts" properties are required 396*0Sstevel@tonic-gate * if the driver wishes to create mappings or field interrupts on behalf 397*0Sstevel@tonic-gate * of the device. 398*0Sstevel@tonic-gate * 399*0Sstevel@tonic-gate * The "reg" property is assumed to be a list of at least one triple 400*0Sstevel@tonic-gate * 401*0Sstevel@tonic-gate * <bustype, address, size>*1 402*0Sstevel@tonic-gate * 403*0Sstevel@tonic-gate * The "intr" property is assumed to be a list of at least one duple 404*0Sstevel@tonic-gate * 405*0Sstevel@tonic-gate * <SPARC ipl, vector#>*1 406*0Sstevel@tonic-gate * 407*0Sstevel@tonic-gate * The "interrupts" property is assumed to be a list of at least one 408*0Sstevel@tonic-gate * n-tuples that describes the interrupt capabilities of the bus the device 409*0Sstevel@tonic-gate * is connected to. For SBus, this looks like 410*0Sstevel@tonic-gate * 411*0Sstevel@tonic-gate * <SBus-level>*1 412*0Sstevel@tonic-gate * 413*0Sstevel@tonic-gate * (This property obsoletes the 'intr' property). 414*0Sstevel@tonic-gate * 415*0Sstevel@tonic-gate * The "ranges" property is optional. 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate void 418*0Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd) 419*0Sstevel@tonic-gate { 420*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 421*0Sstevel@tonic-gate int n; 422*0Sstevel@tonic-gate int *reg_prop, *rng_prop, *intr_prop, *irupts_prop; 423*0Sstevel@tonic-gate uint_t reg_len, rng_len, intr_len, irupts_len; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate *ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate /* 428*0Sstevel@tonic-gate * Handle the 'reg' property. 429*0Sstevel@tonic-gate */ 430*0Sstevel@tonic-gate if ((get_prop_int_array(child, "reg", ®_prop, ®_len) == 431*0Sstevel@tonic-gate DDI_PROP_SUCCESS) && (reg_len != 0)) { 432*0Sstevel@tonic-gate pdptr->par_nreg = reg_len / (int)sizeof (struct regspec); 433*0Sstevel@tonic-gate pdptr->par_reg = (struct regspec *)reg_prop; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* 437*0Sstevel@tonic-gate * See if I have a range (adding one where needed - this 438*0Sstevel@tonic-gate * means to add one for sbus node in sun4c, when romvec > 0, 439*0Sstevel@tonic-gate * if no range is already defined in the PROM node. 440*0Sstevel@tonic-gate * (Currently no sun4c PROMS define range properties, 441*0Sstevel@tonic-gate * but they should and may in the future.) For the SBus 442*0Sstevel@tonic-gate * node, the range is defined by the SBus reg property. 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate if (get_prop_int_array(child, "ranges", &rng_prop, &rng_len) 445*0Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 446*0Sstevel@tonic-gate pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 447*0Sstevel@tonic-gate pdptr->par_rng = (struct rangespec *)rng_prop; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * Handle the 'intr' and 'interrupts' properties 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* 455*0Sstevel@tonic-gate * For backwards compatibility 456*0Sstevel@tonic-gate * we first look for the 'intr' property for the device. 457*0Sstevel@tonic-gate */ 458*0Sstevel@tonic-gate if (get_prop_int_array(child, "intr", &intr_prop, &intr_len) 459*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 460*0Sstevel@tonic-gate intr_len = 0; 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate /* 464*0Sstevel@tonic-gate * If we're to support bus adapters and future platforms cleanly, 465*0Sstevel@tonic-gate * we need to support the generalized 'interrupts' property. 466*0Sstevel@tonic-gate */ 467*0Sstevel@tonic-gate if (get_prop_int_array(child, "interrupts", &irupts_prop, 468*0Sstevel@tonic-gate &irupts_len) != DDI_PROP_SUCCESS) { 469*0Sstevel@tonic-gate irupts_len = 0; 470*0Sstevel@tonic-gate } else if (intr_len != 0) { 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * If both 'intr' and 'interrupts' are defined, 473*0Sstevel@tonic-gate * then 'interrupts' wins and we toss the 'intr' away. 474*0Sstevel@tonic-gate */ 475*0Sstevel@tonic-gate ddi_prop_free((void *)intr_prop); 476*0Sstevel@tonic-gate intr_len = 0; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate if (intr_len != 0) { 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /* 482*0Sstevel@tonic-gate * Translate the 'intr' property into an array 483*0Sstevel@tonic-gate * an array of struct intrspec's. There's not really 484*0Sstevel@tonic-gate * very much to do here except copy what's out there. 485*0Sstevel@tonic-gate */ 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate struct intrspec *new; 488*0Sstevel@tonic-gate struct prop_ispec *l; 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate n = pdptr->par_nintr = 491*0Sstevel@tonic-gate intr_len / sizeof (struct prop_ispec); 492*0Sstevel@tonic-gate l = (struct prop_ispec *)intr_prop; 493*0Sstevel@tonic-gate pdptr->par_intr = 494*0Sstevel@tonic-gate new = kmem_zalloc(n * sizeof (struct intrspec), KM_SLEEP); 495*0Sstevel@tonic-gate while (n--) { 496*0Sstevel@tonic-gate new->intrspec_pri = l->pri; 497*0Sstevel@tonic-gate new->intrspec_vec = l->vec; 498*0Sstevel@tonic-gate new++; 499*0Sstevel@tonic-gate l++; 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate ddi_prop_free((void *)intr_prop); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate } else if ((n = irupts_len) != 0) { 504*0Sstevel@tonic-gate size_t size; 505*0Sstevel@tonic-gate int *out; 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * Translate the 'interrupts' property into an array 509*0Sstevel@tonic-gate * of intrspecs for the rest of the DDI framework to 510*0Sstevel@tonic-gate * toy with. Only our ancestors really know how to 511*0Sstevel@tonic-gate * do this, so ask 'em. We massage the 'interrupts' 512*0Sstevel@tonic-gate * property so that it is pre-pended by a count of 513*0Sstevel@tonic-gate * the number of integers in the argument. 514*0Sstevel@tonic-gate */ 515*0Sstevel@tonic-gate size = sizeof (int) + n; 516*0Sstevel@tonic-gate out = kmem_alloc(size, KM_SLEEP); 517*0Sstevel@tonic-gate *out = n / sizeof (int); 518*0Sstevel@tonic-gate bcopy(irupts_prop, out + 1, (size_t)n); 519*0Sstevel@tonic-gate ddi_prop_free((void *)irupts_prop); 520*0Sstevel@tonic-gate if (ddi_ctlops(child, child, DDI_CTLOPS_XLATE_INTRS, 521*0Sstevel@tonic-gate out, pdptr) != DDI_SUCCESS) { 522*0Sstevel@tonic-gate cmn_err(CE_CONT, 523*0Sstevel@tonic-gate "Unable to translate 'interrupts' for %s%d\n", 524*0Sstevel@tonic-gate DEVI(child)->devi_binding_name, 525*0Sstevel@tonic-gate DEVI(child)->devi_instance); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate kmem_free(out, size); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate /* 532*0Sstevel@tonic-gate * Name a child 533*0Sstevel@tonic-gate */ 534*0Sstevel@tonic-gate static int 535*0Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen) 536*0Sstevel@tonic-gate { 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * Fill in parent-private data and this function returns to us 539*0Sstevel@tonic-gate * an indication if it used "registers" to fill in the data. 540*0Sstevel@tonic-gate */ 541*0Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 542*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 543*0Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 544*0Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate name[0] = '\0'; 548*0Sstevel@tonic-gate if (sparc_pd_getnreg(child) > 0) { 549*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 550*0Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 551*0Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate return (DDI_SUCCESS); 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* 558*0Sstevel@tonic-gate * Called from the bus_ctl op of sunbus (sbus, obio, etc) nexus drivers 559*0Sstevel@tonic-gate * to implement the DDI_CTLOPS_INITCHILD operation. That is, it names 560*0Sstevel@tonic-gate * the children of sun busses based on the reg spec. 561*0Sstevel@tonic-gate * 562*0Sstevel@tonic-gate * Handles the following properties (in make_ddi_ppd): 563*0Sstevel@tonic-gate * Property value 564*0Sstevel@tonic-gate * Name type 565*0Sstevel@tonic-gate * reg register spec 566*0Sstevel@tonic-gate * intr old-form interrupt spec 567*0Sstevel@tonic-gate * interrupts new (bus-oriented) interrupt spec 568*0Sstevel@tonic-gate * ranges range spec 569*0Sstevel@tonic-gate */ 570*0Sstevel@tonic-gate int 571*0Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child) 572*0Sstevel@tonic-gate { 573*0Sstevel@tonic-gate char name[MAXNAMELEN]; 574*0Sstevel@tonic-gate void impl_ddi_sunbus_removechild(dev_info_t *); 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * Name the child, also makes parent private data 578*0Sstevel@tonic-gate */ 579*0Sstevel@tonic-gate (void) impl_sunbus_name_child(child, name, MAXNAMELEN); 580*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate /* 583*0Sstevel@tonic-gate * Attempt to merge a .conf node; if successful, remove the 584*0Sstevel@tonic-gate * .conf node. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && 587*0Sstevel@tonic-gate (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) { 588*0Sstevel@tonic-gate /* 589*0Sstevel@tonic-gate * Return failure to remove node 590*0Sstevel@tonic-gate */ 591*0Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 592*0Sstevel@tonic-gate return (DDI_FAILURE); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate return (DDI_SUCCESS); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate void 598*0Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip) 599*0Sstevel@tonic-gate { 600*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 601*0Sstevel@tonic-gate size_t n; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) == NULL) 604*0Sstevel@tonic-gate return; 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate if ((n = (size_t)pdptr->par_nintr) != 0) 607*0Sstevel@tonic-gate /* 608*0Sstevel@tonic-gate * Note that kmem_free is used here (instead of 609*0Sstevel@tonic-gate * ddi_prop_free) because the contents of the 610*0Sstevel@tonic-gate * property were placed into a separate buffer and 611*0Sstevel@tonic-gate * mucked with a bit before being stored in par_intr. 612*0Sstevel@tonic-gate * The actual return value from the prop lookup 613*0Sstevel@tonic-gate * was freed with ddi_prop_free previously. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate kmem_free(pdptr->par_intr, n * sizeof (struct intrspec)); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate if ((n = (size_t)pdptr->par_nrng) != 0) 618*0Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_rng); 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate if ((n = pdptr->par_nreg) != 0) 621*0Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_reg); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate kmem_free(pdptr, sizeof (*pdptr)); 624*0Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate void 628*0Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip) 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate impl_free_ddi_ppd(dip); 631*0Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 634*0Sstevel@tonic-gate */ 635*0Sstevel@tonic-gate impl_rem_dev_props(dip); 636*0Sstevel@tonic-gate } 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate /* 639*0Sstevel@tonic-gate * DDI Interrupt 640*0Sstevel@tonic-gate */ 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * turn this on to force isa, eisa, and mca device to ignore the new 644*0Sstevel@tonic-gate * hardware nodes in the device tree (normally turned on only for 645*0Sstevel@tonic-gate * drivers that need it by setting the property "ignore-hardware-nodes" 646*0Sstevel@tonic-gate * in their driver.conf file). 647*0Sstevel@tonic-gate * 648*0Sstevel@tonic-gate * 7/31/96 -- Turned off globally. Leaving variable in for the moment 649*0Sstevel@tonic-gate * as safety valve. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate int ignore_hardware_nodes = 0; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate /* 654*0Sstevel@tonic-gate * Local data 655*0Sstevel@tonic-gate */ 656*0Sstevel@tonic-gate static struct impl_bus_promops *impl_busp; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* 660*0Sstevel@tonic-gate * New DDI interrupt framework 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * i_ddi_handle_intr_ops: 665*0Sstevel@tonic-gate */ 666*0Sstevel@tonic-gate int 667*0Sstevel@tonic-gate i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 668*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void * result) 669*0Sstevel@tonic-gate { 670*0Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, op, hdlp, result)); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate /* 674*0Sstevel@tonic-gate * i_ddi_intr_ops: 675*0Sstevel@tonic-gate * 676*0Sstevel@tonic-gate * This is the interrupt operator function wrapper for the bus function 677*0Sstevel@tonic-gate * bus_intr_op. 678*0Sstevel@tonic-gate */ 679*0Sstevel@tonic-gate int 680*0Sstevel@tonic-gate i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 681*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void * result) 682*0Sstevel@tonic-gate { 683*0Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 684*0Sstevel@tonic-gate int ret = DDI_FAILURE; 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* request parent to process this interrupt op */ 687*0Sstevel@tonic-gate if (NEXUS_HAS_INTR_OP(pdip)) 688*0Sstevel@tonic-gate ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_intr_op))( 689*0Sstevel@tonic-gate pdip, rdip, op, hdlp, result); 690*0Sstevel@tonic-gate else 691*0Sstevel@tonic-gate cmn_err(CE_WARN, "Failed to process interrupt " 692*0Sstevel@tonic-gate "for %s%d due to down-rev nexus driver %s%d", 693*0Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 694*0Sstevel@tonic-gate ddi_get_name(pdip), ddi_get_instance(pdip)); 695*0Sstevel@tonic-gate return (ret); 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate /* 699*0Sstevel@tonic-gate * i_ddi_add_softint - allocate and add a soft interrupt to the system 700*0Sstevel@tonic-gate */ 701*0Sstevel@tonic-gate int 702*0Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) 703*0Sstevel@tonic-gate { 704*0Sstevel@tonic-gate int ret; 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate /* add soft interrupt handler */ 707*0Sstevel@tonic-gate ret = add_avsoftintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 708*0Sstevel@tonic-gate DEVI(hdlp->ih_dip)->devi_name, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); 709*0Sstevel@tonic-gate return (ret ? DDI_SUCCESS : DDI_FAILURE); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate void 714*0Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) 715*0Sstevel@tonic-gate { 716*0Sstevel@tonic-gate (void) rem_avsoftintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate extern void (*setsoftint)(int); 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate int 723*0Sstevel@tonic-gate i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp) 724*0Sstevel@tonic-gate { 725*0Sstevel@tonic-gate if (!hdlp->ih_pending) { 726*0Sstevel@tonic-gate update_avsoftintr_args((void *)hdlp, 727*0Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_cb_arg2); 728*0Sstevel@tonic-gate hdlp->ih_pending = 1; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate (*setsoftint)(hdlp->ih_pri); 731*0Sstevel@tonic-gate return (DDI_SUCCESS); 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate /* 735*0Sstevel@tonic-gate * i_ddi_set_softint_pri: 736*0Sstevel@tonic-gate * 737*0Sstevel@tonic-gate * The way this works is that it first tries to add a softint vector 738*0Sstevel@tonic-gate * at the new priority in hdlp. If that succeeds; then it removes the 739*0Sstevel@tonic-gate * existing softint vector at the old priority. 740*0Sstevel@tonic-gate */ 741*0Sstevel@tonic-gate int 742*0Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) 743*0Sstevel@tonic-gate { 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * If a softint is pending at the old priority then fail the request. 746*0Sstevel@tonic-gate * OR 747*0Sstevel@tonic-gate * If we failed to add a softint vector with the new priority; then 748*0Sstevel@tonic-gate * fail the request with a DDI_FAILURE 749*0Sstevel@tonic-gate */ 750*0Sstevel@tonic-gate if (hdlp->ih_pending || i_ddi_add_softint(hdlp) != DDI_SUCCESS) 751*0Sstevel@tonic-gate return (DDI_FAILURE); 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate /* Now, remove the softint at the old priority */ 754*0Sstevel@tonic-gate (void) rem_avsoftintr((void *)hdlp, old_pri, hdlp->ih_cb_func); 755*0Sstevel@tonic-gate return (DDI_SUCCESS); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate /* 759*0Sstevel@tonic-gate * DDI Memory/DMA 760*0Sstevel@tonic-gate */ 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate /* 763*0Sstevel@tonic-gate * Support for allocating DMAable memory to implement 764*0Sstevel@tonic-gate * ddi_dma_mem_alloc(9F) interface. 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate #define KA_ALIGN_SHIFT 7 768*0Sstevel@tonic-gate #define KA_ALIGN (1 << KA_ALIGN_SHIFT) 769*0Sstevel@tonic-gate #define KA_NCACHE (PAGESHIFT + 1 - KA_ALIGN_SHIFT) 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate /* 772*0Sstevel@tonic-gate * Dummy DMA attribute template for kmem_io[].kmem_io_attr. We only 773*0Sstevel@tonic-gate * care about addr_lo, addr_hi, and align. addr_hi will be dynamically set. 774*0Sstevel@tonic-gate */ 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate static ddi_dma_attr_t kmem_io_attr = { 777*0Sstevel@tonic-gate DMA_ATTR_V0, 778*0Sstevel@tonic-gate 0x0000000000000000ULL, /* dma_attr_addr_lo */ 779*0Sstevel@tonic-gate 0x0000000000000000ULL, /* dma_attr_addr_hi */ 780*0Sstevel@tonic-gate 0x00ffffff, 781*0Sstevel@tonic-gate 0x1000, /* dma_attr_align */ 782*0Sstevel@tonic-gate 1, 1, 0xffffffffULL, 0xffffffffULL, 0x1, 1, 0 783*0Sstevel@tonic-gate }; 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* kmem io memory ranges and indices */ 786*0Sstevel@tonic-gate enum { 787*0Sstevel@tonic-gate IO_4P, IO_64G, IO_4G, IO_2G, IO_1G, IO_512M, 788*0Sstevel@tonic-gate IO_256M, IO_128M, IO_64M, IO_32M, IO_16M, MAX_MEM_RANGES 789*0Sstevel@tonic-gate }; 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate static struct { 792*0Sstevel@tonic-gate vmem_t *kmem_io_arena; 793*0Sstevel@tonic-gate kmem_cache_t *kmem_io_cache[KA_NCACHE]; 794*0Sstevel@tonic-gate ddi_dma_attr_t kmem_io_attr; 795*0Sstevel@tonic-gate } kmem_io[MAX_MEM_RANGES]; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate static int kmem_io_idx; /* index of first populated kmem_io[] */ 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate static page_t * 800*0Sstevel@tonic-gate page_create_io_wrapper(void *addr, size_t len, int vmflag, void *arg) 801*0Sstevel@tonic-gate { 802*0Sstevel@tonic-gate extern page_t *page_create_io(vnode_t *, u_offset_t, uint_t, 803*0Sstevel@tonic-gate uint_t, struct as *, caddr_t, ddi_dma_attr_t *); 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate return (page_create_io(&kvp, (u_offset_t)(uintptr_t)addr, len, 806*0Sstevel@tonic-gate PG_EXCL | ((vmflag & VM_NOSLEEP) ? 0 : PG_WAIT), &kas, addr, arg)); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate static void * 810*0Sstevel@tonic-gate segkmem_alloc_io_4P(vmem_t *vmp, size_t size, int vmflag) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 813*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_4P].kmem_io_attr)); 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate static void * 817*0Sstevel@tonic-gate segkmem_alloc_io_64G(vmem_t *vmp, size_t size, int vmflag) 818*0Sstevel@tonic-gate { 819*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 820*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_64G].kmem_io_attr)); 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate static void * 824*0Sstevel@tonic-gate segkmem_alloc_io_4G(vmem_t *vmp, size_t size, int vmflag) 825*0Sstevel@tonic-gate { 826*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 827*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_4G].kmem_io_attr)); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate static void * 831*0Sstevel@tonic-gate segkmem_alloc_io_2G(vmem_t *vmp, size_t size, int vmflag) 832*0Sstevel@tonic-gate { 833*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 834*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_2G].kmem_io_attr)); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate static void * 838*0Sstevel@tonic-gate segkmem_alloc_io_1G(vmem_t *vmp, size_t size, int vmflag) 839*0Sstevel@tonic-gate { 840*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 841*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_1G].kmem_io_attr)); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate static void * 845*0Sstevel@tonic-gate segkmem_alloc_io_512M(vmem_t *vmp, size_t size, int vmflag) 846*0Sstevel@tonic-gate { 847*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 848*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_512M].kmem_io_attr)); 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate static void * 852*0Sstevel@tonic-gate segkmem_alloc_io_256M(vmem_t *vmp, size_t size, int vmflag) 853*0Sstevel@tonic-gate { 854*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 855*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_256M].kmem_io_attr)); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate static void * 859*0Sstevel@tonic-gate segkmem_alloc_io_128M(vmem_t *vmp, size_t size, int vmflag) 860*0Sstevel@tonic-gate { 861*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 862*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_128M].kmem_io_attr)); 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate static void * 866*0Sstevel@tonic-gate segkmem_alloc_io_64M(vmem_t *vmp, size_t size, int vmflag) 867*0Sstevel@tonic-gate { 868*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 869*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_64M].kmem_io_attr)); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate static void * 873*0Sstevel@tonic-gate segkmem_alloc_io_32M(vmem_t *vmp, size_t size, int vmflag) 874*0Sstevel@tonic-gate { 875*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 876*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_32M].kmem_io_attr)); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate static void * 880*0Sstevel@tonic-gate segkmem_alloc_io_16M(vmem_t *vmp, size_t size, int vmflag) 881*0Sstevel@tonic-gate { 882*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, 883*0Sstevel@tonic-gate page_create_io_wrapper, &kmem_io[IO_16M].kmem_io_attr)); 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate struct { 887*0Sstevel@tonic-gate uint64_t io_limit; 888*0Sstevel@tonic-gate char *io_name; 889*0Sstevel@tonic-gate void *(*io_alloc)(vmem_t *, size_t, int); 890*0Sstevel@tonic-gate int io_initial; /* kmem_io_init during startup */ 891*0Sstevel@tonic-gate } io_arena_params[MAX_MEM_RANGES] = { 892*0Sstevel@tonic-gate {0x000fffffffffffffULL, "kmem_io_4P", segkmem_alloc_io_4P, 1}, 893*0Sstevel@tonic-gate {0x0000000fffffffffULL, "kmem_io_64G", segkmem_alloc_io_64G, 0}, 894*0Sstevel@tonic-gate {0x00000000ffffffffULL, "kmem_io_4G", segkmem_alloc_io_4G, 1}, 895*0Sstevel@tonic-gate {0x000000007fffffffULL, "kmem_io_2G", segkmem_alloc_io_2G, 1}, 896*0Sstevel@tonic-gate {0x000000003fffffffULL, "kmem_io_1G", segkmem_alloc_io_1G, 0}, 897*0Sstevel@tonic-gate {0x000000001fffffffULL, "kmem_io_512M", segkmem_alloc_io_512M, 0}, 898*0Sstevel@tonic-gate {0x000000000fffffffULL, "kmem_io_256M", segkmem_alloc_io_256M, 0}, 899*0Sstevel@tonic-gate {0x0000000007ffffffULL, "kmem_io_128M", segkmem_alloc_io_128M, 0}, 900*0Sstevel@tonic-gate {0x0000000003ffffffULL, "kmem_io_64M", segkmem_alloc_io_64M, 0}, 901*0Sstevel@tonic-gate {0x0000000001ffffffULL, "kmem_io_32M", segkmem_alloc_io_32M, 0}, 902*0Sstevel@tonic-gate {0x0000000000ffffffULL, "kmem_io_16M", segkmem_alloc_io_16M, 1} 903*0Sstevel@tonic-gate }; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate void 906*0Sstevel@tonic-gate kmem_io_init(int a) 907*0Sstevel@tonic-gate { 908*0Sstevel@tonic-gate int c; 909*0Sstevel@tonic-gate char name[40]; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate kmem_io[a].kmem_io_arena = vmem_create(io_arena_params[a].io_name, 912*0Sstevel@tonic-gate NULL, 0, PAGESIZE, io_arena_params[a].io_alloc, 913*0Sstevel@tonic-gate segkmem_free, heap_arena, 0, VM_SLEEP); 914*0Sstevel@tonic-gate for (c = 0; c < KA_NCACHE; c++) { 915*0Sstevel@tonic-gate size_t size = KA_ALIGN << c; 916*0Sstevel@tonic-gate (void) sprintf(name, "%s_%lu", 917*0Sstevel@tonic-gate io_arena_params[a].io_name, size); 918*0Sstevel@tonic-gate kmem_io[a].kmem_io_cache[c] = kmem_cache_create(name, 919*0Sstevel@tonic-gate size, size, NULL, NULL, NULL, NULL, 920*0Sstevel@tonic-gate kmem_io[a].kmem_io_arena, 0); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate /* 925*0Sstevel@tonic-gate * Return the index of the highest memory range for addr. 926*0Sstevel@tonic-gate */ 927*0Sstevel@tonic-gate static int 928*0Sstevel@tonic-gate kmem_io_index(uint64_t addr) 929*0Sstevel@tonic-gate { 930*0Sstevel@tonic-gate int n; 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate for (n = kmem_io_idx; n < MAX_MEM_RANGES; n++) { 933*0Sstevel@tonic-gate if (kmem_io[n].kmem_io_attr.dma_attr_addr_hi <= addr) { 934*0Sstevel@tonic-gate if (kmem_io[n].kmem_io_arena == NULL) 935*0Sstevel@tonic-gate kmem_io_init(n); 936*0Sstevel@tonic-gate return (n); 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate panic("kmem_io_index: invalid addr - must be at least 16m"); 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate /*NOTREACHED*/ 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate /* 945*0Sstevel@tonic-gate * Return the index of the next kmem_io populated memory range 946*0Sstevel@tonic-gate * after curindex. 947*0Sstevel@tonic-gate */ 948*0Sstevel@tonic-gate static int 949*0Sstevel@tonic-gate kmem_io_index_next(int curindex) 950*0Sstevel@tonic-gate { 951*0Sstevel@tonic-gate int n; 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate for (n = curindex + 1; n < MAX_MEM_RANGES; n++) { 954*0Sstevel@tonic-gate if (kmem_io[n].kmem_io_arena) 955*0Sstevel@tonic-gate return (n); 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate return (-1); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate void 961*0Sstevel@tonic-gate ka_init(void) 962*0Sstevel@tonic-gate { 963*0Sstevel@tonic-gate int a; 964*0Sstevel@tonic-gate extern pfn_t physmax; 965*0Sstevel@tonic-gate uint64_t maxphysaddr = mmu_ptob((uint64_t)physmax + 1) - 1; 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate ASSERT(maxphysaddr <= io_arena_params[0].io_limit); 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate for (a = 0; a < MAX_MEM_RANGES; a++) { 970*0Sstevel@tonic-gate if (maxphysaddr >= io_arena_params[a + 1].io_limit) { 971*0Sstevel@tonic-gate if (maxphysaddr > io_arena_params[a + 1].io_limit) 972*0Sstevel@tonic-gate io_arena_params[a].io_limit = maxphysaddr; 973*0Sstevel@tonic-gate else 974*0Sstevel@tonic-gate a++; 975*0Sstevel@tonic-gate break; 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate kmem_io_idx = a; 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate for (; a < MAX_MEM_RANGES; a++) { 981*0Sstevel@tonic-gate kmem_io[a].kmem_io_attr = kmem_io_attr; 982*0Sstevel@tonic-gate kmem_io[a].kmem_io_attr.dma_attr_addr_hi = 983*0Sstevel@tonic-gate io_arena_params[a].io_limit; 984*0Sstevel@tonic-gate /* 985*0Sstevel@tonic-gate * initialize kmem_io[] arena/cache corresponding to 986*0Sstevel@tonic-gate * maxphysaddr and to the "common" io memory ranges that 987*0Sstevel@tonic-gate * have io_initial set to a non-zero value. 988*0Sstevel@tonic-gate */ 989*0Sstevel@tonic-gate if (io_arena_params[a].io_initial || a == kmem_io_idx) 990*0Sstevel@tonic-gate kmem_io_init(a); 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate } 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate /* 995*0Sstevel@tonic-gate * put contig address/size 996*0Sstevel@tonic-gate */ 997*0Sstevel@tonic-gate static void * 998*0Sstevel@tonic-gate putctgas(void *addr, size_t size) 999*0Sstevel@tonic-gate { 1000*0Sstevel@tonic-gate struct ctgas *ctgp = &ctglist; 1001*0Sstevel@tonic-gate int i; 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate CTGLOCK(); 1004*0Sstevel@tonic-gate do { 1005*0Sstevel@tonic-gate if ((i = ctgp->ctg_index) < CTGENTRIES) { 1006*0Sstevel@tonic-gate ctgp->ctg_addr[i] = addr; 1007*0Sstevel@tonic-gate ctgp->ctg_size[i] = size; 1008*0Sstevel@tonic-gate ctgp->ctg_index++; 1009*0Sstevel@tonic-gate break; 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate if (!ctgp->ctg_next) 1012*0Sstevel@tonic-gate ctgp->ctg_next = kmem_zalloc(sizeof (struct ctgas), 1013*0Sstevel@tonic-gate KM_NOSLEEP); 1014*0Sstevel@tonic-gate ctgp = ctgp->ctg_next; 1015*0Sstevel@tonic-gate } while (ctgp); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate CTGUNLOCK(); 1018*0Sstevel@tonic-gate return (ctgp); 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate /* 1022*0Sstevel@tonic-gate * get contig size by addr 1023*0Sstevel@tonic-gate */ 1024*0Sstevel@tonic-gate static size_t 1025*0Sstevel@tonic-gate getctgsz(void *addr) 1026*0Sstevel@tonic-gate { 1027*0Sstevel@tonic-gate struct ctgas *ctgp = &ctglist; 1028*0Sstevel@tonic-gate int i, j; 1029*0Sstevel@tonic-gate size_t sz; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate ASSERT(addr); 1032*0Sstevel@tonic-gate CTGLOCK(); 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate while (ctgp) { 1035*0Sstevel@tonic-gate for (i = 0; i < ctgp->ctg_index; i++) { 1036*0Sstevel@tonic-gate if (addr != ctgp->ctg_addr[i]) 1037*0Sstevel@tonic-gate continue; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate sz = ctgp->ctg_size[i]; 1040*0Sstevel@tonic-gate j = --ctgp->ctg_index; 1041*0Sstevel@tonic-gate if (i != j) { 1042*0Sstevel@tonic-gate ctgp->ctg_size[i] = ctgp->ctg_size[j]; 1043*0Sstevel@tonic-gate ctgp->ctg_addr[i] = ctgp->ctg_addr[j]; 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate CTGUNLOCK(); 1046*0Sstevel@tonic-gate return (sz); 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate ctgp = ctgp->ctg_next; 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate CTGUNLOCK(); 1052*0Sstevel@tonic-gate return (0); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate /* 1056*0Sstevel@tonic-gate * contig_alloc: 1057*0Sstevel@tonic-gate * 1058*0Sstevel@tonic-gate * allocates contiguous memory to satisfy the 'size' and dma attributes 1059*0Sstevel@tonic-gate * specified in 'attr'. 1060*0Sstevel@tonic-gate * 1061*0Sstevel@tonic-gate * Not all of memory need to be physically contiguous if the 1062*0Sstevel@tonic-gate * scatter-gather list length is greater than 1. 1063*0Sstevel@tonic-gate */ 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate /*ARGSUSED*/ 1066*0Sstevel@tonic-gate void * 1067*0Sstevel@tonic-gate contig_alloc(size_t size, ddi_dma_attr_t *attr, uintptr_t align, int cansleep) 1068*0Sstevel@tonic-gate { 1069*0Sstevel@tonic-gate pgcnt_t pgcnt = btopr(size); 1070*0Sstevel@tonic-gate size_t asize = pgcnt * PAGESIZE; 1071*0Sstevel@tonic-gate page_t *ppl; 1072*0Sstevel@tonic-gate int pflag; 1073*0Sstevel@tonic-gate void *addr; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate extern page_t *page_create_io(vnode_t *, u_offset_t, uint_t, 1076*0Sstevel@tonic-gate uint_t, struct as *, caddr_t, ddi_dma_attr_t *); 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate /* segkmem_xalloc */ 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate if (align <= PAGESIZE) 1081*0Sstevel@tonic-gate addr = vmem_alloc(heap_arena, asize, 1082*0Sstevel@tonic-gate (cansleep) ? VM_SLEEP : VM_NOSLEEP); 1083*0Sstevel@tonic-gate else 1084*0Sstevel@tonic-gate addr = vmem_xalloc(heap_arena, asize, align, 0, 0, NULL, NULL, 1085*0Sstevel@tonic-gate (cansleep) ? VM_SLEEP : VM_NOSLEEP); 1086*0Sstevel@tonic-gate if (addr) { 1087*0Sstevel@tonic-gate ASSERT(!((uintptr_t)addr & (align - 1))); 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate if (page_resv(pgcnt, 1090*0Sstevel@tonic-gate (cansleep) ? KM_SLEEP : KM_NOSLEEP) == 0) { 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate vmem_free(heap_arena, addr, asize); 1093*0Sstevel@tonic-gate return (NULL); 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate pflag = PG_EXCL; 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate if (cansleep) 1098*0Sstevel@tonic-gate pflag |= PG_WAIT; 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate /* 4k req gets from freelists rather than pfn search */ 1101*0Sstevel@tonic-gate if (pgcnt > 1 || align > PAGESIZE) 1102*0Sstevel@tonic-gate pflag |= PG_PHYSCONTIG; 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate ppl = page_create_io(&kvp, (u_offset_t)(uintptr_t)addr, 1105*0Sstevel@tonic-gate asize, pflag, &kas, (caddr_t)addr, attr); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate if (!ppl) { 1108*0Sstevel@tonic-gate vmem_free(heap_arena, addr, asize); 1109*0Sstevel@tonic-gate page_unresv(pgcnt); 1110*0Sstevel@tonic-gate return (NULL); 1111*0Sstevel@tonic-gate } 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gate while (ppl != NULL) { 1114*0Sstevel@tonic-gate page_t *pp = ppl; 1115*0Sstevel@tonic-gate page_sub(&ppl, pp); 1116*0Sstevel@tonic-gate ASSERT(page_iolock_assert(pp)); 1117*0Sstevel@tonic-gate page_io_unlock(pp); 1118*0Sstevel@tonic-gate page_downgrade(pp); 1119*0Sstevel@tonic-gate hat_memload(kas.a_hat, (caddr_t)(uintptr_t)pp->p_offset, 1120*0Sstevel@tonic-gate pp, (PROT_ALL & ~PROT_USER) | 1121*0Sstevel@tonic-gate HAT_NOSYNC, HAT_LOAD_LOCK); 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate } 1124*0Sstevel@tonic-gate return (addr); 1125*0Sstevel@tonic-gate } 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate static void 1128*0Sstevel@tonic-gate contig_free(void *addr, size_t size) 1129*0Sstevel@tonic-gate { 1130*0Sstevel@tonic-gate pgcnt_t pgcnt = btopr(size); 1131*0Sstevel@tonic-gate size_t asize = pgcnt * PAGESIZE; 1132*0Sstevel@tonic-gate caddr_t a, ea; 1133*0Sstevel@tonic-gate page_t *pp; 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate hat_unload(kas.a_hat, addr, asize, HAT_UNLOAD_UNLOCK); 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate for (a = addr, ea = a + asize; a < ea; a += PAGESIZE) { 1138*0Sstevel@tonic-gate pp = page_find(&kvp, 1139*0Sstevel@tonic-gate (u_offset_t)(uintptr_t)a); 1140*0Sstevel@tonic-gate if (!pp) 1141*0Sstevel@tonic-gate panic("contig_free: contig pp not found"); 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate if (!page_tryupgrade(pp)) { 1144*0Sstevel@tonic-gate page_unlock(pp); 1145*0Sstevel@tonic-gate pp = page_lookup(&kvp, 1146*0Sstevel@tonic-gate (u_offset_t)(uintptr_t)a, SE_EXCL); 1147*0Sstevel@tonic-gate if (pp == NULL) 1148*0Sstevel@tonic-gate panic("contig_free: page freed"); 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate page_destroy(pp, 0); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate page_unresv(pgcnt); 1154*0Sstevel@tonic-gate vmem_free(heap_arena, addr, asize); 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate /* 1158*0Sstevel@tonic-gate * Allocate from the system, aligned on a specific boundary. 1159*0Sstevel@tonic-gate * The alignment, if non-zero, must be a power of 2. 1160*0Sstevel@tonic-gate */ 1161*0Sstevel@tonic-gate static void * 1162*0Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, int physcontig, 1163*0Sstevel@tonic-gate ddi_dma_attr_t *attr) 1164*0Sstevel@tonic-gate { 1165*0Sstevel@tonic-gate size_t *addr, *raddr, rsize; 1166*0Sstevel@tonic-gate size_t hdrsize = 4 * sizeof (size_t); /* must be power of 2 */ 1167*0Sstevel@tonic-gate int a, i, c; 1168*0Sstevel@tonic-gate vmem_t *vmp; 1169*0Sstevel@tonic-gate kmem_cache_t *cp = NULL; 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate align = MAX(align, hdrsize); 1172*0Sstevel@tonic-gate ASSERT((align & (align - 1)) == 0); 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate /* 1175*0Sstevel@tonic-gate * All of our allocators guarantee 16-byte alignment, so we don't 1176*0Sstevel@tonic-gate * need to reserve additional space for the header. 1177*0Sstevel@tonic-gate * To simplify picking the correct kmem_io_cache, we round up to 1178*0Sstevel@tonic-gate * a multiple of KA_ALIGN. 1179*0Sstevel@tonic-gate */ 1180*0Sstevel@tonic-gate rsize = P2ROUNDUP_TYPED(size + align, KA_ALIGN, size_t); 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate if (physcontig && rsize > PAGESIZE) { 1183*0Sstevel@tonic-gate if (addr = contig_alloc(size, attr, align, cansleep)) { 1184*0Sstevel@tonic-gate if (!putctgas(addr, size)) 1185*0Sstevel@tonic-gate contig_free(addr, size); 1186*0Sstevel@tonic-gate else 1187*0Sstevel@tonic-gate return (addr); 1188*0Sstevel@tonic-gate } 1189*0Sstevel@tonic-gate return (NULL); 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate ASSERT(attr->dma_attr_addr_lo <= mmu_ptob((uint64_t)ddiphysmin)); 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate a = kmem_io_index(attr->dma_attr_addr_hi); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate if (rsize > PAGESIZE) { 1197*0Sstevel@tonic-gate vmp = kmem_io[a].kmem_io_arena; 1198*0Sstevel@tonic-gate raddr = vmem_alloc(vmp, rsize, 1199*0Sstevel@tonic-gate (cansleep) ? VM_SLEEP : VM_NOSLEEP); 1200*0Sstevel@tonic-gate } else { 1201*0Sstevel@tonic-gate c = highbit((rsize >> KA_ALIGN_SHIFT) - 1); 1202*0Sstevel@tonic-gate cp = kmem_io[a].kmem_io_cache[c]; 1203*0Sstevel@tonic-gate raddr = kmem_cache_alloc(cp, (cansleep) ? KM_SLEEP : 1204*0Sstevel@tonic-gate KM_NOSLEEP); 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate if (raddr == NULL) { 1208*0Sstevel@tonic-gate int na; 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate ASSERT(cansleep == 0); 1211*0Sstevel@tonic-gate if (rsize > PAGESIZE) 1212*0Sstevel@tonic-gate return (NULL); 1213*0Sstevel@tonic-gate /* 1214*0Sstevel@tonic-gate * System does not have memory in the requested range. 1215*0Sstevel@tonic-gate * Try smaller kmem io ranges and larger cache sizes 1216*0Sstevel@tonic-gate * to see if there might be memory available in 1217*0Sstevel@tonic-gate * these other caches. 1218*0Sstevel@tonic-gate */ 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate for (na = kmem_io_index_next(a); na >= 0; 1221*0Sstevel@tonic-gate na = kmem_io_index_next(na)) { 1222*0Sstevel@tonic-gate ASSERT(kmem_io[na].kmem_io_arena); 1223*0Sstevel@tonic-gate cp = kmem_io[na].kmem_io_cache[c]; 1224*0Sstevel@tonic-gate raddr = kmem_cache_alloc(cp, KM_NOSLEEP); 1225*0Sstevel@tonic-gate if (raddr) 1226*0Sstevel@tonic-gate goto kallocdone; 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate /* now try the larger kmem io cache sizes */ 1229*0Sstevel@tonic-gate for (na = a; na >= 0; na = kmem_io_index_next(na)) { 1230*0Sstevel@tonic-gate for (i = c + 1; i < KA_NCACHE; i++) { 1231*0Sstevel@tonic-gate cp = kmem_io[na].kmem_io_cache[i]; 1232*0Sstevel@tonic-gate raddr = kmem_cache_alloc(cp, KM_NOSLEEP); 1233*0Sstevel@tonic-gate if (raddr) 1234*0Sstevel@tonic-gate goto kallocdone; 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate } 1237*0Sstevel@tonic-gate return (NULL); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate kallocdone: 1241*0Sstevel@tonic-gate ASSERT(!P2CROSS((uintptr_t)raddr, (uintptr_t)raddr + rsize - 1, 1242*0Sstevel@tonic-gate PAGESIZE) || rsize > PAGESIZE); 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align); 1245*0Sstevel@tonic-gate ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize); 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate addr[-4] = (size_t)cp; 1248*0Sstevel@tonic-gate addr[-3] = (size_t)vmp; 1249*0Sstevel@tonic-gate addr[-2] = (size_t)raddr; 1250*0Sstevel@tonic-gate addr[-1] = rsize; 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate return (addr); 1253*0Sstevel@tonic-gate } 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate static void 1256*0Sstevel@tonic-gate kfreea(void *addr) 1257*0Sstevel@tonic-gate { 1258*0Sstevel@tonic-gate size_t size; 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate if (!((uintptr_t)addr & PAGEOFFSET) && (size = getctgsz(addr))) { 1261*0Sstevel@tonic-gate contig_free(addr, size); 1262*0Sstevel@tonic-gate } else { 1263*0Sstevel@tonic-gate size_t *saddr = addr; 1264*0Sstevel@tonic-gate if (saddr[-4] == 0) 1265*0Sstevel@tonic-gate vmem_free((vmem_t *)saddr[-3], (void *)saddr[-2], 1266*0Sstevel@tonic-gate saddr[-1]); 1267*0Sstevel@tonic-gate else 1268*0Sstevel@tonic-gate kmem_cache_free((kmem_cache_t *)saddr[-4], 1269*0Sstevel@tonic-gate (void *)saddr[-2]); 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate } 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate /* 1274*0Sstevel@tonic-gate * This should actually be called i_ddi_dma_mem_alloc. There should 1275*0Sstevel@tonic-gate * also be an i_ddi_pio_mem_alloc. i_ddi_dma_mem_alloc should call 1276*0Sstevel@tonic-gate * through the device tree with the DDI_CTLOPS_DMA_ALIGN ctl ops to 1277*0Sstevel@tonic-gate * get alignment requirements for DMA memory. i_ddi_pio_mem_alloc 1278*0Sstevel@tonic-gate * should use DDI_CTLOPS_PIO_ALIGN. Since we only have i_ddi_mem_alloc 1279*0Sstevel@tonic-gate * so far which is used for both, DMA and PIO, we have to use the DMA 1280*0Sstevel@tonic-gate * ctl ops to make everybody happy. 1281*0Sstevel@tonic-gate */ 1282*0Sstevel@tonic-gate /*ARGSUSED*/ 1283*0Sstevel@tonic-gate int 1284*0Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr, 1285*0Sstevel@tonic-gate size_t length, int cansleep, int streaming, 1286*0Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp, 1287*0Sstevel@tonic-gate size_t *real_length, ddi_acc_hdl_t *ap) 1288*0Sstevel@tonic-gate { 1289*0Sstevel@tonic-gate caddr_t a; 1290*0Sstevel@tonic-gate int iomin; 1291*0Sstevel@tonic-gate ddi_acc_impl_t *iap; 1292*0Sstevel@tonic-gate int physcontig = 0; 1293*0Sstevel@tonic-gate pgcnt_t npages; 1294*0Sstevel@tonic-gate pgcnt_t minctg; 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate /* 1297*0Sstevel@tonic-gate * Check legality of arguments 1298*0Sstevel@tonic-gate */ 1299*0Sstevel@tonic-gate if (length == 0 || kaddrp == NULL || attr == NULL) { 1300*0Sstevel@tonic-gate return (DDI_FAILURE); 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 || 1303*0Sstevel@tonic-gate (attr->dma_attr_align & (attr->dma_attr_align - 1)) || 1304*0Sstevel@tonic-gate (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) { 1305*0Sstevel@tonic-gate return (DDI_FAILURE); 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate /* 1309*0Sstevel@tonic-gate * figure out most restrictive alignment requirement 1310*0Sstevel@tonic-gate */ 1311*0Sstevel@tonic-gate iomin = attr->dma_attr_minxfer; 1312*0Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_align); 1313*0Sstevel@tonic-gate if (iomin == 0) 1314*0Sstevel@tonic-gate return (DDI_FAILURE); 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate ASSERT((iomin & (iomin - 1)) == 0); 1317*0Sstevel@tonic-gate 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate /* 1320*0Sstevel@tonic-gate * Determine if we need to satisfy the request for physically 1321*0Sstevel@tonic-gate * contiguous memory or alignments larger than pagesize. 1322*0Sstevel@tonic-gate */ 1323*0Sstevel@tonic-gate npages = btopr(length + attr->dma_attr_align); 1324*0Sstevel@tonic-gate minctg = howmany(npages, attr->dma_attr_sgllen); 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate if (minctg > 1) { 1327*0Sstevel@tonic-gate uint64_t pfnseg = attr->dma_attr_seg >> PAGESHIFT; 1328*0Sstevel@tonic-gate /* 1329*0Sstevel@tonic-gate * verify that the minimum contig requirement for the 1330*0Sstevel@tonic-gate * actual length does not cross segment boundary. 1331*0Sstevel@tonic-gate */ 1332*0Sstevel@tonic-gate length = P2ROUNDUP_TYPED(length, attr->dma_attr_minxfer, 1333*0Sstevel@tonic-gate size_t); 1334*0Sstevel@tonic-gate npages = btopr(length); 1335*0Sstevel@tonic-gate minctg = howmany(npages, attr->dma_attr_sgllen); 1336*0Sstevel@tonic-gate if (minctg > pfnseg + 1) 1337*0Sstevel@tonic-gate return (DDI_FAILURE); 1338*0Sstevel@tonic-gate physcontig = 1; 1339*0Sstevel@tonic-gate } else { 1340*0Sstevel@tonic-gate length = P2ROUNDUP_TYPED(length, iomin, size_t); 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate /* 1344*0Sstevel@tonic-gate * Allocate the requested amount from the system. 1345*0Sstevel@tonic-gate */ 1346*0Sstevel@tonic-gate a = kalloca(length, iomin, cansleep, physcontig, attr); 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate if ((*kaddrp = a) == NULL) 1349*0Sstevel@tonic-gate return (DDI_FAILURE); 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate if (real_length) { 1352*0Sstevel@tonic-gate *real_length = length; 1353*0Sstevel@tonic-gate } 1354*0Sstevel@tonic-gate if (ap) { 1355*0Sstevel@tonic-gate /* 1356*0Sstevel@tonic-gate * initialize access handle 1357*0Sstevel@tonic-gate */ 1358*0Sstevel@tonic-gate iap = (ddi_acc_impl_t *)ap->ah_platform_private; 1359*0Sstevel@tonic-gate iap->ahi_acc_attr |= DDI_ACCATTR_CPU_VADDR; 1360*0Sstevel@tonic-gate impl_acc_hdl_init(ap); 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate return (DDI_SUCCESS); 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate /* 1366*0Sstevel@tonic-gate * covert old DMA limits structure to DMA attribute structure 1367*0Sstevel@tonic-gate * and continue 1368*0Sstevel@tonic-gate */ 1369*0Sstevel@tonic-gate int 1370*0Sstevel@tonic-gate i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits, 1371*0Sstevel@tonic-gate size_t length, int cansleep, int streaming, 1372*0Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp, 1373*0Sstevel@tonic-gate uint_t *real_length, ddi_acc_hdl_t *ap) 1374*0Sstevel@tonic-gate { 1375*0Sstevel@tonic-gate ddi_dma_attr_t dma_attr, *attrp; 1376*0Sstevel@tonic-gate size_t rlen; 1377*0Sstevel@tonic-gate int ret; 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate if (limits == NULL) { 1380*0Sstevel@tonic-gate return (DDI_FAILURE); 1381*0Sstevel@tonic-gate } 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate /* 1384*0Sstevel@tonic-gate * set up DMA attribute structure to pass to i_ddi_mem_alloc() 1385*0Sstevel@tonic-gate */ 1386*0Sstevel@tonic-gate attrp = &dma_attr; 1387*0Sstevel@tonic-gate attrp->dma_attr_version = DMA_ATTR_V0; 1388*0Sstevel@tonic-gate attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo; 1389*0Sstevel@tonic-gate attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi; 1390*0Sstevel@tonic-gate attrp->dma_attr_count_max = (uint64_t)limits->dlim_ctreg_max; 1391*0Sstevel@tonic-gate attrp->dma_attr_align = 1; 1392*0Sstevel@tonic-gate attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes; 1393*0Sstevel@tonic-gate attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer; 1394*0Sstevel@tonic-gate attrp->dma_attr_maxxfer = (uint64_t)limits->dlim_reqsize; 1395*0Sstevel@tonic-gate attrp->dma_attr_seg = (uint64_t)limits->dlim_adreg_max; 1396*0Sstevel@tonic-gate attrp->dma_attr_sgllen = limits->dlim_sgllen; 1397*0Sstevel@tonic-gate attrp->dma_attr_granular = (uint32_t)limits->dlim_granular; 1398*0Sstevel@tonic-gate attrp->dma_attr_flags = 0; 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming, 1401*0Sstevel@tonic-gate accattrp, kaddrp, &rlen, ap); 1402*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 1403*0Sstevel@tonic-gate if (real_length) 1404*0Sstevel@tonic-gate *real_length = (uint_t)rlen; 1405*0Sstevel@tonic-gate } 1406*0Sstevel@tonic-gate return (ret); 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate /* ARGSUSED */ 1410*0Sstevel@tonic-gate void 1411*0Sstevel@tonic-gate i_ddi_mem_free(caddr_t kaddr, int stream) 1412*0Sstevel@tonic-gate { 1413*0Sstevel@tonic-gate kfreea(kaddr); 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate /* 1417*0Sstevel@tonic-gate * Access Barriers 1418*0Sstevel@tonic-gate * 1419*0Sstevel@tonic-gate */ 1420*0Sstevel@tonic-gate /*ARGSUSED*/ 1421*0Sstevel@tonic-gate int 1422*0Sstevel@tonic-gate i_ddi_ontrap(ddi_acc_handle_t hp) 1423*0Sstevel@tonic-gate { 1424*0Sstevel@tonic-gate return (DDI_FAILURE); 1425*0Sstevel@tonic-gate } 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate /*ARGSUSED*/ 1428*0Sstevel@tonic-gate void 1429*0Sstevel@tonic-gate i_ddi_notrap(ddi_acc_handle_t hp) 1430*0Sstevel@tonic-gate { 1431*0Sstevel@tonic-gate } 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate /* 1435*0Sstevel@tonic-gate * Misc Functions 1436*0Sstevel@tonic-gate */ 1437*0Sstevel@tonic-gate 1438*0Sstevel@tonic-gate /* 1439*0Sstevel@tonic-gate * Implementation instance override functions 1440*0Sstevel@tonic-gate * 1441*0Sstevel@tonic-gate * No override on i86pc 1442*0Sstevel@tonic-gate */ 1443*0Sstevel@tonic-gate /*ARGSUSED*/ 1444*0Sstevel@tonic-gate uint_t 1445*0Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip) 1446*0Sstevel@tonic-gate { 1447*0Sstevel@tonic-gate return ((uint_t)-1); 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate /*ARGSUSED*/ 1451*0Sstevel@tonic-gate int 1452*0Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip) 1453*0Sstevel@tonic-gate { 1454*0Sstevel@tonic-gate return (DDI_FAILURE); 1455*0Sstevel@tonic-gate } 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate /*ARGSUSED*/ 1458*0Sstevel@tonic-gate int 1459*0Sstevel@tonic-gate impl_free_instance(dev_info_t *dip) 1460*0Sstevel@tonic-gate { 1461*0Sstevel@tonic-gate return (DDI_FAILURE); 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate /*ARGSUSED*/ 1465*0Sstevel@tonic-gate int 1466*0Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi) 1467*0Sstevel@tonic-gate { 1468*0Sstevel@tonic-gate return (DDI_SUCCESS); 1469*0Sstevel@tonic-gate } 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate /* 1472*0Sstevel@tonic-gate * Referenced in common/cpr_driver.c: Power off machine. 1473*0Sstevel@tonic-gate * Don't know how to power off i86pc. 1474*0Sstevel@tonic-gate */ 1475*0Sstevel@tonic-gate void 1476*0Sstevel@tonic-gate arch_power_down() 1477*0Sstevel@tonic-gate {} 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate /* 1480*0Sstevel@tonic-gate * Copy name to property_name, since name 1481*0Sstevel@tonic-gate * is in the low address range below kernelbase. 1482*0Sstevel@tonic-gate */ 1483*0Sstevel@tonic-gate static void 1484*0Sstevel@tonic-gate copy_boot_str(const char *boot_str, char *kern_str, int len) 1485*0Sstevel@tonic-gate { 1486*0Sstevel@tonic-gate int i = 0; 1487*0Sstevel@tonic-gate 1488*0Sstevel@tonic-gate while (i < len - 1 && boot_str[i] != '\0') { 1489*0Sstevel@tonic-gate kern_str[i] = boot_str[i]; 1490*0Sstevel@tonic-gate i++; 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate kern_str[i] = 0; /* null terminate */ 1494*0Sstevel@tonic-gate if (boot_str[i] != '\0') 1495*0Sstevel@tonic-gate cmn_err(CE_WARN, 1496*0Sstevel@tonic-gate "boot property string is truncated to %s", kern_str); 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate static void 1500*0Sstevel@tonic-gate get_boot_properties(void) 1501*0Sstevel@tonic-gate { 1502*0Sstevel@tonic-gate extern char hw_provider[]; 1503*0Sstevel@tonic-gate dev_info_t *devi; 1504*0Sstevel@tonic-gate char *name; 1505*0Sstevel@tonic-gate int length; 1506*0Sstevel@tonic-gate char property_name[50], property_val[50]; 1507*0Sstevel@tonic-gate void *bop_staging_area; 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate bop_staging_area = kmem_zalloc(MMU_PAGESIZE, KM_NOSLEEP); 1510*0Sstevel@tonic-gate 1511*0Sstevel@tonic-gate /* 1512*0Sstevel@tonic-gate * Import "root" properties from the boot. 1513*0Sstevel@tonic-gate * 1514*0Sstevel@tonic-gate * We do this by invoking BOP_NEXTPROP until the list 1515*0Sstevel@tonic-gate * is completely copied in. 1516*0Sstevel@tonic-gate */ 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate devi = ddi_root_node(); 1519*0Sstevel@tonic-gate for (name = BOP_NEXTPROP(bootops, ""); /* get first */ 1520*0Sstevel@tonic-gate name; /* NULL => DONE */ 1521*0Sstevel@tonic-gate name = BOP_NEXTPROP(bootops, name)) { /* get next */ 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate /* copy string to memory above kernelbase */ 1524*0Sstevel@tonic-gate copy_boot_str(name, property_name, 50); 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate /* 1527*0Sstevel@tonic-gate * Skip vga properties. They will be picked up later 1528*0Sstevel@tonic-gate * by get_vga_properties. 1529*0Sstevel@tonic-gate */ 1530*0Sstevel@tonic-gate if (strcmp(property_name, "display-edif-block") == 0 || 1531*0Sstevel@tonic-gate strcmp(property_name, "display-edif-id") == 0) { 1532*0Sstevel@tonic-gate continue; 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate length = BOP_GETPROPLEN(bootops, property_name); 1536*0Sstevel@tonic-gate if (length == 0) 1537*0Sstevel@tonic-gate continue; 1538*0Sstevel@tonic-gate if (length > MMU_PAGESIZE) { 1539*0Sstevel@tonic-gate cmn_err(CE_NOTE, 1540*0Sstevel@tonic-gate "boot property %s longer than 0x%x, ignored\n", 1541*0Sstevel@tonic-gate property_name, MMU_PAGESIZE); 1542*0Sstevel@tonic-gate continue; 1543*0Sstevel@tonic-gate } 1544*0Sstevel@tonic-gate BOP_GETPROP(bootops, property_name, bop_staging_area); 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate /* 1547*0Sstevel@tonic-gate * special properties: 1548*0Sstevel@tonic-gate * si-machine, si-hw-provider 1549*0Sstevel@tonic-gate * goes to kernel data structures. 1550*0Sstevel@tonic-gate * bios-boot-device and stdout 1551*0Sstevel@tonic-gate * goes to hardware property list so it may show up 1552*0Sstevel@tonic-gate * in the prtconf -vp output. This is needed by 1553*0Sstevel@tonic-gate * Install/Upgrade. Once we fix install upgrade, 1554*0Sstevel@tonic-gate * this can be taken out. 1555*0Sstevel@tonic-gate */ 1556*0Sstevel@tonic-gate if (strcmp(name, "si-machine") == 0) { 1557*0Sstevel@tonic-gate (void) strncpy(utsname.machine, bop_staging_area, 1558*0Sstevel@tonic-gate SYS_NMLN); 1559*0Sstevel@tonic-gate utsname.machine[SYS_NMLN - 1] = (char)NULL; 1560*0Sstevel@tonic-gate } else if (strcmp(name, "si-hw-provider") == 0) { 1561*0Sstevel@tonic-gate (void) strncpy(hw_provider, bop_staging_area, SYS_NMLN); 1562*0Sstevel@tonic-gate hw_provider[SYS_NMLN - 1] = (char)NULL; 1563*0Sstevel@tonic-gate } else if (strcmp(name, "bios-boot-device") == 0) { 1564*0Sstevel@tonic-gate copy_boot_str(bop_staging_area, property_val, 50); 1565*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, devi, 1566*0Sstevel@tonic-gate property_name, property_val); 1567*0Sstevel@tonic-gate } else if (strcmp(name, "stdout") == 0) { 1568*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, 1569*0Sstevel@tonic-gate property_name, *((int *)bop_staging_area)); 1570*0Sstevel@tonic-gate } else { 1571*0Sstevel@tonic-gate /* Property type unknown, use old prop interface */ 1572*0Sstevel@tonic-gate (void) e_ddi_prop_create(DDI_DEV_T_NONE, devi, 1573*0Sstevel@tonic-gate DDI_PROP_CANSLEEP, property_name, bop_staging_area, 1574*0Sstevel@tonic-gate length); 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate kmem_free(bop_staging_area, MMU_PAGESIZE); 1579*0Sstevel@tonic-gate } 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate static void 1582*0Sstevel@tonic-gate get_vga_properties(void) 1583*0Sstevel@tonic-gate { 1584*0Sstevel@tonic-gate dev_info_t *devi; 1585*0Sstevel@tonic-gate major_t major; 1586*0Sstevel@tonic-gate char *name; 1587*0Sstevel@tonic-gate int length; 1588*0Sstevel@tonic-gate char property_val[50]; 1589*0Sstevel@tonic-gate void *bop_staging_area; 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate major = ddi_name_to_major("vgatext"); 1592*0Sstevel@tonic-gate if (major == (major_t)-1) 1593*0Sstevel@tonic-gate return; 1594*0Sstevel@tonic-gate devi = devnamesp[major].dn_head; 1595*0Sstevel@tonic-gate if (devi == NULL) 1596*0Sstevel@tonic-gate return; 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate bop_staging_area = kmem_zalloc(MMU_PAGESIZE, KM_SLEEP); 1599*0Sstevel@tonic-gate 1600*0Sstevel@tonic-gate /* 1601*0Sstevel@tonic-gate * Import "vga" properties from the boot. 1602*0Sstevel@tonic-gate */ 1603*0Sstevel@tonic-gate name = "display-edif-block"; 1604*0Sstevel@tonic-gate length = BOP_GETPROPLEN(bootops, name); 1605*0Sstevel@tonic-gate if (length > 0 && length < MMU_PAGESIZE) { 1606*0Sstevel@tonic-gate BOP_GETPROP(bootops, name, bop_staging_area); 1607*0Sstevel@tonic-gate (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, 1608*0Sstevel@tonic-gate devi, name, bop_staging_area, length); 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate /* 1612*0Sstevel@tonic-gate * kdmconfig is also looking for display-type and 1613*0Sstevel@tonic-gate * video-adapter-type. We default to color and svga. 1614*0Sstevel@tonic-gate * 1615*0Sstevel@tonic-gate * Could it be "monochrome", "vga"? 1616*0Sstevel@tonic-gate * Nah, you've got to come to the 21st century... 1617*0Sstevel@tonic-gate * And you can set monitor type manually in kdmconfig 1618*0Sstevel@tonic-gate * if you are really an old junky. 1619*0Sstevel@tonic-gate */ 1620*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 1621*0Sstevel@tonic-gate devi, "display-type", "color"); 1622*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 1623*0Sstevel@tonic-gate devi, "video-adapter-type", "svga"); 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate name = "display-edif-id"; 1626*0Sstevel@tonic-gate length = BOP_GETPROPLEN(bootops, name); 1627*0Sstevel@tonic-gate if (length > 0 && length < MMU_PAGESIZE) { 1628*0Sstevel@tonic-gate BOP_GETPROP(bootops, name, bop_staging_area); 1629*0Sstevel@tonic-gate copy_boot_str(bop_staging_area, property_val, length); 1630*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 1631*0Sstevel@tonic-gate devi, name, property_val); 1632*0Sstevel@tonic-gate } 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate kmem_free(bop_staging_area, MMU_PAGESIZE); 1635*0Sstevel@tonic-gate } 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate /* 1639*0Sstevel@tonic-gate * This is temporary, but absolutely necessary. If we are being 1640*0Sstevel@tonic-gate * booted with a device tree created by the DevConf project's bootconf 1641*0Sstevel@tonic-gate * program, then we have device information nodes that reflect 1642*0Sstevel@tonic-gate * reality. At this point in time in the Solaris release schedule, the 1643*0Sstevel@tonic-gate * kernel drivers aren't prepared for reality. They still depend on their 1644*0Sstevel@tonic-gate * own ad-hoc interpretations of the properties created when their .conf 1645*0Sstevel@tonic-gate * files were interpreted. These drivers use an "ignore-hardware-nodes" 1646*0Sstevel@tonic-gate * property to prevent them from using the nodes passed up from the bootconf 1647*0Sstevel@tonic-gate * device tree. 1648*0Sstevel@tonic-gate * 1649*0Sstevel@tonic-gate * Trying to assemble root file system drivers as we are booting from 1650*0Sstevel@tonic-gate * devconf will fail if the kernel driver is basing its name_addr's on the 1651*0Sstevel@tonic-gate * psuedo-node device info while the bootpath passed up from bootconf is using 1652*0Sstevel@tonic-gate * reality-based name_addrs. We help the boot along in this case by 1653*0Sstevel@tonic-gate * looking at the pre-bootconf bootpath and determining if we would have 1654*0Sstevel@tonic-gate * successfully matched if that had been the bootpath we had chosen. 1655*0Sstevel@tonic-gate * 1656*0Sstevel@tonic-gate * Note that we only even perform this extra check if we've booted 1657*0Sstevel@tonic-gate * using bootconf's 1275 compliant bootpath, this is the boot device, and 1658*0Sstevel@tonic-gate * we're trying to match the name_addr specified in the 1275 bootpath. 1659*0Sstevel@tonic-gate */ 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate #define MAXCOMPONENTLEN 32 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate int 1664*0Sstevel@tonic-gate x86_old_bootpath_name_addr_match(dev_info_t *cdip, char *caddr, char *naddr) 1665*0Sstevel@tonic-gate { 1666*0Sstevel@tonic-gate /* 1667*0Sstevel@tonic-gate * There are multiple criteria to be met before we can even 1668*0Sstevel@tonic-gate * consider allowing a name_addr match here. 1669*0Sstevel@tonic-gate * 1670*0Sstevel@tonic-gate * 1) We must have been booted such that the bootconf program 1671*0Sstevel@tonic-gate * created device tree nodes and properties. This can be 1672*0Sstevel@tonic-gate * determined by examining the 'bootpath' property. This 1673*0Sstevel@tonic-gate * property will be a non-null string iff bootconf was 1674*0Sstevel@tonic-gate * involved in the boot. 1675*0Sstevel@tonic-gate * 1676*0Sstevel@tonic-gate * 2) The module that we want to match must be the boot device. 1677*0Sstevel@tonic-gate * 1678*0Sstevel@tonic-gate * 3) The instance of the module we are thinking of letting be 1679*0Sstevel@tonic-gate * our match must be ignoring hardware nodes. 1680*0Sstevel@tonic-gate * 1681*0Sstevel@tonic-gate * 4) The name_addr we want to match must be the name_addr 1682*0Sstevel@tonic-gate * specified in the 1275 bootpath. 1683*0Sstevel@tonic-gate */ 1684*0Sstevel@tonic-gate static char bootdev_module[MAXCOMPONENTLEN]; 1685*0Sstevel@tonic-gate static char bootdev_oldmod[MAXCOMPONENTLEN]; 1686*0Sstevel@tonic-gate static char bootdev_newaddr[MAXCOMPONENTLEN]; 1687*0Sstevel@tonic-gate static char bootdev_oldaddr[MAXCOMPONENTLEN]; 1688*0Sstevel@tonic-gate static int quickexit; 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate char *daddr; 1691*0Sstevel@tonic-gate int dlen; 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate char *lkupname; 1694*0Sstevel@tonic-gate int rv = DDI_FAILURE; 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate if ((ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 1697*0Sstevel@tonic-gate "devconf-addr", (caddr_t)&daddr, &dlen) == DDI_PROP_SUCCESS) && 1698*0Sstevel@tonic-gate (ddi_getprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 1699*0Sstevel@tonic-gate "ignore-hardware-nodes", -1) != -1)) { 1700*0Sstevel@tonic-gate if (strcmp(daddr, caddr) == 0) { 1701*0Sstevel@tonic-gate return (DDI_SUCCESS); 1702*0Sstevel@tonic-gate } 1703*0Sstevel@tonic-gate } 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate if (quickexit) 1706*0Sstevel@tonic-gate return (rv); 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate if (bootdev_module[0] == '\0') { 1709*0Sstevel@tonic-gate char *addrp, *eoaddrp; 1710*0Sstevel@tonic-gate char *busp, *modp, *atp; 1711*0Sstevel@tonic-gate char *bp1275, *bp; 1712*0Sstevel@tonic-gate int bp1275len, bplen; 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate bp1275 = bp = addrp = eoaddrp = busp = modp = atp = NULL; 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 1717*0Sstevel@tonic-gate ddi_root_node(), 0, "bootpath", 1718*0Sstevel@tonic-gate (caddr_t)&bp1275, &bp1275len) != DDI_PROP_SUCCESS || 1719*0Sstevel@tonic-gate bp1275len <= 1) { 1720*0Sstevel@tonic-gate /* 1721*0Sstevel@tonic-gate * We didn't boot from bootconf so we never need to 1722*0Sstevel@tonic-gate * do any special matches. 1723*0Sstevel@tonic-gate */ 1724*0Sstevel@tonic-gate quickexit = 1; 1725*0Sstevel@tonic-gate if (bp1275) 1726*0Sstevel@tonic-gate kmem_free(bp1275, bp1275len); 1727*0Sstevel@tonic-gate return (rv); 1728*0Sstevel@tonic-gate } 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 1731*0Sstevel@tonic-gate ddi_root_node(), 0, "boot-path", 1732*0Sstevel@tonic-gate (caddr_t)&bp, &bplen) != DDI_PROP_SUCCESS || bplen <= 1) { 1733*0Sstevel@tonic-gate /* 1734*0Sstevel@tonic-gate * No fallback position for matching. This is 1735*0Sstevel@tonic-gate * certainly unexpected, but we'll handle it 1736*0Sstevel@tonic-gate * just in case. 1737*0Sstevel@tonic-gate */ 1738*0Sstevel@tonic-gate quickexit = 1; 1739*0Sstevel@tonic-gate kmem_free(bp1275, bp1275len); 1740*0Sstevel@tonic-gate if (bp) 1741*0Sstevel@tonic-gate kmem_free(bp, bplen); 1742*0Sstevel@tonic-gate return (rv); 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate /* 1746*0Sstevel@tonic-gate * Determine boot device module and 1275 name_addr 1747*0Sstevel@tonic-gate * 1748*0Sstevel@tonic-gate * bootpath assumed to be of the form /bus/module@name_addr 1749*0Sstevel@tonic-gate */ 1750*0Sstevel@tonic-gate if (busp = strchr(bp1275, '/')) { 1751*0Sstevel@tonic-gate if (modp = strchr(busp + 1, '/')) { 1752*0Sstevel@tonic-gate if (atp = strchr(modp + 1, '@')) { 1753*0Sstevel@tonic-gate *atp = '\0'; 1754*0Sstevel@tonic-gate addrp = atp + 1; 1755*0Sstevel@tonic-gate if (eoaddrp = strchr(addrp, '/')) 1756*0Sstevel@tonic-gate *eoaddrp = '\0'; 1757*0Sstevel@tonic-gate } 1758*0Sstevel@tonic-gate } 1759*0Sstevel@tonic-gate } 1760*0Sstevel@tonic-gate 1761*0Sstevel@tonic-gate if (modp && addrp) { 1762*0Sstevel@tonic-gate (void) strncpy(bootdev_module, modp + 1, 1763*0Sstevel@tonic-gate MAXCOMPONENTLEN); 1764*0Sstevel@tonic-gate bootdev_module[MAXCOMPONENTLEN - 1] = '\0'; 1765*0Sstevel@tonic-gate 1766*0Sstevel@tonic-gate (void) strncpy(bootdev_newaddr, addrp, MAXCOMPONENTLEN); 1767*0Sstevel@tonic-gate bootdev_newaddr[MAXCOMPONENTLEN - 1] = '\0'; 1768*0Sstevel@tonic-gate } else { 1769*0Sstevel@tonic-gate quickexit = 1; 1770*0Sstevel@tonic-gate kmem_free(bp1275, bp1275len); 1771*0Sstevel@tonic-gate kmem_free(bp, bplen); 1772*0Sstevel@tonic-gate return (rv); 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate 1775*0Sstevel@tonic-gate /* 1776*0Sstevel@tonic-gate * Determine fallback name_addr 1777*0Sstevel@tonic-gate * 1778*0Sstevel@tonic-gate * 10/3/96 - Also save fallback module name because it 1779*0Sstevel@tonic-gate * might actually be different than the current module 1780*0Sstevel@tonic-gate * name. E.G., ISA pnp drivers have new names. 1781*0Sstevel@tonic-gate * 1782*0Sstevel@tonic-gate * bootpath assumed to be of the form /bus/module@name_addr 1783*0Sstevel@tonic-gate */ 1784*0Sstevel@tonic-gate addrp = NULL; 1785*0Sstevel@tonic-gate if (busp = strchr(bp, '/')) { 1786*0Sstevel@tonic-gate if (modp = strchr(busp + 1, '/')) { 1787*0Sstevel@tonic-gate if (atp = strchr(modp + 1, '@')) { 1788*0Sstevel@tonic-gate *atp = '\0'; 1789*0Sstevel@tonic-gate addrp = atp + 1; 1790*0Sstevel@tonic-gate if (eoaddrp = strchr(addrp, '/')) 1791*0Sstevel@tonic-gate *eoaddrp = '\0'; 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate } 1794*0Sstevel@tonic-gate } 1795*0Sstevel@tonic-gate 1796*0Sstevel@tonic-gate if (modp && addrp) { 1797*0Sstevel@tonic-gate (void) strncpy(bootdev_oldmod, modp + 1, 1798*0Sstevel@tonic-gate MAXCOMPONENTLEN); 1799*0Sstevel@tonic-gate bootdev_module[MAXCOMPONENTLEN - 1] = '\0'; 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate (void) strncpy(bootdev_oldaddr, addrp, MAXCOMPONENTLEN); 1802*0Sstevel@tonic-gate bootdev_oldaddr[MAXCOMPONENTLEN - 1] = '\0'; 1803*0Sstevel@tonic-gate } 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate /* Free up the bootpath storage now that we're done with it. */ 1806*0Sstevel@tonic-gate kmem_free(bp1275, bp1275len); 1807*0Sstevel@tonic-gate kmem_free(bp, bplen); 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate if (bootdev_oldaddr[0] == '\0') { 1810*0Sstevel@tonic-gate quickexit = 1; 1811*0Sstevel@tonic-gate return (rv); 1812*0Sstevel@tonic-gate } 1813*0Sstevel@tonic-gate } 1814*0Sstevel@tonic-gate 1815*0Sstevel@tonic-gate if (((lkupname = ddi_get_name(cdip)) != NULL) && 1816*0Sstevel@tonic-gate (strcmp(bootdev_module, lkupname) == 0 || 1817*0Sstevel@tonic-gate strcmp(bootdev_oldmod, lkupname) == 0) && 1818*0Sstevel@tonic-gate ((ddi_getprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 1819*0Sstevel@tonic-gate "ignore-hardware-nodes", -1) != -1) || 1820*0Sstevel@tonic-gate ignore_hardware_nodes) && 1821*0Sstevel@tonic-gate strcmp(bootdev_newaddr, caddr) == 0 && 1822*0Sstevel@tonic-gate strcmp(bootdev_oldaddr, naddr) == 0) { 1823*0Sstevel@tonic-gate rv = DDI_SUCCESS; 1824*0Sstevel@tonic-gate } 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate return (rv); 1827*0Sstevel@tonic-gate } 1828*0Sstevel@tonic-gate 1829*0Sstevel@tonic-gate /* 1830*0Sstevel@tonic-gate * Perform a copy from a memory mapped device (whose devinfo pointer is devi) 1831*0Sstevel@tonic-gate * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. 1832*0Sstevel@tonic-gate */ 1833*0Sstevel@tonic-gate /*ARGSUSED*/ 1834*0Sstevel@tonic-gate int 1835*0Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi, 1836*0Sstevel@tonic-gate off_t off, const void *devaddr, void *kaddr, size_t len) 1837*0Sstevel@tonic-gate { 1838*0Sstevel@tonic-gate bcopy(devaddr, kaddr, len); 1839*0Sstevel@tonic-gate return (0); 1840*0Sstevel@tonic-gate } 1841*0Sstevel@tonic-gate 1842*0Sstevel@tonic-gate /* 1843*0Sstevel@tonic-gate * Perform a copy to a memory mapped device (whose devinfo pointer is devi) 1844*0Sstevel@tonic-gate * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. 1845*0Sstevel@tonic-gate */ 1846*0Sstevel@tonic-gate /*ARGSUSED*/ 1847*0Sstevel@tonic-gate int 1848*0Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi, 1849*0Sstevel@tonic-gate off_t off, const void *kaddr, void *devaddr, size_t len) 1850*0Sstevel@tonic-gate { 1851*0Sstevel@tonic-gate bcopy(kaddr, devaddr, len); 1852*0Sstevel@tonic-gate return (0); 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate static int 1857*0Sstevel@tonic-gate poke_mem(peekpoke_ctlops_t *in_args) 1858*0Sstevel@tonic-gate { 1859*0Sstevel@tonic-gate int err = DDI_SUCCESS; 1860*0Sstevel@tonic-gate on_trap_data_t otd; 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate /* Set up protected environment. */ 1863*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 1864*0Sstevel@tonic-gate switch (in_args->size) { 1865*0Sstevel@tonic-gate case sizeof (uint8_t): 1866*0Sstevel@tonic-gate *(uint8_t *)(in_args->dev_addr) = 1867*0Sstevel@tonic-gate *(uint8_t *)in_args->host_addr; 1868*0Sstevel@tonic-gate break; 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate case sizeof (uint16_t): 1871*0Sstevel@tonic-gate *(uint16_t *)(in_args->dev_addr) = 1872*0Sstevel@tonic-gate *(uint16_t *)in_args->host_addr; 1873*0Sstevel@tonic-gate break; 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate case sizeof (uint32_t): 1876*0Sstevel@tonic-gate *(uint32_t *)(in_args->dev_addr) = 1877*0Sstevel@tonic-gate *(uint32_t *)in_args->host_addr; 1878*0Sstevel@tonic-gate break; 1879*0Sstevel@tonic-gate 1880*0Sstevel@tonic-gate case sizeof (uint64_t): 1881*0Sstevel@tonic-gate *(uint64_t *)(in_args->dev_addr) = 1882*0Sstevel@tonic-gate *(uint64_t *)in_args->host_addr; 1883*0Sstevel@tonic-gate break; 1884*0Sstevel@tonic-gate 1885*0Sstevel@tonic-gate default: 1886*0Sstevel@tonic-gate err = DDI_FAILURE; 1887*0Sstevel@tonic-gate break; 1888*0Sstevel@tonic-gate } 1889*0Sstevel@tonic-gate } else 1890*0Sstevel@tonic-gate err = DDI_FAILURE; 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate /* Take down protected environment. */ 1893*0Sstevel@tonic-gate no_trap(); 1894*0Sstevel@tonic-gate 1895*0Sstevel@tonic-gate return (err); 1896*0Sstevel@tonic-gate } 1897*0Sstevel@tonic-gate 1898*0Sstevel@tonic-gate 1899*0Sstevel@tonic-gate static int 1900*0Sstevel@tonic-gate peek_mem(peekpoke_ctlops_t *in_args) 1901*0Sstevel@tonic-gate { 1902*0Sstevel@tonic-gate int err = DDI_SUCCESS; 1903*0Sstevel@tonic-gate on_trap_data_t otd; 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 1906*0Sstevel@tonic-gate switch (in_args->size) { 1907*0Sstevel@tonic-gate case sizeof (uint8_t): 1908*0Sstevel@tonic-gate *(uint8_t *)in_args->host_addr = 1909*0Sstevel@tonic-gate *(uint8_t *)in_args->dev_addr; 1910*0Sstevel@tonic-gate break; 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate case sizeof (uint16_t): 1913*0Sstevel@tonic-gate *(uint16_t *)in_args->host_addr = 1914*0Sstevel@tonic-gate *(uint16_t *)in_args->dev_addr; 1915*0Sstevel@tonic-gate break; 1916*0Sstevel@tonic-gate 1917*0Sstevel@tonic-gate case sizeof (uint32_t): 1918*0Sstevel@tonic-gate *(uint32_t *)in_args->host_addr = 1919*0Sstevel@tonic-gate *(uint32_t *)in_args->dev_addr; 1920*0Sstevel@tonic-gate break; 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate case sizeof (uint64_t): 1923*0Sstevel@tonic-gate *(uint64_t *)in_args->host_addr = 1924*0Sstevel@tonic-gate *(uint64_t *)in_args->dev_addr; 1925*0Sstevel@tonic-gate break; 1926*0Sstevel@tonic-gate 1927*0Sstevel@tonic-gate default: 1928*0Sstevel@tonic-gate err = DDI_FAILURE; 1929*0Sstevel@tonic-gate break; 1930*0Sstevel@tonic-gate } 1931*0Sstevel@tonic-gate } else 1932*0Sstevel@tonic-gate err = DDI_FAILURE; 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate no_trap(); 1935*0Sstevel@tonic-gate return (err); 1936*0Sstevel@tonic-gate } 1937*0Sstevel@tonic-gate 1938*0Sstevel@tonic-gate 1939*0Sstevel@tonic-gate /* 1940*0Sstevel@tonic-gate * This is called only to process peek/poke when the DIP is NULL. 1941*0Sstevel@tonic-gate * Assume that this is for memory, as nexi take care of device safe accesses. 1942*0Sstevel@tonic-gate */ 1943*0Sstevel@tonic-gate int 1944*0Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args) 1945*0Sstevel@tonic-gate { 1946*0Sstevel@tonic-gate return (cmd == DDI_CTLOPS_PEEK ? peek_mem(in_args) : poke_mem(in_args)); 1947*0Sstevel@tonic-gate } 1948*0Sstevel@tonic-gate 1949*0Sstevel@tonic-gate void 1950*0Sstevel@tonic-gate impl_setup_ddi(void) 1951*0Sstevel@tonic-gate { 1952*0Sstevel@tonic-gate dev_info_t *xdip, *isa_dip; 1953*0Sstevel@tonic-gate rd_existing_t rd_mem_prop; 1954*0Sstevel@tonic-gate int err; 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate ndi_devi_alloc_sleep(ddi_root_node(), "ramdisk", 1957*0Sstevel@tonic-gate (dnode_t)DEVI_SID_NODEID, &xdip); 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate (void) BOP_GETPROP(bootops, 1960*0Sstevel@tonic-gate "ramdisk_start", (void *)&ramdisk_start); 1961*0Sstevel@tonic-gate (void) BOP_GETPROP(bootops, 1962*0Sstevel@tonic-gate "ramdisk_end", (void *)&ramdisk_end); 1963*0Sstevel@tonic-gate 1964*0Sstevel@tonic-gate rd_mem_prop.phys = ramdisk_start; 1965*0Sstevel@tonic-gate rd_mem_prop.size = ramdisk_end - ramdisk_start + 1; 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, xdip, 1968*0Sstevel@tonic-gate RD_EXISTING_PROP_NAME, (uchar_t *)&rd_mem_prop, 1969*0Sstevel@tonic-gate sizeof (rd_mem_prop)); 1970*0Sstevel@tonic-gate err = ndi_devi_bind_driver(xdip, 0); 1971*0Sstevel@tonic-gate ASSERT(err == 0); 1972*0Sstevel@tonic-gate 1973*0Sstevel@tonic-gate /* isa node */ 1974*0Sstevel@tonic-gate ndi_devi_alloc_sleep(ddi_root_node(), "isa", 1975*0Sstevel@tonic-gate (dnode_t)DEVI_SID_NODEID, &isa_dip); 1976*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, isa_dip, 1977*0Sstevel@tonic-gate "device_type", "isa"); 1978*0Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, isa_dip, 1979*0Sstevel@tonic-gate "bus-type", "isa"); 1980*0Sstevel@tonic-gate (void) ndi_devi_bind_driver(isa_dip, 0); 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate /* 1983*0Sstevel@tonic-gate * Read in the properties from the boot. 1984*0Sstevel@tonic-gate */ 1985*0Sstevel@tonic-gate get_boot_properties(); 1986*0Sstevel@tonic-gate 1987*0Sstevel@tonic-gate /* do bus dependent probes. */ 1988*0Sstevel@tonic-gate impl_bus_initialprobe(); 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate /* not framebuffer should be enumerated, if present */ 1991*0Sstevel@tonic-gate get_vga_properties(); 1992*0Sstevel@tonic-gate } 1993*0Sstevel@tonic-gate 1994*0Sstevel@tonic-gate dev_t 1995*0Sstevel@tonic-gate getrootdev(void) 1996*0Sstevel@tonic-gate { 1997*0Sstevel@tonic-gate /* 1998*0Sstevel@tonic-gate * Precedence given to rootdev if set in /etc/system 1999*0Sstevel@tonic-gate */ 2000*0Sstevel@tonic-gate if (root_is_svm) { 2001*0Sstevel@tonic-gate return (ddi_pathname_to_dev_t(svm_bootpath)); 2002*0Sstevel@tonic-gate } 2003*0Sstevel@tonic-gate 2004*0Sstevel@tonic-gate /* 2005*0Sstevel@tonic-gate * Usually rootfs.bo_name is initialized by the 2006*0Sstevel@tonic-gate * the bootpath property from bootenv.rc, but 2007*0Sstevel@tonic-gate * defaults to "/ramdisk:a" otherwise. 2008*0Sstevel@tonic-gate */ 2009*0Sstevel@tonic-gate return (ddi_pathname_to_dev_t(rootfs.bo_name)); 2010*0Sstevel@tonic-gate } 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate static struct bus_probe { 2013*0Sstevel@tonic-gate struct bus_probe *next; 2014*0Sstevel@tonic-gate void (*probe)(int); 2015*0Sstevel@tonic-gate } *bus_probes; 2016*0Sstevel@tonic-gate 2017*0Sstevel@tonic-gate void 2018*0Sstevel@tonic-gate impl_bus_add_probe(void (*func)(int)) 2019*0Sstevel@tonic-gate { 2020*0Sstevel@tonic-gate struct bus_probe *probe; 2021*0Sstevel@tonic-gate 2022*0Sstevel@tonic-gate probe = kmem_alloc(sizeof (*probe), KM_SLEEP); 2023*0Sstevel@tonic-gate probe->next = bus_probes; 2024*0Sstevel@tonic-gate probe->probe = func; 2025*0Sstevel@tonic-gate bus_probes = probe; 2026*0Sstevel@tonic-gate } 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate /*ARGSUSED*/ 2029*0Sstevel@tonic-gate void 2030*0Sstevel@tonic-gate impl_bus_delete_probe(void (*func)(int)) 2031*0Sstevel@tonic-gate { 2032*0Sstevel@tonic-gate struct bus_probe *prev = NULL; 2033*0Sstevel@tonic-gate struct bus_probe *probe = bus_probes; 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate while (probe) { 2036*0Sstevel@tonic-gate if (probe->probe == func) 2037*0Sstevel@tonic-gate break; 2038*0Sstevel@tonic-gate prev = probe; 2039*0Sstevel@tonic-gate probe = probe->next; 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate 2042*0Sstevel@tonic-gate if (probe == NULL) 2043*0Sstevel@tonic-gate return; 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate if (prev) 2046*0Sstevel@tonic-gate prev->next = probe->next; 2047*0Sstevel@tonic-gate else 2048*0Sstevel@tonic-gate bus_probes = probe->next; 2049*0Sstevel@tonic-gate 2050*0Sstevel@tonic-gate kmem_free(probe, sizeof (struct bus_probe)); 2051*0Sstevel@tonic-gate } 2052*0Sstevel@tonic-gate 2053*0Sstevel@tonic-gate /* 2054*0Sstevel@tonic-gate * impl_bus_initialprobe 2055*0Sstevel@tonic-gate * Modload the prom simulator, then let it probe to verify existence 2056*0Sstevel@tonic-gate * and type of PCI support. 2057*0Sstevel@tonic-gate */ 2058*0Sstevel@tonic-gate static void 2059*0Sstevel@tonic-gate impl_bus_initialprobe(void) 2060*0Sstevel@tonic-gate { 2061*0Sstevel@tonic-gate struct bus_probe *probe; 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate /* load modules to install bus probes */ 2064*0Sstevel@tonic-gate if (modload("misc", "pci_autoconfig") < 0) { 2065*0Sstevel@tonic-gate cmn_err(CE_PANIC, "failed to load misc/pci_autoconfig"); 2066*0Sstevel@tonic-gate } 2067*0Sstevel@tonic-gate 2068*0Sstevel@tonic-gate probe = bus_probes; 2069*0Sstevel@tonic-gate while (probe) { 2070*0Sstevel@tonic-gate /* run the probe function */ 2071*0Sstevel@tonic-gate (*probe->probe)(0); 2072*0Sstevel@tonic-gate probe = probe->next; 2073*0Sstevel@tonic-gate } 2074*0Sstevel@tonic-gate } 2075*0Sstevel@tonic-gate 2076*0Sstevel@tonic-gate /* 2077*0Sstevel@tonic-gate * impl_bus_reprobe 2078*0Sstevel@tonic-gate * Reprogram devices not set up by firmware. 2079*0Sstevel@tonic-gate */ 2080*0Sstevel@tonic-gate static void 2081*0Sstevel@tonic-gate impl_bus_reprobe(void) 2082*0Sstevel@tonic-gate { 2083*0Sstevel@tonic-gate struct bus_probe *probe; 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate probe = bus_probes; 2086*0Sstevel@tonic-gate while (probe) { 2087*0Sstevel@tonic-gate /* run the probe function */ 2088*0Sstevel@tonic-gate (*probe->probe)(1); 2089*0Sstevel@tonic-gate probe = probe->next; 2090*0Sstevel@tonic-gate } 2091*0Sstevel@tonic-gate } 2092