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 root nexus driver 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/conf.h> 34*0Sstevel@tonic-gate #include <sys/modctl.h> 35*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 36*0Sstevel@tonic-gate #include <sys/sunndi.h> 37*0Sstevel@tonic-gate #include <sys/vmsystm.h> 38*0Sstevel@tonic-gate #include <sys/async.h> 39*0Sstevel@tonic-gate #include <sys/intr.h> 40*0Sstevel@tonic-gate #include <sys/ndifm.h> 41*0Sstevel@tonic-gate #include <vm/seg_dev.h> 42*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 43*0Sstevel@tonic-gate #include <sys/ontrap.h> 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate /* Useful debugging Stuff */ 46*0Sstevel@tonic-gate #include <sys/nexusdebug.h> 47*0Sstevel@tonic-gate #define ROOTNEX_MAP_DEBUG 0x1 48*0Sstevel@tonic-gate #define ROOTNEX_INTR_DEBUG 0x2 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate /* 51*0Sstevel@tonic-gate * config information 52*0Sstevel@tonic-gate */ 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static int 55*0Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 56*0Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static int 59*0Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 60*0Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate static int 63*0Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip, 64*0Sstevel@tonic-gate struct hat *hat, struct seg *seg, caddr_t addr, 65*0Sstevel@tonic-gate struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate static int 68*0Sstevel@tonic-gate rootnex_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate static int 71*0Sstevel@tonic-gate rootnex_busop_fminit(dev_info_t *dip, dev_info_t *tdip, int tcap, 72*0Sstevel@tonic-gate ddi_iblock_cookie_t *ibc); 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate static void 75*0Sstevel@tonic-gate rootnex_fm_init(dev_info_t *); 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate static int 78*0Sstevel@tonic-gate rootnex_ctlops_peekpoke(ddi_ctl_enum_t, peekpoke_ctlops_t *, void *result); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate /* 81*0Sstevel@tonic-gate * Defined in $KARCH/io/mach_rootnex.c 82*0Sstevel@tonic-gate */ 83*0Sstevel@tonic-gate int rootnex_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 84*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 85*0Sstevel@tonic-gate #pragma weak rootnex_add_intr_impl 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate int rootnex_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 88*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 89*0Sstevel@tonic-gate #pragma weak rootnex_remove_intr_impl 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate void rootnex_get_intr_pri(dev_info_t *dip, dev_info_t *rdip, 92*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 93*0Sstevel@tonic-gate #pragma weak rootnex_get_intr_pri 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate int rootnex_name_child_impl(dev_info_t *child, char *name, int namelen); 96*0Sstevel@tonic-gate #pragma weak rootnex_name_child_impl 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate int rootnex_ctl_initchild_impl(dev_info_t *dip); 99*0Sstevel@tonic-gate #pragma weak rootnex_initchild_impl 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate void rootnex_ctl_uninitchild_impl(dev_info_t *dip); 102*0Sstevel@tonic-gate #pragma weak rootnex_uninitchild_impl 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate int rootnex_ctl_reportdev_impl(dev_info_t *dev); 105*0Sstevel@tonic-gate #pragma weak rootnex_reportdev_impl 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate static struct cb_ops rootnex_cb_ops = { 108*0Sstevel@tonic-gate nodev, /* open */ 109*0Sstevel@tonic-gate nodev, /* close */ 110*0Sstevel@tonic-gate nodev, /* strategy */ 111*0Sstevel@tonic-gate nodev, /* print */ 112*0Sstevel@tonic-gate nodev, /* dump */ 113*0Sstevel@tonic-gate nodev, /* read */ 114*0Sstevel@tonic-gate nodev, /* write */ 115*0Sstevel@tonic-gate nodev, /* ioctl */ 116*0Sstevel@tonic-gate nodev, /* devmap */ 117*0Sstevel@tonic-gate nodev, /* mmap */ 118*0Sstevel@tonic-gate nodev, /* segmap */ 119*0Sstevel@tonic-gate nochpoll, /* chpoll */ 120*0Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 121*0Sstevel@tonic-gate NULL, /* struct streamtab */ 122*0Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* compatibility flags */ 123*0Sstevel@tonic-gate CB_REV, /* Rev */ 124*0Sstevel@tonic-gate nodev, /* cb_aread */ 125*0Sstevel@tonic-gate nodev /* cb_awrite */ 126*0Sstevel@tonic-gate }; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate static struct bus_ops rootnex_bus_ops = { 129*0Sstevel@tonic-gate BUSO_REV, 130*0Sstevel@tonic-gate rootnex_map, 131*0Sstevel@tonic-gate NULL, 132*0Sstevel@tonic-gate NULL, 133*0Sstevel@tonic-gate NULL, 134*0Sstevel@tonic-gate rootnex_map_fault, 135*0Sstevel@tonic-gate ddi_no_dma_map, /* no rootnex_dma_map- now in sysio nexus */ 136*0Sstevel@tonic-gate ddi_no_dma_allochdl, 137*0Sstevel@tonic-gate ddi_no_dma_freehdl, 138*0Sstevel@tonic-gate ddi_no_dma_bindhdl, 139*0Sstevel@tonic-gate ddi_no_dma_unbindhdl, 140*0Sstevel@tonic-gate ddi_no_dma_flush, 141*0Sstevel@tonic-gate ddi_no_dma_win, 142*0Sstevel@tonic-gate ddi_no_dma_mctl, /* no rootnex_dma_mctl- now in sysio nexus */ 143*0Sstevel@tonic-gate rootnex_ctlops, 144*0Sstevel@tonic-gate ddi_bus_prop_op, 145*0Sstevel@tonic-gate i_ddi_rootnex_get_eventcookie, 146*0Sstevel@tonic-gate i_ddi_rootnex_add_eventcall, 147*0Sstevel@tonic-gate i_ddi_rootnex_remove_eventcall, 148*0Sstevel@tonic-gate i_ddi_rootnex_post_event, 149*0Sstevel@tonic-gate NULL, /* bus_intr_ctl */ 150*0Sstevel@tonic-gate NULL, /* bus_config */ 151*0Sstevel@tonic-gate NULL, /* bus_unconfig */ 152*0Sstevel@tonic-gate rootnex_busop_fminit, /* bus_fm_init */ 153*0Sstevel@tonic-gate NULL, /* bus_fm_fini */ 154*0Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 155*0Sstevel@tonic-gate NULL, /* bus_fm_access_fini */ 156*0Sstevel@tonic-gate NULL, /* bus_power */ 157*0Sstevel@tonic-gate rootnex_intr_ops /* bus_intr_op */ 158*0Sstevel@tonic-gate }; 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate static int rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 161*0Sstevel@tonic-gate static int rootnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate static struct dev_ops rootnex_ops = { 164*0Sstevel@tonic-gate DEVO_REV, 165*0Sstevel@tonic-gate 0, /* refcnt */ 166*0Sstevel@tonic-gate ddi_no_info, /* info */ 167*0Sstevel@tonic-gate nulldev, 168*0Sstevel@tonic-gate nulldev, /* probe */ 169*0Sstevel@tonic-gate rootnex_attach, 170*0Sstevel@tonic-gate rootnex_detach, 171*0Sstevel@tonic-gate nodev, /* reset */ 172*0Sstevel@tonic-gate &rootnex_cb_ops, 173*0Sstevel@tonic-gate &rootnex_bus_ops 174*0Sstevel@tonic-gate }; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate extern uint_t root_phys_addr_lo_mask; 178*0Sstevel@tonic-gate extern uint_t root_phys_addr_hi_mask; 179*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 180*0Sstevel@tonic-gate extern struct dev_ops rootnex_ops; 181*0Sstevel@tonic-gate extern struct cpu cpu0; 182*0Sstevel@tonic-gate extern ddi_iblock_cookie_t rootnex_err_ibc; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Add statically defined root properties to this list... 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate static const int pagesize = PAGESIZE; 189*0Sstevel@tonic-gate static const int mmu_pagesize = MMU_PAGESIZE; 190*0Sstevel@tonic-gate static const int mmu_pageoffset = MMU_PAGEOFFSET; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate struct prop_def { 193*0Sstevel@tonic-gate char *prop_name; 194*0Sstevel@tonic-gate caddr_t prop_value; 195*0Sstevel@tonic-gate }; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static struct prop_def root_props[] = { 198*0Sstevel@tonic-gate { "PAGESIZE", (caddr_t)&pagesize }, 199*0Sstevel@tonic-gate { "MMU_PAGESIZE", (caddr_t)&mmu_pagesize}, 200*0Sstevel@tonic-gate { "MMU_PAGEOFFSET", (caddr_t)&mmu_pageoffset}, 201*0Sstevel@tonic-gate }; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate static vmem_t *rootnex_regspec_arena; 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate #define NROOT_PROPS (sizeof (root_props) / sizeof (struct prop_def)) 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Module linkage information for the kernel. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate static struct modldrv modldrv = { 214*0Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a nexus driver */ 215*0Sstevel@tonic-gate "sun4 root nexus %I%", 216*0Sstevel@tonic-gate &rootnex_ops, /* Driver ops */ 217*0Sstevel@tonic-gate }; 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 220*0Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 221*0Sstevel@tonic-gate }; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate int 224*0Sstevel@tonic-gate _init(void) 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate int 230*0Sstevel@tonic-gate _fini(void) 231*0Sstevel@tonic-gate { 232*0Sstevel@tonic-gate return (EBUSY); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate int 236*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate /* 242*0Sstevel@tonic-gate * rootnex_attach: 243*0Sstevel@tonic-gate * 244*0Sstevel@tonic-gate * attach the root nexus. 245*0Sstevel@tonic-gate */ 246*0Sstevel@tonic-gate static void add_root_props(dev_info_t *); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /*ARGSUSED*/ 249*0Sstevel@tonic-gate static int 250*0Sstevel@tonic-gate rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 251*0Sstevel@tonic-gate { 252*0Sstevel@tonic-gate int length; 253*0Sstevel@tonic-gate char *valuep = NULL; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * Only do these functions when the driver is acting as the 257*0Sstevel@tonic-gate * root nexus, not when it is driving a memory controller. 258*0Sstevel@tonic-gate */ 259*0Sstevel@tonic-gate if (ddi_root_node() == devi) { 260*0Sstevel@tonic-gate rootnex_fm_init(devi); 261*0Sstevel@tonic-gate add_root_props(devi); 262*0Sstevel@tonic-gate i_ddi_rootnex_init_events(devi); 263*0Sstevel@tonic-gate rootnex_regspec_arena = vmem_create("regspec", 264*0Sstevel@tonic-gate (void *)PIOMAPBASE, PIOMAPSIZE, MMU_PAGESIZE, NULL, NULL, 265*0Sstevel@tonic-gate NULL, 0, VM_SLEEP); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, devi, PROP_LEN_AND_VAL_ALLOC, 269*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "banner-name", (caddr_t)&valuep, 270*0Sstevel@tonic-gate &length) == DDI_PROP_SUCCESS) { 271*0Sstevel@tonic-gate cmn_err(CE_CONT, "?root nexus = %s\n", valuep); 272*0Sstevel@tonic-gate kmem_free(valuep, length); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate /* 275*0Sstevel@tonic-gate * Add a no-suspend-resume property so that NDI 276*0Sstevel@tonic-gate * does not attempt to suspend/resume the rootnex 277*0Sstevel@tonic-gate * (or any of its aliases) node. 278*0Sstevel@tonic-gate */ 279*0Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 280*0Sstevel@tonic-gate "pm-hardware-state", "no-suspend-resume"); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate return (DDI_SUCCESS); 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate /*ARGSUSED*/ 286*0Sstevel@tonic-gate static int 287*0Sstevel@tonic-gate rootnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 288*0Sstevel@tonic-gate { 289*0Sstevel@tonic-gate return (DDI_SUCCESS); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate static void 293*0Sstevel@tonic-gate add_root_props(dev_info_t *devi) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate int i; 296*0Sstevel@tonic-gate struct prop_def *rpp; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * Note that this for loop works because all of the 300*0Sstevel@tonic-gate * properties in root_prop are integers 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate for (i = 0, rpp = root_props; i < NROOT_PROPS; ++i, ++rpp) { 303*0Sstevel@tonic-gate (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, 304*0Sstevel@tonic-gate rpp->prop_name, *((int *)rpp->prop_value)); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * Create the root node "boolean" property 309*0Sstevel@tonic-gate * corresponding to addressing type supported in the root node: 310*0Sstevel@tonic-gate * 311*0Sstevel@tonic-gate * Choices are: 312*0Sstevel@tonic-gate * "relative-addressing" (OBP PROMS) 313*0Sstevel@tonic-gate * "generic-addressing" (SunMon -- pseudo OBP/DDI) 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, 317*0Sstevel@tonic-gate DDI_RELATIVE_ADDRESSING, 1); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Create fault management capability property 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, "fm-capable", 323*0Sstevel@tonic-gate ddi_fm_capable(devi)); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate static int 327*0Sstevel@tonic-gate rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp, uint_t mapping_attr) 328*0Sstevel@tonic-gate { 329*0Sstevel@tonic-gate ulong_t base; 330*0Sstevel@tonic-gate caddr_t kaddr; 331*0Sstevel@tonic-gate pgcnt_t npages; 332*0Sstevel@tonic-gate pfn_t pfn; 333*0Sstevel@tonic-gate uint_t pgoffset; 334*0Sstevel@tonic-gate struct regspec *rp = mp->map_obj.rp; 335*0Sstevel@tonic-gate ddi_acc_hdl_t *hp; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */ 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * Take the bustype and the physical page base within the 341*0Sstevel@tonic-gate * bus space and turn it into a 28 bit page frame number. 342*0Sstevel@tonic-gate */ 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate pfn = BUSTYPE_TO_PFN(((rp->regspec_bustype) & root_phys_addr_hi_mask), 345*0Sstevel@tonic-gate mmu_btop(base)); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * Do a quick sanity check to make sure we are in I/O space. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate if (pf_is_memory(pfn)) 352*0Sstevel@tonic-gate return (DDI_ME_INVAL); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate if (rp->regspec_size == 0) { 355*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_regspec: zero " 356*0Sstevel@tonic-gate "regspec_size\n")); 357*0Sstevel@tonic-gate return (DDI_ME_INVAL); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if (mp->map_flags & DDI_MF_DEVICE_MAPPING) 361*0Sstevel@tonic-gate *vaddrp = (caddr_t)pfn; 362*0Sstevel@tonic-gate else { 363*0Sstevel@tonic-gate pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET; 364*0Sstevel@tonic-gate npages = mmu_btopr(rp->regspec_size + pgoffset); 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_regspec: Mapping " 367*0Sstevel@tonic-gate "%lu pages physical %x.%lx ", npages, rp->regspec_bustype, 368*0Sstevel@tonic-gate base)); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate if ((kaddr = vmem_alloc(rootnex_regspec_arena, 371*0Sstevel@tonic-gate ptob(npages), VM_NOSLEEP)) == NULL) 372*0Sstevel@tonic-gate return (DDI_ME_NORESOURCES); 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* 375*0Sstevel@tonic-gate * Now map in the pages we've allocated... 376*0Sstevel@tonic-gate */ 377*0Sstevel@tonic-gate hat_devload(kas.a_hat, kaddr, ptob(npages), pfn, 378*0Sstevel@tonic-gate mp->map_prot | mapping_attr, HAT_LOAD_LOCK); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate *vaddrp = kaddr + pgoffset; 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate hp = mp->map_handlep; 383*0Sstevel@tonic-gate if (hp) { 384*0Sstevel@tonic-gate hp->ah_pfn = pfn; 385*0Sstevel@tonic-gate hp->ah_pnum = npages; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("at virtual 0x%x\n", *vaddrp)); 390*0Sstevel@tonic-gate return (0); 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate static int 394*0Sstevel@tonic-gate rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) 395*0Sstevel@tonic-gate { 396*0Sstevel@tonic-gate caddr_t addr = *vaddrp; 397*0Sstevel@tonic-gate pgcnt_t npages; 398*0Sstevel@tonic-gate uint_t pgoffset; 399*0Sstevel@tonic-gate caddr_t base; 400*0Sstevel@tonic-gate struct regspec *rp; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate if (mp->map_flags & DDI_MF_DEVICE_MAPPING) 403*0Sstevel@tonic-gate return (0); 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate rp = mp->map_obj.rp; 406*0Sstevel@tonic-gate pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (rp->regspec_size == 0) { 409*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_unmap_regspec: " 410*0Sstevel@tonic-gate "zero regspec_size\n")); 411*0Sstevel@tonic-gate return (DDI_ME_INVAL); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate base = addr - pgoffset; 415*0Sstevel@tonic-gate npages = mmu_btopr(rp->regspec_size + pgoffset); 416*0Sstevel@tonic-gate hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK); 417*0Sstevel@tonic-gate vmem_free(rootnex_regspec_arena, base, ptob(npages)); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * Destroy the pointer - the mapping has logically gone 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate *vaddrp = (caddr_t)0; 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate return (0); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate static int 428*0Sstevel@tonic-gate rootnex_map_handle(ddi_map_req_t *mp) 429*0Sstevel@tonic-gate { 430*0Sstevel@tonic-gate ddi_acc_hdl_t *hp; 431*0Sstevel@tonic-gate uint_t hat_flags; 432*0Sstevel@tonic-gate register struct regspec *rp; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * Set up the hat_flags for the mapping. 436*0Sstevel@tonic-gate */ 437*0Sstevel@tonic-gate hp = mp->map_handlep; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_endian_flags) { 440*0Sstevel@tonic-gate case DDI_NEVERSWAP_ACC: 441*0Sstevel@tonic-gate hat_flags = HAT_NEVERSWAP | HAT_STRICTORDER; 442*0Sstevel@tonic-gate break; 443*0Sstevel@tonic-gate case DDI_STRUCTURE_BE_ACC: 444*0Sstevel@tonic-gate hat_flags = HAT_STRUCTURE_BE; 445*0Sstevel@tonic-gate break; 446*0Sstevel@tonic-gate case DDI_STRUCTURE_LE_ACC: 447*0Sstevel@tonic-gate hat_flags = HAT_STRUCTURE_LE; 448*0Sstevel@tonic-gate break; 449*0Sstevel@tonic-gate default: 450*0Sstevel@tonic-gate return (DDI_REGS_ACC_CONFLICT); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_dataorder) { 454*0Sstevel@tonic-gate case DDI_STRICTORDER_ACC: 455*0Sstevel@tonic-gate break; 456*0Sstevel@tonic-gate case DDI_UNORDERED_OK_ACC: 457*0Sstevel@tonic-gate hat_flags |= HAT_UNORDERED_OK; 458*0Sstevel@tonic-gate break; 459*0Sstevel@tonic-gate case DDI_MERGING_OK_ACC: 460*0Sstevel@tonic-gate hat_flags |= HAT_MERGING_OK; 461*0Sstevel@tonic-gate break; 462*0Sstevel@tonic-gate case DDI_LOADCACHING_OK_ACC: 463*0Sstevel@tonic-gate hat_flags |= HAT_LOADCACHING_OK; 464*0Sstevel@tonic-gate break; 465*0Sstevel@tonic-gate case DDI_STORECACHING_OK_ACC: 466*0Sstevel@tonic-gate hat_flags |= HAT_STORECACHING_OK; 467*0Sstevel@tonic-gate break; 468*0Sstevel@tonic-gate default: 469*0Sstevel@tonic-gate return (DDI_FAILURE); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate rp = mp->map_obj.rp; 473*0Sstevel@tonic-gate if (rp->regspec_size == 0) 474*0Sstevel@tonic-gate return (DDI_ME_INVAL); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate hp->ah_hat_flags = hat_flags; 477*0Sstevel@tonic-gate hp->ah_pfn = mmu_btop((ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET)); 478*0Sstevel@tonic-gate hp->ah_pnum = mmu_btopr(rp->regspec_size + 479*0Sstevel@tonic-gate (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET); 480*0Sstevel@tonic-gate return (DDI_SUCCESS); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate static int 484*0Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 485*0Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate struct regspec *rp, tmp_reg; 488*0Sstevel@tonic-gate ddi_map_req_t mr = *mp; /* Get private copy of request */ 489*0Sstevel@tonic-gate int error; 490*0Sstevel@tonic-gate uint_t mapping_attr; 491*0Sstevel@tonic-gate ddi_acc_hdl_t *hp = NULL; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate mp = &mr; 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate switch (mp->map_op) { 496*0Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 497*0Sstevel@tonic-gate case DDI_MO_UNMAP: 498*0Sstevel@tonic-gate case DDI_MO_MAP_HANDLE: 499*0Sstevel@tonic-gate break; 500*0Sstevel@tonic-gate default: 501*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: unimplemented map " 502*0Sstevel@tonic-gate "op %d.", mp->map_op)); 503*0Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (mp->map_flags & DDI_MF_USER_MAPPING) { 507*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: unimplemented map " 508*0Sstevel@tonic-gate "type: user.")); 509*0Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /* 513*0Sstevel@tonic-gate * First, if given an rnumber, convert it to a regspec... 514*0Sstevel@tonic-gate * (Presumably, this is on behalf of a child of the root node?) 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) { 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate int rnumber = mp->map_obj.rnumber; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate rp = i_ddi_rnumber_to_regspec(rdip, rnumber); 522*0Sstevel@tonic-gate if (rp == (struct regspec *)0) { 523*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: Out of " 524*0Sstevel@tonic-gate "range rnumber <%d>, device <%s>", rnumber, 525*0Sstevel@tonic-gate ddi_get_name(rdip))); 526*0Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate /* 530*0Sstevel@tonic-gate * Convert the given ddi_map_req_t from rnumber to regspec... 531*0Sstevel@tonic-gate */ 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 534*0Sstevel@tonic-gate mp->map_obj.rp = rp; 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * Adjust offset and length corresponding to called values... 539*0Sstevel@tonic-gate * XXX: A non-zero length means override the one in the regspec 540*0Sstevel@tonic-gate * XXX: regardless of what's in the parent's range?. 541*0Sstevel@tonic-gate */ 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */ 544*0Sstevel@tonic-gate rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */ 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate rp->regspec_addr += (uint_t)offset; 547*0Sstevel@tonic-gate if (len != 0) 548*0Sstevel@tonic-gate rp->regspec_size = (uint_t)len; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Apply any parent ranges at this level, if applicable. 552*0Sstevel@tonic-gate * (This is where nexus specific regspec translation takes place. 553*0Sstevel@tonic-gate * Use of this function is implicit agreement that translation is 554*0Sstevel@tonic-gate * provided via ddi_apply_range.) 555*0Sstevel@tonic-gate */ 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: applying range of parent " 558*0Sstevel@tonic-gate "<%s> to child <%s>...\n", ddi_get_name(dip), ddi_get_name(rdip))); 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0) 561*0Sstevel@tonic-gate return (error); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate switch (mp->map_op) { 564*0Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate /* 567*0Sstevel@tonic-gate * Set up the locked down kernel mapping to the regspec... 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate /* 571*0Sstevel@tonic-gate * If we were passed an access handle we need to determine 572*0Sstevel@tonic-gate * the "endian-ness" of the mapping and fill in the handle. 573*0Sstevel@tonic-gate */ 574*0Sstevel@tonic-gate if (mp->map_handlep) { 575*0Sstevel@tonic-gate hp = mp->map_handlep; 576*0Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_endian_flags) { 577*0Sstevel@tonic-gate case DDI_NEVERSWAP_ACC: 578*0Sstevel@tonic-gate mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER; 579*0Sstevel@tonic-gate break; 580*0Sstevel@tonic-gate case DDI_STRUCTURE_BE_ACC: 581*0Sstevel@tonic-gate mapping_attr = HAT_STRUCTURE_BE; 582*0Sstevel@tonic-gate break; 583*0Sstevel@tonic-gate case DDI_STRUCTURE_LE_ACC: 584*0Sstevel@tonic-gate mapping_attr = HAT_STRUCTURE_LE; 585*0Sstevel@tonic-gate break; 586*0Sstevel@tonic-gate default: 587*0Sstevel@tonic-gate return (DDI_REGS_ACC_CONFLICT); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_dataorder) { 591*0Sstevel@tonic-gate case DDI_STRICTORDER_ACC: 592*0Sstevel@tonic-gate break; 593*0Sstevel@tonic-gate case DDI_UNORDERED_OK_ACC: 594*0Sstevel@tonic-gate mapping_attr |= HAT_UNORDERED_OK; 595*0Sstevel@tonic-gate break; 596*0Sstevel@tonic-gate case DDI_MERGING_OK_ACC: 597*0Sstevel@tonic-gate mapping_attr |= HAT_MERGING_OK; 598*0Sstevel@tonic-gate break; 599*0Sstevel@tonic-gate case DDI_LOADCACHING_OK_ACC: 600*0Sstevel@tonic-gate mapping_attr |= HAT_LOADCACHING_OK; 601*0Sstevel@tonic-gate break; 602*0Sstevel@tonic-gate case DDI_STORECACHING_OK_ACC: 603*0Sstevel@tonic-gate mapping_attr |= HAT_STORECACHING_OK; 604*0Sstevel@tonic-gate break; 605*0Sstevel@tonic-gate default: 606*0Sstevel@tonic-gate return (DDI_REGS_ACC_CONFLICT); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate } else { 609*0Sstevel@tonic-gate mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER; 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate /* 613*0Sstevel@tonic-gate * Set up the mapping. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate error = rootnex_map_regspec(mp, vaddrp, mapping_attr); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate /* 618*0Sstevel@tonic-gate * Fill in the access handle if needed. 619*0Sstevel@tonic-gate */ 620*0Sstevel@tonic-gate if (hp) { 621*0Sstevel@tonic-gate hp->ah_addr = *vaddrp; 622*0Sstevel@tonic-gate hp->ah_hat_flags = mapping_attr; 623*0Sstevel@tonic-gate if (error == 0) 624*0Sstevel@tonic-gate impl_acc_hdl_init(hp); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate return (error); 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate case DDI_MO_UNMAP: 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate /* 631*0Sstevel@tonic-gate * Release mapping... 632*0Sstevel@tonic-gate */ 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate return (rootnex_unmap_regspec(mp, vaddrp)); 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate case DDI_MO_MAP_HANDLE: 637*0Sstevel@tonic-gate return (rootnex_map_handle(mp)); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate } 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate static int 645*0Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 646*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 647*0Sstevel@tonic-gate { 648*0Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 649*0Sstevel@tonic-gate int ret = DDI_SUCCESS; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate DPRINTF(ROOTNEX_INTR_DEBUG, ("rootnex_intr_ops: rdip=%s%d " 652*0Sstevel@tonic-gate "intr_op 0x%x hdlp 0x%p\n", ddi_driver_name(rdip), 653*0Sstevel@tonic-gate ddi_get_instance(rdip), intr_op, hdlp)); 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate switch (intr_op) { 656*0Sstevel@tonic-gate case DDI_INTROP_GETCAP: 657*0Sstevel@tonic-gate *(int *)result = 0; 658*0Sstevel@tonic-gate break; 659*0Sstevel@tonic-gate case DDI_INTROP_SETCAP: 660*0Sstevel@tonic-gate ret = DDI_ENOTSUP; 661*0Sstevel@tonic-gate break; 662*0Sstevel@tonic-gate case DDI_INTROP_ALLOC: 663*0Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 664*0Sstevel@tonic-gate break; 665*0Sstevel@tonic-gate case DDI_INTROP_FREE: 666*0Sstevel@tonic-gate break; 667*0Sstevel@tonic-gate case DDI_INTROP_GETPRI: 668*0Sstevel@tonic-gate rootnex_get_intr_pri(dip, rdip, hdlp); 669*0Sstevel@tonic-gate *(int *)result = ip->is_pil; 670*0Sstevel@tonic-gate break; 671*0Sstevel@tonic-gate case DDI_INTROP_SETPRI: 672*0Sstevel@tonic-gate ip->is_pil = (*(int *)result); 673*0Sstevel@tonic-gate break; 674*0Sstevel@tonic-gate case DDI_INTROP_ADDISR: 675*0Sstevel@tonic-gate ret = rootnex_add_intr_impl(dip, rdip, hdlp); 676*0Sstevel@tonic-gate break; 677*0Sstevel@tonic-gate case DDI_INTROP_REMISR: 678*0Sstevel@tonic-gate ret = rootnex_remove_intr_impl(dip, rdip, hdlp); 679*0Sstevel@tonic-gate break; 680*0Sstevel@tonic-gate case DDI_INTROP_ENABLE: 681*0Sstevel@tonic-gate case DDI_INTROP_DISABLE: 682*0Sstevel@tonic-gate break; 683*0Sstevel@tonic-gate case DDI_INTROP_NINTRS: 684*0Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 685*0Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip); 686*0Sstevel@tonic-gate break; 687*0Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 688*0Sstevel@tonic-gate /* Root nexus driver supports only fixed interrupts */ 689*0Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip) ? 690*0Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 691*0Sstevel@tonic-gate break; 692*0Sstevel@tonic-gate default: 693*0Sstevel@tonic-gate ret = DDI_ENOTSUP; 694*0Sstevel@tonic-gate break; 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate return (ret); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate /* 702*0Sstevel@tonic-gate * Shorthand defines 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate #define DMAOBJ_PP_PP dmao_obj.pp_obj.pp_pp 706*0Sstevel@tonic-gate #define DMAOBJ_PP_OFF dmao_ogj.pp_obj.pp_offset 707*0Sstevel@tonic-gate #define ALO dma_lim->dlim_addr_lo 708*0Sstevel@tonic-gate #define AHI dma_lim->dlim_addr_hi 709*0Sstevel@tonic-gate #define OBJSIZE dmareq->dmar_object.dmao_size 710*0Sstevel@tonic-gate #define ORIGVADDR dmareq->dmar_object.dmao_obj.virt_obj.v_addr 711*0Sstevel@tonic-gate #define RED ((mp->dmai_rflags & DDI_DMA_REDZONE)? 1 : 0) 712*0Sstevel@tonic-gate #define DIRECTION (mp->dmai_rflags & DDI_DMA_RDWR) 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /* 715*0Sstevel@tonic-gate * rootnex_map_fault: 716*0Sstevel@tonic-gate * 717*0Sstevel@tonic-gate * fault in mappings for requestors 718*0Sstevel@tonic-gate */ 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate /*ARGSUSED*/ 721*0Sstevel@tonic-gate static int 722*0Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip, 723*0Sstevel@tonic-gate struct hat *hat, struct seg *seg, caddr_t addr, 724*0Sstevel@tonic-gate struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock) 725*0Sstevel@tonic-gate { 726*0Sstevel@tonic-gate extern struct seg_ops segdev_ops; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_fault: address <%x> " 729*0Sstevel@tonic-gate "pfn <%x>", addr, pfn)); 730*0Sstevel@tonic-gate DPRINTF(ROOTNEX_MAP_DEBUG, (" Seg <%s>\n", 731*0Sstevel@tonic-gate seg->s_ops == &segdev_ops ? "segdev" : 732*0Sstevel@tonic-gate seg == &kvseg ? "segkmem" : "NONE!")); 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate /* 735*0Sstevel@tonic-gate * This is all terribly broken, but it is a start 736*0Sstevel@tonic-gate * 737*0Sstevel@tonic-gate * XXX Note that this test means that segdev_ops 738*0Sstevel@tonic-gate * must be exported from seg_dev.c. 739*0Sstevel@tonic-gate * XXX What about devices with their own segment drivers? 740*0Sstevel@tonic-gate */ 741*0Sstevel@tonic-gate if (seg->s_ops == &segdev_ops) { 742*0Sstevel@tonic-gate register struct segdev_data *sdp = 743*0Sstevel@tonic-gate (struct segdev_data *)seg->s_data; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate if (hat == NULL) { 746*0Sstevel@tonic-gate /* 747*0Sstevel@tonic-gate * This is one plausible interpretation of 748*0Sstevel@tonic-gate * a null hat i.e. use the first hat on the 749*0Sstevel@tonic-gate * address space hat list which by convention is 750*0Sstevel@tonic-gate * the hat of the system MMU. At alternative 751*0Sstevel@tonic-gate * would be to panic .. this might well be better .. 752*0Sstevel@tonic-gate */ 753*0Sstevel@tonic-gate ASSERT(AS_READ_HELD(seg->s_as, &seg->s_as->a_lock)); 754*0Sstevel@tonic-gate hat = seg->s_as->a_hat; 755*0Sstevel@tonic-gate cmn_err(CE_NOTE, "rootnex_map_fault: nil hat"); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate hat_devload(hat, addr, MMU_PAGESIZE, pfn, prot | sdp->hat_attr, 758*0Sstevel@tonic-gate (lock ? HAT_LOAD_LOCK : HAT_LOAD)); 759*0Sstevel@tonic-gate } else if (seg == &kvseg && dp == (struct devpage *)0) { 760*0Sstevel@tonic-gate hat_devload(kas.a_hat, addr, MMU_PAGESIZE, pfn, prot, 761*0Sstevel@tonic-gate HAT_LOAD_LOCK); 762*0Sstevel@tonic-gate } else 763*0Sstevel@tonic-gate return (DDI_FAILURE); 764*0Sstevel@tonic-gate return (DDI_SUCCESS); 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate /* 768*0Sstevel@tonic-gate * Name a child of rootnex 769*0Sstevel@tonic-gate * 770*0Sstevel@tonic-gate * This may be called multiple times, independent of initchild calls. 771*0Sstevel@tonic-gate */ 772*0Sstevel@tonic-gate int 773*0Sstevel@tonic-gate rootnex_name_child(dev_info_t *child, char *name, int namelen) 774*0Sstevel@tonic-gate { 775*0Sstevel@tonic-gate return (rootnex_name_child_impl(child, name, namelen)); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate static int 780*0Sstevel@tonic-gate rootnex_ctl_initchild(dev_info_t *dip) 781*0Sstevel@tonic-gate { 782*0Sstevel@tonic-gate return (rootnex_ctl_initchild_impl(dip)); 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate int 787*0Sstevel@tonic-gate rootnex_ctl_uninitchild(dev_info_t *dip) 788*0Sstevel@tonic-gate { 789*0Sstevel@tonic-gate extern void impl_free_ddi_ppd(dev_info_t *); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate rootnex_ctl_uninitchild_impl(dip); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate /* 794*0Sstevel@tonic-gate * strip properties and convert node to prototype form 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate impl_free_ddi_ppd(dip); 797*0Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 798*0Sstevel@tonic-gate impl_rem_dev_props(dip); 799*0Sstevel@tonic-gate return (DDI_SUCCESS); 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate static int 804*0Sstevel@tonic-gate rootnex_ctl_reportdev(dev_info_t *dev) 805*0Sstevel@tonic-gate { 806*0Sstevel@tonic-gate return (rootnex_ctl_reportdev_impl(dev)); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate static int 811*0Sstevel@tonic-gate rootnex_ctlops_peekpoke(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args, 812*0Sstevel@tonic-gate void *result) 813*0Sstevel@tonic-gate { 814*0Sstevel@tonic-gate int err = DDI_SUCCESS; 815*0Sstevel@tonic-gate on_trap_data_t otd; 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate /* No safe access except for peek/poke is supported. */ 818*0Sstevel@tonic-gate if (in_args->handle != NULL) 819*0Sstevel@tonic-gate return (DDI_FAILURE); 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* Set up protected environment. */ 822*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 823*0Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate if (cmd == DDI_CTLOPS_POKE) { 826*0Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 827*0Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 828*0Sstevel@tonic-gate (void *)in_args->host_addr); 829*0Sstevel@tonic-gate } else { 830*0Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 831*0Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 832*0Sstevel@tonic-gate (void *)in_args->host_addr); 833*0Sstevel@tonic-gate result = (void *)in_args->host_addr; 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate otd.ot_trampoline = tramp; 836*0Sstevel@tonic-gate } else 837*0Sstevel@tonic-gate err = DDI_FAILURE; 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* Take down protected environment. */ 840*0Sstevel@tonic-gate no_trap(); 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate return (err); 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /*ARGSUSED*/ 846*0Sstevel@tonic-gate static int 847*0Sstevel@tonic-gate rootnex_ctlops(dev_info_t *dip, dev_info_t *rdip, 848*0Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 849*0Sstevel@tonic-gate { 850*0Sstevel@tonic-gate register int n, *ptr; 851*0Sstevel@tonic-gate register struct ddi_parent_private_data *pdp; 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate static boolean_t reserved_msg_printed = B_FALSE; 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate switch (ctlop) { 856*0Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC: 857*0Sstevel@tonic-gate return (DDI_FAILURE); 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate case DDI_CTLOPS_BTOP: 860*0Sstevel@tonic-gate /* 861*0Sstevel@tonic-gate * Convert byte count input to physical page units. 862*0Sstevel@tonic-gate * (byte counts that are not a page-size multiple 863*0Sstevel@tonic-gate * are rounded down) 864*0Sstevel@tonic-gate */ 865*0Sstevel@tonic-gate *(ulong_t *)result = btop(*(ulong_t *)arg); 866*0Sstevel@tonic-gate return (DDI_SUCCESS); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate case DDI_CTLOPS_PTOB: 869*0Sstevel@tonic-gate /* 870*0Sstevel@tonic-gate * Convert size in physical pages to bytes 871*0Sstevel@tonic-gate */ 872*0Sstevel@tonic-gate *(ulong_t *)result = ptob(*(ulong_t *)arg); 873*0Sstevel@tonic-gate return (DDI_SUCCESS); 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate case DDI_CTLOPS_BTOPR: 876*0Sstevel@tonic-gate /* 877*0Sstevel@tonic-gate * Convert byte count input to physical page units 878*0Sstevel@tonic-gate * (byte counts that are not a page-size multiple 879*0Sstevel@tonic-gate * are rounded up) 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate *(ulong_t *)result = btopr(*(ulong_t *)arg); 882*0Sstevel@tonic-gate return (DDI_SUCCESS); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 885*0Sstevel@tonic-gate return (rootnex_ctl_initchild((dev_info_t *)arg)); 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 888*0Sstevel@tonic-gate return (rootnex_ctl_uninitchild((dev_info_t *)arg)); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 891*0Sstevel@tonic-gate return (rootnex_ctl_reportdev(rdip)); 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: 894*0Sstevel@tonic-gate /* 895*0Sstevel@tonic-gate * Nothing to do here but reflect back.. 896*0Sstevel@tonic-gate */ 897*0Sstevel@tonic-gate return (DDI_SUCCESS); 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 900*0Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 901*0Sstevel@tonic-gate break; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 904*0Sstevel@tonic-gate if (ndi_dev_is_prom_node(rdip)) 905*0Sstevel@tonic-gate return (DDI_SUCCESS); 906*0Sstevel@tonic-gate if (ndi_dev_is_persistent_node(rdip)) 907*0Sstevel@tonic-gate return (DDI_SUCCESS); 908*0Sstevel@tonic-gate return (DDI_FAILURE); 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate case DDI_CTLOPS_POWER: { 911*0Sstevel@tonic-gate return ((*pm_platform_power)((power_req_t *)arg)); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate case DDI_CTLOPS_RESERVED1: /* Was DDI_CTLOPS_POKE_INIT, obsolete */ 915*0Sstevel@tonic-gate case DDI_CTLOPS_RESERVED2: /* Was DDI_CTLOPS_POKE_FLUSH, obsolete */ 916*0Sstevel@tonic-gate case DDI_CTLOPS_RESERVED3: /* Was DDI_CTLOPS_POKE_FINI, obsolete */ 917*0Sstevel@tonic-gate if (!reserved_msg_printed) { 918*0Sstevel@tonic-gate reserved_msg_printed = B_TRUE; 919*0Sstevel@tonic-gate cmn_err(CE_WARN, "Failing ddi_ctlops call(s) for " 920*0Sstevel@tonic-gate "1 or more reserved/obsolete operations."); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate return (DDI_FAILURE); 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate case DDI_CTLOPS_POKE: 925*0Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 926*0Sstevel@tonic-gate return (rootnex_ctlops_peekpoke(ctlop, (peekpoke_ctlops_t *)arg, 927*0Sstevel@tonic-gate result)); 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate default: 930*0Sstevel@tonic-gate return (DDI_FAILURE); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * The rest are for "hardware" properties 935*0Sstevel@tonic-gate */ 936*0Sstevel@tonic-gate if ((pdp = ddi_get_parent_data(rdip)) == NULL) 937*0Sstevel@tonic-gate return (DDI_FAILURE); 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) { 940*0Sstevel@tonic-gate ptr = (int *)result; 941*0Sstevel@tonic-gate *ptr = pdp->par_nreg; 942*0Sstevel@tonic-gate } else if (ctlop == DDI_CTLOPS_NINTRS) { 943*0Sstevel@tonic-gate return (DDI_FAILURE); 944*0Sstevel@tonic-gate } else { /* ctlop == DDI_CTLOPS_REGSIZE */ 945*0Sstevel@tonic-gate off_t *size = (off_t *)result; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate ptr = (int *)arg; 948*0Sstevel@tonic-gate n = *ptr; 949*0Sstevel@tonic-gate if (n >= pdp->par_nreg) { 950*0Sstevel@tonic-gate return (DDI_FAILURE); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate *size = (off_t)pdp->par_reg[n].regspec_size; 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate return (DDI_SUCCESS); 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate /* ARGSUSED */ 958*0Sstevel@tonic-gate int 959*0Sstevel@tonic-gate rootnex_busop_fminit(dev_info_t *dip, dev_info_t *tdip, int cap, 960*0Sstevel@tonic-gate ddi_iblock_cookie_t *ibc) 961*0Sstevel@tonic-gate { 962*0Sstevel@tonic-gate *ibc = rootnex_err_ibc; 963*0Sstevel@tonic-gate return (ddi_system_fmcap | DDI_FM_ACCCHK_CAPABLE | 964*0Sstevel@tonic-gate DDI_FM_DMACHK_CAPABLE); 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate static void 968*0Sstevel@tonic-gate rootnex_fm_init(dev_info_t *dip) 969*0Sstevel@tonic-gate { 970*0Sstevel@tonic-gate int fmcap; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate /* Minimum fm capability level for sun4u platforms */ 973*0Sstevel@tonic-gate ddi_system_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE; 974*0Sstevel@tonic-gate 975*0Sstevel@tonic-gate fmcap = ddi_system_fmcap; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate /* 978*0Sstevel@tonic-gate * Initialize ECC error handling 979*0Sstevel@tonic-gate */ 980*0Sstevel@tonic-gate rootnex_err_ibc = (ddi_iblock_cookie_t)PIL_15; 981*0Sstevel@tonic-gate ddi_fm_init(dip, &fmcap, &rootnex_err_ibc); 982*0Sstevel@tonic-gate } 983