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 * sun4 specific DDI implementation 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate #include <sys/cpuvar.h> 33*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 34*0Sstevel@tonic-gate #include <sys/machsystm.h> 35*0Sstevel@tonic-gate #include <sys/sunndi.h> 36*0Sstevel@tonic-gate #include <sys/sysmacros.h> 37*0Sstevel@tonic-gate #include <sys/ontrap.h> 38*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 39*0Sstevel@tonic-gate #include <sys/membar.h> 40*0Sstevel@tonic-gate #include <sys/dditypes.h> 41*0Sstevel@tonic-gate #include <sys/ndifm.h> 42*0Sstevel@tonic-gate #include <sys/fm/io/ddi.h> 43*0Sstevel@tonic-gate #include <sys/ivintr.h> 44*0Sstevel@tonic-gate #include <sys/bootconf.h> 45*0Sstevel@tonic-gate #include <sys/conf.h> 46*0Sstevel@tonic-gate #include <sys/ethernet.h> 47*0Sstevel@tonic-gate #include <sys/idprom.h> 48*0Sstevel@tonic-gate #include <sys/promif.h> 49*0Sstevel@tonic-gate #include <sys/prom_plat.h> 50*0Sstevel@tonic-gate #include <sys/systeminfo.h> 51*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 52*0Sstevel@tonic-gate #include <sys/vm.h> 53*0Sstevel@tonic-gate #include <sys/fs/dv_node.h> 54*0Sstevel@tonic-gate #include <sys/fs/snode.h> 55*0Sstevel@tonic-gate #include <sys/ddi_isa.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *, 58*0Sstevel@tonic-gate ddi_ispec_t *, ddi_ispec_t **); 59*0Sstevel@tonic-gate #pragma weak get_intr_parent 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 62*0Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 63*0Sstevel@tonic-gate #pragma weak process_intr_ops 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t); 66*0Sstevel@tonic-gate prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *, 67*0Sstevel@tonic-gate int32_t len); 68*0Sstevel@tonic-gate #pragma weak cells_1275_copy 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * Wrapper for ddi_prop_lookup_int_array(). 72*0Sstevel@tonic-gate * This is handy because it returns the prop length in 73*0Sstevel@tonic-gate * bytes which is what most of the callers require. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate static int 77*0Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate int ret; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di, 82*0Sstevel@tonic-gate DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) { 83*0Sstevel@tonic-gate *plen = (*plen) * (uint_t)sizeof (int); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate return (ret); 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * SECTION: DDI Node Configuration 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate /* 93*0Sstevel@tonic-gate * init_regspec_64: 94*0Sstevel@tonic-gate * 95*0Sstevel@tonic-gate * If the parent #size-cells is 2, convert the upa-style or 96*0Sstevel@tonic-gate * safari-style reg property from 2-size cells to 1 size cell 97*0Sstevel@tonic-gate * format, ignoring the size_hi, which must be zero for devices. 98*0Sstevel@tonic-gate * (It won't be zero in the memory list properties in the memory 99*0Sstevel@tonic-gate * nodes, but that doesn't matter here.) 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate struct ddi_parent_private_data * 102*0Sstevel@tonic-gate init_regspec_64(dev_info_t *dip) 103*0Sstevel@tonic-gate { 104*0Sstevel@tonic-gate struct ddi_parent_private_data *pd; 105*0Sstevel@tonic-gate dev_info_t *parent; 106*0Sstevel@tonic-gate int size_cells; 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate /* 109*0Sstevel@tonic-gate * If there are no "reg"s in the child node, return. 110*0Sstevel@tonic-gate */ 111*0Sstevel@tonic-gate pd = ddi_get_parent_data(dip); 112*0Sstevel@tonic-gate if ((pd == NULL) || (pd->par_nreg == 0)) { 113*0Sstevel@tonic-gate return (pd); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate parent = ddi_get_parent(dip); 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 118*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (size_cells != 1) { 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate int n, j; 123*0Sstevel@tonic-gate struct regspec *irp; 124*0Sstevel@tonic-gate struct reg_64 { 125*0Sstevel@tonic-gate uint_t addr_hi, addr_lo, size_hi, size_lo; 126*0Sstevel@tonic-gate }; 127*0Sstevel@tonic-gate struct reg_64 *r64_rp; 128*0Sstevel@tonic-gate struct regspec *rp; 129*0Sstevel@tonic-gate uint_t len = 0; 130*0Sstevel@tonic-gate int *reg_prop; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate ASSERT(size_cells == 2); 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * We already looked the property up once before if 136*0Sstevel@tonic-gate * pd is non-NULL. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate (void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 139*0Sstevel@tonic-gate DDI_PROP_DONTPASS, OBP_REG, ®_prop, &len); 140*0Sstevel@tonic-gate ASSERT(len != 0); 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate n = sizeof (struct reg_64) / sizeof (int); 143*0Sstevel@tonic-gate n = len / n; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * We're allocating a buffer the size of the PROM's property, 147*0Sstevel@tonic-gate * but we're only using a smaller portion when we assign it 148*0Sstevel@tonic-gate * to a regspec. We do this so that in the 149*0Sstevel@tonic-gate * impl_ddi_sunbus_removechild function, we will 150*0Sstevel@tonic-gate * always free the right amount of memory. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate irp = rp = (struct regspec *)reg_prop; 153*0Sstevel@tonic-gate r64_rp = (struct reg_64 *)pd->par_reg; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate for (j = 0; j < n; ++j, ++rp, ++r64_rp) { 156*0Sstevel@tonic-gate ASSERT(r64_rp->size_hi == 0); 157*0Sstevel@tonic-gate rp->regspec_bustype = r64_rp->addr_hi; 158*0Sstevel@tonic-gate rp->regspec_addr = r64_rp->addr_lo; 159*0Sstevel@tonic-gate rp->regspec_size = r64_rp->size_lo; 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate ddi_prop_free((void *)pd->par_reg); 163*0Sstevel@tonic-gate pd->par_nreg = n; 164*0Sstevel@tonic-gate pd->par_reg = irp; 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate return (pd); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Create a ddi_parent_private_data structure from the ddi properties of 171*0Sstevel@tonic-gate * the dev_info node. 172*0Sstevel@tonic-gate * 173*0Sstevel@tonic-gate * The "reg" is required if the driver wishes to create mappings on behalf 174*0Sstevel@tonic-gate * of the device. The "reg" property is assumed to be a list of at least 175*0Sstevel@tonic-gate * one triplet 176*0Sstevel@tonic-gate * 177*0Sstevel@tonic-gate * <bustype, address, size>*1 178*0Sstevel@tonic-gate * 179*0Sstevel@tonic-gate * The "interrupt" property is no longer part of parent private data on 180*0Sstevel@tonic-gate * sun4u. The interrupt parent is may not be the device tree parent. 181*0Sstevel@tonic-gate * 182*0Sstevel@tonic-gate * The "ranges" property describes the mapping of child addresses to parent 183*0Sstevel@tonic-gate * addresses. 184*0Sstevel@tonic-gate * 185*0Sstevel@tonic-gate * N.B. struct rangespec is defined for the following default values: 186*0Sstevel@tonic-gate * parent child 187*0Sstevel@tonic-gate * #address-cells 2 2 188*0Sstevel@tonic-gate * #size-cells 1 1 189*0Sstevel@tonic-gate * This function doesn't deal with non-default cells and will not create 190*0Sstevel@tonic-gate * ranges in such cases. 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate void 193*0Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd) 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 196*0Sstevel@tonic-gate int *reg_prop, *rng_prop; 197*0Sstevel@tonic-gate uint_t reg_len = 0, rng_len = 0; 198*0Sstevel@tonic-gate dev_info_t *parent; 199*0Sstevel@tonic-gate int parent_addr_cells, parent_size_cells; 200*0Sstevel@tonic-gate int child_addr_cells, child_size_cells; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate *ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate /* 205*0Sstevel@tonic-gate * root node has no parent private data, so *ppd should 206*0Sstevel@tonic-gate * be initialized for naming to work properly. 207*0Sstevel@tonic-gate */ 208*0Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 209*0Sstevel@tonic-gate return; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * Set reg field of parent data from "reg" property 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate if ((get_prop_int_array(child, OBP_REG, ®_prop, ®_len) 215*0Sstevel@tonic-gate == DDI_PROP_SUCCESS) && (reg_len != 0)) { 216*0Sstevel@tonic-gate pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec)); 217*0Sstevel@tonic-gate pdptr->par_reg = (struct regspec *)reg_prop; 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * "ranges" property ... 222*0Sstevel@tonic-gate * 223*0Sstevel@tonic-gate * This function does not handle cases where #address-cells != 2 224*0Sstevel@tonic-gate * and * min(parent, child) #size-cells != 1 (see bugid 4211124). 225*0Sstevel@tonic-gate * 226*0Sstevel@tonic-gate * Nexus drivers with such exceptions (e.g. pci ranges) 227*0Sstevel@tonic-gate * should either create a separate function for handling 228*0Sstevel@tonic-gate * ranges or not use parent private data to store ranges. 229*0Sstevel@tonic-gate */ 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* root node has no ranges */ 232*0Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 233*0Sstevel@tonic-gate return; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 236*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 237*0Sstevel@tonic-gate child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 238*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 239*0Sstevel@tonic-gate parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 240*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 241*0Sstevel@tonic-gate parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 242*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 243*0Sstevel@tonic-gate if (child_addr_cells != 2 || parent_addr_cells != 2 || 244*0Sstevel@tonic-gate (child_size_cells != 1 && parent_size_cells != 1)) { 245*0Sstevel@tonic-gate NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; " 246*0Sstevel@tonic-gate "#address-cells or #size-cells have non-default value")); 247*0Sstevel@tonic-gate return; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len) 251*0Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 252*0Sstevel@tonic-gate pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 253*0Sstevel@tonic-gate pdptr->par_rng = (struct rangespec *)rng_prop; 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * Free ddi_parent_private_data structure 259*0Sstevel@tonic-gate */ 260*0Sstevel@tonic-gate void 261*0Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip) 262*0Sstevel@tonic-gate { 263*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip); 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate if (pdptr == NULL) 266*0Sstevel@tonic-gate return; 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (pdptr->par_nrng != 0) 269*0Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_rng); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if (pdptr->par_nreg != 0) 272*0Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_reg); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate kmem_free(pdptr, sizeof (*pdptr)); 275*0Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate /* 279*0Sstevel@tonic-gate * Name a child of sun busses based on the reg spec. 280*0Sstevel@tonic-gate * Handles the following properties: 281*0Sstevel@tonic-gate * 282*0Sstevel@tonic-gate * Property value 283*0Sstevel@tonic-gate * Name type 284*0Sstevel@tonic-gate * 285*0Sstevel@tonic-gate * reg register spec 286*0Sstevel@tonic-gate * interrupts new (bus-oriented) interrupt spec 287*0Sstevel@tonic-gate * ranges range spec 288*0Sstevel@tonic-gate * 289*0Sstevel@tonic-gate * This may be called multiple times, independent of 290*0Sstevel@tonic-gate * initchild calls. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate static int 293*0Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 296*0Sstevel@tonic-gate struct regspec *rp; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * Fill in parent-private data and this function returns to us 300*0Sstevel@tonic-gate * an indication if it used "registers" to fill in the data. 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 303*0Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 304*0Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * No reg property, return null string as address 309*0Sstevel@tonic-gate * (e.g. root node) 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate name[0] = '\0'; 312*0Sstevel@tonic-gate if (sparc_pd_getnreg(child) == 0) { 313*0Sstevel@tonic-gate return (DDI_SUCCESS); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate rp = sparc_pd_getreg(child, 0); 317*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 318*0Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr); 319*0Sstevel@tonic-gate return (DDI_SUCCESS); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * Called from the bus_ctl op of some drivers. 325*0Sstevel@tonic-gate * to implement the DDI_CTLOPS_INITCHILD operation. 326*0Sstevel@tonic-gate * 327*0Sstevel@tonic-gate * NEW drivers should NOT use this function, but should declare 328*0Sstevel@tonic-gate * there own initchild/uninitchild handlers. (This function assumes 329*0Sstevel@tonic-gate * the layout of the parent private data and the format of "reg", 330*0Sstevel@tonic-gate * "ranges", "interrupts" properties and that #address-cells and 331*0Sstevel@tonic-gate * #size-cells of the parent bus are defined to be default values.) 332*0Sstevel@tonic-gate */ 333*0Sstevel@tonic-gate int 334*0Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child) 335*0Sstevel@tonic-gate { 336*0Sstevel@tonic-gate char name[MAXNAMELEN]; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate (void) impl_sunbus_name_child(child, name, MAXNAMELEN); 339*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* 342*0Sstevel@tonic-gate * Try to merge .conf node. If successful, return failure to 343*0Sstevel@tonic-gate * remove this child. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && 346*0Sstevel@tonic-gate (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) { 347*0Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 348*0Sstevel@tonic-gate return (DDI_FAILURE); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate return (DDI_SUCCESS); 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * A better name for this function would be impl_ddi_sunbus_uninitchild() 355*0Sstevel@tonic-gate * It does not remove the child, it uninitializes it, reclaiming the 356*0Sstevel@tonic-gate * resources taken by impl_ddi_sunbus_initchild. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate void 359*0Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate impl_free_ddi_ppd(dip); 362*0Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate impl_rem_dev_props(dip); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * SECTION: DDI Interrupt 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate void 374*0Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len) 375*0Sstevel@tonic-gate { 376*0Sstevel@tonic-gate int i; 377*0Sstevel@tonic-gate for (i = 0; i < len; i++) 378*0Sstevel@tonic-gate *to = *from; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate prop_1275_cell_t * 382*0Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len) 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate prop_1275_cell_t *match_cell = 0; 385*0Sstevel@tonic-gate int32_t i; 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate for (i = 0; i < len; i++) 388*0Sstevel@tonic-gate if (cell1[i] != cell2[i]) { 389*0Sstevel@tonic-gate match_cell = &cell1[i]; 390*0Sstevel@tonic-gate break; 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate return (match_cell); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * Wrapper functions used by New DDI interrupt framework. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate /* 401*0Sstevel@tonic-gate * i_ddi_handle_intr_ops: 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate int 404*0Sstevel@tonic-gate i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 405*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 406*0Sstevel@tonic-gate { 407*0Sstevel@tonic-gate ddi_intrspec_t ispec; 408*0Sstevel@tonic-gate int ret; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 411*0Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, op, hdlp, result)); 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate i_ddi_alloc_ispec(dip, hdlp->ih_inum, &ispec); 414*0Sstevel@tonic-gate if ((ddi_ispec_t *)ispec == NULL) 415*0Sstevel@tonic-gate return (DDI_FAILURE); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 418*0Sstevel@tonic-gate ret = i_ddi_intr_ops(dip, rdip, op, hdlp, result); 419*0Sstevel@tonic-gate hdlp->ih_private = NULL; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate i_ddi_free_ispec(ispec); 422*0Sstevel@tonic-gate return (ret); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate /* 426*0Sstevel@tonic-gate * i_ddi_intr_ops: 427*0Sstevel@tonic-gate */ 428*0Sstevel@tonic-gate int 429*0Sstevel@tonic-gate i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 430*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate ddi_ispec_t *sav_ip, *ip = NULL; 433*0Sstevel@tonic-gate dev_info_t *pdip = ddi_get_parent(dip); 434*0Sstevel@tonic-gate int ret = DDI_FAILURE; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 437*0Sstevel@tonic-gate return (process_intr_ops(pdip, rdip, op, hdlp, result)); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate switch (op) { 440*0Sstevel@tonic-gate case DDI_INTROP_ADDISR: 441*0Sstevel@tonic-gate case DDI_INTROP_REMISR: 442*0Sstevel@tonic-gate case DDI_INTROP_ENABLE: 443*0Sstevel@tonic-gate case DDI_INTROP_DISABLE: 444*0Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 445*0Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 446*0Sstevel@tonic-gate /* Save the ispec */ 447*0Sstevel@tonic-gate sav_ip = (ddi_ispec_t *)hdlp->ih_private; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * If we have an ispec struct, try and determine our 451*0Sstevel@tonic-gate * parent and possibly an interrupt translation. 452*0Sstevel@tonic-gate * intr parent dip returned held 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate if ((pdip = get_intr_parent(pdip, dip, sav_ip, &ip)) != NULL) { 455*0Sstevel@tonic-gate /* Insert the interrupt info structure */ 456*0Sstevel@tonic-gate hdlp->ih_private = (void *)ip; 457*0Sstevel@tonic-gate } else 458*0Sstevel@tonic-gate goto done; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate ret = process_intr_ops(pdip, rdip, op, hdlp, result); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate done: 464*0Sstevel@tonic-gate switch (op) { 465*0Sstevel@tonic-gate case DDI_INTROP_ADDISR: 466*0Sstevel@tonic-gate case DDI_INTROP_REMISR: 467*0Sstevel@tonic-gate case DDI_INTROP_ENABLE: 468*0Sstevel@tonic-gate case DDI_INTROP_DISABLE: 469*0Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 470*0Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 471*0Sstevel@tonic-gate /* Release hold acquired in get_intr_parent() */ 472*0Sstevel@tonic-gate if (pdip) 473*0Sstevel@tonic-gate ndi_rele_devi(pdip); 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if (ip) { 476*0Sstevel@tonic-gate /* Set the PIL according to what the parent did */ 477*0Sstevel@tonic-gate sav_ip->is_pil = ip->is_pil; 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* Free the stacked ispec structure */ 480*0Sstevel@tonic-gate i_ddi_free_ispec((ddi_intrspec_t)ip); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate /* Restore the interrupt info */ 484*0Sstevel@tonic-gate hdlp->ih_private = (void *)sav_ip; 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate return (ret); 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate /* 491*0Sstevel@tonic-gate * process_intr_ops: 492*0Sstevel@tonic-gate * 493*0Sstevel@tonic-gate * Process the interrupt op via the interrupt parent. 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate int 496*0Sstevel@tonic-gate process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op, 497*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 498*0Sstevel@tonic-gate { 499*0Sstevel@tonic-gate int ret = DDI_FAILURE; 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate if (NEXUS_HAS_INTR_OP(pdip)) { 502*0Sstevel@tonic-gate ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops-> 503*0Sstevel@tonic-gate bus_intr_op)) (pdip, rdip, op, hdlp, result); 504*0Sstevel@tonic-gate } else { 505*0Sstevel@tonic-gate cmn_err(CE_WARN, "Failed to process interrupt " 506*0Sstevel@tonic-gate "for %s%d due to down-rev nexus driver %s%d", 507*0Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 508*0Sstevel@tonic-gate ddi_get_name(pdip), ddi_get_instance(pdip)); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate return (ret); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate /* 515*0Sstevel@tonic-gate * i_ddi_add_ivintr: 516*0Sstevel@tonic-gate */ 517*0Sstevel@tonic-gate /*ARGSUSED*/ 518*0Sstevel@tonic-gate int 519*0Sstevel@tonic-gate i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) 520*0Sstevel@tonic-gate { 521*0Sstevel@tonic-gate /* Sanity check the entry we're about to add */ 522*0Sstevel@tonic-gate if (GET_IVINTR(hdlp->ih_vector)) { 523*0Sstevel@tonic-gate cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector); 524*0Sstevel@tonic-gate return (DDI_FAILURE); 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate /* 528*0Sstevel@tonic-gate * If the PIL was set and is valid use it, otherwise 529*0Sstevel@tonic-gate * default it to 1 530*0Sstevel@tonic-gate */ 531*0Sstevel@tonic-gate if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) 532*0Sstevel@tonic-gate hdlp->ih_pri = 1; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, 535*0Sstevel@tonic-gate (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0); 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate return (DDI_SUCCESS); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate /* 541*0Sstevel@tonic-gate * i_ddi_rem_ivintr: 542*0Sstevel@tonic-gate */ 543*0Sstevel@tonic-gate /*ARGSUSED*/ 544*0Sstevel@tonic-gate void 545*0Sstevel@tonic-gate i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) 546*0Sstevel@tonic-gate { 547*0Sstevel@tonic-gate rem_ivintr(hdlp->ih_vector, NULL); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * i_ddi_add_softint - allocate and add a soft interrupt to the system 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate int 554*0Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) 555*0Sstevel@tonic-gate { 556*0Sstevel@tonic-gate uint_t rval; 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if ((rval = (uint_t)add_softintr(hdlp->ih_pri, 559*0Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1)) == 0) { 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate return (DDI_FAILURE); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate hdlp->ih_private = (void *)rval; 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate return (DDI_SUCCESS); 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate void 570*0Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) 571*0Sstevel@tonic-gate { 572*0Sstevel@tonic-gate uint_t intr_id; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* disable */ 575*0Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 576*0Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 577*0Sstevel@tonic-gate rem_softintr(intr_id); 578*0Sstevel@tonic-gate hdlp->ih_private = NULL; 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate int 582*0Sstevel@tonic-gate i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp) 583*0Sstevel@tonic-gate { 584*0Sstevel@tonic-gate uint_t intr_id; 585*0Sstevel@tonic-gate int ret; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate ASSERT(hdlp != NULL); 588*0Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* update the vector table for the 2nd arg */ 593*0Sstevel@tonic-gate ret = update_softint_arg2(intr_id, hdlp->ih_cb_arg2); 594*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) 595*0Sstevel@tonic-gate setsoftint(intr_id); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate return (ret); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate /* ARGSUSED */ 601*0Sstevel@tonic-gate int 602*0Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) 603*0Sstevel@tonic-gate { 604*0Sstevel@tonic-gate uint_t intr_id; 605*0Sstevel@tonic-gate int ret; 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate ASSERT(hdlp != NULL); 608*0Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate /* update the vector table for the new priority */ 613*0Sstevel@tonic-gate ret = update_softint_pri(intr_id, hdlp->ih_pri); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate return (ret); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * Support routine for allocating and initializing an interrupt specification. 620*0Sstevel@tonic-gate * The bus interrupt value will be allocated at the end of this structure, so 621*0Sstevel@tonic-gate * the corresponding routine i_ddi_free_ispec() should be used to free the 622*0Sstevel@tonic-gate * interrupt specification. 623*0Sstevel@tonic-gate */ 624*0Sstevel@tonic-gate void 625*0Sstevel@tonic-gate i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp) 626*0Sstevel@tonic-gate { 627*0Sstevel@tonic-gate int32_t intrlen, intr_cells, max_intrs; 628*0Sstevel@tonic-gate prop_1275_cell_t *ip; 629*0Sstevel@tonic-gate prop_1275_cell_t intr_sz; 630*0Sstevel@tonic-gate ddi_ispec_t **ispecp = (ddi_ispec_t **)intrspecp; 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate *ispecp = NULL; 633*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS | 634*0Sstevel@tonic-gate DDI_PROP_CANSLEEP, 635*0Sstevel@tonic-gate "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 638*0Sstevel@tonic-gate "#interrupt-cells", 1); 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate /* adjust for number of bytes */ 641*0Sstevel@tonic-gate intr_sz = CELLS_1275_TO_BYTES(intr_cells); 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate /* Calculate the number of interrupts */ 644*0Sstevel@tonic-gate max_intrs = intrlen / intr_sz; 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate if (inumber < max_intrs) { 647*0Sstevel@tonic-gate prop_1275_cell_t *intrp = ip; 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate *ispecp = kmem_zalloc( 650*0Sstevel@tonic-gate (sizeof (ddi_ispec_t) + intr_sz), KM_SLEEP); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate (*ispecp)->is_intr = 653*0Sstevel@tonic-gate (uint32_t *)(*ispecp + 1); 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* Index into interrupt property */ 656*0Sstevel@tonic-gate intrp += (inumber * intr_cells); 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate cells_1275_copy(intrp, 659*0Sstevel@tonic-gate (*ispecp)->is_intr, intr_cells); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate (*ispecp)->is_intr_sz = intr_sz; 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate (*ispecp)->is_pil = i_ddi_get_intr_pri(dip, inumber); 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate kmem_free(ip, intrlen); 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* 671*0Sstevel@tonic-gate * Analog routine to i_ddi_alloc_ispec() used to free the interrupt 672*0Sstevel@tonic-gate * specification and the associated bus interrupt value. 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate void 675*0Sstevel@tonic-gate i_ddi_free_ispec(ddi_intrspec_t intrspecp) 676*0Sstevel@tonic-gate { 677*0Sstevel@tonic-gate ddi_ispec_t *ispecp = (ddi_ispec_t *)intrspecp; 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate kmem_free(ispecp, sizeof (ddi_ispec_t) + (ispecp->is_intr_sz)); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate /* 683*0Sstevel@tonic-gate * i_ddi_get_intr_pri - Get the interrupt-priorities property from 684*0Sstevel@tonic-gate * the specified device. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate uint32_t 687*0Sstevel@tonic-gate i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber) 688*0Sstevel@tonic-gate { 689*0Sstevel@tonic-gate uint32_t *intr_prio_p; 690*0Sstevel@tonic-gate uint32_t pri = 0; 691*0Sstevel@tonic-gate int32_t i; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate /* 694*0Sstevel@tonic-gate * Use the "interrupt-priorities" property to determine the 695*0Sstevel@tonic-gate * the pil/ipl for the interrupt handler. 696*0Sstevel@tonic-gate */ 697*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 698*0Sstevel@tonic-gate "interrupt-priorities", (caddr_t)&intr_prio_p, 699*0Sstevel@tonic-gate &i) == DDI_SUCCESS) { 700*0Sstevel@tonic-gate if (inumber < (i / sizeof (int32_t))) 701*0Sstevel@tonic-gate pri = intr_prio_p[inumber]; 702*0Sstevel@tonic-gate kmem_free(intr_prio_p, i); 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate return (pri); 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * SECTION: DDI Memory/DMA 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate static vmem_t *little_endian_arena; 713*0Sstevel@tonic-gate static vmem_t *big_endian_arena; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate static void * 716*0Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag) 717*0Sstevel@tonic-gate { 718*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE, 719*0Sstevel@tonic-gate segkmem_page_create, NULL)); 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate static void * 723*0Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag) 724*0Sstevel@tonic-gate { 725*0Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE, 726*0Sstevel@tonic-gate segkmem_page_create, NULL)); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate void 730*0Sstevel@tonic-gate ka_init(void) 731*0Sstevel@tonic-gate { 732*0Sstevel@tonic-gate little_endian_arena = vmem_create("little_endian", NULL, 0, 1, 733*0Sstevel@tonic-gate segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP); 734*0Sstevel@tonic-gate big_endian_arena = vmem_create("big_endian", NULL, 0, 1, 735*0Sstevel@tonic-gate segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate /* 739*0Sstevel@tonic-gate * Allocate from the system, aligned on a specific boundary. 740*0Sstevel@tonic-gate * The alignment, if non-zero, must be a power of 2. 741*0Sstevel@tonic-gate */ 742*0Sstevel@tonic-gate static void * 743*0Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags) 744*0Sstevel@tonic-gate { 745*0Sstevel@tonic-gate size_t *addr, *raddr, rsize; 746*0Sstevel@tonic-gate size_t hdrsize = 4 * sizeof (size_t); /* must be power of 2 */ 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate align = MAX(align, hdrsize); 749*0Sstevel@tonic-gate ASSERT((align & (align - 1)) == 0); 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* 752*0Sstevel@tonic-gate * We need to allocate 753*0Sstevel@tonic-gate * rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment) 754*0Sstevel@tonic-gate * bytes to be sure we have enough freedom to satisfy the request. 755*0Sstevel@tonic-gate * Since the buffer alignment depends on the request size, this is 756*0Sstevel@tonic-gate * not straightforward to use directly. 757*0Sstevel@tonic-gate * 758*0Sstevel@tonic-gate * kmem guarantees that any allocation of a 64-byte multiple will be 759*0Sstevel@tonic-gate * 64-byte aligned. Since rounding up the request could add more 760*0Sstevel@tonic-gate * than we save, we compute the size with and without alignment, and 761*0Sstevel@tonic-gate * use the smaller of the two. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate rsize = size + hdrsize + align; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate if (endian_flags == DDI_STRUCTURE_LE_ACC) { 766*0Sstevel@tonic-gate raddr = vmem_alloc(little_endian_arena, rsize, 767*0Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 768*0Sstevel@tonic-gate } else { 769*0Sstevel@tonic-gate raddr = vmem_alloc(big_endian_arena, rsize, 770*0Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate if (raddr == NULL) 774*0Sstevel@tonic-gate return (NULL); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align); 777*0Sstevel@tonic-gate ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize); 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate addr[-3] = (size_t)endian_flags; 780*0Sstevel@tonic-gate addr[-2] = (size_t)raddr; 781*0Sstevel@tonic-gate addr[-1] = rsize; 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate return (addr); 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate static void 787*0Sstevel@tonic-gate kfreea(void *addr) 788*0Sstevel@tonic-gate { 789*0Sstevel@tonic-gate size_t *saddr = addr; 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate if (saddr[-3] == DDI_STRUCTURE_LE_ACC) 792*0Sstevel@tonic-gate vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]); 793*0Sstevel@tonic-gate else 794*0Sstevel@tonic-gate vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]); 795*0Sstevel@tonic-gate } 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate int 798*0Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr, 799*0Sstevel@tonic-gate size_t length, int cansleep, int streaming, 800*0Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, 801*0Sstevel@tonic-gate caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep) 802*0Sstevel@tonic-gate { 803*0Sstevel@tonic-gate caddr_t a; 804*0Sstevel@tonic-gate int iomin, align; 805*0Sstevel@tonic-gate uint_t endian_flags = DDI_NEVERSWAP_ACC; 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate #if defined(lint) 808*0Sstevel@tonic-gate *handlep = *handlep; 809*0Sstevel@tonic-gate #endif 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate /* 812*0Sstevel@tonic-gate * Check legality of arguments 813*0Sstevel@tonic-gate */ 814*0Sstevel@tonic-gate if (length == 0 || kaddrp == NULL || attr == NULL) { 815*0Sstevel@tonic-gate return (DDI_FAILURE); 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 || 818*0Sstevel@tonic-gate (attr->dma_attr_align & (attr->dma_attr_align - 1)) || 819*0Sstevel@tonic-gate (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) { 820*0Sstevel@tonic-gate return (DDI_FAILURE); 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate /* 824*0Sstevel@tonic-gate * Drivers for 64-bit capable SBus devices will encode 825*0Sstevel@tonic-gate * the burtsizes for 64-bit xfers in the upper 16-bits. 826*0Sstevel@tonic-gate * For DMA alignment, we use the most restrictive 827*0Sstevel@tonic-gate * alignment of 32-bit and 64-bit xfers. 828*0Sstevel@tonic-gate */ 829*0Sstevel@tonic-gate iomin = (attr->dma_attr_burstsizes & 0xffff) | 830*0Sstevel@tonic-gate ((attr->dma_attr_burstsizes >> 16) & 0xffff); 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * If a driver set burtsizes to 0, we give him byte alignment. 833*0Sstevel@tonic-gate * Otherwise align at the burtsizes boundary. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate if (iomin == 0) 836*0Sstevel@tonic-gate iomin = 1; 837*0Sstevel@tonic-gate else 838*0Sstevel@tonic-gate iomin = 1 << (ddi_fls(iomin) - 1); 839*0Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_minxfer); 840*0Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_align); 841*0Sstevel@tonic-gate iomin = ddi_iomin(dip, iomin, streaming); 842*0Sstevel@tonic-gate if (iomin == 0) 843*0Sstevel@tonic-gate return (DDI_FAILURE); 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate ASSERT((iomin & (iomin - 1)) == 0); 846*0Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_minxfer); 847*0Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_align); 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate length = P2ROUNDUP(length, iomin); 850*0Sstevel@tonic-gate align = iomin; 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate if (accattrp != NULL) 853*0Sstevel@tonic-gate endian_flags = accattrp->devacc_attr_endian_flags; 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate a = kalloca(length, align, cansleep, endian_flags); 856*0Sstevel@tonic-gate if ((*kaddrp = a) == 0) { 857*0Sstevel@tonic-gate return (DDI_FAILURE); 858*0Sstevel@tonic-gate } else { 859*0Sstevel@tonic-gate if (real_length) { 860*0Sstevel@tonic-gate *real_length = length; 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate if (handlep) { 863*0Sstevel@tonic-gate /* 864*0Sstevel@tonic-gate * assign handle information 865*0Sstevel@tonic-gate */ 866*0Sstevel@tonic-gate impl_acc_hdl_init(handlep); 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate return (DDI_SUCCESS); 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * covert old DMA limits structure to DMA attribute structure 874*0Sstevel@tonic-gate * and continue 875*0Sstevel@tonic-gate */ 876*0Sstevel@tonic-gate int 877*0Sstevel@tonic-gate i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits, 878*0Sstevel@tonic-gate size_t length, int cansleep, int streaming, 879*0Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp, 880*0Sstevel@tonic-gate uint_t *real_length, ddi_acc_hdl_t *ap) 881*0Sstevel@tonic-gate { 882*0Sstevel@tonic-gate ddi_dma_attr_t dma_attr, *attrp; 883*0Sstevel@tonic-gate size_t rlen; 884*0Sstevel@tonic-gate int ret; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate ASSERT(limits); 887*0Sstevel@tonic-gate attrp = &dma_attr; 888*0Sstevel@tonic-gate attrp->dma_attr_version = DMA_ATTR_V0; 889*0Sstevel@tonic-gate attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo; 890*0Sstevel@tonic-gate attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi; 891*0Sstevel@tonic-gate attrp->dma_attr_count_max = (uint64_t)-1; 892*0Sstevel@tonic-gate attrp->dma_attr_align = 1; 893*0Sstevel@tonic-gate attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes; 894*0Sstevel@tonic-gate attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer; 895*0Sstevel@tonic-gate attrp->dma_attr_maxxfer = (uint64_t)-1; 896*0Sstevel@tonic-gate attrp->dma_attr_seg = (uint64_t)limits->dlim_cntr_max; 897*0Sstevel@tonic-gate attrp->dma_attr_sgllen = 1; 898*0Sstevel@tonic-gate attrp->dma_attr_granular = 1; 899*0Sstevel@tonic-gate attrp->dma_attr_flags = 0; 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming, 902*0Sstevel@tonic-gate accattrp, kaddrp, &rlen, ap); 903*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 904*0Sstevel@tonic-gate if (real_length) 905*0Sstevel@tonic-gate *real_length = (uint_t)rlen; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate return (ret); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate /* ARGSUSED */ 911*0Sstevel@tonic-gate void 912*0Sstevel@tonic-gate i_ddi_mem_free(caddr_t kaddr, int stream) 913*0Sstevel@tonic-gate { 914*0Sstevel@tonic-gate kfreea(kaddr); 915*0Sstevel@tonic-gate } 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate /* 918*0Sstevel@tonic-gate * SECTION: DDI Data Access 919*0Sstevel@tonic-gate */ 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0; 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate /* 924*0Sstevel@tonic-gate * access handle allocator 925*0Sstevel@tonic-gate */ 926*0Sstevel@tonic-gate ddi_acc_hdl_t * 927*0Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl) 928*0Sstevel@tonic-gate { 929*0Sstevel@tonic-gate /* 930*0Sstevel@tonic-gate * Extract the access handle address from the DDI implemented 931*0Sstevel@tonic-gate * access handle 932*0Sstevel@tonic-gate */ 933*0Sstevel@tonic-gate return (&((ddi_acc_impl_t *)hdl)->ahi_common); 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate ddi_acc_handle_t 937*0Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg) 938*0Sstevel@tonic-gate { 939*0Sstevel@tonic-gate ddi_acc_impl_t *hp; 940*0Sstevel@tonic-gate on_trap_data_t *otp; 941*0Sstevel@tonic-gate int sleepflag; 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate /* 946*0Sstevel@tonic-gate * Allocate and initialize the data access handle and error status. 947*0Sstevel@tonic-gate */ 948*0Sstevel@tonic-gate if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL) 949*0Sstevel@tonic-gate goto fail; 950*0Sstevel@tonic-gate if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc( 951*0Sstevel@tonic-gate sizeof (ndi_err_t), sleepflag)) == NULL) { 952*0Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 953*0Sstevel@tonic-gate goto fail; 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate if ((otp = (on_trap_data_t *)kmem_zalloc( 956*0Sstevel@tonic-gate sizeof (on_trap_data_t), sleepflag)) == NULL) { 957*0Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 958*0Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 959*0Sstevel@tonic-gate goto fail; 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate hp->ahi_err->err_ontrap = otp; 962*0Sstevel@tonic-gate hp->ahi_common.ah_platform_private = (void *)hp; 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate return ((ddi_acc_handle_t)hp); 965*0Sstevel@tonic-gate fail: 966*0Sstevel@tonic-gate if ((waitfp != (int (*)())KM_SLEEP) && 967*0Sstevel@tonic-gate (waitfp != (int (*)())KM_NOSLEEP)) 968*0Sstevel@tonic-gate ddi_set_callback(waitfp, arg, &impl_acc_hdl_id); 969*0Sstevel@tonic-gate return (NULL); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate void 973*0Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle) 974*0Sstevel@tonic-gate { 975*0Sstevel@tonic-gate ddi_acc_impl_t *hp; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate /* 978*0Sstevel@tonic-gate * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *), 979*0Sstevel@tonic-gate * because that's what we allocated in impl_acc_hdl_alloc() above. 980*0Sstevel@tonic-gate */ 981*0Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handle; 982*0Sstevel@tonic-gate if (hp) { 983*0Sstevel@tonic-gate kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t)); 984*0Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 985*0Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 986*0Sstevel@tonic-gate if (impl_acc_hdl_id) 987*0Sstevel@tonic-gate ddi_run_callback(&impl_acc_hdl_id); 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate void 992*0Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep) 993*0Sstevel@tonic-gate { 994*0Sstevel@tonic-gate int fmcap; 995*0Sstevel@tonic-gate ndi_err_t *errp; 996*0Sstevel@tonic-gate on_trap_data_t *otp; 997*0Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep; 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate fmcap = ddi_fm_capable(handlep->ah_dip); 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 || 1002*0Sstevel@tonic-gate !DDI_FM_ACC_ERR_CAP(fmcap)) { 1003*0Sstevel@tonic-gate handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC; 1004*0Sstevel@tonic-gate } else if (DDI_FM_ACC_ERR_CAP(fmcap)) { 1005*0Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) { 1006*0Sstevel@tonic-gate i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP, 1007*0Sstevel@tonic-gate NULL, DDI_NOSLEEP); 1008*0Sstevel@tonic-gate } else { 1009*0Sstevel@tonic-gate errp = hp->ahi_err; 1010*0Sstevel@tonic-gate otp = (on_trap_data_t *)errp->err_ontrap; 1011*0Sstevel@tonic-gate otp->ot_handle = (void *)(hp); 1012*0Sstevel@tonic-gate otp->ot_prot = OT_DATA_ACCESS; 1013*0Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == 1014*0Sstevel@tonic-gate DDI_CAUTIOUS_ACC) 1015*0Sstevel@tonic-gate otp->ot_trampoline = 1016*0Sstevel@tonic-gate (uintptr_t)&i_ddi_caut_trampoline; 1017*0Sstevel@tonic-gate else 1018*0Sstevel@tonic-gate otp->ot_trampoline = 1019*0Sstevel@tonic-gate (uintptr_t)&i_ddi_prot_trampoline; 1020*0Sstevel@tonic-gate errp->err_status = DDI_FM_OK; 1021*0Sstevel@tonic-gate errp->err_expected = DDI_FM_ERR_UNEXPECTED; 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate void 1027*0Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep) 1028*0Sstevel@tonic-gate { 1029*0Sstevel@tonic-gate ddi_acc_impl_t *hp; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate ASSERT(handlep); 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handlep; 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate /* 1036*0Sstevel@tonic-gate * check for SW byte-swapping 1037*0Sstevel@tonic-gate */ 1038*0Sstevel@tonic-gate hp->ahi_get8 = i_ddi_get8; 1039*0Sstevel@tonic-gate hp->ahi_put8 = i_ddi_put8; 1040*0Sstevel@tonic-gate hp->ahi_rep_get8 = i_ddi_rep_get8; 1041*0Sstevel@tonic-gate hp->ahi_rep_put8 = i_ddi_rep_put8; 1042*0Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) { 1043*0Sstevel@tonic-gate hp->ahi_get16 = i_ddi_swap_get16; 1044*0Sstevel@tonic-gate hp->ahi_get32 = i_ddi_swap_get32; 1045*0Sstevel@tonic-gate hp->ahi_get64 = i_ddi_swap_get64; 1046*0Sstevel@tonic-gate hp->ahi_put16 = i_ddi_swap_put16; 1047*0Sstevel@tonic-gate hp->ahi_put32 = i_ddi_swap_put32; 1048*0Sstevel@tonic-gate hp->ahi_put64 = i_ddi_swap_put64; 1049*0Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_swap_rep_get16; 1050*0Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_swap_rep_get32; 1051*0Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_swap_rep_get64; 1052*0Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_swap_rep_put16; 1053*0Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_swap_rep_put32; 1054*0Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_swap_rep_put64; 1055*0Sstevel@tonic-gate } else { 1056*0Sstevel@tonic-gate hp->ahi_get16 = i_ddi_get16; 1057*0Sstevel@tonic-gate hp->ahi_get32 = i_ddi_get32; 1058*0Sstevel@tonic-gate hp->ahi_get64 = i_ddi_get64; 1059*0Sstevel@tonic-gate hp->ahi_put16 = i_ddi_put16; 1060*0Sstevel@tonic-gate hp->ahi_put32 = i_ddi_put32; 1061*0Sstevel@tonic-gate hp->ahi_put64 = i_ddi_put64; 1062*0Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_rep_get16; 1063*0Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_rep_get32; 1064*0Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_rep_get64; 1065*0Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_rep_put16; 1066*0Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_rep_put32; 1067*0Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_rep_put64; 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate /* Legacy fault flags and support */ 1071*0Sstevel@tonic-gate hp->ahi_fault_check = i_ddi_acc_fault_check; 1072*0Sstevel@tonic-gate hp->ahi_fault_notify = i_ddi_acc_fault_notify; 1073*0Sstevel@tonic-gate hp->ahi_fault = 0; 1074*0Sstevel@tonic-gate impl_acc_err_init(handlep); 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate 1077*0Sstevel@tonic-gate void 1078*0Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle) 1079*0Sstevel@tonic-gate { 1080*0Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 1081*0Sstevel@tonic-gate 1082*0Sstevel@tonic-gate if (!hp->ahi_fault) { 1083*0Sstevel@tonic-gate hp->ahi_fault = 1; 1084*0Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate void 1089*0Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle) 1090*0Sstevel@tonic-gate { 1091*0Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 1092*0Sstevel@tonic-gate 1093*0Sstevel@tonic-gate if (hp->ahi_fault) { 1094*0Sstevel@tonic-gate hp->ahi_fault = 0; 1095*0Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* ARGSUSED */ 1100*0Sstevel@tonic-gate void 1101*0Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp) 1102*0Sstevel@tonic-gate { 1103*0Sstevel@tonic-gate /* Default version, does nothing */ 1104*0Sstevel@tonic-gate } 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate /* 1107*0Sstevel@tonic-gate * SECTION: Misc functions 1108*0Sstevel@tonic-gate */ 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate /* 1111*0Sstevel@tonic-gate * instance wrappers 1112*0Sstevel@tonic-gate */ 1113*0Sstevel@tonic-gate /*ARGSUSED*/ 1114*0Sstevel@tonic-gate uint_t 1115*0Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip) 1116*0Sstevel@tonic-gate { 1117*0Sstevel@tonic-gate return ((uint_t)-1); 1118*0Sstevel@tonic-gate } 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate /*ARGSUSED*/ 1121*0Sstevel@tonic-gate int 1122*0Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip) 1123*0Sstevel@tonic-gate { 1124*0Sstevel@tonic-gate return (DDI_FAILURE); 1125*0Sstevel@tonic-gate } 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate /*ARGSUSED*/ 1128*0Sstevel@tonic-gate int 1129*0Sstevel@tonic-gate impl_free_instance(dev_info_t *dip) 1130*0Sstevel@tonic-gate { 1131*0Sstevel@tonic-gate return (DDI_FAILURE); 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate /*ARGSUSED*/ 1135*0Sstevel@tonic-gate int 1136*0Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi) 1137*0Sstevel@tonic-gate { 1138*0Sstevel@tonic-gate return (DDI_SUCCESS); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate static const char *nocopydevs[] = { 1143*0Sstevel@tonic-gate "SUNW,ffb", 1144*0Sstevel@tonic-gate "SUNW,afb", 1145*0Sstevel@tonic-gate NULL 1146*0Sstevel@tonic-gate }; 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* 1149*0Sstevel@tonic-gate * Perform a copy from a memory mapped device (whose devinfo pointer is devi) 1150*0Sstevel@tonic-gate * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. 1151*0Sstevel@tonic-gate */ 1152*0Sstevel@tonic-gate /*ARGSUSED*/ 1153*0Sstevel@tonic-gate int 1154*0Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi, 1155*0Sstevel@tonic-gate off_t off, const void *devaddr, void *kaddr, size_t len) 1156*0Sstevel@tonic-gate { 1157*0Sstevel@tonic-gate const char **argv; 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 1160*0Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) { 1161*0Sstevel@tonic-gate bzero(kaddr, len); 1162*0Sstevel@tonic-gate return (0); 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate bcopy(devaddr, kaddr, len); 1166*0Sstevel@tonic-gate return (0); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate /* 1170*0Sstevel@tonic-gate * Perform a copy to a memory mapped device (whose devinfo pointer is devi) 1171*0Sstevel@tonic-gate * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. 1172*0Sstevel@tonic-gate */ 1173*0Sstevel@tonic-gate /*ARGSUSED*/ 1174*0Sstevel@tonic-gate int 1175*0Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi, 1176*0Sstevel@tonic-gate off_t off, const void *kaddr, void *devaddr, size_t len) 1177*0Sstevel@tonic-gate { 1178*0Sstevel@tonic-gate const char **argv; 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 1181*0Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) 1182*0Sstevel@tonic-gate return (1); 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate bcopy(kaddr, devaddr, len); 1185*0Sstevel@tonic-gate return (0); 1186*0Sstevel@tonic-gate } 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate /* 1189*0Sstevel@tonic-gate * Boot Configuration 1190*0Sstevel@tonic-gate */ 1191*0Sstevel@tonic-gate idprom_t idprom; 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate /* 1194*0Sstevel@tonic-gate * Configure the hardware on the system. 1195*0Sstevel@tonic-gate * Called before the rootfs is mounted 1196*0Sstevel@tonic-gate */ 1197*0Sstevel@tonic-gate void 1198*0Sstevel@tonic-gate configure(void) 1199*0Sstevel@tonic-gate { 1200*0Sstevel@tonic-gate extern void i_ddi_init_root(); 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate /* We better have released boot by this time! */ 1203*0Sstevel@tonic-gate ASSERT(!bootops); 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate /* 1206*0Sstevel@tonic-gate * Determine whether or not to use the fpu, V9 SPARC cpus 1207*0Sstevel@tonic-gate * always have one. Could check for existence of a fp queue, 1208*0Sstevel@tonic-gate * Ultra I, II and IIa do not have a fp queue. 1209*0Sstevel@tonic-gate */ 1210*0Sstevel@tonic-gate if (fpu_exists) 1211*0Sstevel@tonic-gate fpu_probe(); 1212*0Sstevel@tonic-gate else 1213*0Sstevel@tonic-gate cmn_err(CE_CONT, "FPU not in use\n"); 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate #if 0 /* XXXQ - not necessary for sun4u */ 1216*0Sstevel@tonic-gate /* 1217*0Sstevel@tonic-gate * This following line fixes bugid 1041296; we need to do a 1218*0Sstevel@tonic-gate * prom_nextnode(0) because this call ALSO patches the DMA+ 1219*0Sstevel@tonic-gate * bug in Campus-B and Phoenix. The prom uncaches the traptable 1220*0Sstevel@tonic-gate * page as a side-effect of devr_next(0) (which prom_nextnode calls), 1221*0Sstevel@tonic-gate * so this *must* be executed early on. (XXX This is untrue for sun4u) 1222*0Sstevel@tonic-gate */ 1223*0Sstevel@tonic-gate (void) prom_nextnode((dnode_t)0); 1224*0Sstevel@tonic-gate #endif 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate /* 1227*0Sstevel@tonic-gate * Initialize devices on the machine. 1228*0Sstevel@tonic-gate * Uses configuration tree built by the PROMs to determine what 1229*0Sstevel@tonic-gate * is present, and builds a tree of prototype dev_info nodes 1230*0Sstevel@tonic-gate * corresponding to the hardware which identified itself. 1231*0Sstevel@tonic-gate */ 1232*0Sstevel@tonic-gate i_ddi_init_root(); 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate #ifdef DDI_PROP_DEBUG 1235*0Sstevel@tonic-gate (void) ddi_prop_debug(1); /* Enable property debugging */ 1236*0Sstevel@tonic-gate #endif /* DDI_PROP_DEBUG */ 1237*0Sstevel@tonic-gate } 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate /* 1240*0Sstevel@tonic-gate * The "status" property indicates the operational status of a device. 1241*0Sstevel@tonic-gate * If this property is present, the value is a string indicating the 1242*0Sstevel@tonic-gate * status of the device as follows: 1243*0Sstevel@tonic-gate * 1244*0Sstevel@tonic-gate * "okay" operational. 1245*0Sstevel@tonic-gate * "disabled" not operational, but might become operational. 1246*0Sstevel@tonic-gate * "fail" not operational because a fault has been detected, 1247*0Sstevel@tonic-gate * and it is unlikely that the device will become 1248*0Sstevel@tonic-gate * operational without repair. no additional details 1249*0Sstevel@tonic-gate * are available. 1250*0Sstevel@tonic-gate * "fail-xxx" not operational because a fault has been detected, 1251*0Sstevel@tonic-gate * and it is unlikely that the device will become 1252*0Sstevel@tonic-gate * operational without repair. "xxx" is additional 1253*0Sstevel@tonic-gate * human-readable information about the particular 1254*0Sstevel@tonic-gate * fault condition that was detected. 1255*0Sstevel@tonic-gate * 1256*0Sstevel@tonic-gate * The absence of this property means that the operational status is 1257*0Sstevel@tonic-gate * unknown or okay. 1258*0Sstevel@tonic-gate * 1259*0Sstevel@tonic-gate * This routine checks the status property of the specified device node 1260*0Sstevel@tonic-gate * and returns 0 if the operational status indicates failure, and 1 otherwise. 1261*0Sstevel@tonic-gate * 1262*0Sstevel@tonic-gate * The property may exist on plug-in cards the existed before IEEE 1275-1994. 1263*0Sstevel@tonic-gate * And, in that case, the property may not even be a string. So we carefully 1264*0Sstevel@tonic-gate * check for the value "fail", in the beginning of the string, noting 1265*0Sstevel@tonic-gate * the property length. 1266*0Sstevel@tonic-gate */ 1267*0Sstevel@tonic-gate int 1268*0Sstevel@tonic-gate status_okay(int id, char *buf, int buflen) 1269*0Sstevel@tonic-gate { 1270*0Sstevel@tonic-gate char status_buf[OBP_MAXPROPNAME]; 1271*0Sstevel@tonic-gate char *bufp = buf; 1272*0Sstevel@tonic-gate int len = buflen; 1273*0Sstevel@tonic-gate int proplen; 1274*0Sstevel@tonic-gate static const char *status = "status"; 1275*0Sstevel@tonic-gate static const char *fail = "fail"; 1276*0Sstevel@tonic-gate size_t fail_len = strlen(fail); 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate /* 1279*0Sstevel@tonic-gate * Get the proplen ... if it's smaller than "fail", 1280*0Sstevel@tonic-gate * or doesn't exist ... then we don't care, since 1281*0Sstevel@tonic-gate * the value can't begin with the char string "fail". 1282*0Sstevel@tonic-gate * 1283*0Sstevel@tonic-gate * NB: proplen, if it's a string, includes the NULL in the 1284*0Sstevel@tonic-gate * the size of the property, and fail_len does not. 1285*0Sstevel@tonic-gate */ 1286*0Sstevel@tonic-gate proplen = prom_getproplen((dnode_t)id, (caddr_t)status); 1287*0Sstevel@tonic-gate if (proplen <= fail_len) /* nonexistent or uninteresting len */ 1288*0Sstevel@tonic-gate return (1); 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate /* 1291*0Sstevel@tonic-gate * if a buffer was provided, use it 1292*0Sstevel@tonic-gate */ 1293*0Sstevel@tonic-gate if ((buf == (char *)NULL) || (buflen <= 0)) { 1294*0Sstevel@tonic-gate bufp = status_buf; 1295*0Sstevel@tonic-gate len = sizeof (status_buf); 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate *bufp = (char)0; 1298*0Sstevel@tonic-gate 1299*0Sstevel@tonic-gate /* 1300*0Sstevel@tonic-gate * Get the property into the buffer, to the extent of the buffer, 1301*0Sstevel@tonic-gate * and in case the buffer is smaller than the property size, 1302*0Sstevel@tonic-gate * NULL terminate the buffer. (This handles the case where 1303*0Sstevel@tonic-gate * a buffer was passed in and the caller wants to print the 1304*0Sstevel@tonic-gate * value, but the buffer was too small). 1305*0Sstevel@tonic-gate */ 1306*0Sstevel@tonic-gate (void) prom_bounded_getprop((dnode_t)id, (caddr_t)status, 1307*0Sstevel@tonic-gate (caddr_t)bufp, len); 1308*0Sstevel@tonic-gate *(bufp + len - 1) = (char)0; 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate /* 1311*0Sstevel@tonic-gate * If the value begins with the char string "fail", 1312*0Sstevel@tonic-gate * then it means the node is failed. We don't care 1313*0Sstevel@tonic-gate * about any other values. We assume the node is ok 1314*0Sstevel@tonic-gate * although it might be 'disabled'. 1315*0Sstevel@tonic-gate */ 1316*0Sstevel@tonic-gate if (strncmp(bufp, fail, fail_len) == 0) 1317*0Sstevel@tonic-gate return (0); 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate return (1); 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate /* 1324*0Sstevel@tonic-gate * We set the cpu type from the idprom, if we can. 1325*0Sstevel@tonic-gate * Note that we just read out the contents of it, for the most part. 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate void 1328*0Sstevel@tonic-gate setcputype(void) 1329*0Sstevel@tonic-gate { 1330*0Sstevel@tonic-gate /* 1331*0Sstevel@tonic-gate * We cache the idprom info early on so that we don't 1332*0Sstevel@tonic-gate * rummage through the NVRAM unnecessarily later. 1333*0Sstevel@tonic-gate */ 1334*0Sstevel@tonic-gate (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate /* 1338*0Sstevel@tonic-gate * Here is where we actually infer meanings to the members of idprom_t 1339*0Sstevel@tonic-gate */ 1340*0Sstevel@tonic-gate void 1341*0Sstevel@tonic-gate parse_idprom(void) 1342*0Sstevel@tonic-gate { 1343*0Sstevel@tonic-gate if (idprom.id_format == IDFORM_1) { 1344*0Sstevel@tonic-gate uint_t i; 1345*0Sstevel@tonic-gate 1346*0Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)idprom.id_ether, 1347*0Sstevel@tonic-gate (struct ether_addr *)NULL); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate i = idprom.id_machine << 24; 1350*0Sstevel@tonic-gate i = i + idprom.id_serial; 1351*0Sstevel@tonic-gate numtos((ulong_t)i, hw_serial); 1352*0Sstevel@tonic-gate } else 1353*0Sstevel@tonic-gate prom_printf("Invalid format code in IDprom.\n"); 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate /* 1357*0Sstevel@tonic-gate * Allow for implementation specific correction of PROM property values. 1358*0Sstevel@tonic-gate */ 1359*0Sstevel@tonic-gate /*ARGSUSED*/ 1360*0Sstevel@tonic-gate void 1361*0Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, 1362*0Sstevel@tonic-gate caddr_t buffer) 1363*0Sstevel@tonic-gate { 1364*0Sstevel@tonic-gate /* 1365*0Sstevel@tonic-gate * There are no adjustments needed in this implementation. 1366*0Sstevel@tonic-gate */ 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate /* 1370*0Sstevel@tonic-gate * SECTION: DDI Interrupt 1371*0Sstevel@tonic-gate */ 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate /* 1374*0Sstevel@tonic-gate * get_intr_parent() is a generic routine that process a 1275 interrupt 1375*0Sstevel@tonic-gate * map (imap) property. This function returns a dev_info_t structure 1376*0Sstevel@tonic-gate * which claims ownership of the interrupt domain. 1377*0Sstevel@tonic-gate * It also returns the new interrupt translation within this new domain. 1378*0Sstevel@tonic-gate * If an interrupt-parent or interrupt-map property are not found, 1379*0Sstevel@tonic-gate * then we fallback to using the device tree's parent. 1380*0Sstevel@tonic-gate * 1381*0Sstevel@tonic-gate * imap entry format: 1382*0Sstevel@tonic-gate * <reg>,<interrupt>,<phandle>,<translated interrupt> 1383*0Sstevel@tonic-gate * reg - The register specification in the interrupts domain 1384*0Sstevel@tonic-gate * interrupt - The interrupt specification 1385*0Sstevel@tonic-gate * phandle - PROM handle of the device that owns the xlated interrupt domain 1386*0Sstevel@tonic-gate * translated interrupt - interrupt specifier in the parents domain 1387*0Sstevel@tonic-gate * note: <reg>,<interrupt> - The reg and interrupt can be combined to create 1388*0Sstevel@tonic-gate * a unique entry called a unit interrupt specifier. 1389*0Sstevel@tonic-gate * 1390*0Sstevel@tonic-gate * Here's the processing steps: 1391*0Sstevel@tonic-gate * step1 - If the interrupt-parent property exists, create the ispec and 1392*0Sstevel@tonic-gate * return the dip of the interrupt parent. 1393*0Sstevel@tonic-gate * step2 - Extract the interrupt-map property and the interrupt-map-mask 1394*0Sstevel@tonic-gate * If these don't exist, just return the device tree parent. 1395*0Sstevel@tonic-gate * step3 - build up the unit interrupt specifier to match against the 1396*0Sstevel@tonic-gate * interrupt map property 1397*0Sstevel@tonic-gate * step4 - Scan the interrupt-map property until a match is found 1398*0Sstevel@tonic-gate * step4a - Extract the interrupt parent 1399*0Sstevel@tonic-gate * step4b - Compare the unit interrupt specifier 1400*0Sstevel@tonic-gate */ 1401*0Sstevel@tonic-gate dev_info_t * 1402*0Sstevel@tonic-gate get_intr_parent(dev_info_t *pdip, dev_info_t *dip, 1403*0Sstevel@tonic-gate ddi_ispec_t *child_ispecp, ddi_ispec_t **new_ispecp) 1404*0Sstevel@tonic-gate { 1405*0Sstevel@tonic-gate prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req; 1406*0Sstevel@tonic-gate int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz, 1407*0Sstevel@tonic-gate addr_cells, intr_cells, reg_len, i, j; 1408*0Sstevel@tonic-gate int32_t match_found = 0; 1409*0Sstevel@tonic-gate dev_info_t *intr_parent_dip = NULL; 1410*0Sstevel@tonic-gate ddi_ispec_t *ispecp; 1411*0Sstevel@tonic-gate uint32_t *intr = child_ispecp->is_intr; 1412*0Sstevel@tonic-gate uint32_t nodeid; 1413*0Sstevel@tonic-gate static ddi_ispec_t *dup_ispec(ddi_ispec_t *ispecp); 1414*0Sstevel@tonic-gate #ifdef DEBUG 1415*0Sstevel@tonic-gate static int debug = 0; 1416*0Sstevel@tonic-gate #endif 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate *new_ispecp = (ddi_ispec_t *)NULL; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate /* 1421*0Sstevel@tonic-gate * step1 1422*0Sstevel@tonic-gate * If we have an interrupt-parent property, this property represents 1423*0Sstevel@tonic-gate * the nodeid of our interrupt parent. 1424*0Sstevel@tonic-gate */ 1425*0Sstevel@tonic-gate if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 1426*0Sstevel@tonic-gate "interrupt-parent", -1)) != -1) { 1427*0Sstevel@tonic-gate intr_parent_dip = e_ddi_nodeid_to_dip(nodeid); 1428*0Sstevel@tonic-gate ASSERT(intr_parent_dip); 1429*0Sstevel@tonic-gate /* 1430*0Sstevel@tonic-gate * Attach the interrupt parent. 1431*0Sstevel@tonic-gate * 1432*0Sstevel@tonic-gate * N.B. e_ddi_nodeid_to_dip() isn't safe under DR. 1433*0Sstevel@tonic-gate * Also, interrupt parent isn't held. This needs 1434*0Sstevel@tonic-gate * to be revisited if DR-capable platforms implement 1435*0Sstevel@tonic-gate * interrupt redirection. 1436*0Sstevel@tonic-gate */ 1437*0Sstevel@tonic-gate if (i_ddi_attach_node_hierarchy(intr_parent_dip) 1438*0Sstevel@tonic-gate != DDI_SUCCESS) { 1439*0Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 1440*0Sstevel@tonic-gate return (NULL); 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 1444*0Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate *new_ispecp = ispecp; 1447*0Sstevel@tonic-gate return (intr_parent_dip); 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate /* 1451*0Sstevel@tonic-gate * step2 1452*0Sstevel@tonic-gate * Get interrupt map structure from PROM property 1453*0Sstevel@tonic-gate */ 1454*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 1455*0Sstevel@tonic-gate "interrupt-map", (caddr_t)&imap, &imap_sz) 1456*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 1457*0Sstevel@tonic-gate /* 1458*0Sstevel@tonic-gate * If we don't have an imap property, default to using the 1459*0Sstevel@tonic-gate * device tree. 1460*0Sstevel@tonic-gate */ 1461*0Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 1462*0Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate *new_ispecp = ispecp; 1465*0Sstevel@tonic-gate ndi_hold_devi(pdip); 1466*0Sstevel@tonic-gate return (pdip); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate /* Get the interrupt mask property */ 1470*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 1471*0Sstevel@tonic-gate "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz) 1472*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 1473*0Sstevel@tonic-gate /* 1474*0Sstevel@tonic-gate * If we don't find this property, we have to fail the request 1475*0Sstevel@tonic-gate * because the 1275 imap property wasn't defined correctly. 1476*0Sstevel@tonic-gate */ 1477*0Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 1478*0Sstevel@tonic-gate goto exit2; 1479*0Sstevel@tonic-gate } 1480*0Sstevel@tonic-gate 1481*0Sstevel@tonic-gate /* Get the address cell size */ 1482*0Sstevel@tonic-gate addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 1483*0Sstevel@tonic-gate "#address-cells", 2); 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate /* Get the interrupts cell size */ 1486*0Sstevel@tonic-gate intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 1487*0Sstevel@tonic-gate "#interrupt-cells", 1); 1488*0Sstevel@tonic-gate 1489*0Sstevel@tonic-gate /* 1490*0Sstevel@tonic-gate * step3 1491*0Sstevel@tonic-gate * Now lets build up the unit interrupt specifier e.g. reg,intr 1492*0Sstevel@tonic-gate * and apply the imap mask. match_req will hold this when we're 1493*0Sstevel@tonic-gate * through. 1494*0Sstevel@tonic-gate */ 1495*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "reg", 1496*0Sstevel@tonic-gate (caddr_t)®_p, ®_len) != DDI_SUCCESS) { 1497*0Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 1498*0Sstevel@tonic-gate goto exit3; 1499*0Sstevel@tonic-gate } 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) + 1502*0Sstevel@tonic-gate CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP); 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate for (i = 0; i < addr_cells; i++) 1505*0Sstevel@tonic-gate match_req[i] = (reg_p[i] & imap_mask[i]); 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate for (j = 0; j < intr_cells; i++, j++) 1508*0Sstevel@tonic-gate match_req[i] = (intr[j] & imap_mask[i]); 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate /* Calculate the imap size in cells */ 1511*0Sstevel@tonic-gate imap_cells = BYTES_TO_1275_CELLS(imap_sz); 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate #ifdef DEBUG 1514*0Sstevel@tonic-gate if (debug) 1515*0Sstevel@tonic-gate prom_printf("reg cell size 0x%x, intr cell size 0x%x, " 1516*0Sstevel@tonic-gate "match_request 0x%x, imap 0x%x\n", addr_cells, intr_cells, 1517*0Sstevel@tonic-gate match_req, imap); 1518*0Sstevel@tonic-gate #endif 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate /* 1521*0Sstevel@tonic-gate * Scan the imap property looking for a match of the interrupt unit 1522*0Sstevel@tonic-gate * specifier. This loop is rather complex since the data within the 1523*0Sstevel@tonic-gate * imap property may vary in size. 1524*0Sstevel@tonic-gate */ 1525*0Sstevel@tonic-gate for (scan = imap, imap_scan_cells = i = 0; 1526*0Sstevel@tonic-gate imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) { 1527*0Sstevel@tonic-gate int new_intr_cells; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate /* Set the index to the nodeid field */ 1530*0Sstevel@tonic-gate i = addr_cells + intr_cells; 1531*0Sstevel@tonic-gate 1532*0Sstevel@tonic-gate /* 1533*0Sstevel@tonic-gate * step4a 1534*0Sstevel@tonic-gate * Translate the nodeid field to a dip 1535*0Sstevel@tonic-gate */ 1536*0Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 1537*0Sstevel@tonic-gate intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]); 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate ASSERT(intr_parent_dip != 0); 1540*0Sstevel@tonic-gate #ifdef DEBUG 1541*0Sstevel@tonic-gate if (debug) 1542*0Sstevel@tonic-gate prom_printf("scan 0x%x\n", scan); 1543*0Sstevel@tonic-gate #endif 1544*0Sstevel@tonic-gate /* 1545*0Sstevel@tonic-gate * The tmp_dip describes the new domain, get it's interrupt 1546*0Sstevel@tonic-gate * cell size 1547*0Sstevel@tonic-gate */ 1548*0Sstevel@tonic-gate new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0, 1549*0Sstevel@tonic-gate "#interrupts-cells", 1); 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate /* 1552*0Sstevel@tonic-gate * step4b 1553*0Sstevel@tonic-gate * See if we have a match on the interrupt unit specifier 1554*0Sstevel@tonic-gate */ 1555*0Sstevel@tonic-gate if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells) 1556*0Sstevel@tonic-gate == 0) { 1557*0Sstevel@tonic-gate ddi_ispec_t ispec; 1558*0Sstevel@tonic-gate uint32_t *intr; 1559*0Sstevel@tonic-gate 1560*0Sstevel@tonic-gate /* 1561*0Sstevel@tonic-gate * Copy The childs ispec info excluding the interrupt 1562*0Sstevel@tonic-gate */ 1563*0Sstevel@tonic-gate ispec = *child_ispecp; 1564*0Sstevel@tonic-gate 1565*0Sstevel@tonic-gate match_found = 1; 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate /* 1568*0Sstevel@tonic-gate * If we have an imap parent whose not in our device 1569*0Sstevel@tonic-gate * tree path, we need to hold and install that driver. 1570*0Sstevel@tonic-gate */ 1571*0Sstevel@tonic-gate if (i_ddi_attach_node_hierarchy(intr_parent_dip) 1572*0Sstevel@tonic-gate != DDI_SUCCESS) { 1573*0Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 1574*0Sstevel@tonic-gate intr_parent_dip = (dev_info_t *)NULL; 1575*0Sstevel@tonic-gate goto exit4; 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate /* 1579*0Sstevel@tonic-gate * We need to handcraft an ispec along with a bus 1580*0Sstevel@tonic-gate * interrupt value, so we can dup it into our 1581*0Sstevel@tonic-gate * standard ispec structure. 1582*0Sstevel@tonic-gate */ 1583*0Sstevel@tonic-gate /* Extract the translated interrupt information */ 1584*0Sstevel@tonic-gate intr = kmem_alloc( 1585*0Sstevel@tonic-gate CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP); 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate for (j = 0; j < new_intr_cells; j++, i++) 1588*0Sstevel@tonic-gate intr[j] = scan[i]; 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate ispec.is_intr_sz = 1591*0Sstevel@tonic-gate CELLS_1275_TO_BYTES(new_intr_cells); 1592*0Sstevel@tonic-gate ispec.is_intr = intr; 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate ispecp = dup_ispec(&ispec); 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells)); 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate #ifdef DEBUG 1599*0Sstevel@tonic-gate if (debug) 1600*0Sstevel@tonic-gate prom_printf("dip 0x%x, intr info 0x%x\n", 1601*0Sstevel@tonic-gate intr_parent_dip, ispecp); 1602*0Sstevel@tonic-gate #endif 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate break; 1605*0Sstevel@tonic-gate } else { 1606*0Sstevel@tonic-gate #ifdef DEBUG 1607*0Sstevel@tonic-gate if (debug) 1608*0Sstevel@tonic-gate prom_printf("dip 0x%x\n", intr_parent_dip); 1609*0Sstevel@tonic-gate #endif 1610*0Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 1611*0Sstevel@tonic-gate intr_parent_dip = NULL; 1612*0Sstevel@tonic-gate i += new_intr_cells; 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate } 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate /* 1617*0Sstevel@tonic-gate * If we haven't found our interrupt parent at this point, fallback 1618*0Sstevel@tonic-gate * to using the device tree. 1619*0Sstevel@tonic-gate */ 1620*0Sstevel@tonic-gate if (!match_found) { 1621*0Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 1622*0Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate ndi_hold_devi(pdip); 1625*0Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 1626*0Sstevel@tonic-gate intr_parent_dip = pdip; 1627*0Sstevel@tonic-gate } 1628*0Sstevel@tonic-gate 1629*0Sstevel@tonic-gate ASSERT(ispecp != NULL); 1630*0Sstevel@tonic-gate ASSERT(intr_parent_dip != NULL); 1631*0Sstevel@tonic-gate *new_ispecp = ispecp; 1632*0Sstevel@tonic-gate 1633*0Sstevel@tonic-gate exit4: 1634*0Sstevel@tonic-gate kmem_free(reg_p, reg_len); 1635*0Sstevel@tonic-gate kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) + 1636*0Sstevel@tonic-gate CELLS_1275_TO_BYTES(intr_cells)); 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate exit3: 1639*0Sstevel@tonic-gate kmem_free(imap_mask, imap_mask_sz); 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate exit2: 1642*0Sstevel@tonic-gate kmem_free(imap, imap_sz); 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate return (intr_parent_dip); 1645*0Sstevel@tonic-gate } 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate /* 1648*0Sstevel@tonic-gate * Support routine for duplicating and initializing an interrupt specification. 1649*0Sstevel@tonic-gate * The bus interrupt value will be allocated at the end of this structure, so 1650*0Sstevel@tonic-gate * the corresponding routine i_ddi_free_ispec() should be used to free the 1651*0Sstevel@tonic-gate * interrupt specification. 1652*0Sstevel@tonic-gate */ 1653*0Sstevel@tonic-gate static ddi_ispec_t * 1654*0Sstevel@tonic-gate dup_ispec(ddi_ispec_t *ispecp) 1655*0Sstevel@tonic-gate { 1656*0Sstevel@tonic-gate ddi_ispec_t *new_ispecp; 1657*0Sstevel@tonic-gate 1658*0Sstevel@tonic-gate new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz, 1659*0Sstevel@tonic-gate KM_SLEEP); 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate /* Copy the contents of the ispec */ 1662*0Sstevel@tonic-gate *new_ispecp = *ispecp; 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate /* Reset the intr pointer to the one just created */ 1665*0Sstevel@tonic-gate new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1); 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr, 1668*0Sstevel@tonic-gate BYTES_TO_1275_CELLS(ispecp->is_intr_sz)); 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate return (new_ispecp); 1671*0Sstevel@tonic-gate } 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate int 1674*0Sstevel@tonic-gate i_ddi_get_nintrs(dev_info_t *dip) 1675*0Sstevel@tonic-gate { 1676*0Sstevel@tonic-gate int32_t intrlen; 1677*0Sstevel@tonic-gate prop_1275_cell_t intr_sz; 1678*0Sstevel@tonic-gate prop_1275_cell_t *ip; 1679*0Sstevel@tonic-gate int32_t ret = 0; 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS | 1682*0Sstevel@tonic-gate DDI_PROP_CANSLEEP, 1683*0Sstevel@tonic-gate "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 1686*0Sstevel@tonic-gate "#interrupt-cells", 1); 1687*0Sstevel@tonic-gate /* adjust for number of bytes */ 1688*0Sstevel@tonic-gate intr_sz = CELLS_1275_TO_BYTES(intr_sz); 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate ret = intrlen / intr_sz; 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate kmem_free(ip, intrlen); 1693*0Sstevel@tonic-gate } 1694*0Sstevel@tonic-gate 1695*0Sstevel@tonic-gate return (ret); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate /*ARGSUSED*/ 1699*0Sstevel@tonic-gate uint_t 1700*0Sstevel@tonic-gate softlevel1(caddr_t arg) 1701*0Sstevel@tonic-gate { 1702*0Sstevel@tonic-gate extern int siron_pending; 1703*0Sstevel@tonic-gate 1704*0Sstevel@tonic-gate siron_pending = 0; 1705*0Sstevel@tonic-gate softint(); 1706*0Sstevel@tonic-gate return (1); 1707*0Sstevel@tonic-gate } 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate /* 1710*0Sstevel@tonic-gate * indirection table, to save us some large switch statements 1711*0Sstevel@tonic-gate * NOTE: This must agree with "INTLEVEL_foo" constants in 1712*0Sstevel@tonic-gate * <sys/avintr.h> 1713*0Sstevel@tonic-gate */ 1714*0Sstevel@tonic-gate struct autovec *const vectorlist[] = { 0 }; 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate /* 1717*0Sstevel@tonic-gate * This value is exported here for the functions in avintr.c 1718*0Sstevel@tonic-gate */ 1719*0Sstevel@tonic-gate const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); 1720*0Sstevel@tonic-gate 1721*0Sstevel@tonic-gate /* 1722*0Sstevel@tonic-gate * Check for machine specific interrupt levels which cannot be reassigned by 1723*0Sstevel@tonic-gate * settrap(), sun4u version. 1724*0Sstevel@tonic-gate * 1725*0Sstevel@tonic-gate * sun4u does not support V8 SPARC "fast trap" handlers. 1726*0Sstevel@tonic-gate */ 1727*0Sstevel@tonic-gate /*ARGSUSED*/ 1728*0Sstevel@tonic-gate int 1729*0Sstevel@tonic-gate exclude_settrap(int lvl) 1730*0Sstevel@tonic-gate { 1731*0Sstevel@tonic-gate return (1); 1732*0Sstevel@tonic-gate } 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate /* 1735*0Sstevel@tonic-gate * Check for machine specific interrupt levels which cannot have interrupt 1736*0Sstevel@tonic-gate * handlers added. We allow levels 1 through 15; level 0 is nonsense. 1737*0Sstevel@tonic-gate */ 1738*0Sstevel@tonic-gate /*ARGSUSED*/ 1739*0Sstevel@tonic-gate int 1740*0Sstevel@tonic-gate exclude_level(int lvl) 1741*0Sstevel@tonic-gate { 1742*0Sstevel@tonic-gate return ((lvl < 1) || (lvl > 15)); 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate /* 1746*0Sstevel@tonic-gate * The following functions ready a cautious request to go up to the nexus 1747*0Sstevel@tonic-gate * driver. It is up to the nexus driver to decide how to process the request. 1748*0Sstevel@tonic-gate * It may choose to call i_ddi_do_caut_get/put in this file, or do it 1749*0Sstevel@tonic-gate * differently. 1750*0Sstevel@tonic-gate */ 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate static void 1753*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops( 1754*0Sstevel@tonic-gate ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size, 1755*0Sstevel@tonic-gate size_t repcount, uint_t flags, ddi_ctl_enum_t cmd) 1756*0Sstevel@tonic-gate { 1757*0Sstevel@tonic-gate peekpoke_ctlops_t cautacc_ctlops_arg; 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate cautacc_ctlops_arg.size = size; 1760*0Sstevel@tonic-gate cautacc_ctlops_arg.dev_addr = dev_addr; 1761*0Sstevel@tonic-gate cautacc_ctlops_arg.host_addr = host_addr; 1762*0Sstevel@tonic-gate cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp; 1763*0Sstevel@tonic-gate cautacc_ctlops_arg.repcount = repcount; 1764*0Sstevel@tonic-gate cautacc_ctlops_arg.flags = flags; 1765*0Sstevel@tonic-gate 1766*0Sstevel@tonic-gate (void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd, 1767*0Sstevel@tonic-gate &cautacc_ctlops_arg, NULL); 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate 1770*0Sstevel@tonic-gate uint8_t 1771*0Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr) 1772*0Sstevel@tonic-gate { 1773*0Sstevel@tonic-gate uint8_t value; 1774*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1775*0Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK); 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate return (value); 1778*0Sstevel@tonic-gate } 1779*0Sstevel@tonic-gate 1780*0Sstevel@tonic-gate uint16_t 1781*0Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr) 1782*0Sstevel@tonic-gate { 1783*0Sstevel@tonic-gate uint16_t value; 1784*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1785*0Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK); 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate return (value); 1788*0Sstevel@tonic-gate } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate uint32_t 1791*0Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr) 1792*0Sstevel@tonic-gate { 1793*0Sstevel@tonic-gate uint32_t value; 1794*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1795*0Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK); 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate return (value); 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate uint64_t 1801*0Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr) 1802*0Sstevel@tonic-gate { 1803*0Sstevel@tonic-gate uint64_t value; 1804*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1805*0Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK); 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate return (value); 1808*0Sstevel@tonic-gate } 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate void 1811*0Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value) 1812*0Sstevel@tonic-gate { 1813*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1814*0Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE); 1815*0Sstevel@tonic-gate } 1816*0Sstevel@tonic-gate 1817*0Sstevel@tonic-gate void 1818*0Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value) 1819*0Sstevel@tonic-gate { 1820*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1821*0Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE); 1822*0Sstevel@tonic-gate } 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate void 1825*0Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value) 1826*0Sstevel@tonic-gate { 1827*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1828*0Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE); 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate void 1832*0Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value) 1833*0Sstevel@tonic-gate { 1834*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1835*0Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE); 1836*0Sstevel@tonic-gate } 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate void 1839*0Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 1840*0Sstevel@tonic-gate size_t repcount, uint_t flags) 1841*0Sstevel@tonic-gate { 1842*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1843*0Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK); 1844*0Sstevel@tonic-gate } 1845*0Sstevel@tonic-gate 1846*0Sstevel@tonic-gate void 1847*0Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr, 1848*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 1849*0Sstevel@tonic-gate { 1850*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1851*0Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK); 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gate void 1855*0Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr, 1856*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 1857*0Sstevel@tonic-gate { 1858*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1859*0Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK); 1860*0Sstevel@tonic-gate } 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate void 1863*0Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr, 1864*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 1865*0Sstevel@tonic-gate { 1866*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1867*0Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK); 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate void 1871*0Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 1872*0Sstevel@tonic-gate size_t repcount, uint_t flags) 1873*0Sstevel@tonic-gate { 1874*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1875*0Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE); 1876*0Sstevel@tonic-gate } 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate void 1879*0Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr, 1880*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 1881*0Sstevel@tonic-gate { 1882*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1883*0Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE); 1884*0Sstevel@tonic-gate } 1885*0Sstevel@tonic-gate 1886*0Sstevel@tonic-gate void 1887*0Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr, 1888*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 1889*0Sstevel@tonic-gate { 1890*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1891*0Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE); 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate void 1895*0Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr, 1896*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 1897*0Sstevel@tonic-gate { 1898*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1899*0Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE); 1900*0Sstevel@tonic-gate } 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate /* 1903*0Sstevel@tonic-gate * This is called only to process peek/poke when the DIP is NULL. 1904*0Sstevel@tonic-gate * Assume that this is for memory, as nexi take care of device safe accesses. 1905*0Sstevel@tonic-gate */ 1906*0Sstevel@tonic-gate int 1907*0Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args) 1908*0Sstevel@tonic-gate { 1909*0Sstevel@tonic-gate int err = DDI_SUCCESS; 1910*0Sstevel@tonic-gate on_trap_data_t otd; 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate /* Set up protected environment. */ 1913*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 1914*0Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 1915*0Sstevel@tonic-gate 1916*0Sstevel@tonic-gate if (cmd == DDI_CTLOPS_POKE) { 1917*0Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 1918*0Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 1919*0Sstevel@tonic-gate (void *)in_args->host_addr); 1920*0Sstevel@tonic-gate } else { 1921*0Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 1922*0Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 1923*0Sstevel@tonic-gate (void *)in_args->host_addr); 1924*0Sstevel@tonic-gate } 1925*0Sstevel@tonic-gate otd.ot_trampoline = tramp; 1926*0Sstevel@tonic-gate } else 1927*0Sstevel@tonic-gate err = DDI_FAILURE; 1928*0Sstevel@tonic-gate 1929*0Sstevel@tonic-gate /* Take down protected environment. */ 1930*0Sstevel@tonic-gate no_trap(); 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate return (err); 1933*0Sstevel@tonic-gate } 1934