1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Intel PC root nexus driver 31*7c478bd9Sstevel@tonic-gate * based on sun4c root nexus driver 1.30 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/psw.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/devops.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 45*7c478bd9Sstevel@tonic-gate #include <vm/seg.h> 46*7c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 47*7c478bd9Sstevel@tonic-gate #include <vm/seg_dev.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 50*7c478bd9Sstevel@tonic-gate #include <vm/hat.h> 51*7c478bd9Sstevel@tonic-gate #include <vm/as.h> 52*7c478bd9Sstevel@tonic-gate #include <vm/page.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/avintr.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/psm.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/ontrap.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate #define ptob64(x) (((uint64_t)(x)) << PAGESHIFT) 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate extern void i86_pp_map(page_t *, caddr_t); 65*7c478bd9Sstevel@tonic-gate extern void i86_va_map(caddr_t, struct as *, caddr_t); 66*7c478bd9Sstevel@tonic-gate extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 67*7c478bd9Sstevel@tonic-gate psm_intr_op_t, int *); 68*7c478bd9Sstevel@tonic-gate extern int isa_resource_setup(void); 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* Semi-temporary patchables to phase in bug fixes */ 71*7c478bd9Sstevel@tonic-gate int rootnex_bind_fail = 1; 72*7c478bd9Sstevel@tonic-gate int rootnex_bind_warn = 1; 73*7c478bd9Sstevel@tonic-gate uint8_t *rootnex_warn_list; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* bitmasks for rootnex_warn_list. Up to 8 different warnings with uint8_t */ 76*7c478bd9Sstevel@tonic-gate #define ROOTNEX_BIND_WARNING (0x1 << 0) 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * DMA related static data 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate static uintptr_t dvma_call_list_id = 0; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * Use device arena to use for device control register mappings. 85*7c478bd9Sstevel@tonic-gate * Various kernel memory walkers (debugger, dtrace) need to know 86*7c478bd9Sstevel@tonic-gate * to avoid this address range to prevent undesired device activity. 87*7c478bd9Sstevel@tonic-gate */ 88*7c478bd9Sstevel@tonic-gate extern void *device_arena_alloc(size_t size, int vm_flag); 89*7c478bd9Sstevel@tonic-gate extern void device_arena_free(void * vaddr, size_t size); 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * Hack to handle poke faults on Calvin-class machines 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate extern int pokefault; 96*7c478bd9Sstevel@tonic-gate static kmutex_t pokefault_mutex; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate * Internal functions 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate static int 103*7c478bd9Sstevel@tonic-gate rootnex_ctl_children(dev_info_t *dip, dev_info_t *rdip, 104*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, dev_info_t *child); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static int 107*7c478bd9Sstevel@tonic-gate rootnex_ctlops_poke(peekpoke_ctlops_t *in_args); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate static int 110*7c478bd9Sstevel@tonic-gate rootnex_ctlops_peek(peekpoke_ctlops_t *in_args, void *result); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * config information 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate static int 117*7c478bd9Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 118*7c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate static int 121*7c478bd9Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip, 122*7c478bd9Sstevel@tonic-gate struct hat *hat, struct seg *seg, caddr_t addr, 123*7c478bd9Sstevel@tonic-gate struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate static int 126*7c478bd9Sstevel@tonic-gate rootnex_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 127*7c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate static int 130*7c478bd9Sstevel@tonic-gate rootnex_dma_freehdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate static int 133*7c478bd9Sstevel@tonic-gate rootnex_dma_bindhdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 134*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *); 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate static int 137*7c478bd9Sstevel@tonic-gate rootnex_dma_unbindhdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate static int 140*7c478bd9Sstevel@tonic-gate rootnex_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 141*7c478bd9Sstevel@tonic-gate off_t, size_t, uint_t); 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate static int 144*7c478bd9Sstevel@tonic-gate rootnex_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 145*7c478bd9Sstevel@tonic-gate uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate static int 148*7c478bd9Sstevel@tonic-gate rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip, 149*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep); 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate static int 152*7c478bd9Sstevel@tonic-gate rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 153*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 154*7c478bd9Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t cache_flags); 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate static int 157*7c478bd9Sstevel@tonic-gate rootnex_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate static struct intrspec * 160*7c478bd9Sstevel@tonic-gate rootnex_get_ispec(dev_info_t *rdip, int inum); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate static int 163*7c478bd9Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 164*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate static struct bus_ops rootnex_bus_ops = { 167*7c478bd9Sstevel@tonic-gate BUSO_REV, 168*7c478bd9Sstevel@tonic-gate rootnex_map, 169*7c478bd9Sstevel@tonic-gate NULL, 170*7c478bd9Sstevel@tonic-gate NULL, 171*7c478bd9Sstevel@tonic-gate NULL, 172*7c478bd9Sstevel@tonic-gate rootnex_map_fault, 173*7c478bd9Sstevel@tonic-gate rootnex_dma_map, 174*7c478bd9Sstevel@tonic-gate rootnex_dma_allochdl, 175*7c478bd9Sstevel@tonic-gate rootnex_dma_freehdl, 176*7c478bd9Sstevel@tonic-gate rootnex_dma_bindhdl, 177*7c478bd9Sstevel@tonic-gate rootnex_dma_unbindhdl, 178*7c478bd9Sstevel@tonic-gate rootnex_dma_flush, 179*7c478bd9Sstevel@tonic-gate rootnex_dma_win, 180*7c478bd9Sstevel@tonic-gate rootnex_dma_mctl, 181*7c478bd9Sstevel@tonic-gate rootnex_ctlops, 182*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 183*7c478bd9Sstevel@tonic-gate i_ddi_rootnex_get_eventcookie, 184*7c478bd9Sstevel@tonic-gate i_ddi_rootnex_add_eventcall, 185*7c478bd9Sstevel@tonic-gate i_ddi_rootnex_remove_eventcall, 186*7c478bd9Sstevel@tonic-gate i_ddi_rootnex_post_event, 187*7c478bd9Sstevel@tonic-gate 0, /* bus_intr_ctl */ 188*7c478bd9Sstevel@tonic-gate 0, /* bus_config */ 189*7c478bd9Sstevel@tonic-gate 0, /* bus_unconfig */ 190*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_init */ 191*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_fini */ 192*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 193*7c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_exit */ 194*7c478bd9Sstevel@tonic-gate NULL, /* bus_powr */ 195*7c478bd9Sstevel@tonic-gate rootnex_intr_ops /* bus_intr_op */ 196*7c478bd9Sstevel@tonic-gate }; 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate struct priv_handle { 199*7c478bd9Sstevel@tonic-gate caddr_t ph_vaddr; 200*7c478bd9Sstevel@tonic-gate union { 201*7c478bd9Sstevel@tonic-gate page_t *pp; 202*7c478bd9Sstevel@tonic-gate struct as *asp; 203*7c478bd9Sstevel@tonic-gate }ph_u; 204*7c478bd9Sstevel@tonic-gate uint_t ph_mapinfo; 205*7c478bd9Sstevel@tonic-gate uint64_t ph_padr; 206*7c478bd9Sstevel@tonic-gate }; 207*7c478bd9Sstevel@tonic-gate static uint64_t rootnex_get_phyaddr(); 208*7c478bd9Sstevel@tonic-gate static int rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 209*7c478bd9Sstevel@tonic-gate static int rootnex_io_rdsync(ddi_dma_impl_t *hp); 210*7c478bd9Sstevel@tonic-gate static int rootnex_io_wtsync(ddi_dma_impl_t *hp, int); 211*7c478bd9Sstevel@tonic-gate static int rootnex_io_brkup_attr(dev_info_t *dip, dev_info_t *rdip, 212*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t handle, 213*7c478bd9Sstevel@tonic-gate struct priv_handle *php); 214*7c478bd9Sstevel@tonic-gate static int rootnex_io_brkup_lim(dev_info_t *dip, dev_info_t *rdip, 215*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep, 216*7c478bd9Sstevel@tonic-gate ddi_dma_lim_t *dma_lim, struct priv_handle *php); 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate static struct dev_ops rootnex_ops = { 219*7c478bd9Sstevel@tonic-gate DEVO_REV, 220*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 221*7c478bd9Sstevel@tonic-gate ddi_no_info, /* info */ 222*7c478bd9Sstevel@tonic-gate nulldev, 223*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 224*7c478bd9Sstevel@tonic-gate rootnex_attach, 225*7c478bd9Sstevel@tonic-gate nulldev, /* detach */ 226*7c478bd9Sstevel@tonic-gate nulldev, /* reset */ 227*7c478bd9Sstevel@tonic-gate 0, /* cb_ops */ 228*7c478bd9Sstevel@tonic-gate &rootnex_bus_ops 229*7c478bd9Sstevel@tonic-gate }; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate /* 232*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 233*7c478bd9Sstevel@tonic-gate */ 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 236*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a nexus driver */ 237*7c478bd9Sstevel@tonic-gate "i86pc root nexus %I%", 238*7c478bd9Sstevel@tonic-gate &rootnex_ops, /* Driver ops */ 239*7c478bd9Sstevel@tonic-gate }; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 242*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 243*7c478bd9Sstevel@tonic-gate }; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate int 247*7c478bd9Sstevel@tonic-gate _init(void) 248*7c478bd9Sstevel@tonic-gate { 249*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate int 253*7c478bd9Sstevel@tonic-gate _fini(void) 254*7c478bd9Sstevel@tonic-gate { 255*7c478bd9Sstevel@tonic-gate return (EBUSY); 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate int 259*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 260*7c478bd9Sstevel@tonic-gate { 261*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * rootnex_attach: 266*7c478bd9Sstevel@tonic-gate * 267*7c478bd9Sstevel@tonic-gate * attach the root nexus. 268*7c478bd9Sstevel@tonic-gate */ 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate static void add_root_props(dev_info_t *); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 273*7c478bd9Sstevel@tonic-gate static int 274*7c478bd9Sstevel@tonic-gate rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 275*7c478bd9Sstevel@tonic-gate { 276*7c478bd9Sstevel@tonic-gate mutex_init(&pokefault_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(15)); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate add_root_props(devi); 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?root nexus = %s\n", ddi_get_name(devi)); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate i_ddi_rootnex_init_events(devi); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* 285*7c478bd9Sstevel@tonic-gate * allocate array to track which major numbers we have printed warnings 286*7c478bd9Sstevel@tonic-gate * for. 287*7c478bd9Sstevel@tonic-gate */ 288*7c478bd9Sstevel@tonic-gate rootnex_warn_list = kmem_zalloc(devcnt * sizeof (*rootnex_warn_list), 289*7c478bd9Sstevel@tonic-gate KM_SLEEP); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 292*7c478bd9Sstevel@tonic-gate } 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * Add statically defined root properties to this list... 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate static const int pagesize = PAGESIZE; 300*7c478bd9Sstevel@tonic-gate static const int mmu_pagesize = MMU_PAGESIZE; 301*7c478bd9Sstevel@tonic-gate static const int mmu_pageoffset = MMU_PAGEOFFSET; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate struct prop_def { 304*7c478bd9Sstevel@tonic-gate char *prop_name; 305*7c478bd9Sstevel@tonic-gate caddr_t prop_value; 306*7c478bd9Sstevel@tonic-gate }; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate static struct prop_def root_props[] = { 309*7c478bd9Sstevel@tonic-gate { "PAGESIZE", (caddr_t)&pagesize }, 310*7c478bd9Sstevel@tonic-gate { "MMU_PAGESIZE", (caddr_t)&mmu_pagesize}, 311*7c478bd9Sstevel@tonic-gate { "MMU_PAGEOFFSET", (caddr_t)&mmu_pageoffset}, 312*7c478bd9Sstevel@tonic-gate }; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate #define NROOT_PROPS (sizeof (root_props) / sizeof (struct prop_def)) 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate static void 317*7c478bd9Sstevel@tonic-gate add_root_props(dev_info_t *devi) 318*7c478bd9Sstevel@tonic-gate { 319*7c478bd9Sstevel@tonic-gate int i; 320*7c478bd9Sstevel@tonic-gate struct prop_def *rpp; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Note this for loop works because all of the root_prop 324*7c478bd9Sstevel@tonic-gate * properties are integers - if this changes, the for 325*7c478bd9Sstevel@tonic-gate * loop will have to change. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate for (i = 0, rpp = root_props; i < NROOT_PROPS; ++i, ++rpp) { 328*7c478bd9Sstevel@tonic-gate (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, 329*7c478bd9Sstevel@tonic-gate rpp->prop_name, *((int *)rpp->prop_value)); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Create the root node "boolean" property 334*7c478bd9Sstevel@tonic-gate * corresponding to addressing type supported in the root node: 335*7c478bd9Sstevel@tonic-gate * 336*7c478bd9Sstevel@tonic-gate * Choices are: 337*7c478bd9Sstevel@tonic-gate * "relative-addressing" (OBP PROMS) 338*7c478bd9Sstevel@tonic-gate * "generic-addressing" (Sun4 -- pseudo OBP/DDI) 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, 342*7c478bd9Sstevel@tonic-gate DDI_RELATIVE_ADDRESSING, 1); 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * #define DDI_MAP_DEBUG (c.f. ddi_impl.c) 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 350*7c478bd9Sstevel@tonic-gate extern int ddi_map_debug_flag; 351*7c478bd9Sstevel@tonic-gate #define ddi_map_debug if (ddi_map_debug_flag) prom_printf 352*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate * we don't support mapping of I/O cards above 4Gb 357*7c478bd9Sstevel@tonic-gate */ 358*7c478bd9Sstevel@tonic-gate static int 359*7c478bd9Sstevel@tonic-gate rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate ulong_t base; 362*7c478bd9Sstevel@tonic-gate void *cvaddr; 363*7c478bd9Sstevel@tonic-gate uint_t npages, pgoffset; 364*7c478bd9Sstevel@tonic-gate struct regspec *rp; 365*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 366*7c478bd9Sstevel@tonic-gate ddi_acc_impl_t *ap; 367*7c478bd9Sstevel@tonic-gate uint_t hat_acc_flags; 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate rp = mp->map_obj.rp; 370*7c478bd9Sstevel@tonic-gate hp = mp->map_handlep; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 373*7c478bd9Sstevel@tonic-gate ddi_map_debug( 374*7c478bd9Sstevel@tonic-gate "rootnex_map_regspec: <0x%x 0x%x 0x%x> handle 0x%x\n", 375*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, 376*7c478bd9Sstevel@tonic-gate rp->regspec_size, mp->map_handlep); 377*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * I/O or memory mapping 381*7c478bd9Sstevel@tonic-gate * 382*7c478bd9Sstevel@tonic-gate * <bustype=0, addr=x, len=x>: memory 383*7c478bd9Sstevel@tonic-gate * <bustype=1, addr=x, len=x>: i/o 384*7c478bd9Sstevel@tonic-gate * <bustype>1, addr=0, len=x>: x86-compatibility i/o 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) { 388*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "rootnex: invalid register spec" 389*7c478bd9Sstevel@tonic-gate " <0x%x, 0x%x, 0x%x>", rp->regspec_bustype, 390*7c478bd9Sstevel@tonic-gate rp->regspec_addr, rp->regspec_size); 391*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype != 0) { 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * I/O space - needs a handle. 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate if (hp == NULL) { 399*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate ap = (ddi_acc_impl_t *)hp->ah_platform_private; 402*7c478bd9Sstevel@tonic-gate ap->ahi_acc_attr |= DDI_ACCATTR_IO_SPACE; 403*7c478bd9Sstevel@tonic-gate impl_acc_hdl_init(hp); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_DEVICE_MAPPING) { 406*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 407*7c478bd9Sstevel@tonic-gate ddi_map_debug("rootnex_map_regspec: mmap() \ 408*7c478bd9Sstevel@tonic-gate to I/O space is not supported.\n"); 409*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 410*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 411*7c478bd9Sstevel@tonic-gate } else { 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * 1275-compliant vs. compatibility i/o mapping 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate *vaddrp = 416*7c478bd9Sstevel@tonic-gate (rp->regspec_bustype > 1 && rp->regspec_addr == 0) ? 417*7c478bd9Sstevel@tonic-gate ((caddr_t)(uintptr_t)rp->regspec_bustype) : 418*7c478bd9Sstevel@tonic-gate ((caddr_t)(uintptr_t)rp->regspec_addr); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 422*7c478bd9Sstevel@tonic-gate ddi_map_debug( 423*7c478bd9Sstevel@tonic-gate "rootnex_map_regspec: \"Mapping\" %d bytes I/O space at 0x%x\n", 424*7c478bd9Sstevel@tonic-gate rp->regspec_size, *vaddrp); 425*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 426*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* 430*7c478bd9Sstevel@tonic-gate * Memory space 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate if (hp != NULL) { 434*7c478bd9Sstevel@tonic-gate /* 435*7c478bd9Sstevel@tonic-gate * hat layer ignores 436*7c478bd9Sstevel@tonic-gate * hp->ah_acc.devacc_attr_endian_flags. 437*7c478bd9Sstevel@tonic-gate */ 438*7c478bd9Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_dataorder) { 439*7c478bd9Sstevel@tonic-gate case DDI_STRICTORDER_ACC: 440*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_STRICTORDER; 441*7c478bd9Sstevel@tonic-gate break; 442*7c478bd9Sstevel@tonic-gate case DDI_UNORDERED_OK_ACC: 443*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_UNORDERED_OK; 444*7c478bd9Sstevel@tonic-gate break; 445*7c478bd9Sstevel@tonic-gate case DDI_MERGING_OK_ACC: 446*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_MERGING_OK; 447*7c478bd9Sstevel@tonic-gate break; 448*7c478bd9Sstevel@tonic-gate case DDI_LOADCACHING_OK_ACC: 449*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_LOADCACHING_OK; 450*7c478bd9Sstevel@tonic-gate break; 451*7c478bd9Sstevel@tonic-gate case DDI_STORECACHING_OK_ACC: 452*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_STORECACHING_OK; 453*7c478bd9Sstevel@tonic-gate break; 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate ap = (ddi_acc_impl_t *)hp->ah_platform_private; 456*7c478bd9Sstevel@tonic-gate ap->ahi_acc_attr |= DDI_ACCATTR_CPU_VADDR; 457*7c478bd9Sstevel@tonic-gate impl_acc_hdl_init(hp); 458*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags = hat_acc_flags; 459*7c478bd9Sstevel@tonic-gate } else { 460*7c478bd9Sstevel@tonic-gate hat_acc_flags = HAT_STRICTORDER; 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */ 464*7c478bd9Sstevel@tonic-gate pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET; /* offset */ 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate if (rp->regspec_size == 0) { 467*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 468*7c478bd9Sstevel@tonic-gate ddi_map_debug("rootnex_map_regspec: zero regspec_size\n"); 469*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 470*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_DEVICE_MAPPING) { 474*7c478bd9Sstevel@tonic-gate *vaddrp = (caddr_t)mmu_btop(base); 475*7c478bd9Sstevel@tonic-gate } else { 476*7c478bd9Sstevel@tonic-gate npages = mmu_btopr(rp->regspec_size + pgoffset); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 479*7c478bd9Sstevel@tonic-gate ddi_map_debug("rootnex_map_regspec: Mapping %d pages \ 480*7c478bd9Sstevel@tonic-gate physical %x ", 481*7c478bd9Sstevel@tonic-gate npages, base); 482*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate cvaddr = device_arena_alloc(ptob(npages), VM_NOSLEEP); 485*7c478bd9Sstevel@tonic-gate if (cvaddr == NULL) 486*7c478bd9Sstevel@tonic-gate return (DDI_ME_NORESOURCES); 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* 489*7c478bd9Sstevel@tonic-gate * Now map in the pages we've allocated... 490*7c478bd9Sstevel@tonic-gate */ 491*7c478bd9Sstevel@tonic-gate hat_devload(kas.a_hat, cvaddr, mmu_ptob(npages), mmu_btop(base), 492*7c478bd9Sstevel@tonic-gate mp->map_prot | hat_acc_flags, HAT_LOAD_LOCK); 493*7c478bd9Sstevel@tonic-gate *vaddrp = (caddr_t)cvaddr + pgoffset; 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 497*7c478bd9Sstevel@tonic-gate ddi_map_debug("at virtual 0x%x\n", *vaddrp); 498*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 499*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate static int 503*7c478bd9Sstevel@tonic-gate rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp) 504*7c478bd9Sstevel@tonic-gate { 505*7c478bd9Sstevel@tonic-gate caddr_t addr = (caddr_t)*vaddrp; 506*7c478bd9Sstevel@tonic-gate uint_t npages, pgoffset; 507*7c478bd9Sstevel@tonic-gate struct regspec *rp; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_DEVICE_MAPPING) 510*7c478bd9Sstevel@tonic-gate return (0); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate rp = mp->map_obj.rp; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate if (rp->regspec_size == 0) { 515*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 516*7c478bd9Sstevel@tonic-gate ddi_map_debug("rootnex_unmap_regspec: zero regspec_size\n"); 517*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 518*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate * I/O or memory mapping: 523*7c478bd9Sstevel@tonic-gate * 524*7c478bd9Sstevel@tonic-gate * <bustype=0, addr=x, len=x>: memory 525*7c478bd9Sstevel@tonic-gate * <bustype=1, addr=x, len=x>: i/o 526*7c478bd9Sstevel@tonic-gate * <bustype>1, addr=0, len=x>: x86-compatibility i/o 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype != 0) { 529*7c478bd9Sstevel@tonic-gate /* 530*7c478bd9Sstevel@tonic-gate * This is I/O space, which requires no particular 531*7c478bd9Sstevel@tonic-gate * processing on unmap since it isn't mapped in the 532*7c478bd9Sstevel@tonic-gate * first place. 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * Memory space 539*7c478bd9Sstevel@tonic-gate */ 540*7c478bd9Sstevel@tonic-gate pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET; 541*7c478bd9Sstevel@tonic-gate npages = mmu_btopr(rp->regspec_size + pgoffset); 542*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, addr - pgoffset, ptob(npages), HAT_UNLOAD_UNLOCK); 543*7c478bd9Sstevel@tonic-gate device_arena_free(addr - pgoffset, ptob(npages)); 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * Destroy the pointer - the mapping has logically gone 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate *vaddrp = NULL; 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate static int 554*7c478bd9Sstevel@tonic-gate rootnex_map_handle(ddi_map_req_t *mp) 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 557*7c478bd9Sstevel@tonic-gate ulong_t base; 558*7c478bd9Sstevel@tonic-gate uint_t pgoffset; 559*7c478bd9Sstevel@tonic-gate struct regspec *rp; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate rp = mp->map_obj.rp; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 564*7c478bd9Sstevel@tonic-gate ddi_map_debug( 565*7c478bd9Sstevel@tonic-gate "rootnex_map_handle: <0x%x 0x%x 0x%x> handle 0x%x\n", 566*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, 567*7c478bd9Sstevel@tonic-gate rp->regspec_size, mp->map_handlep); 568*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate /* 571*7c478bd9Sstevel@tonic-gate * I/O or memory mapping: 572*7c478bd9Sstevel@tonic-gate * 573*7c478bd9Sstevel@tonic-gate * <bustype=0, addr=x, len=x>: memory 574*7c478bd9Sstevel@tonic-gate * <bustype=1, addr=x, len=x>: i/o 575*7c478bd9Sstevel@tonic-gate * <bustype>1, addr=0, len=x>: x86-compatibility i/o 576*7c478bd9Sstevel@tonic-gate */ 577*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype != 0) { 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * This refers to I/O space, and we don't support "mapping" 580*7c478bd9Sstevel@tonic-gate * I/O space to a user. 581*7c478bd9Sstevel@tonic-gate */ 582*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * Set up the hat_flags for the mapping. 587*7c478bd9Sstevel@tonic-gate */ 588*7c478bd9Sstevel@tonic-gate hp = mp->map_handlep; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_endian_flags) { 591*7c478bd9Sstevel@tonic-gate case DDI_NEVERSWAP_ACC: 592*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags = HAT_NEVERSWAP | HAT_STRICTORDER; 593*7c478bd9Sstevel@tonic-gate break; 594*7c478bd9Sstevel@tonic-gate case DDI_STRUCTURE_LE_ACC: 595*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags = HAT_STRUCTURE_LE; 596*7c478bd9Sstevel@tonic-gate break; 597*7c478bd9Sstevel@tonic-gate case DDI_STRUCTURE_BE_ACC: 598*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 599*7c478bd9Sstevel@tonic-gate default: 600*7c478bd9Sstevel@tonic-gate return (DDI_REGS_ACC_CONFLICT); 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate switch (hp->ah_acc.devacc_attr_dataorder) { 604*7c478bd9Sstevel@tonic-gate case DDI_STRICTORDER_ACC: 605*7c478bd9Sstevel@tonic-gate break; 606*7c478bd9Sstevel@tonic-gate case DDI_UNORDERED_OK_ACC: 607*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags |= HAT_UNORDERED_OK; 608*7c478bd9Sstevel@tonic-gate break; 609*7c478bd9Sstevel@tonic-gate case DDI_MERGING_OK_ACC: 610*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags |= HAT_MERGING_OK; 611*7c478bd9Sstevel@tonic-gate break; 612*7c478bd9Sstevel@tonic-gate case DDI_LOADCACHING_OK_ACC: 613*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags |= HAT_LOADCACHING_OK; 614*7c478bd9Sstevel@tonic-gate break; 615*7c478bd9Sstevel@tonic-gate case DDI_STORECACHING_OK_ACC: 616*7c478bd9Sstevel@tonic-gate hp->ah_hat_flags |= HAT_STORECACHING_OK; 617*7c478bd9Sstevel@tonic-gate break; 618*7c478bd9Sstevel@tonic-gate default: 619*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */ 623*7c478bd9Sstevel@tonic-gate pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET; /* offset */ 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate if (rp->regspec_size == 0) 626*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate hp->ah_pfn = mmu_btop(base); 629*7c478bd9Sstevel@tonic-gate hp->ah_pnum = mmu_btopr(rp->regspec_size + pgoffset); 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate static int 635*7c478bd9Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 636*7c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate struct regspec *rp, tmp_reg; 639*7c478bd9Sstevel@tonic-gate ddi_map_req_t mr = *mp; /* Get private copy of request */ 640*7c478bd9Sstevel@tonic-gate int error; 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate mp = &mr; 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate switch (mp->map_op) { 645*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 646*7c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 647*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_HANDLE: 648*7c478bd9Sstevel@tonic-gate break; 649*7c478bd9Sstevel@tonic-gate default: 650*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 651*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "rootnex_map: unimplemented map op %d.", 652*7c478bd9Sstevel@tonic-gate mp->map_op); 653*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 654*7c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_USER_MAPPING) { 658*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 659*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "rootnex_map: unimplemented map type: user."); 660*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 661*7c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* 665*7c478bd9Sstevel@tonic-gate * First, if given an rnumber, convert it to a regspec... 666*7c478bd9Sstevel@tonic-gate * (Presumably, this is on behalf of a child of the root node?) 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) { 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate int rnumber = mp->map_obj.rnumber; 672*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 673*7c478bd9Sstevel@tonic-gate static char *out_of_range = 674*7c478bd9Sstevel@tonic-gate "rootnex_map: Out of range rnumber <%d>, device <%s>"; 675*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate rp = i_ddi_rnumber_to_regspec(rdip, rnumber); 678*7c478bd9Sstevel@tonic-gate if (rp == NULL) { 679*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 680*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, rnumber, 681*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip)); 682*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 683*7c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * Convert the given ddi_map_req_t from rnumber to regspec... 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 691*7c478bd9Sstevel@tonic-gate mp->map_obj.rp = rp; 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * Adjust offset and length correspnding to called values... 696*7c478bd9Sstevel@tonic-gate * XXX: A non-zero length means override the one in the regspec 697*7c478bd9Sstevel@tonic-gate * XXX: (regardless of what's in the parent's range?) 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */ 701*7c478bd9Sstevel@tonic-gate rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */ 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 704*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 705*7c478bd9Sstevel@tonic-gate "rootnex: <%s,%s> <0x%x, 0x%x, 0x%d>" 706*7c478bd9Sstevel@tonic-gate " offset %d len %d handle 0x%x\n", 707*7c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_name(rdip), 708*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, 709*7c478bd9Sstevel@tonic-gate offset, len, mp->map_handlep); 710*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate /* 713*7c478bd9Sstevel@tonic-gate * I/O or memory mapping: 714*7c478bd9Sstevel@tonic-gate * 715*7c478bd9Sstevel@tonic-gate * <bustype=0, addr=x, len=x>: memory 716*7c478bd9Sstevel@tonic-gate * <bustype=1, addr=x, len=x>: i/o 717*7c478bd9Sstevel@tonic-gate * <bustype>1, addr=0, len=x>: x86-compatibility i/o 718*7c478bd9Sstevel@tonic-gate */ 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) { 721*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "<%s,%s> invalid register spec" 722*7c478bd9Sstevel@tonic-gate " <0x%x, 0x%x, 0x%x>", ddi_get_name(dip), 723*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), rp->regspec_bustype, 724*7c478bd9Sstevel@tonic-gate rp->regspec_addr, rp->regspec_size); 725*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate if (rp->regspec_bustype > 1 && rp->regspec_addr == 0) { 729*7c478bd9Sstevel@tonic-gate /* 730*7c478bd9Sstevel@tonic-gate * compatibility i/o mapping 731*7c478bd9Sstevel@tonic-gate */ 732*7c478bd9Sstevel@tonic-gate rp->regspec_bustype += (uint_t)offset; 733*7c478bd9Sstevel@tonic-gate } else { 734*7c478bd9Sstevel@tonic-gate /* 735*7c478bd9Sstevel@tonic-gate * Normal memory or i/o mapping 736*7c478bd9Sstevel@tonic-gate */ 737*7c478bd9Sstevel@tonic-gate rp->regspec_addr += (uint_t)offset; 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate if (len != 0) 741*7c478bd9Sstevel@tonic-gate rp->regspec_size = (uint_t)len; 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 744*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 745*7c478bd9Sstevel@tonic-gate " <%s,%s> <0x%x, 0x%x, 0x%d>" 746*7c478bd9Sstevel@tonic-gate " offset %d len %d handle 0x%x\n", 747*7c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_name(rdip), 748*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, 749*7c478bd9Sstevel@tonic-gate offset, len, mp->map_handlep); 750*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate /* 753*7c478bd9Sstevel@tonic-gate * Apply any parent ranges at this level, if applicable. 754*7c478bd9Sstevel@tonic-gate * (This is where nexus specific regspec translation takes place. 755*7c478bd9Sstevel@tonic-gate * Use of this function is implicit agreement that translation is 756*7c478bd9Sstevel@tonic-gate * provided via ddi_apply_range.) 757*7c478bd9Sstevel@tonic-gate */ 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 760*7c478bd9Sstevel@tonic-gate ddi_map_debug("applying range of parent <%s> to child <%s>...\n", 761*7c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_name(rdip)); 762*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0) 765*7c478bd9Sstevel@tonic-gate return (error); 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate switch (mp->map_op) { 768*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * Set up the locked down kernel mapping to the regspec... 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate return (rootnex_map_regspec(mp, vaddrp)); 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate /* 779*7c478bd9Sstevel@tonic-gate * Release mapping... 780*7c478bd9Sstevel@tonic-gate */ 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate return (rootnex_unmap_regspec(mp, vaddrp)); 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_HANDLE: 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate return (rootnex_map_handle(mp)); 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate default: 789*7c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate } 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * rootnex_map_fault: 796*7c478bd9Sstevel@tonic-gate * 797*7c478bd9Sstevel@tonic-gate * fault in mappings for requestors 798*7c478bd9Sstevel@tonic-gate */ 799*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 800*7c478bd9Sstevel@tonic-gate static int 801*7c478bd9Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip, 802*7c478bd9Sstevel@tonic-gate struct hat *hat, struct seg *seg, caddr_t addr, 803*7c478bd9Sstevel@tonic-gate struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock) 804*7c478bd9Sstevel@tonic-gate { 805*7c478bd9Sstevel@tonic-gate extern struct seg_ops segdev_ops; 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate #ifdef DDI_MAP_DEBUG 808*7c478bd9Sstevel@tonic-gate ddi_map_debug("rootnex_map_fault: address <%x> pfn <%x>", addr, pfn); 809*7c478bd9Sstevel@tonic-gate ddi_map_debug(" Seg <%s>\n", 810*7c478bd9Sstevel@tonic-gate seg->s_ops == &segdev_ops ? "segdev" : 811*7c478bd9Sstevel@tonic-gate seg == &kvseg ? "segkmem" : "NONE!"); 812*7c478bd9Sstevel@tonic-gate #endif /* DDI_MAP_DEBUG */ 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* 815*7c478bd9Sstevel@tonic-gate * This is all terribly broken, but it is a start 816*7c478bd9Sstevel@tonic-gate * 817*7c478bd9Sstevel@tonic-gate * XXX Note that this test means that segdev_ops 818*7c478bd9Sstevel@tonic-gate * must be exported from seg_dev.c. 819*7c478bd9Sstevel@tonic-gate * XXX What about devices with their own segment drivers? 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate if (seg->s_ops == &segdev_ops) { 822*7c478bd9Sstevel@tonic-gate struct segdev_data *sdp = 823*7c478bd9Sstevel@tonic-gate (struct segdev_data *)seg->s_data; 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate if (hat == NULL) { 826*7c478bd9Sstevel@tonic-gate /* 827*7c478bd9Sstevel@tonic-gate * This is one plausible interpretation of 828*7c478bd9Sstevel@tonic-gate * a null hat i.e. use the first hat on the 829*7c478bd9Sstevel@tonic-gate * address space hat list which by convention is 830*7c478bd9Sstevel@tonic-gate * the hat of the system MMU. At alternative 831*7c478bd9Sstevel@tonic-gate * would be to panic .. this might well be better .. 832*7c478bd9Sstevel@tonic-gate */ 833*7c478bd9Sstevel@tonic-gate ASSERT(AS_READ_HELD(seg->s_as, &seg->s_as->a_lock)); 834*7c478bd9Sstevel@tonic-gate hat = seg->s_as->a_hat; 835*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "rootnex_map_fault: nil hat"); 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate hat_devload(hat, addr, MMU_PAGESIZE, pfn, prot | sdp->hat_attr, 838*7c478bd9Sstevel@tonic-gate (lock ? HAT_LOAD_LOCK : HAT_LOAD)); 839*7c478bd9Sstevel@tonic-gate } else if (seg == &kvseg && dp == NULL) { 840*7c478bd9Sstevel@tonic-gate hat_devload(kas.a_hat, addr, MMU_PAGESIZE, pfn, prot, 841*7c478bd9Sstevel@tonic-gate HAT_LOAD_LOCK); 842*7c478bd9Sstevel@tonic-gate } else 843*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 844*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * DMA routines- for all 80x86 machines. 850*7c478bd9Sstevel@tonic-gate */ 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* 853*7c478bd9Sstevel@tonic-gate * Shorthand defines 854*7c478bd9Sstevel@tonic-gate */ 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate #define MAP 0 857*7c478bd9Sstevel@tonic-gate #define BIND 1 858*7c478bd9Sstevel@tonic-gate #define MAX_INT_BUF (16*MMU_PAGESIZE) 859*7c478bd9Sstevel@tonic-gate #define AHI_LIM dma_lim->dlim_addr_hi 860*7c478bd9Sstevel@tonic-gate #define AHI_ATTR dma_attr->dma_attr_addr_hi 861*7c478bd9Sstevel@tonic-gate #define OBJSIZE dmareq->dmar_object.dmao_size 862*7c478bd9Sstevel@tonic-gate #define OBJTYPE dmareq->dmar_object.dmao_type 863*7c478bd9Sstevel@tonic-gate #define FOURG 0x100000000ULL 864*7c478bd9Sstevel@tonic-gate #define SIXTEEN_MB 0x1000000 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate /* #define DMADEBUG */ 867*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint) 868*7c478bd9Sstevel@tonic-gate #define DMADEBUG 869*7c478bd9Sstevel@tonic-gate static int dmadebug = 0; 870*7c478bd9Sstevel@tonic-gate #define DMAPRINT(a) if (dmadebug) prom_printf a 871*7c478bd9Sstevel@tonic-gate #else 872*7c478bd9Sstevel@tonic-gate #define DMAPRINT(a) { } 873*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate /* 878*7c478bd9Sstevel@tonic-gate * allocate DMA handle 879*7c478bd9Sstevel@tonic-gate */ 880*7c478bd9Sstevel@tonic-gate static int 881*7c478bd9Sstevel@tonic-gate rootnex_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr, 882*7c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 883*7c478bd9Sstevel@tonic-gate { 884*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp; 885*7c478bd9Sstevel@tonic-gate uint64_t maxsegmentsize_ll; 886*7c478bd9Sstevel@tonic-gate uint_t maxsegmentsize; 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate #ifdef lint 889*7c478bd9Sstevel@tonic-gate dip = dip; 890*7c478bd9Sstevel@tonic-gate #endif 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate * Validate the dma request. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 896*7c478bd9Sstevel@tonic-gate if (attr->dma_attr_seg < MMU_PAGEOFFSET || 897*7c478bd9Sstevel@tonic-gate attr->dma_attr_count_max < MMU_PAGEOFFSET || 898*7c478bd9Sstevel@tonic-gate attr->dma_attr_granular > MMU_PAGESIZE || 899*7c478bd9Sstevel@tonic-gate attr->dma_attr_maxxfer < MMU_PAGESIZE) { 900*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits\n")); 901*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate #endif 904*7c478bd9Sstevel@tonic-gate /* 905*7c478bd9Sstevel@tonic-gate * validate the attribute structure. For now we do not support 906*7c478bd9Sstevel@tonic-gate * negative sgllen. 907*7c478bd9Sstevel@tonic-gate */ 908*7c478bd9Sstevel@tonic-gate if ((attr->dma_attr_addr_hi <= attr->dma_attr_addr_lo) || 909*7c478bd9Sstevel@tonic-gate (attr->dma_attr_sgllen <= 0)) { 910*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADATTR); 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate if ((attr->dma_attr_seg & MMU_PAGEOFFSET) != MMU_PAGEOFFSET || 913*7c478bd9Sstevel@tonic-gate MMU_PAGESIZE & (attr->dma_attr_granular - 1) || 914*7c478bd9Sstevel@tonic-gate attr->dma_attr_sgllen < 0) { 915*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADATTR); 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate maxsegmentsize_ll = MIN(attr->dma_attr_seg, 920*7c478bd9Sstevel@tonic-gate MIN((attr->dma_attr_count_max + 1) * 921*7c478bd9Sstevel@tonic-gate attr->dma_attr_minxfer, 922*7c478bd9Sstevel@tonic-gate attr->dma_attr_maxxfer) - 1) + 1; 923*7c478bd9Sstevel@tonic-gate /* 924*7c478bd9Sstevel@tonic-gate * We will calculate a 64 bit segment size, if the segment size 925*7c478bd9Sstevel@tonic-gate * is greater that 4G, we will limit it to (4G - 1). 926*7c478bd9Sstevel@tonic-gate * The size of dma object (ddi_dma_obj_t.dmao_size) 927*7c478bd9Sstevel@tonic-gate * is 32 bits. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate if (maxsegmentsize_ll == 0 || (maxsegmentsize_ll > FOURG)) 930*7c478bd9Sstevel@tonic-gate maxsegmentsize = FOURG - 1; 931*7c478bd9Sstevel@tonic-gate else 932*7c478bd9Sstevel@tonic-gate maxsegmentsize = maxsegmentsize_ll; 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate /* 935*7c478bd9Sstevel@tonic-gate * We should be able to DMA into every byte offset in a page. 936*7c478bd9Sstevel@tonic-gate */ 937*7c478bd9Sstevel@tonic-gate if (maxsegmentsize < MMU_PAGESIZE) { 938*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits, maxsegmentsize\n")); 939*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate hp = kmem_zalloc(sizeof (*hp), 944*7c478bd9Sstevel@tonic-gate (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 945*7c478bd9Sstevel@tonic-gate if (hp == NULL) { 946*7c478bd9Sstevel@tonic-gate if (waitfp != DDI_DMA_DONTWAIT) { 947*7c478bd9Sstevel@tonic-gate ddi_set_callback(waitfp, arg, &dvma_call_list_id); 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate return (DDI_DMA_NORESOURCES); 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate /* 952*7c478bd9Sstevel@tonic-gate * Preallocate space for cookie structures. We will use this when 953*7c478bd9Sstevel@tonic-gate * the request does not span more than (DMAI_SOMEMORE_COOKIES - 1) 954*7c478bd9Sstevel@tonic-gate * pages. 955*7c478bd9Sstevel@tonic-gate */ 956*7c478bd9Sstevel@tonic-gate hp->dmai_additionalcookiep = 957*7c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ddi_dma_cookie_t) * DMAI_SOMEMORE_COOKIES, 958*7c478bd9Sstevel@tonic-gate (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate /* 961*7c478bd9Sstevel@tonic-gate * Save requestor's information 962*7c478bd9Sstevel@tonic-gate */ 963*7c478bd9Sstevel@tonic-gate hp->dmai_wins = NULL; 964*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = 965*7c478bd9Sstevel@tonic-gate hp->dmai_ibufp = NULL; 966*7c478bd9Sstevel@tonic-gate hp->dmai_inuse = 0; 967*7c478bd9Sstevel@tonic-gate hp->dmai_minxfer = attr->dma_attr_minxfer; 968*7c478bd9Sstevel@tonic-gate hp->dmai_burstsizes = attr->dma_attr_burstsizes; 969*7c478bd9Sstevel@tonic-gate hp->dmai_minfo = NULL; 970*7c478bd9Sstevel@tonic-gate hp->dmai_rdip = rdip; 971*7c478bd9Sstevel@tonic-gate hp->dmai_attr = *attr; 972*7c478bd9Sstevel@tonic-gate hp->dmai_mctl = rootnex_dma_mctl; 973*7c478bd9Sstevel@tonic-gate hp->dmai_segmentsize = maxsegmentsize; 974*7c478bd9Sstevel@tonic-gate *handlep = (ddi_dma_handle_t)hp; 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 980*7c478bd9Sstevel@tonic-gate static int 981*7c478bd9Sstevel@tonic-gate rootnex_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 982*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle) 983*7c478bd9Sstevel@tonic-gate { 984*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate /* 987*7c478bd9Sstevel@tonic-gate * free the additional cookie space. 988*7c478bd9Sstevel@tonic-gate */ 989*7c478bd9Sstevel@tonic-gate if (hp->dmai_additionalcookiep) 990*7c478bd9Sstevel@tonic-gate kmem_free(hp->dmai_additionalcookiep, 991*7c478bd9Sstevel@tonic-gate sizeof (ddi_dma_cookie_t) * DMAI_SOMEMORE_COOKIES); 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (*hp)); 994*7c478bd9Sstevel@tonic-gate if (dvma_call_list_id) 995*7c478bd9Sstevel@tonic-gate ddi_run_callback(&dvma_call_list_id); 996*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate static int 1000*7c478bd9Sstevel@tonic-gate rootnex_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 1001*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 1002*7c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cookiep, uint_t *ccountp) 1003*7c478bd9Sstevel@tonic-gate { 1004*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 1005*7c478bd9Sstevel@tonic-gate ddi_dma_attr_t *dma_attr = &hp->dmai_attr; 1006*7c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cp; 1007*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *segp; 1008*7c478bd9Sstevel@tonic-gate uint_t segcount = 1; 1009*7c478bd9Sstevel@tonic-gate int rval; 1010*7c478bd9Sstevel@tonic-gate struct priv_handle php; 1011*7c478bd9Sstevel@tonic-gate uint_t size, offset; 1012*7c478bd9Sstevel@tonic-gate uint64_t padr; 1013*7c478bd9Sstevel@tonic-gate major_t mnum; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * no mutex for speed 1017*7c478bd9Sstevel@tonic-gate */ 1018*7c478bd9Sstevel@tonic-gate if (hp->dmai_inuse) { 1019*7c478bd9Sstevel@tonic-gate return (DDI_DMA_INUSE); 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate hp->dmai_inuse = 1; 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate size = OBJSIZE; 1024*7c478bd9Sstevel@tonic-gate /* 1025*7c478bd9Sstevel@tonic-gate * get the physical address of the first page of an object 1026*7c478bd9Sstevel@tonic-gate * defined through 'dmareq' structure. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate padr = rootnex_get_phyaddr(dmareq, 0, &php); 1029*7c478bd9Sstevel@tonic-gate offset = padr & MMU_PAGEOFFSET; 1030*7c478bd9Sstevel@tonic-gate if (offset & (dma_attr->dma_attr_minxfer - 1)) { 1031*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits/mapping\n")); 1032*7c478bd9Sstevel@tonic-gate return (DDI_DMA_NOMAPPING); 1033*7c478bd9Sstevel@tonic-gate } else if ((dma_attr->dma_attr_sgllen > 1) && 1034*7c478bd9Sstevel@tonic-gate (size <= MMU_PAGESIZE) && (padr < AHI_ATTR)) { 1035*7c478bd9Sstevel@tonic-gate /* 1036*7c478bd9Sstevel@tonic-gate * The object is not more than a PAGESIZE and we could DMA into 1037*7c478bd9Sstevel@tonic-gate * the physical page. 1038*7c478bd9Sstevel@tonic-gate * The cache is completely coherent, set the NOSYNC flag. 1039*7c478bd9Sstevel@tonic-gate */ 1040*7c478bd9Sstevel@tonic-gate hp->dmai_rflags = (dmareq->dmar_flags & DMP_DDIFLAGS) | 1041*7c478bd9Sstevel@tonic-gate DMP_NOSYNC; 1042*7c478bd9Sstevel@tonic-gate /* 1043*7c478bd9Sstevel@tonic-gate * Fill in the physical address in the cookie pointer. 1044*7c478bd9Sstevel@tonic-gate */ 1045*7c478bd9Sstevel@tonic-gate cookiep->dmac_type = php.ph_mapinfo; 1046*7c478bd9Sstevel@tonic-gate cookiep->dmac_laddress = padr; 1047*7c478bd9Sstevel@tonic-gate if ((offset + size) <= MMU_PAGESIZE) { 1048*7c478bd9Sstevel@tonic-gate cookiep->dmac_size = size; 1049*7c478bd9Sstevel@tonic-gate hp->dmai_cookie = NULL; 1050*7c478bd9Sstevel@tonic-gate *ccountp = 1; 1051*7c478bd9Sstevel@tonic-gate } else if (hp->dmai_additionalcookiep) { 1052*7c478bd9Sstevel@tonic-gate /* 1053*7c478bd9Sstevel@tonic-gate * The object spans a page boundary. We will use the space 1054*7c478bd9Sstevel@tonic-gate * that we preallocated to store the additional cookie. 1055*7c478bd9Sstevel@tonic-gate */ 1056*7c478bd9Sstevel@tonic-gate cookiep->dmac_size = MMU_PAGESIZE - offset; 1057*7c478bd9Sstevel@tonic-gate hp->dmai_cookie = hp->dmai_additionalcookiep; 1058*7c478bd9Sstevel@tonic-gate padr = rootnex_get_phyaddr(dmareq, 1059*7c478bd9Sstevel@tonic-gate (uint_t)cookiep->dmac_size, &php); 1060*7c478bd9Sstevel@tonic-gate if (padr > AHI_ATTR) { 1061*7c478bd9Sstevel@tonic-gate /* 1062*7c478bd9Sstevel@tonic-gate * We can not DMA into this physical page. We will 1063*7c478bd9Sstevel@tonic-gate * need intermediate buffers. Reset the state in 1064*7c478bd9Sstevel@tonic-gate * the php structure. 1065*7c478bd9Sstevel@tonic-gate */ 1066*7c478bd9Sstevel@tonic-gate padr = rootnex_get_phyaddr(dmareq, 0, &php); 1067*7c478bd9Sstevel@tonic-gate goto io_brkup_attr; 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate hp->dmai_additionalcookiep->dmac_type = php.ph_mapinfo; 1070*7c478bd9Sstevel@tonic-gate hp->dmai_additionalcookiep->dmac_laddress = padr; 1071*7c478bd9Sstevel@tonic-gate hp->dmai_additionalcookiep->dmac_size = 1072*7c478bd9Sstevel@tonic-gate size - cookiep->dmac_size; 1073*7c478bd9Sstevel@tonic-gate *ccountp = 2; 1074*7c478bd9Sstevel@tonic-gate } else { 1075*7c478bd9Sstevel@tonic-gate goto io_brkup_attr; 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = NULL; 1078*7c478bd9Sstevel@tonic-gate hp->dmai_segp = NULL; 1079*7c478bd9Sstevel@tonic-gate hp->dmai_ibufp = NULL; 1080*7c478bd9Sstevel@tonic-gate return (DDI_DMA_MAPPED); 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate io_brkup_attr: 1083*7c478bd9Sstevel@tonic-gate /* 1084*7c478bd9Sstevel@tonic-gate * The function rootnex_get_phyaddr() does not save the physical 1085*7c478bd9Sstevel@tonic-gate * address in the php structure. Save it here for 1086*7c478bd9Sstevel@tonic-gate * rootnext_io_brkup_attr(). 1087*7c478bd9Sstevel@tonic-gate */ 1088*7c478bd9Sstevel@tonic-gate php.ph_padr = padr; 1089*7c478bd9Sstevel@tonic-gate rval = rootnex_io_brkup_attr(dip, rdip, dmareq, handle, &php); 1090*7c478bd9Sstevel@tonic-gate if (rval && (rval != DDI_DMA_PARTIAL_MAP)) { 1091*7c478bd9Sstevel@tonic-gate hp->dmai_inuse = 0; 1092*7c478bd9Sstevel@tonic-gate return (rval); 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate hp->dmai_wins = segp = hp->dmai_hds; 1095*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) { 1096*7c478bd9Sstevel@tonic-gate (void) rootnex_io_wtsync(hp, BIND); 1097*7c478bd9Sstevel@tonic-gate } 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate while ((segp->dmais_flags & DMAIS_WINEND) == 0) { 1100*7c478bd9Sstevel@tonic-gate segp = segp->dmais_link; 1101*7c478bd9Sstevel@tonic-gate segcount++; 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate *ccountp = segcount; 1104*7c478bd9Sstevel@tonic-gate cp = hp->dmai_cookie; 1105*7c478bd9Sstevel@tonic-gate ASSERT(cp); 1106*7c478bd9Sstevel@tonic-gate cookiep->dmac_type = cp->dmac_type; 1107*7c478bd9Sstevel@tonic-gate cookiep->dmac_laddress = cp->dmac_laddress; 1108*7c478bd9Sstevel@tonic-gate cookiep->dmac_size = cp->dmac_size; 1109*7c478bd9Sstevel@tonic-gate hp->dmai_cookie++; 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate /* 1112*7c478bd9Sstevel@tonic-gate * If we ended up with more cookies that the caller specified as 1113*7c478bd9Sstevel@tonic-gate * the maximum that it can handle (sgllen), and they didn't specify 1114*7c478bd9Sstevel@tonic-gate * DDI_DMA_PARTIAL, cleanup and return failure. 1115*7c478bd9Sstevel@tonic-gate * 1116*7c478bd9Sstevel@tonic-gate * Not the cleanest fix, but lowest risk. The DMA code in 1117*7c478bd9Sstevel@tonic-gate * this file should get a good cleaning for some performance 1118*7c478bd9Sstevel@tonic-gate * improvement. This should be cleaned up also during that work. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate if ((dma_attr->dma_attr_sgllen < *ccountp) && 1121*7c478bd9Sstevel@tonic-gate ((dmareq->dmar_flags & DDI_DMA_PARTIAL) == 0)) { 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate mnum = ddi_driver_major(rdip); 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate /* 1126*7c478bd9Sstevel@tonic-gate * patchable which allows us to print one warning per major 1127*7c478bd9Sstevel@tonic-gate * number. 1128*7c478bd9Sstevel@tonic-gate */ 1129*7c478bd9Sstevel@tonic-gate if ((rootnex_bind_warn) && 1130*7c478bd9Sstevel@tonic-gate ((rootnex_warn_list[mnum] & ROOTNEX_BIND_WARNING) == 0)) { 1131*7c478bd9Sstevel@tonic-gate rootnex_warn_list[mnum] |= ROOTNEX_BIND_WARNING; 1132*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!%s: coding error detected, the " 1133*7c478bd9Sstevel@tonic-gate "driver is using ddi_dma_attr(9S) incorrectly. " 1134*7c478bd9Sstevel@tonic-gate "There is a small risk of data corruption in " 1135*7c478bd9Sstevel@tonic-gate "particular with large I/Os. The driver should be " 1136*7c478bd9Sstevel@tonic-gate "replaced with a corrected version for proper " 1137*7c478bd9Sstevel@tonic-gate "system operation. To disable this warning, add " 1138*7c478bd9Sstevel@tonic-gate "'set rootnex:rootnex_bind_warn=0' to " 1139*7c478bd9Sstevel@tonic-gate "/etc/system(4).", ddi_driver_name(rdip)); 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate /* 1143*7c478bd9Sstevel@tonic-gate * Patchable which allows us to fail or pass the bind. The 1144*7c478bd9Sstevel@tonic-gate * correct behavior should be to fail the bind. To be safe for 1145*7c478bd9Sstevel@tonic-gate * now, the patchable allows the previous behavior to be set 1146*7c478bd9Sstevel@tonic-gate * via /etc/system 1147*7c478bd9Sstevel@tonic-gate */ 1148*7c478bd9Sstevel@tonic-gate if (rootnex_bind_fail) { 1149*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) 1150*7c478bd9Sstevel@tonic-gate ddi_mem_free(hp->dmai_ibufp); 1151*7c478bd9Sstevel@tonic-gate if (hp->dmai_kaddr) 1152*7c478bd9Sstevel@tonic-gate vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE); 1153*7c478bd9Sstevel@tonic-gate if (hp->dmai_segp) 1154*7c478bd9Sstevel@tonic-gate kmem_free(hp->dmai_segp, hp->dmai_kmsize); 1155*7c478bd9Sstevel@tonic-gate hp->dmai_inuse = 0; 1156*7c478bd9Sstevel@tonic-gate *ccountp = 0; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate return (DDI_DMA_TOOBIG); 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate return (rval); 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1166*7c478bd9Sstevel@tonic-gate static int 1167*7c478bd9Sstevel@tonic-gate rootnex_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 1168*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle) 1169*7c478bd9Sstevel@tonic-gate { 1170*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 1171*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) { 1174*7c478bd9Sstevel@tonic-gate rval = rootnex_io_rdsync(hp); 1175*7c478bd9Sstevel@tonic-gate ddi_mem_free(hp->dmai_ibufp); 1176*7c478bd9Sstevel@tonic-gate } 1177*7c478bd9Sstevel@tonic-gate if (hp->dmai_kaddr) 1178*7c478bd9Sstevel@tonic-gate vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE); 1179*7c478bd9Sstevel@tonic-gate if (hp->dmai_segp) 1180*7c478bd9Sstevel@tonic-gate kmem_free(hp->dmai_segp, hp->dmai_kmsize); 1181*7c478bd9Sstevel@tonic-gate if (dvma_call_list_id) 1182*7c478bd9Sstevel@tonic-gate ddi_run_callback(&dvma_call_list_id); 1183*7c478bd9Sstevel@tonic-gate hp->dmai_inuse = 0; 1184*7c478bd9Sstevel@tonic-gate return (rval); 1185*7c478bd9Sstevel@tonic-gate } 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1188*7c478bd9Sstevel@tonic-gate static int 1189*7c478bd9Sstevel@tonic-gate rootnex_dma_flush(dev_info_t *dip, dev_info_t *rdip, 1190*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, off_t off, size_t len, 1191*7c478bd9Sstevel@tonic-gate uint_t cache_flags) 1192*7c478bd9Sstevel@tonic-gate { 1193*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 1194*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) { 1197*7c478bd9Sstevel@tonic-gate if (cache_flags == DDI_DMA_SYNC_FORDEV) { 1198*7c478bd9Sstevel@tonic-gate rval = rootnex_io_wtsync(hp, MAP); 1199*7c478bd9Sstevel@tonic-gate } else { 1200*7c478bd9Sstevel@tonic-gate rval = rootnex_io_rdsync(hp); 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate } 1203*7c478bd9Sstevel@tonic-gate return (rval); 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1207*7c478bd9Sstevel@tonic-gate static int 1208*7c478bd9Sstevel@tonic-gate rootnex_dma_win(dev_info_t *dip, dev_info_t *rdip, 1209*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, uint_t win, off_t *offp, 1210*7c478bd9Sstevel@tonic-gate size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 1211*7c478bd9Sstevel@tonic-gate { 1212*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 1213*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *segp, *winp = hp->dmai_hds; 1214*7c478bd9Sstevel@tonic-gate uint_t len, segcount = 1; 1215*7c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cp; 1216*7c478bd9Sstevel@tonic-gate int i; 1217*7c478bd9Sstevel@tonic-gate 1218*7c478bd9Sstevel@tonic-gate /* 1219*7c478bd9Sstevel@tonic-gate * win is in the range [0 .. dmai_nwin-1] 1220*7c478bd9Sstevel@tonic-gate */ 1221*7c478bd9Sstevel@tonic-gate if (win >= hp->dmai_nwin) { 1222*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1223*7c478bd9Sstevel@tonic-gate } 1224*7c478bd9Sstevel@tonic-gate if (hp->dmai_wins && hp->dmai_ibufp) { 1225*7c478bd9Sstevel@tonic-gate (void) rootnex_io_rdsync(hp); 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate ASSERT(winp->dmais_flags & DMAIS_WINSTRT); 1228*7c478bd9Sstevel@tonic-gate for (i = 0; i < win; i++) { 1229*7c478bd9Sstevel@tonic-gate winp = winp->_win._dmais_nex; 1230*7c478bd9Sstevel@tonic-gate ASSERT(winp); 1231*7c478bd9Sstevel@tonic-gate ASSERT(winp->dmais_flags & DMAIS_WINSTRT); 1232*7c478bd9Sstevel@tonic-gate } 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate hp->dmai_wins = (impl_dma_segment_t *)winp; 1235*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) 1236*7c478bd9Sstevel@tonic-gate (void) rootnex_io_wtsync(hp, BIND); 1237*7c478bd9Sstevel@tonic-gate segp = winp; 1238*7c478bd9Sstevel@tonic-gate len = segp->dmais_size; 1239*7c478bd9Sstevel@tonic-gate *offp = segp->dmais_ofst; 1240*7c478bd9Sstevel@tonic-gate while ((segp->dmais_flags & DMAIS_WINEND) == 0) { 1241*7c478bd9Sstevel@tonic-gate segp = segp->dmais_link; 1242*7c478bd9Sstevel@tonic-gate len += segp->dmais_size; 1243*7c478bd9Sstevel@tonic-gate segcount++; 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate *lenp = len; 1247*7c478bd9Sstevel@tonic-gate *ccountp = segcount; 1248*7c478bd9Sstevel@tonic-gate cp = hp->dmai_cookie = winp->dmais_cookie; 1249*7c478bd9Sstevel@tonic-gate ASSERT(cp); 1250*7c478bd9Sstevel@tonic-gate cookiep->dmac_type = cp->dmac_type; 1251*7c478bd9Sstevel@tonic-gate cookiep->dmac_laddress = cp->dmac_laddress; 1252*7c478bd9Sstevel@tonic-gate cookiep->dmac_size = cp->dmac_size; 1253*7c478bd9Sstevel@tonic-gate hp->dmai_cookie++; 1254*7c478bd9Sstevel@tonic-gate DMAPRINT(("getwin win %p mapping %llx size %lx\n", 1255*7c478bd9Sstevel@tonic-gate (void *)winp, (unsigned long long)cp->dmac_laddress, 1256*7c478bd9Sstevel@tonic-gate cp->dmac_size)); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate static int 1262*7c478bd9Sstevel@tonic-gate rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip, 1263*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep) 1264*7c478bd9Sstevel@tonic-gate { 1265*7c478bd9Sstevel@tonic-gate ddi_dma_lim_t *dma_lim = dmareq->dmar_limits; 1266*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *segmentp; 1267*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp; 1268*7c478bd9Sstevel@tonic-gate struct priv_handle php; 1269*7c478bd9Sstevel@tonic-gate uint64_t padr; 1270*7c478bd9Sstevel@tonic-gate uint_t offset, size; 1271*7c478bd9Sstevel@tonic-gate int sizehandle; 1272*7c478bd9Sstevel@tonic-gate int mapinfo; 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate #ifdef lint 1275*7c478bd9Sstevel@tonic-gate dip = dip; 1276*7c478bd9Sstevel@tonic-gate #endif 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate DMAPRINT(("dma_map: %s (%s) reqp %p ", (handlep)? "alloc" : "advisory", 1279*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), (void *)dmareq)); 1280*7c478bd9Sstevel@tonic-gate 1281*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 1282*7c478bd9Sstevel@tonic-gate /* 1283*7c478bd9Sstevel@tonic-gate * Validate range checks on DMA limits 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate if ((dma_lim->dlim_adreg_max & MMU_PAGEOFFSET) != MMU_PAGEOFFSET || 1286*7c478bd9Sstevel@tonic-gate dma_lim->dlim_granular > MMU_PAGESIZE || 1287*7c478bd9Sstevel@tonic-gate dma_lim->dlim_sgllen <= 0) { 1288*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits\n")); 1289*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate #endif 1292*7c478bd9Sstevel@tonic-gate size = OBJSIZE; 1293*7c478bd9Sstevel@tonic-gate /* 1294*7c478bd9Sstevel@tonic-gate * get the physical address of the first page of an object 1295*7c478bd9Sstevel@tonic-gate * defined through 'dmareq' structure. 1296*7c478bd9Sstevel@tonic-gate */ 1297*7c478bd9Sstevel@tonic-gate padr = rootnex_get_phyaddr(dmareq, 0, &php); 1298*7c478bd9Sstevel@tonic-gate mapinfo = php.ph_mapinfo; 1299*7c478bd9Sstevel@tonic-gate offset = padr & MMU_PAGEOFFSET; 1300*7c478bd9Sstevel@tonic-gate if (offset & (dma_lim->dlim_minxfer - 1)) { 1301*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits/mapping\n")); 1302*7c478bd9Sstevel@tonic-gate return (DDI_DMA_NOMAPPING); 1303*7c478bd9Sstevel@tonic-gate } else if (((offset + size) < MMU_PAGESIZE) && (padr < AHI_LIM)) { 1304*7c478bd9Sstevel@tonic-gate /* 1305*7c478bd9Sstevel@tonic-gate * The object is less than a PAGESIZE and we could DMA into 1306*7c478bd9Sstevel@tonic-gate * the physical page. 1307*7c478bd9Sstevel@tonic-gate */ 1308*7c478bd9Sstevel@tonic-gate if (!handlep) 1309*7c478bd9Sstevel@tonic-gate return (DDI_DMA_MAPOK); 1310*7c478bd9Sstevel@tonic-gate sizehandle = sizeof (ddi_dma_impl_t) + 1311*7c478bd9Sstevel@tonic-gate sizeof (impl_dma_segment_t); 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate hp = kmem_alloc(sizehandle, (dmareq->dmar_fp == DDI_DMA_SLEEP) ? 1314*7c478bd9Sstevel@tonic-gate KM_SLEEP : KM_NOSLEEP); 1315*7c478bd9Sstevel@tonic-gate if (!hp) { 1316*7c478bd9Sstevel@tonic-gate /* let other routine do callback */ 1317*7c478bd9Sstevel@tonic-gate goto breakup_req; 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate hp->dmai_kmsize = sizehandle; 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate /* 1322*7c478bd9Sstevel@tonic-gate * locate segments after dma_impl handle structure 1323*7c478bd9Sstevel@tonic-gate */ 1324*7c478bd9Sstevel@tonic-gate segmentp = (impl_dma_segment_t *)(hp + 1); 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate /* FMA related initialization */ 1327*7c478bd9Sstevel@tonic-gate hp->dmai_fault = 0; 1328*7c478bd9Sstevel@tonic-gate hp->dmai_fault_check = NULL; 1329*7c478bd9Sstevel@tonic-gate hp->dmai_fault_notify = NULL; 1330*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_ena = 0; 1331*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_status = DDI_FM_OK; 1332*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_expected = DDI_FM_ERR_UNEXPECTED; 1333*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_ontrap = NULL; 1334*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_fep = NULL; 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate /* 1337*7c478bd9Sstevel@tonic-gate * Save requestor's information 1338*7c478bd9Sstevel@tonic-gate */ 1339*7c478bd9Sstevel@tonic-gate hp->dmai_minxfer = dma_lim->dlim_minxfer; 1340*7c478bd9Sstevel@tonic-gate hp->dmai_burstsizes = dma_lim->dlim_burstsizes; 1341*7c478bd9Sstevel@tonic-gate hp->dmai_rdip = rdip; 1342*7c478bd9Sstevel@tonic-gate hp->dmai_mctl = rootnex_dma_mctl; 1343*7c478bd9Sstevel@tonic-gate hp->dmai_wins = NULL; 1344*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = hp->dmai_ibufp = NULL; 1345*7c478bd9Sstevel@tonic-gate hp->dmai_hds = segmentp; 1346*7c478bd9Sstevel@tonic-gate hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS; 1347*7c478bd9Sstevel@tonic-gate hp->dmai_minfo = (void *)(uintptr_t)mapinfo; 1348*7c478bd9Sstevel@tonic-gate hp->dmai_object = dmareq->dmar_object; 1349*7c478bd9Sstevel@tonic-gate if (mapinfo == DMAMI_PAGES) { 1350*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_pp = php.ph_u.pp; 1351*7c478bd9Sstevel@tonic-gate segmentp->dmais_ofst = (uint_t)offset; 1352*7c478bd9Sstevel@tonic-gate } else { 1353*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_va = php.ph_vaddr; 1354*7c478bd9Sstevel@tonic-gate segmentp->dmais_ofst = 0; 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate segmentp->_win._dmais_nex = NULL; 1357*7c478bd9Sstevel@tonic-gate segmentp->dmais_link = NULL; 1358*7c478bd9Sstevel@tonic-gate segmentp->_pdmu._dmais_lpd = padr; 1359*7c478bd9Sstevel@tonic-gate segmentp->dmais_size = size; 1360*7c478bd9Sstevel@tonic-gate segmentp->dmais_flags = DMAIS_WINSTRT | DMAIS_WINEND; 1361*7c478bd9Sstevel@tonic-gate segmentp->dmais_hndl = hp; 1362*7c478bd9Sstevel@tonic-gate *handlep = (ddi_dma_handle_t)hp; 1363*7c478bd9Sstevel@tonic-gate DMAPRINT((" QUICKIE handle %p\n", (void *)hp)); 1364*7c478bd9Sstevel@tonic-gate return (DDI_DMA_MAPPED); 1365*7c478bd9Sstevel@tonic-gate } else if (!handlep) { 1366*7c478bd9Sstevel@tonic-gate return (DDI_DMA_NOMAPPING); 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate breakup_req: 1369*7c478bd9Sstevel@tonic-gate /* 1370*7c478bd9Sstevel@tonic-gate * The function rootnex_get_phyaddr() does not save the physical 1371*7c478bd9Sstevel@tonic-gate * address in the php structure. Save it here for 1372*7c478bd9Sstevel@tonic-gate * rootnext_io_brkup_attr(). 1373*7c478bd9Sstevel@tonic-gate */ 1374*7c478bd9Sstevel@tonic-gate php.ph_padr = padr; 1375*7c478bd9Sstevel@tonic-gate return (rootnex_io_brkup_lim(dip, rdip, dmareq, handlep, 1376*7c478bd9Sstevel@tonic-gate dma_lim, &php)); 1377*7c478bd9Sstevel@tonic-gate } 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 1380*7c478bd9Sstevel@tonic-gate #define CAN_COMBINE(psegp, paddr, segsize, sgsize, mxsegsize, attr, flg) \ 1381*7c478bd9Sstevel@tonic-gate ((psegp) && \ 1382*7c478bd9Sstevel@tonic-gate ((psegp)->_pdmu._dmais_lpd + (psegp)->dmais_size) == (paddr) && \ 1383*7c478bd9Sstevel@tonic-gate (((psegp)->dmais_flags & (DMAIS_NEEDINTBUF | DMAIS_COMPLEMENT)) == 0) && \ 1384*7c478bd9Sstevel@tonic-gate (((flg) & DMAIS_NEEDINTBUF) == 0) && \ 1385*7c478bd9Sstevel@tonic-gate (((psegp)->dmais_size + (segsize)) <= (mxsegsize)) && \ 1386*7c478bd9Sstevel@tonic-gate ((paddr) & (attr)->dma_attr_seg)) 1387*7c478bd9Sstevel@tonic-gate 1388*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 1389*7c478bd9Sstevel@tonic-gate #define MARK_WIN_END(segp, prvwinp, cwinp) \ 1390*7c478bd9Sstevel@tonic-gate (segp)->dmais_flags |= DMAIS_WINEND; \ 1391*7c478bd9Sstevel@tonic-gate (prvwinp) = (cwinp); \ 1392*7c478bd9Sstevel@tonic-gate (cwinp)->dmais_flags |= DMAIS_WINUIB; \ 1393*7c478bd9Sstevel@tonic-gate (cwinp) = NULL; 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate /* 1396*7c478bd9Sstevel@tonic-gate * This function works with the ddi_dma_attr structure. 1397*7c478bd9Sstevel@tonic-gate * Bugs fixed 1398*7c478bd9Sstevel@tonic-gate * 1. The old code would ignore the size of the first segment when 1399*7c478bd9Sstevel@tonic-gate * computing the total size of the reuqest (sglistsize) for sgllen == 1 1400*7c478bd9Sstevel@tonic-gate */ 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1403*7c478bd9Sstevel@tonic-gate int 1404*7c478bd9Sstevel@tonic-gate rootnex_io_brkup_attr(dev_info_t *dip, dev_info_t *rdip, 1405*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t handle, 1406*7c478bd9Sstevel@tonic-gate struct priv_handle *php) 1407*7c478bd9Sstevel@tonic-gate { 1408*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *segmentp; 1409*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *curwinp; 1410*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *previousp; 1411*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *prewinp; 1412*7c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cookiep; 1413*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 1414*7c478bd9Sstevel@tonic-gate caddr_t basevadr; 1415*7c478bd9Sstevel@tonic-gate caddr_t segmentvadr; 1416*7c478bd9Sstevel@tonic-gate uint64_t segmentpadr; 1417*7c478bd9Sstevel@tonic-gate uint_t maxsegmentsize, sizesegment, residual_size; 1418*7c478bd9Sstevel@tonic-gate uint_t offset, needintbuf, sglistsize, trim; 1419*7c478bd9Sstevel@tonic-gate int nsegments; 1420*7c478bd9Sstevel@tonic-gate int mapinfo; 1421*7c478bd9Sstevel@tonic-gate int reqneedintbuf; 1422*7c478bd9Sstevel@tonic-gate int rval; 1423*7c478bd9Sstevel@tonic-gate int segment_flags, win_flags; 1424*7c478bd9Sstevel@tonic-gate int sgcount; 1425*7c478bd9Sstevel@tonic-gate int wcount; 1426*7c478bd9Sstevel@tonic-gate ddi_dma_attr_t *dma_attr = &hp->dmai_attr; 1427*7c478bd9Sstevel@tonic-gate int sizehandle; 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate #ifdef lint 1430*7c478bd9Sstevel@tonic-gate dip = dip; 1431*7c478bd9Sstevel@tonic-gate #endif 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate /* 1434*7c478bd9Sstevel@tonic-gate * Initialize our local variables from the php structure. 1435*7c478bd9Sstevel@tonic-gate * rootnex_get_phyaddr() has populated php structure on its 1436*7c478bd9Sstevel@tonic-gate * previous invocation in rootnex_dma_bindhdl(). 1437*7c478bd9Sstevel@tonic-gate */ 1438*7c478bd9Sstevel@tonic-gate residual_size = OBJSIZE; 1439*7c478bd9Sstevel@tonic-gate mapinfo = php->ph_mapinfo; 1440*7c478bd9Sstevel@tonic-gate segmentpadr = php->ph_padr; 1441*7c478bd9Sstevel@tonic-gate segmentvadr = php->ph_vaddr; 1442*7c478bd9Sstevel@tonic-gate basevadr = (mapinfo == DMAMI_PAGES) ? 0 : segmentvadr; 1443*7c478bd9Sstevel@tonic-gate offset = segmentpadr & MMU_PAGEOFFSET; 1444*7c478bd9Sstevel@tonic-gate /* 1445*7c478bd9Sstevel@tonic-gate * maxsegmentsize was computed and saved in rootnex_dma_allochdl(). 1446*7c478bd9Sstevel@tonic-gate */ 1447*7c478bd9Sstevel@tonic-gate maxsegmentsize = hp->dmai_segmentsize; 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate /* 1450*7c478bd9Sstevel@tonic-gate * The number of segments is the number of 4k pages that the 1451*7c478bd9Sstevel@tonic-gate * object spans. 1452*7c478bd9Sstevel@tonic-gate * Each 4k segment may need another segment to satisfy 1453*7c478bd9Sstevel@tonic-gate * device granularity reqirements. 1454*7c478bd9Sstevel@tonic-gate * We will never need more than two segments per page. 1455*7c478bd9Sstevel@tonic-gate * This may be an overestimate in some cases but it avoids 1456*7c478bd9Sstevel@tonic-gate * 64 bit divide operations. 1457*7c478bd9Sstevel@tonic-gate */ 1458*7c478bd9Sstevel@tonic-gate nsegments = (offset + residual_size + MMU_PAGEOFFSET) >> 1459*7c478bd9Sstevel@tonic-gate (MMU_PAGESHIFT - 1); 1460*7c478bd9Sstevel@tonic-gate 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate sizehandle = nsegments * (sizeof (impl_dma_segment_t) + 1464*7c478bd9Sstevel@tonic-gate sizeof (ddi_dma_cookie_t)); 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate hp->dmai_segp = kmem_zalloc(sizehandle, 1467*7c478bd9Sstevel@tonic-gate (dmareq->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1468*7c478bd9Sstevel@tonic-gate if (!hp->dmai_segp) { 1469*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NORESOURCES; 1470*7c478bd9Sstevel@tonic-gate goto bad; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate hp->dmai_kmsize = sizehandle; 1473*7c478bd9Sstevel@tonic-gate segmentp = (impl_dma_segment_t *)hp->dmai_segp; 1474*7c478bd9Sstevel@tonic-gate cookiep = (ddi_dma_cookie_t *)(segmentp + nsegments); 1475*7c478bd9Sstevel@tonic-gate hp->dmai_cookie = cookiep; 1476*7c478bd9Sstevel@tonic-gate hp->dmai_wins = NULL; 1477*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = hp->dmai_ibufp = NULL; 1478*7c478bd9Sstevel@tonic-gate hp->dmai_hds = prewinp = segmentp; 1479*7c478bd9Sstevel@tonic-gate hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS; 1480*7c478bd9Sstevel@tonic-gate hp->dmai_minfo = (void *)(uintptr_t)mapinfo; 1481*7c478bd9Sstevel@tonic-gate hp->dmai_object = dmareq->dmar_object; 1482*7c478bd9Sstevel@tonic-gate 1483*7c478bd9Sstevel@tonic-gate /* 1484*7c478bd9Sstevel@tonic-gate * Breakup the memory object 1485*7c478bd9Sstevel@tonic-gate * and build an i/o segment at each boundary condition 1486*7c478bd9Sstevel@tonic-gate */ 1487*7c478bd9Sstevel@tonic-gate curwinp = 0; 1488*7c478bd9Sstevel@tonic-gate needintbuf = 0; 1489*7c478bd9Sstevel@tonic-gate previousp = 0; 1490*7c478bd9Sstevel@tonic-gate reqneedintbuf = 0; 1491*7c478bd9Sstevel@tonic-gate sglistsize = 0; 1492*7c478bd9Sstevel@tonic-gate wcount = 0; 1493*7c478bd9Sstevel@tonic-gate sgcount = 1; 1494*7c478bd9Sstevel@tonic-gate do { 1495*7c478bd9Sstevel@tonic-gate sizesegment = MIN((MMU_PAGESIZE - offset), residual_size); 1496*7c478bd9Sstevel@tonic-gate segment_flags = (segmentpadr > AHI_ATTR) ? DMAIS_NEEDINTBUF : 0; 1497*7c478bd9Sstevel@tonic-gate sglistsize += sizesegment; 1498*7c478bd9Sstevel@tonic-gate if (sglistsize >= dma_attr->dma_attr_maxxfer) { 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * limit the number of bytes to dma_attr_maxxfer 1501*7c478bd9Sstevel@tonic-gate */ 1502*7c478bd9Sstevel@tonic-gate sizesegment -= 1503*7c478bd9Sstevel@tonic-gate (sglistsize - dma_attr->dma_attr_maxxfer); 1504*7c478bd9Sstevel@tonic-gate sglistsize = dma_attr->dma_attr_maxxfer; 1505*7c478bd9Sstevel@tonic-gate sgcount = dma_attr->dma_attr_sgllen + 1; 1506*7c478bd9Sstevel@tonic-gate } 1507*7c478bd9Sstevel@tonic-gate if ((dma_attr->dma_attr_sgllen == 1) && 1508*7c478bd9Sstevel@tonic-gate (segmentpadr & (dma_attr->dma_attr_granular - 1)) && 1509*7c478bd9Sstevel@tonic-gate (residual_size != sizesegment)) { 1510*7c478bd9Sstevel@tonic-gate /* 1511*7c478bd9Sstevel@tonic-gate * _no_ scatter/gather capability, 1512*7c478bd9Sstevel@tonic-gate * so ensure that size of each segment is a 1513*7c478bd9Sstevel@tonic-gate * multiple of dma_attr_granular (== sector size) 1514*7c478bd9Sstevel@tonic-gate */ 1515*7c478bd9Sstevel@tonic-gate sizesegment = MIN((uint_t)MMU_PAGESIZE, residual_size); 1516*7c478bd9Sstevel@tonic-gate segment_flags |= DMAIS_NEEDINTBUF; 1517*7c478bd9Sstevel@tonic-gate sglistsize = sizesegment; 1518*7c478bd9Sstevel@tonic-gate } 1519*7c478bd9Sstevel@tonic-gate if (CAN_COMBINE(previousp, segmentpadr, sizesegment, 1520*7c478bd9Sstevel@tonic-gate sglistsize, maxsegmentsize, dma_attr, segment_flags)) { 1521*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= segment_flags; 1522*7c478bd9Sstevel@tonic-gate previousp->dmais_size += sizesegment; 1523*7c478bd9Sstevel@tonic-gate previousp->dmais_cookie->dmac_size += sizesegment; 1524*7c478bd9Sstevel@tonic-gate } else { 1525*7c478bd9Sstevel@tonic-gate if (dma_attr->dma_attr_sgllen == 1) 1526*7c478bd9Sstevel@tonic-gate /* 1527*7c478bd9Sstevel@tonic-gate * If we can not combine this segment with the 1528*7c478bd9Sstevel@tonic-gate * previous segment or if there are no previous 1529*7c478bd9Sstevel@tonic-gate * segments, sglistsize should be set to 1530*7c478bd9Sstevel@tonic-gate * segmentsize. 1531*7c478bd9Sstevel@tonic-gate */ 1532*7c478bd9Sstevel@tonic-gate sglistsize = sizesegment; 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate if (previousp) { 1535*7c478bd9Sstevel@tonic-gate previousp->dmais_link = segmentp; 1536*7c478bd9Sstevel@tonic-gate } 1537*7c478bd9Sstevel@tonic-gate segmentp->dmais_cookie = cookiep; 1538*7c478bd9Sstevel@tonic-gate segmentp->dmais_hndl = hp; 1539*7c478bd9Sstevel@tonic-gate if (curwinp == 0) { 1540*7c478bd9Sstevel@tonic-gate prewinp->_win._dmais_nex = curwinp = segmentp; 1541*7c478bd9Sstevel@tonic-gate segment_flags |= DMAIS_WINSTRT; 1542*7c478bd9Sstevel@tonic-gate win_flags = segment_flags; 1543*7c478bd9Sstevel@tonic-gate wcount++; 1544*7c478bd9Sstevel@tonic-gate } else { 1545*7c478bd9Sstevel@tonic-gate segmentp->_win._dmais_cur = curwinp; 1546*7c478bd9Sstevel@tonic-gate win_flags |= segment_flags; 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate segmentp->dmais_ofst = segmentvadr - basevadr; 1549*7c478bd9Sstevel@tonic-gate if (mapinfo == DMAMI_PAGES) 1550*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_pp = php->ph_u.pp; 1551*7c478bd9Sstevel@tonic-gate else 1552*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_va = (caddr_t)segmentvadr; 1553*7c478bd9Sstevel@tonic-gate segmentp->_pdmu._dmais_lpd = segmentpadr; 1554*7c478bd9Sstevel@tonic-gate segmentp->dmais_flags = (ushort_t)segment_flags; 1555*7c478bd9Sstevel@tonic-gate segmentp->dmais_size = sizesegment; 1556*7c478bd9Sstevel@tonic-gate cookiep->dmac_laddress = segmentpadr; 1557*7c478bd9Sstevel@tonic-gate cookiep->dmac_type = (ulong_t)segmentp; 1558*7c478bd9Sstevel@tonic-gate cookiep->dmac_size = sizesegment; 1559*7c478bd9Sstevel@tonic-gate cookiep++; 1560*7c478bd9Sstevel@tonic-gate --nsegments; 1561*7c478bd9Sstevel@tonic-gate if (dma_attr->dma_attr_sgllen > 1) 1562*7c478bd9Sstevel@tonic-gate sgcount++; 1563*7c478bd9Sstevel@tonic-gate if (segment_flags & DMAIS_NEEDINTBUF) { 1564*7c478bd9Sstevel@tonic-gate if ((dma_attr->dma_attr_sgllen > 1) && 1565*7c478bd9Sstevel@tonic-gate (needintbuf += ptob(btopr(sizesegment))) 1566*7c478bd9Sstevel@tonic-gate == MAX_INT_BUF) { 1567*7c478bd9Sstevel@tonic-gate /* 1568*7c478bd9Sstevel@tonic-gate * Intermediate buffers need not be contiguous. 1569*7c478bd9Sstevel@tonic-gate * we allocate a page of intermediate buffer 1570*7c478bd9Sstevel@tonic-gate * for every segment. 1571*7c478bd9Sstevel@tonic-gate */ 1572*7c478bd9Sstevel@tonic-gate reqneedintbuf = needintbuf; 1573*7c478bd9Sstevel@tonic-gate needintbuf = 0; 1574*7c478bd9Sstevel@tonic-gate sgcount = dma_attr->dma_attr_sgllen + 1; 1575*7c478bd9Sstevel@tonic-gate MARK_WIN_END(segmentp, prewinp, curwinp); 1576*7c478bd9Sstevel@tonic-gate } else if (dma_attr->dma_attr_sgllen == 1) { 1577*7c478bd9Sstevel@tonic-gate needintbuf = MMU_PAGESIZE; 1578*7c478bd9Sstevel@tonic-gate MARK_WIN_END(segmentp, prewinp, curwinp); 1579*7c478bd9Sstevel@tonic-gate } 1580*7c478bd9Sstevel@tonic-gate } 1581*7c478bd9Sstevel@tonic-gate previousp = segmentp++; 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate if (sgcount > dma_attr->dma_attr_sgllen) { 1585*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= DMAIS_COMPLEMENT; 1586*7c478bd9Sstevel@tonic-gate sgcount = 1; 1587*7c478bd9Sstevel@tonic-gate trim = sglistsize & (dma_attr->dma_attr_granular - 1); 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate if ((sizesegment != residual_size) && 1590*7c478bd9Sstevel@tonic-gate (trim == sizesegment)) { 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate /* 1593*7c478bd9Sstevel@tonic-gate * Normally we would trim the buffer to make it a 1594*7c478bd9Sstevel@tonic-gate * multiple of the granularity. But in this case, 1595*7c478bd9Sstevel@tonic-gate * the size is < the granularity so we'll roll back 1596*7c478bd9Sstevel@tonic-gate * this segment and pick this up the next time around. 1597*7c478bd9Sstevel@tonic-gate * 1598*7c478bd9Sstevel@tonic-gate * This case occurs when sgcount naturally (i.e. not 1599*7c478bd9Sstevel@tonic-gate * forced) is greater than > dma_attr_sgllen. In this 1600*7c478bd9Sstevel@tonic-gate * case, if the very next segment fills up the 1601*7c478bd9Sstevel@tonic-gate * intermediate buffer, and the amount required to fill 1602*7c478bd9Sstevel@tonic-gate * the intermediate buffer < granularity, we would end 1603*7c478bd9Sstevel@tonic-gate * up with a zero sized cookie if we didn't roll back 1604*7c478bd9Sstevel@tonic-gate * the segment. 1605*7c478bd9Sstevel@tonic-gate */ 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate /* 1608*7c478bd9Sstevel@tonic-gate * Make sure we really understand the code path here, 1609*7c478bd9Sstevel@tonic-gate * we should only get here if we are at an end of a 1610*7c478bd9Sstevel@tonic-gate * window which is a single page long < granularity 1611*7c478bd9Sstevel@tonic-gate */ 1612*7c478bd9Sstevel@tonic-gate ASSERT(previousp->dmais_flags & DMAIS_WINEND); 1613*7c478bd9Sstevel@tonic-gate ASSERT(sizesegment == sglistsize); 1614*7c478bd9Sstevel@tonic-gate 1615*7c478bd9Sstevel@tonic-gate /* Zero out this segment and add it back to the count */ 1616*7c478bd9Sstevel@tonic-gate sizesegment = 0; 1617*7c478bd9Sstevel@tonic-gate sglistsize = 0; 1618*7c478bd9Sstevel@tonic-gate nsegments++; 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate /* fix the segment and cookie pointers */ 1621*7c478bd9Sstevel@tonic-gate segmentp = previousp; 1622*7c478bd9Sstevel@tonic-gate bzero(previousp, sizeof (impl_dma_segment_t)); 1623*7c478bd9Sstevel@tonic-gate previousp--; 1624*7c478bd9Sstevel@tonic-gate bzero(cookiep, sizeof (ddi_dma_cookie_t)); 1625*7c478bd9Sstevel@tonic-gate cookiep--; 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate /* 1628*7c478bd9Sstevel@tonic-gate * cleanup the new previous pointer. Make sure we 1629*7c478bd9Sstevel@tonic-gate * carry over the WINEND maker. 1630*7c478bd9Sstevel@tonic-gate */ 1631*7c478bd9Sstevel@tonic-gate previousp->dmais_link = NULL; 1632*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= DMAIS_WINEND; 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate } else if ((sizesegment != residual_size) && trim) { 1635*7c478bd9Sstevel@tonic-gate /* 1636*7c478bd9Sstevel@tonic-gate * end of a scatter/gather list! 1637*7c478bd9Sstevel@tonic-gate * ensure that total length of list is a 1638*7c478bd9Sstevel@tonic-gate * multiple of granular (sector size) 1639*7c478bd9Sstevel@tonic-gate */ 1640*7c478bd9Sstevel@tonic-gate previousp->dmais_size -= trim; 1641*7c478bd9Sstevel@tonic-gate previousp->dmais_cookie->dmac_size -= trim; 1642*7c478bd9Sstevel@tonic-gate sizesegment -= trim; 1643*7c478bd9Sstevel@tonic-gate } 1644*7c478bd9Sstevel@tonic-gate sglistsize = 0; 1645*7c478bd9Sstevel@tonic-gate } 1646*7c478bd9Sstevel@tonic-gate if (sizesegment && (residual_size -= sizesegment)) { 1647*7c478bd9Sstevel@tonic-gate /* 1648*7c478bd9Sstevel@tonic-gate * Get the physical address of the next page in the 1649*7c478bd9Sstevel@tonic-gate * dma object. 1650*7c478bd9Sstevel@tonic-gate */ 1651*7c478bd9Sstevel@tonic-gate segmentpadr = 1652*7c478bd9Sstevel@tonic-gate rootnex_get_phyaddr(dmareq, sizesegment, php); 1653*7c478bd9Sstevel@tonic-gate offset = segmentpadr & MMU_PAGEOFFSET; 1654*7c478bd9Sstevel@tonic-gate segmentvadr += sizesegment; 1655*7c478bd9Sstevel@tonic-gate } 1656*7c478bd9Sstevel@tonic-gate } while (residual_size && nsegments); 1657*7c478bd9Sstevel@tonic-gate ASSERT(residual_size == 0); 1658*7c478bd9Sstevel@tonic-gate 1659*7c478bd9Sstevel@tonic-gate previousp->dmais_link = NULL; 1660*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= DMAIS_WINEND; 1661*7c478bd9Sstevel@tonic-gate if (curwinp) { 1662*7c478bd9Sstevel@tonic-gate if (win_flags & DMAIS_NEEDINTBUF) 1663*7c478bd9Sstevel@tonic-gate curwinp->dmais_flags |= DMAIS_WINUIB; 1664*7c478bd9Sstevel@tonic-gate curwinp->_win._dmais_nex = NULL; 1665*7c478bd9Sstevel@tonic-gate } else 1666*7c478bd9Sstevel@tonic-gate prewinp->_win._dmais_nex = NULL; 1667*7c478bd9Sstevel@tonic-gate 1668*7c478bd9Sstevel@tonic-gate if ((needintbuf = MAX(needintbuf, reqneedintbuf)) != 0) { 1669*7c478bd9Sstevel@tonic-gate uint64_t saved_align; 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate saved_align = dma_attr->dma_attr_align; 1672*7c478bd9Sstevel@tonic-gate /* 1673*7c478bd9Sstevel@tonic-gate * Allocate intermediate buffer. To start with we request 1674*7c478bd9Sstevel@tonic-gate * for a page aligned area. This request is satisfied from 1675*7c478bd9Sstevel@tonic-gate * the system page free list pool. 1676*7c478bd9Sstevel@tonic-gate */ 1677*7c478bd9Sstevel@tonic-gate dma_attr->dma_attr_align = MMU_PAGESIZE; 1678*7c478bd9Sstevel@tonic-gate if (i_ddi_mem_alloc(dip, dma_attr, needintbuf, 1679*7c478bd9Sstevel@tonic-gate (dmareq->dmar_fp == DDI_DMA_SLEEP) ? 0x1 : 0, 1, 0, 1680*7c478bd9Sstevel@tonic-gate &hp->dmai_ibufp, (ulong_t *)&hp->dmai_ibfsz, 1681*7c478bd9Sstevel@tonic-gate NULL) != DDI_SUCCESS) { 1682*7c478bd9Sstevel@tonic-gate dma_attr->dma_attr_align = saved_align; 1683*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NORESOURCES; 1684*7c478bd9Sstevel@tonic-gate goto bad; 1685*7c478bd9Sstevel@tonic-gate } 1686*7c478bd9Sstevel@tonic-gate if (mapinfo != DMAMI_KVADR) { 1687*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = vmem_alloc(heap_arena, PAGESIZE, 1688*7c478bd9Sstevel@tonic-gate VM_SLEEP); 1689*7c478bd9Sstevel@tonic-gate } 1690*7c478bd9Sstevel@tonic-gate dma_attr->dma_attr_align = saved_align; 1691*7c478bd9Sstevel@tonic-gate } 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate /* 1694*7c478bd9Sstevel@tonic-gate * return success 1695*7c478bd9Sstevel@tonic-gate */ 1696*7c478bd9Sstevel@tonic-gate ASSERT(wcount > 0); 1697*7c478bd9Sstevel@tonic-gate if (wcount == 1) { 1698*7c478bd9Sstevel@tonic-gate hp->dmai_rflags &= ~DDI_DMA_PARTIAL; 1699*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_MAPPED; 1700*7c478bd9Sstevel@tonic-gate } else if (hp->dmai_rflags & DDI_DMA_PARTIAL) { 1701*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_PARTIAL_MAP; 1702*7c478bd9Sstevel@tonic-gate } else { 1703*7c478bd9Sstevel@tonic-gate if (hp->dmai_segp) 1704*7c478bd9Sstevel@tonic-gate kmem_free(hp->dmai_segp, hp->dmai_kmsize); 1705*7c478bd9Sstevel@tonic-gate return (DDI_DMA_TOOBIG); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate hp->dmai_nwin = wcount; 1708*7c478bd9Sstevel@tonic-gate return (rval); 1709*7c478bd9Sstevel@tonic-gate bad: 1710*7c478bd9Sstevel@tonic-gate hp->dmai_cookie = NULL; 1711*7c478bd9Sstevel@tonic-gate if (hp->dmai_segp) 1712*7c478bd9Sstevel@tonic-gate kmem_free(hp->dmai_segp, hp->dmai_kmsize); 1713*7c478bd9Sstevel@tonic-gate if (rval == DDI_DMA_NORESOURCES && 1714*7c478bd9Sstevel@tonic-gate dmareq->dmar_fp != DDI_DMA_DONTWAIT && 1715*7c478bd9Sstevel@tonic-gate dmareq->dmar_fp != DDI_DMA_SLEEP) 1716*7c478bd9Sstevel@tonic-gate ddi_set_callback(dmareq->dmar_fp, dmareq->dmar_arg, 1717*7c478bd9Sstevel@tonic-gate &dvma_call_list_id); 1718*7c478bd9Sstevel@tonic-gate return (rval); 1719*7c478bd9Sstevel@tonic-gate } 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate /* 1722*7c478bd9Sstevel@tonic-gate * This function works with the limit structure and does 32 bit arithmetic. 1723*7c478bd9Sstevel@tonic-gate */ 1724*7c478bd9Sstevel@tonic-gate int 1725*7c478bd9Sstevel@tonic-gate rootnex_io_brkup_lim(dev_info_t *dip, dev_info_t *rdip, 1726*7c478bd9Sstevel@tonic-gate struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep, 1727*7c478bd9Sstevel@tonic-gate ddi_dma_lim_t *dma_lim, struct priv_handle *php) 1728*7c478bd9Sstevel@tonic-gate { 1729*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *segmentp; 1730*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *curwinp; 1731*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *previousp; 1732*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *prewinp; 1733*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = 0; 1734*7c478bd9Sstevel@tonic-gate caddr_t basevadr; 1735*7c478bd9Sstevel@tonic-gate caddr_t segmentvadr; 1736*7c478bd9Sstevel@tonic-gate uint64_t segmentpadr; 1737*7c478bd9Sstevel@tonic-gate uint_t maxsegmentsize, sizesegment; 1738*7c478bd9Sstevel@tonic-gate uint_t needintbuf; 1739*7c478bd9Sstevel@tonic-gate uint_t offset; 1740*7c478bd9Sstevel@tonic-gate uint_t residual_size; 1741*7c478bd9Sstevel@tonic-gate uint_t sglistsize; 1742*7c478bd9Sstevel@tonic-gate int nsegments; 1743*7c478bd9Sstevel@tonic-gate int mapinfo; 1744*7c478bd9Sstevel@tonic-gate int reqneedintbuf; 1745*7c478bd9Sstevel@tonic-gate int rval; 1746*7c478bd9Sstevel@tonic-gate int segment_flags, win_flags; 1747*7c478bd9Sstevel@tonic-gate int sgcount; 1748*7c478bd9Sstevel@tonic-gate int wcount; 1749*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 1750*7c478bd9Sstevel@tonic-gate int numsegments; 1751*7c478bd9Sstevel@tonic-gate #endif 1752*7c478bd9Sstevel@tonic-gate int sizehandle; 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate #ifdef lint 1755*7c478bd9Sstevel@tonic-gate dip = dip; 1756*7c478bd9Sstevel@tonic-gate #endif 1757*7c478bd9Sstevel@tonic-gate 1758*7c478bd9Sstevel@tonic-gate /* 1759*7c478bd9Sstevel@tonic-gate * Validate the dma request. 1760*7c478bd9Sstevel@tonic-gate */ 1761*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 1762*7c478bd9Sstevel@tonic-gate if (dma_lim->dlim_adreg_max < MMU_PAGEOFFSET || 1763*7c478bd9Sstevel@tonic-gate dma_lim->dlim_ctreg_max < MMU_PAGEOFFSET || 1764*7c478bd9Sstevel@tonic-gate dma_lim->dlim_granular > MMU_PAGESIZE || 1765*7c478bd9Sstevel@tonic-gate dma_lim->dlim_reqsize < MMU_PAGESIZE) { 1766*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits\n")); 1767*7c478bd9Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 1768*7c478bd9Sstevel@tonic-gate } 1769*7c478bd9Sstevel@tonic-gate #endif 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate /* 1772*7c478bd9Sstevel@tonic-gate * Initialize our local variables from the php structure. 1773*7c478bd9Sstevel@tonic-gate * rootnex_get_phyaddr() has populated php structure on its 1774*7c478bd9Sstevel@tonic-gate * previous invocation in rootnex_dma_map(). 1775*7c478bd9Sstevel@tonic-gate */ 1776*7c478bd9Sstevel@tonic-gate residual_size = OBJSIZE; 1777*7c478bd9Sstevel@tonic-gate mapinfo = php->ph_mapinfo; 1778*7c478bd9Sstevel@tonic-gate segmentpadr = php->ph_padr; 1779*7c478bd9Sstevel@tonic-gate segmentvadr = php->ph_vaddr; 1780*7c478bd9Sstevel@tonic-gate basevadr = (mapinfo == DMAMI_PAGES) ? 0 : segmentvadr; 1781*7c478bd9Sstevel@tonic-gate offset = segmentpadr & MMU_PAGEOFFSET; 1782*7c478bd9Sstevel@tonic-gate if (dma_lim->dlim_sgllen <= 0 || 1783*7c478bd9Sstevel@tonic-gate (offset & (dma_lim->dlim_minxfer - 1))) { 1784*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits/mapping\n")); 1785*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NOMAPPING; 1786*7c478bd9Sstevel@tonic-gate goto bad; 1787*7c478bd9Sstevel@tonic-gate } 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate maxsegmentsize = MIN(dma_lim->dlim_adreg_max, 1790*7c478bd9Sstevel@tonic-gate MIN((dma_lim->dlim_ctreg_max + 1) * dma_lim->dlim_minxfer, 1791*7c478bd9Sstevel@tonic-gate dma_lim->dlim_reqsize) - 1) + 1; 1792*7c478bd9Sstevel@tonic-gate if (maxsegmentsize == 0) 1793*7c478bd9Sstevel@tonic-gate maxsegmentsize = FOURG - 1; 1794*7c478bd9Sstevel@tonic-gate if (maxsegmentsize < MMU_PAGESIZE) { 1795*7c478bd9Sstevel@tonic-gate DMAPRINT((" bad_limits, maxsegmentsize\n")); 1796*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_BADLIMITS; 1797*7c478bd9Sstevel@tonic-gate goto bad; 1798*7c478bd9Sstevel@tonic-gate } 1799*7c478bd9Sstevel@tonic-gate 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate /* 1802*7c478bd9Sstevel@tonic-gate * The number of segments is the number of 4k pages that the 1803*7c478bd9Sstevel@tonic-gate * object spans. 1804*7c478bd9Sstevel@tonic-gate * Each 4k segment may need another segment to satisfy 1805*7c478bd9Sstevel@tonic-gate * device granularity reqirements. 1806*7c478bd9Sstevel@tonic-gate * We will never need more than two segments per page. 1807*7c478bd9Sstevel@tonic-gate * This may be an overestimate in some cases but it avoids 1808*7c478bd9Sstevel@tonic-gate * 64 bit divide operations. 1809*7c478bd9Sstevel@tonic-gate */ 1810*7c478bd9Sstevel@tonic-gate nsegments = (offset + residual_size + MMU_PAGEOFFSET) >> 1811*7c478bd9Sstevel@tonic-gate (MMU_PAGESHIFT - 1); 1812*7c478bd9Sstevel@tonic-gate 1813*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 1814*7c478bd9Sstevel@tonic-gate numsegments = nsegments; 1815*7c478bd9Sstevel@tonic-gate #endif 1816*7c478bd9Sstevel@tonic-gate ASSERT(nsegments > 0); 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate sizehandle = sizeof (ddi_dma_impl_t) + 1820*7c478bd9Sstevel@tonic-gate (nsegments * sizeof (impl_dma_segment_t)); 1821*7c478bd9Sstevel@tonic-gate 1822*7c478bd9Sstevel@tonic-gate hp = kmem_alloc(sizehandle, 1823*7c478bd9Sstevel@tonic-gate (dmareq->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1824*7c478bd9Sstevel@tonic-gate if (!hp) { 1825*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NORESOURCES; 1826*7c478bd9Sstevel@tonic-gate goto bad; 1827*7c478bd9Sstevel@tonic-gate } 1828*7c478bd9Sstevel@tonic-gate hp->dmai_kmsize = sizehandle; 1829*7c478bd9Sstevel@tonic-gate 1830*7c478bd9Sstevel@tonic-gate /* 1831*7c478bd9Sstevel@tonic-gate * locate segments after dma_impl handle structure 1832*7c478bd9Sstevel@tonic-gate */ 1833*7c478bd9Sstevel@tonic-gate segmentp = (impl_dma_segment_t *)(hp + 1); 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate /* FMA related initialization */ 1836*7c478bd9Sstevel@tonic-gate hp->dmai_fault = 0; 1837*7c478bd9Sstevel@tonic-gate hp->dmai_fault_check = NULL; 1838*7c478bd9Sstevel@tonic-gate hp->dmai_fault_notify = NULL; 1839*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_ena = 0; 1840*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_status = DDI_FM_OK; 1841*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_expected = DDI_FM_ERR_UNEXPECTED; 1842*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_ontrap = NULL; 1843*7c478bd9Sstevel@tonic-gate hp->dmai_error.err_fep = NULL; 1844*7c478bd9Sstevel@tonic-gate 1845*7c478bd9Sstevel@tonic-gate /* 1846*7c478bd9Sstevel@tonic-gate * Save requestor's information 1847*7c478bd9Sstevel@tonic-gate */ 1848*7c478bd9Sstevel@tonic-gate hp->dmai_minxfer = dma_lim->dlim_minxfer; 1849*7c478bd9Sstevel@tonic-gate hp->dmai_burstsizes = dma_lim->dlim_burstsizes; 1850*7c478bd9Sstevel@tonic-gate hp->dmai_rdip = rdip; 1851*7c478bd9Sstevel@tonic-gate hp->dmai_mctl = rootnex_dma_mctl; 1852*7c478bd9Sstevel@tonic-gate hp->dmai_wins = NULL; 1853*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = hp->dmai_ibufp = NULL; 1854*7c478bd9Sstevel@tonic-gate hp->dmai_hds = prewinp = segmentp; 1855*7c478bd9Sstevel@tonic-gate hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS; 1856*7c478bd9Sstevel@tonic-gate hp->dmai_minfo = (void *)(uintptr_t)mapinfo; 1857*7c478bd9Sstevel@tonic-gate hp->dmai_object = dmareq->dmar_object; 1858*7c478bd9Sstevel@tonic-gate 1859*7c478bd9Sstevel@tonic-gate /* 1860*7c478bd9Sstevel@tonic-gate * Breakup the memory object 1861*7c478bd9Sstevel@tonic-gate * and build an i/o segment at each boundary condition 1862*7c478bd9Sstevel@tonic-gate */ 1863*7c478bd9Sstevel@tonic-gate curwinp = 0; 1864*7c478bd9Sstevel@tonic-gate needintbuf = 0; 1865*7c478bd9Sstevel@tonic-gate previousp = 0; 1866*7c478bd9Sstevel@tonic-gate reqneedintbuf = 0; 1867*7c478bd9Sstevel@tonic-gate sglistsize = 0; 1868*7c478bd9Sstevel@tonic-gate wcount = 0; 1869*7c478bd9Sstevel@tonic-gate sgcount = 1; 1870*7c478bd9Sstevel@tonic-gate do { 1871*7c478bd9Sstevel@tonic-gate sizesegment = 1872*7c478bd9Sstevel@tonic-gate MIN(((uint_t)MMU_PAGESIZE - offset), residual_size); 1873*7c478bd9Sstevel@tonic-gate segment_flags = (segmentpadr > AHI_LIM) ? DMAIS_NEEDINTBUF : 0; 1874*7c478bd9Sstevel@tonic-gate 1875*7c478bd9Sstevel@tonic-gate if (dma_lim->dlim_sgllen == 1) { 1876*7c478bd9Sstevel@tonic-gate /* 1877*7c478bd9Sstevel@tonic-gate * _no_ scatter/gather capability, 1878*7c478bd9Sstevel@tonic-gate * so ensure that size of each segment is a 1879*7c478bd9Sstevel@tonic-gate * multiple of dlim_granular (== sector size) 1880*7c478bd9Sstevel@tonic-gate */ 1881*7c478bd9Sstevel@tonic-gate if ((segmentpadr & (dma_lim->dlim_granular - 1)) && 1882*7c478bd9Sstevel@tonic-gate residual_size != sizesegment) { 1883*7c478bd9Sstevel@tonic-gate /* 1884*7c478bd9Sstevel@tonic-gate * this segment needs an intermediate buffer 1885*7c478bd9Sstevel@tonic-gate */ 1886*7c478bd9Sstevel@tonic-gate sizesegment = 1887*7c478bd9Sstevel@tonic-gate MIN((uint_t)MMU_PAGESIZE, residual_size); 1888*7c478bd9Sstevel@tonic-gate segment_flags |= DMAIS_NEEDINTBUF; 1889*7c478bd9Sstevel@tonic-gate } 1890*7c478bd9Sstevel@tonic-gate } 1891*7c478bd9Sstevel@tonic-gate 1892*7c478bd9Sstevel@tonic-gate if (previousp && 1893*7c478bd9Sstevel@tonic-gate (previousp->_pdmu._dmais_lpd + previousp->dmais_size) == 1894*7c478bd9Sstevel@tonic-gate segmentpadr && 1895*7c478bd9Sstevel@tonic-gate (previousp->dmais_flags & 1896*7c478bd9Sstevel@tonic-gate (DMAIS_NEEDINTBUF | DMAIS_COMPLEMENT)) == 0 && 1897*7c478bd9Sstevel@tonic-gate (segment_flags & DMAIS_NEEDINTBUF) == 0 && 1898*7c478bd9Sstevel@tonic-gate (previousp->dmais_size + sizesegment) <= maxsegmentsize && 1899*7c478bd9Sstevel@tonic-gate (segmentpadr & dma_lim->dlim_adreg_max) && 1900*7c478bd9Sstevel@tonic-gate (sglistsize + sizesegment) <= dma_lim->dlim_reqsize) { 1901*7c478bd9Sstevel@tonic-gate /* 1902*7c478bd9Sstevel@tonic-gate * combine new segment with previous segment 1903*7c478bd9Sstevel@tonic-gate */ 1904*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= segment_flags; 1905*7c478bd9Sstevel@tonic-gate previousp->dmais_size += sizesegment; 1906*7c478bd9Sstevel@tonic-gate if ((sglistsize += sizesegment) == 1907*7c478bd9Sstevel@tonic-gate dma_lim->dlim_reqsize) 1908*7c478bd9Sstevel@tonic-gate /* 1909*7c478bd9Sstevel@tonic-gate * force end of scatter/gather list 1910*7c478bd9Sstevel@tonic-gate */ 1911*7c478bd9Sstevel@tonic-gate sgcount = dma_lim->dlim_sgllen + 1; 1912*7c478bd9Sstevel@tonic-gate } else { 1913*7c478bd9Sstevel@tonic-gate /* 1914*7c478bd9Sstevel@tonic-gate * add new segment to linked list 1915*7c478bd9Sstevel@tonic-gate */ 1916*7c478bd9Sstevel@tonic-gate if (previousp) { 1917*7c478bd9Sstevel@tonic-gate previousp->dmais_link = segmentp; 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate segmentp->dmais_hndl = hp; 1920*7c478bd9Sstevel@tonic-gate if (curwinp == 0) { 1921*7c478bd9Sstevel@tonic-gate prewinp->_win._dmais_nex = 1922*7c478bd9Sstevel@tonic-gate curwinp = segmentp; 1923*7c478bd9Sstevel@tonic-gate segment_flags |= DMAIS_WINSTRT; 1924*7c478bd9Sstevel@tonic-gate win_flags = segment_flags; 1925*7c478bd9Sstevel@tonic-gate wcount++; 1926*7c478bd9Sstevel@tonic-gate } else { 1927*7c478bd9Sstevel@tonic-gate segmentp->_win._dmais_cur = curwinp; 1928*7c478bd9Sstevel@tonic-gate win_flags |= segment_flags; 1929*7c478bd9Sstevel@tonic-gate } 1930*7c478bd9Sstevel@tonic-gate segmentp->dmais_ofst = segmentvadr - basevadr; 1931*7c478bd9Sstevel@tonic-gate if (mapinfo == DMAMI_PAGES) { 1932*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_pp = php->ph_u.pp; 1933*7c478bd9Sstevel@tonic-gate } else { 1934*7c478bd9Sstevel@tonic-gate segmentp->_vdmu._dmais_va = segmentvadr; 1935*7c478bd9Sstevel@tonic-gate } 1936*7c478bd9Sstevel@tonic-gate segmentp->_pdmu._dmais_lpd = segmentpadr; 1937*7c478bd9Sstevel@tonic-gate segmentp->dmais_flags = (ushort_t)segment_flags; 1938*7c478bd9Sstevel@tonic-gate 1939*7c478bd9Sstevel@tonic-gate if (dma_lim->dlim_sgllen > 1) { 1940*7c478bd9Sstevel@tonic-gate if (segment_flags & DMAIS_NEEDINTBUF) { 1941*7c478bd9Sstevel@tonic-gate needintbuf += ptob(btopr(sizesegment)); 1942*7c478bd9Sstevel@tonic-gate if (needintbuf >= MAX_INT_BUF) { 1943*7c478bd9Sstevel@tonic-gate /* 1944*7c478bd9Sstevel@tonic-gate * limit size of intermediate 1945*7c478bd9Sstevel@tonic-gate * buffer 1946*7c478bd9Sstevel@tonic-gate */ 1947*7c478bd9Sstevel@tonic-gate reqneedintbuf = MAX_INT_BUF; 1948*7c478bd9Sstevel@tonic-gate needintbuf = 0; 1949*7c478bd9Sstevel@tonic-gate /* 1950*7c478bd9Sstevel@tonic-gate * end of current window 1951*7c478bd9Sstevel@tonic-gate */ 1952*7c478bd9Sstevel@tonic-gate segmentp->dmais_flags |= 1953*7c478bd9Sstevel@tonic-gate DMAIS_WINEND; 1954*7c478bd9Sstevel@tonic-gate prewinp = curwinp; 1955*7c478bd9Sstevel@tonic-gate curwinp->dmais_flags |= 1956*7c478bd9Sstevel@tonic-gate DMAIS_WINUIB; 1957*7c478bd9Sstevel@tonic-gate curwinp = NULL; 1958*7c478bd9Sstevel@tonic-gate /* 1959*7c478bd9Sstevel@tonic-gate * force end of scatter/gather 1960*7c478bd9Sstevel@tonic-gate * list 1961*7c478bd9Sstevel@tonic-gate */ 1962*7c478bd9Sstevel@tonic-gate sgcount = dma_lim->dlim_sgllen; 1963*7c478bd9Sstevel@tonic-gate } 1964*7c478bd9Sstevel@tonic-gate } 1965*7c478bd9Sstevel@tonic-gate sglistsize += sizesegment; 1966*7c478bd9Sstevel@tonic-gate if (sglistsize >= dma_lim->dlim_reqsize) { 1967*7c478bd9Sstevel@tonic-gate /* 1968*7c478bd9Sstevel@tonic-gate * limit size of xfer 1969*7c478bd9Sstevel@tonic-gate */ 1970*7c478bd9Sstevel@tonic-gate sizesegment -= (sglistsize - 1971*7c478bd9Sstevel@tonic-gate dma_lim->dlim_reqsize); 1972*7c478bd9Sstevel@tonic-gate sglistsize = dma_lim->dlim_reqsize; 1973*7c478bd9Sstevel@tonic-gate sgcount = dma_lim->dlim_sgllen; 1974*7c478bd9Sstevel@tonic-gate } 1975*7c478bd9Sstevel@tonic-gate sgcount++; 1976*7c478bd9Sstevel@tonic-gate } else { 1977*7c478bd9Sstevel@tonic-gate /* 1978*7c478bd9Sstevel@tonic-gate * _no_ scatter/gather capability, 1979*7c478bd9Sstevel@tonic-gate */ 1980*7c478bd9Sstevel@tonic-gate if (segment_flags & DMAIS_NEEDINTBUF) { 1981*7c478bd9Sstevel@tonic-gate /* 1982*7c478bd9Sstevel@tonic-gate * end of window 1983*7c478bd9Sstevel@tonic-gate */ 1984*7c478bd9Sstevel@tonic-gate needintbuf = MMU_PAGESIZE; 1985*7c478bd9Sstevel@tonic-gate segmentp->dmais_flags |= DMAIS_WINEND; 1986*7c478bd9Sstevel@tonic-gate prewinp = curwinp; 1987*7c478bd9Sstevel@tonic-gate curwinp->dmais_flags |= DMAIS_WINUIB; 1988*7c478bd9Sstevel@tonic-gate curwinp = NULL; 1989*7c478bd9Sstevel@tonic-gate } 1990*7c478bd9Sstevel@tonic-gate } 1991*7c478bd9Sstevel@tonic-gate segmentp->dmais_size = sizesegment; 1992*7c478bd9Sstevel@tonic-gate previousp = segmentp++; 1993*7c478bd9Sstevel@tonic-gate --nsegments; 1994*7c478bd9Sstevel@tonic-gate } 1995*7c478bd9Sstevel@tonic-gate 1996*7c478bd9Sstevel@tonic-gate if (sgcount > dma_lim->dlim_sgllen) { 1997*7c478bd9Sstevel@tonic-gate /* 1998*7c478bd9Sstevel@tonic-gate * end of a scatter/gather list! 1999*7c478bd9Sstevel@tonic-gate * ensure that total length of list is a 2000*7c478bd9Sstevel@tonic-gate * multiple of granular (sector size) 2001*7c478bd9Sstevel@tonic-gate */ 2002*7c478bd9Sstevel@tonic-gate if (sizesegment != residual_size) { 2003*7c478bd9Sstevel@tonic-gate uint_t trim; 2004*7c478bd9Sstevel@tonic-gate 2005*7c478bd9Sstevel@tonic-gate trim = sglistsize & 2006*7c478bd9Sstevel@tonic-gate (dma_lim->dlim_granular - 1); 2007*7c478bd9Sstevel@tonic-gate if (trim >= sizesegment) { 2008*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2009*7c478bd9Sstevel@tonic-gate "unable to reduce segment size"); 2010*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NOMAPPING; 2011*7c478bd9Sstevel@tonic-gate goto bad; 2012*7c478bd9Sstevel@tonic-gate } 2013*7c478bd9Sstevel@tonic-gate previousp->dmais_size -= trim; 2014*7c478bd9Sstevel@tonic-gate sizesegment -= trim; 2015*7c478bd9Sstevel@tonic-gate /* start new scatter/gather list */ 2016*7c478bd9Sstevel@tonic-gate sgcount = 1; 2017*7c478bd9Sstevel@tonic-gate sglistsize = 0; 2018*7c478bd9Sstevel@tonic-gate } 2019*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= DMAIS_COMPLEMENT; 2020*7c478bd9Sstevel@tonic-gate } 2021*7c478bd9Sstevel@tonic-gate if (sizesegment && (residual_size -= sizesegment)) { 2022*7c478bd9Sstevel@tonic-gate segmentpadr = 2023*7c478bd9Sstevel@tonic-gate rootnex_get_phyaddr(dmareq, sizesegment, php); 2024*7c478bd9Sstevel@tonic-gate offset = segmentpadr & MMU_PAGEOFFSET; 2025*7c478bd9Sstevel@tonic-gate segmentvadr += sizesegment; 2026*7c478bd9Sstevel@tonic-gate } 2027*7c478bd9Sstevel@tonic-gate } while (residual_size && nsegments); 2028*7c478bd9Sstevel@tonic-gate ASSERT(residual_size == 0); 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate previousp->dmais_link = NULL; 2031*7c478bd9Sstevel@tonic-gate previousp->dmais_flags |= DMAIS_WINEND; 2032*7c478bd9Sstevel@tonic-gate if (curwinp) { 2033*7c478bd9Sstevel@tonic-gate if (win_flags & DMAIS_NEEDINTBUF) 2034*7c478bd9Sstevel@tonic-gate curwinp->dmais_flags |= DMAIS_WINUIB; 2035*7c478bd9Sstevel@tonic-gate curwinp->_win._dmais_nex = NULL; 2036*7c478bd9Sstevel@tonic-gate } else 2037*7c478bd9Sstevel@tonic-gate prewinp->_win._dmais_nex = NULL; 2038*7c478bd9Sstevel@tonic-gate 2039*7c478bd9Sstevel@tonic-gate if ((needintbuf = MAX(needintbuf, reqneedintbuf)) != 0) { 2040*7c478bd9Sstevel@tonic-gate ddi_dma_attr_t dma_attr; 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate 2043*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_version = DMA_ATTR_V0; 2044*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_addr_lo = dma_lim->dlim_addr_lo; 2045*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_addr_hi = dma_lim->dlim_addr_hi; 2046*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_minxfer = dma_lim->dlim_minxfer; 2047*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_seg = dma_lim->dlim_adreg_max; 2048*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_count_max = dma_lim->dlim_ctreg_max; 2049*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_granular = dma_lim->dlim_granular; 2050*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_sgllen = dma_lim->dlim_sgllen; 2051*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_maxxfer = dma_lim->dlim_reqsize; 2052*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_burstsizes = dma_lim->dlim_burstsizes; 2053*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_align = MMU_PAGESIZE; 2054*7c478bd9Sstevel@tonic-gate dma_attr.dma_attr_flags = 0; 2055*7c478bd9Sstevel@tonic-gate 2056*7c478bd9Sstevel@tonic-gate /* 2057*7c478bd9Sstevel@tonic-gate * Allocate intermediate buffer. 2058*7c478bd9Sstevel@tonic-gate */ 2059*7c478bd9Sstevel@tonic-gate if (i_ddi_mem_alloc(dip, &dma_attr, needintbuf, 2060*7c478bd9Sstevel@tonic-gate (dmareq->dmar_fp == DDI_DMA_SLEEP) ? 0x1 : 0, 1, 0, 2061*7c478bd9Sstevel@tonic-gate &hp->dmai_ibufp, (ulong_t *)&hp->dmai_ibfsz, 2062*7c478bd9Sstevel@tonic-gate NULL) != DDI_SUCCESS) { 2063*7c478bd9Sstevel@tonic-gate rval = DDI_DMA_NORESOURCES; 2064*7c478bd9Sstevel@tonic-gate goto bad; 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate if (mapinfo != DMAMI_KVADR) { 2067*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr = vmem_alloc(heap_arena, PAGESIZE, 2068*7c478bd9Sstevel@tonic-gate VM_SLEEP); 2069*7c478bd9Sstevel@tonic-gate } 2070*7c478bd9Sstevel@tonic-gate } 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate /* 2073*7c478bd9Sstevel@tonic-gate * return success 2074*7c478bd9Sstevel@tonic-gate */ 2075*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG 2076*7c478bd9Sstevel@tonic-gate DMAPRINT(("dma_brkup: handle %p nsegments %x \n", 2077*7c478bd9Sstevel@tonic-gate (void *)hp, numsegments - nsegments)); 2078*7c478bd9Sstevel@tonic-gate #endif 2079*7c478bd9Sstevel@tonic-gate hp->dmai_cookie = NULL; 2080*7c478bd9Sstevel@tonic-gate *handlep = (ddi_dma_handle_t)hp; 2081*7c478bd9Sstevel@tonic-gate return (DDI_DMA_MAPPED); 2082*7c478bd9Sstevel@tonic-gate bad: 2083*7c478bd9Sstevel@tonic-gate if (hp) 2084*7c478bd9Sstevel@tonic-gate kmem_free(hp, hp->dmai_kmsize); 2085*7c478bd9Sstevel@tonic-gate if (rval == DDI_DMA_NORESOURCES && 2086*7c478bd9Sstevel@tonic-gate dmareq->dmar_fp != DDI_DMA_DONTWAIT && 2087*7c478bd9Sstevel@tonic-gate dmareq->dmar_fp != DDI_DMA_SLEEP) 2088*7c478bd9Sstevel@tonic-gate ddi_set_callback(dmareq->dmar_fp, dmareq->dmar_arg, 2089*7c478bd9Sstevel@tonic-gate &dvma_call_list_id); 2090*7c478bd9Sstevel@tonic-gate return (rval); 2091*7c478bd9Sstevel@tonic-gate } 2092*7c478bd9Sstevel@tonic-gate 2093*7c478bd9Sstevel@tonic-gate int 2094*7c478bd9Sstevel@tonic-gate rootnex_io_wtsync(ddi_dma_impl_t *hp, int type) 2095*7c478bd9Sstevel@tonic-gate { 2096*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *sp = hp->dmai_wins; 2097*7c478bd9Sstevel@tonic-gate caddr_t kviradr, addr; 2098*7c478bd9Sstevel@tonic-gate caddr_t vsrc; 2099*7c478bd9Sstevel@tonic-gate ulong_t segoffset, vsoffset; 2100*7c478bd9Sstevel@tonic-gate int cpycnt; 2101*7c478bd9Sstevel@tonic-gate 2102*7c478bd9Sstevel@tonic-gate addr = hp->dmai_ibufp; 2103*7c478bd9Sstevel@tonic-gate if ((uintptr_t)addr & MMU_PAGEOFFSET) { 2104*7c478bd9Sstevel@tonic-gate addr = (caddr_t)(((uintptr_t)addr + MMU_PAGEOFFSET) & 2105*7c478bd9Sstevel@tonic-gate ~MMU_PAGEOFFSET); 2106*7c478bd9Sstevel@tonic-gate } 2107*7c478bd9Sstevel@tonic-gate if ((sp->dmais_flags & DMAIS_WINUIB) == 0) 2108*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate switch ((intptr_t)hp->dmai_minfo) { 2111*7c478bd9Sstevel@tonic-gate 2112*7c478bd9Sstevel@tonic-gate case DMAMI_KVADR: 2113*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2114*7c478bd9Sstevel@tonic-gate 2115*7c478bd9Sstevel@tonic-gate if (hp->dmai_rflags & DDI_DMA_WRITE) 2116*7c478bd9Sstevel@tonic-gate /* 2117*7c478bd9Sstevel@tonic-gate * copy from segment to buffer 2118*7c478bd9Sstevel@tonic-gate */ 2119*7c478bd9Sstevel@tonic-gate bcopy(sp->_vdmu._dmais_va, addr, 2120*7c478bd9Sstevel@tonic-gate sp->dmais_size); 2121*7c478bd9Sstevel@tonic-gate /* 2122*7c478bd9Sstevel@tonic-gate * save phys addr of intermediate buffer 2123*7c478bd9Sstevel@tonic-gate */ 2124*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd = 2125*7c478bd9Sstevel@tonic-gate ptob64(hat_getpfnum(kas.a_hat, addr)); 2126*7c478bd9Sstevel@tonic-gate if (type == BIND) { 2127*7c478bd9Sstevel@tonic-gate sp->dmais_cookie->dmac_laddress = 2128*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd; 2129*7c478bd9Sstevel@tonic-gate } 2130*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2131*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2132*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2133*7c478bd9Sstevel@tonic-gate break; 2134*7c478bd9Sstevel@tonic-gate 2135*7c478bd9Sstevel@tonic-gate case DMAMI_PAGES: 2136*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2137*7c478bd9Sstevel@tonic-gate 2138*7c478bd9Sstevel@tonic-gate if (hp->dmai_rflags & DDI_DMA_WRITE) { 2139*7c478bd9Sstevel@tonic-gate /* 2140*7c478bd9Sstevel@tonic-gate * need to mapin page so we can have a 2141*7c478bd9Sstevel@tonic-gate * virtual address to do copying 2142*7c478bd9Sstevel@tonic-gate */ 2143*7c478bd9Sstevel@tonic-gate i86_pp_map(sp->_vdmu._dmais_pp, hp->dmai_kaddr); 2144*7c478bd9Sstevel@tonic-gate /* 2145*7c478bd9Sstevel@tonic-gate * copy from segment to buffer 2146*7c478bd9Sstevel@tonic-gate */ 2147*7c478bd9Sstevel@tonic-gate bcopy(hp->dmai_kaddr + 2148*7c478bd9Sstevel@tonic-gate (sp->dmais_ofst & MMU_PAGEOFFSET), 2149*7c478bd9Sstevel@tonic-gate addr, sp->dmais_size); 2150*7c478bd9Sstevel@tonic-gate /* 2151*7c478bd9Sstevel@tonic-gate * need to mapout page 2152*7c478bd9Sstevel@tonic-gate */ 2153*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, hp->dmai_kaddr, 2154*7c478bd9Sstevel@tonic-gate MMU_PAGESIZE, HAT_UNLOAD); 2155*7c478bd9Sstevel@tonic-gate } 2156*7c478bd9Sstevel@tonic-gate /* 2157*7c478bd9Sstevel@tonic-gate * save phys addr of intemediate buffer 2158*7c478bd9Sstevel@tonic-gate */ 2159*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd = 2160*7c478bd9Sstevel@tonic-gate ptob64(hat_getpfnum(kas.a_hat, addr)); 2161*7c478bd9Sstevel@tonic-gate if (type == BIND) { 2162*7c478bd9Sstevel@tonic-gate sp->dmais_cookie->dmac_laddress = 2163*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd; 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2166*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2167*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2168*7c478bd9Sstevel@tonic-gate break; 2169*7c478bd9Sstevel@tonic-gate 2170*7c478bd9Sstevel@tonic-gate case DMAMI_UVADR: 2171*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2172*7c478bd9Sstevel@tonic-gate 2173*7c478bd9Sstevel@tonic-gate if (hp->dmai_rflags & DDI_DMA_WRITE) { 2174*7c478bd9Sstevel@tonic-gate struct page **pplist; 2175*7c478bd9Sstevel@tonic-gate segoffset = 0; 2176*7c478bd9Sstevel@tonic-gate do { 2177*7c478bd9Sstevel@tonic-gate /* 2178*7c478bd9Sstevel@tonic-gate * need to mapin page so we can have a 2179*7c478bd9Sstevel@tonic-gate * virtual address to do copying 2180*7c478bd9Sstevel@tonic-gate */ 2181*7c478bd9Sstevel@tonic-gate vsrc = sp->_vdmu._dmais_va + segoffset; 2182*7c478bd9Sstevel@tonic-gate vsoffset = 2183*7c478bd9Sstevel@tonic-gate (ulong_t)vsrc & MMU_PAGEOFFSET; 2184*7c478bd9Sstevel@tonic-gate pplist = hp->dmai_object.dmao_obj. 2185*7c478bd9Sstevel@tonic-gate virt_obj.v_priv; 2186*7c478bd9Sstevel@tonic-gate /* 2187*7c478bd9Sstevel@tonic-gate * check if we have to use the 2188*7c478bd9Sstevel@tonic-gate * shadow list or the CPU mapping. 2189*7c478bd9Sstevel@tonic-gate */ 2190*7c478bd9Sstevel@tonic-gate if (pplist != NULL) { 2191*7c478bd9Sstevel@tonic-gate ulong_t base, off; 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate base = (ulong_t)hp->dmai_object. 2194*7c478bd9Sstevel@tonic-gate dmao_obj.virt_obj.v_addr; 2195*7c478bd9Sstevel@tonic-gate off = (base & MMU_PAGEOFFSET) + 2196*7c478bd9Sstevel@tonic-gate (ulong_t)vsrc - base; 2197*7c478bd9Sstevel@tonic-gate i86_pp_map(pplist[btop(off)], 2198*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr); 2199*7c478bd9Sstevel@tonic-gate } else { 2200*7c478bd9Sstevel@tonic-gate i86_va_map(vsrc, 2201*7c478bd9Sstevel@tonic-gate hp->dmai_object.dmao_obj. 2202*7c478bd9Sstevel@tonic-gate virt_obj.v_as, 2203*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr); 2204*7c478bd9Sstevel@tonic-gate } 2205*7c478bd9Sstevel@tonic-gate kviradr = hp->dmai_kaddr + vsoffset; 2206*7c478bd9Sstevel@tonic-gate cpycnt = sp->dmais_size - segoffset; 2207*7c478bd9Sstevel@tonic-gate if (vsoffset + cpycnt > MMU_PAGESIZE) 2208*7c478bd9Sstevel@tonic-gate cpycnt = MMU_PAGESIZE - 2209*7c478bd9Sstevel@tonic-gate vsoffset; 2210*7c478bd9Sstevel@tonic-gate /* 2211*7c478bd9Sstevel@tonic-gate * copy from segment to buffer 2212*7c478bd9Sstevel@tonic-gate */ 2213*7c478bd9Sstevel@tonic-gate bcopy(kviradr, addr + segoffset, 2214*7c478bd9Sstevel@tonic-gate cpycnt); 2215*7c478bd9Sstevel@tonic-gate /* 2216*7c478bd9Sstevel@tonic-gate * need to mapout page 2217*7c478bd9Sstevel@tonic-gate */ 2218*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, hp->dmai_kaddr, 2219*7c478bd9Sstevel@tonic-gate MMU_PAGESIZE, HAT_UNLOAD); 2220*7c478bd9Sstevel@tonic-gate segoffset += cpycnt; 2221*7c478bd9Sstevel@tonic-gate } while (segoffset < sp->dmais_size); 2222*7c478bd9Sstevel@tonic-gate } 2223*7c478bd9Sstevel@tonic-gate /* 2224*7c478bd9Sstevel@tonic-gate * save phys addr of intermediate buffer 2225*7c478bd9Sstevel@tonic-gate */ 2226*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd = 2227*7c478bd9Sstevel@tonic-gate ptob64(hat_getpfnum(kas.a_hat, addr)); 2228*7c478bd9Sstevel@tonic-gate if (type == BIND) { 2229*7c478bd9Sstevel@tonic-gate sp->dmais_cookie->dmac_laddress = 2230*7c478bd9Sstevel@tonic-gate sp->_pdmu._dmais_lpd; 2231*7c478bd9Sstevel@tonic-gate } 2232*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2233*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2234*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2235*7c478bd9Sstevel@tonic-gate break; 2236*7c478bd9Sstevel@tonic-gate 2237*7c478bd9Sstevel@tonic-gate default: 2238*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Invalid dma handle/map info"); 2239*7c478bd9Sstevel@tonic-gate } 2240*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate 2243*7c478bd9Sstevel@tonic-gate int 2244*7c478bd9Sstevel@tonic-gate rootnex_io_rdsync(ddi_dma_impl_t *hp) 2245*7c478bd9Sstevel@tonic-gate { 2246*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *sp = hp->dmai_wins; 2247*7c478bd9Sstevel@tonic-gate caddr_t kviradr; 2248*7c478bd9Sstevel@tonic-gate caddr_t vdest, addr; 2249*7c478bd9Sstevel@tonic-gate ulong_t segoffset, vdoffset; 2250*7c478bd9Sstevel@tonic-gate int cpycnt; 2251*7c478bd9Sstevel@tonic-gate 2252*7c478bd9Sstevel@tonic-gate addr = hp->dmai_ibufp; 2253*7c478bd9Sstevel@tonic-gate if ((uintptr_t)addr & MMU_PAGEOFFSET) { 2254*7c478bd9Sstevel@tonic-gate addr = (caddr_t) 2255*7c478bd9Sstevel@tonic-gate (((uintptr_t)addr + MMU_PAGEOFFSET) & ~MMU_PAGEOFFSET); 2256*7c478bd9Sstevel@tonic-gate } 2257*7c478bd9Sstevel@tonic-gate if (!(sp->dmais_flags & DMAIS_WINUIB) || 2258*7c478bd9Sstevel@tonic-gate !(hp->dmai_rflags & DDI_DMA_READ)) 2259*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2260*7c478bd9Sstevel@tonic-gate 2261*7c478bd9Sstevel@tonic-gate switch ((intptr_t)hp->dmai_minfo) { 2262*7c478bd9Sstevel@tonic-gate 2263*7c478bd9Sstevel@tonic-gate case DMAMI_KVADR: 2264*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2265*7c478bd9Sstevel@tonic-gate /* 2266*7c478bd9Sstevel@tonic-gate * copy from buffer to segment 2267*7c478bd9Sstevel@tonic-gate */ 2268*7c478bd9Sstevel@tonic-gate bcopy(addr, sp->_vdmu._dmais_va, sp->dmais_size); 2269*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2270*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2271*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2272*7c478bd9Sstevel@tonic-gate break; 2273*7c478bd9Sstevel@tonic-gate 2274*7c478bd9Sstevel@tonic-gate case DMAMI_PAGES: 2275*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2276*7c478bd9Sstevel@tonic-gate /* 2277*7c478bd9Sstevel@tonic-gate * need to mapin page 2278*7c478bd9Sstevel@tonic-gate */ 2279*7c478bd9Sstevel@tonic-gate i86_pp_map(sp->_vdmu._dmais_pp, hp->dmai_kaddr); 2280*7c478bd9Sstevel@tonic-gate /* 2281*7c478bd9Sstevel@tonic-gate * copy from buffer to segment 2282*7c478bd9Sstevel@tonic-gate */ 2283*7c478bd9Sstevel@tonic-gate bcopy(addr, 2284*7c478bd9Sstevel@tonic-gate (hp->dmai_kaddr + 2285*7c478bd9Sstevel@tonic-gate (sp->dmais_ofst & MMU_PAGEOFFSET)), 2286*7c478bd9Sstevel@tonic-gate sp->dmais_size); 2287*7c478bd9Sstevel@tonic-gate 2288*7c478bd9Sstevel@tonic-gate /* 2289*7c478bd9Sstevel@tonic-gate * need to mapout page 2290*7c478bd9Sstevel@tonic-gate */ 2291*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, hp->dmai_kaddr, 2292*7c478bd9Sstevel@tonic-gate MMU_PAGESIZE, HAT_UNLOAD); 2293*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2294*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2295*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2296*7c478bd9Sstevel@tonic-gate break; 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate case DMAMI_UVADR: 2299*7c478bd9Sstevel@tonic-gate do if (sp->dmais_flags & DMAIS_NEEDINTBUF) { 2300*7c478bd9Sstevel@tonic-gate struct page **pplist; 2301*7c478bd9Sstevel@tonic-gate segoffset = 0; 2302*7c478bd9Sstevel@tonic-gate do { 2303*7c478bd9Sstevel@tonic-gate /* 2304*7c478bd9Sstevel@tonic-gate * need to map_in user virtual address 2305*7c478bd9Sstevel@tonic-gate */ 2306*7c478bd9Sstevel@tonic-gate vdest = sp->_vdmu._dmais_va + segoffset; 2307*7c478bd9Sstevel@tonic-gate vdoffset = (ulong_t)vdest & MMU_PAGEOFFSET; 2308*7c478bd9Sstevel@tonic-gate pplist = hp->dmai_object.dmao_obj. 2309*7c478bd9Sstevel@tonic-gate virt_obj.v_priv; 2310*7c478bd9Sstevel@tonic-gate /* 2311*7c478bd9Sstevel@tonic-gate * check if we have to use the 2312*7c478bd9Sstevel@tonic-gate * shadow list or the CPU mapping. 2313*7c478bd9Sstevel@tonic-gate */ 2314*7c478bd9Sstevel@tonic-gate if (pplist != NULL) { 2315*7c478bd9Sstevel@tonic-gate ulong_t base, off; 2316*7c478bd9Sstevel@tonic-gate 2317*7c478bd9Sstevel@tonic-gate base = (ulong_t)hp->dmai_object. 2318*7c478bd9Sstevel@tonic-gate dmao_obj.virt_obj.v_addr; 2319*7c478bd9Sstevel@tonic-gate off = (base & MMU_PAGEOFFSET) + 2320*7c478bd9Sstevel@tonic-gate (ulong_t)vdest - base; 2321*7c478bd9Sstevel@tonic-gate i86_pp_map(pplist[btop(off)], 2322*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr); 2323*7c478bd9Sstevel@tonic-gate } else { 2324*7c478bd9Sstevel@tonic-gate i86_va_map(vdest, 2325*7c478bd9Sstevel@tonic-gate hp->dmai_object.dmao_obj. 2326*7c478bd9Sstevel@tonic-gate virt_obj.v_as, 2327*7c478bd9Sstevel@tonic-gate hp->dmai_kaddr); 2328*7c478bd9Sstevel@tonic-gate } 2329*7c478bd9Sstevel@tonic-gate kviradr = hp->dmai_kaddr + vdoffset; 2330*7c478bd9Sstevel@tonic-gate cpycnt = sp->dmais_size - segoffset; 2331*7c478bd9Sstevel@tonic-gate if (vdoffset + cpycnt > MMU_PAGESIZE) 2332*7c478bd9Sstevel@tonic-gate cpycnt = MMU_PAGESIZE - vdoffset; 2333*7c478bd9Sstevel@tonic-gate /* 2334*7c478bd9Sstevel@tonic-gate * copy from buffer to segment 2335*7c478bd9Sstevel@tonic-gate */ 2336*7c478bd9Sstevel@tonic-gate bcopy(addr + segoffset, kviradr, cpycnt); 2337*7c478bd9Sstevel@tonic-gate /* 2338*7c478bd9Sstevel@tonic-gate * need to map_out page 2339*7c478bd9Sstevel@tonic-gate */ 2340*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, hp->dmai_kaddr, 2341*7c478bd9Sstevel@tonic-gate MMU_PAGESIZE, HAT_UNLOAD); 2342*7c478bd9Sstevel@tonic-gate segoffset += cpycnt; 2343*7c478bd9Sstevel@tonic-gate } while (segoffset < sp->dmais_size); 2344*7c478bd9Sstevel@tonic-gate addr += MMU_PAGESIZE; 2345*7c478bd9Sstevel@tonic-gate } while (!(sp->dmais_flags & DMAIS_WINEND) && 2346*7c478bd9Sstevel@tonic-gate (sp = sp->dmais_link)); 2347*7c478bd9Sstevel@tonic-gate break; 2348*7c478bd9Sstevel@tonic-gate 2349*7c478bd9Sstevel@tonic-gate default: 2350*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Invalid dma handle/map info"); 2351*7c478bd9Sstevel@tonic-gate } 2352*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2353*7c478bd9Sstevel@tonic-gate } 2354*7c478bd9Sstevel@tonic-gate 2355*7c478bd9Sstevel@tonic-gate static int 2356*7c478bd9Sstevel@tonic-gate rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 2357*7c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 2358*7c478bd9Sstevel@tonic-gate off_t *offp, size_t *lenp, 2359*7c478bd9Sstevel@tonic-gate caddr_t *objpp, uint_t cache_flags) 2360*7c478bd9Sstevel@tonic-gate { 2361*7c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle; 2362*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *sp = (impl_dma_segment_t *)lenp; 2363*7c478bd9Sstevel@tonic-gate impl_dma_segment_t *wp = (impl_dma_segment_t *)offp; 2364*7c478bd9Sstevel@tonic-gate #if !defined(__amd64) 2365*7c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cp; 2366*7c478bd9Sstevel@tonic-gate #endif 2367*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate #ifdef lint 2370*7c478bd9Sstevel@tonic-gate dip = dip; 2371*7c478bd9Sstevel@tonic-gate rdip = rdip; 2372*7c478bd9Sstevel@tonic-gate #endif 2373*7c478bd9Sstevel@tonic-gate 2374*7c478bd9Sstevel@tonic-gate DMAPRINT(("io_mctl: handle %p ", (void *)hp)); 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate switch (request) { 2377*7c478bd9Sstevel@tonic-gate 2378*7c478bd9Sstevel@tonic-gate case DDI_DMA_SEGTOC: 2379*7c478bd9Sstevel@tonic-gate #if defined(__amd64) 2380*7c478bd9Sstevel@tonic-gate /* 2381*7c478bd9Sstevel@tonic-gate * ddi_dma_segtocookie(9F) is Obsolete, and the whole 2382*7c478bd9Sstevel@tonic-gate * passing-the-pointer-through-the-cache-flags thing just 2383*7c478bd9Sstevel@tonic-gate * doesn't work when pointers are 64-bit and cache_flags 2384*7c478bd9Sstevel@tonic-gate * are 32-bit. 2385*7c478bd9Sstevel@tonic-gate */ 2386*7c478bd9Sstevel@tonic-gate DMAPRINT(("stoc invoked but not implemented.\n")); 2387*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2388*7c478bd9Sstevel@tonic-gate #else 2389*7c478bd9Sstevel@tonic-gate /* return device specific dma cookie for segment */ 2390*7c478bd9Sstevel@tonic-gate sp = (impl_dma_segment_t *)(uintptr_t)cache_flags; 2391*7c478bd9Sstevel@tonic-gate if (!sp) { 2392*7c478bd9Sstevel@tonic-gate DMAPRINT(("stoc segment %p end\n", (void *)sp)); 2393*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate cp = (ddi_dma_cookie_t *)objpp; 2396*7c478bd9Sstevel@tonic-gate 2397*7c478bd9Sstevel@tonic-gate /* 2398*7c478bd9Sstevel@tonic-gate * use phys addr of actual buffer or intermediate buffer 2399*7c478bd9Sstevel@tonic-gate */ 2400*7c478bd9Sstevel@tonic-gate cp->dmac_laddress = sp->_pdmu._dmais_lpd; 2401*7c478bd9Sstevel@tonic-gate 2402*7c478bd9Sstevel@tonic-gate DMAPRINT(("stoc segment %p mapping %lx size %lx\n", 2403*7c478bd9Sstevel@tonic-gate (void *)sp, (ulong_t)sp->_vdmu._dmais_va, sp->dmais_size)); 2404*7c478bd9Sstevel@tonic-gate 2405*7c478bd9Sstevel@tonic-gate cp->dmac_type = (ulong_t)sp; 2406*7c478bd9Sstevel@tonic-gate *lenp = cp->dmac_size = sp->dmais_size; 2407*7c478bd9Sstevel@tonic-gate *offp = sp->dmais_ofst; 2408*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2409*7c478bd9Sstevel@tonic-gate #endif 2410*7c478bd9Sstevel@tonic-gate 2411*7c478bd9Sstevel@tonic-gate case DDI_DMA_NEXTSEG: /* get next DMA segment */ 2412*7c478bd9Sstevel@tonic-gate ASSERT(wp->dmais_flags & DMAIS_WINSTRT); 2413*7c478bd9Sstevel@tonic-gate if (wp != hp->dmai_wins) { 2414*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxseg: not current window %p\n", 2415*7c478bd9Sstevel@tonic-gate (void *)wp)); 2416*7c478bd9Sstevel@tonic-gate return (DDI_DMA_STALE); 2417*7c478bd9Sstevel@tonic-gate } 2418*7c478bd9Sstevel@tonic-gate if (!sp) { 2419*7c478bd9Sstevel@tonic-gate /* 2420*7c478bd9Sstevel@tonic-gate * reset to first segment in current window 2421*7c478bd9Sstevel@tonic-gate */ 2422*7c478bd9Sstevel@tonic-gate *objpp = (caddr_t)wp; 2423*7c478bd9Sstevel@tonic-gate } else { 2424*7c478bd9Sstevel@tonic-gate if (sp->dmais_flags & DMAIS_WINEND) { 2425*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxseg: seg %p eow\n", (void *)sp)); 2426*7c478bd9Sstevel@tonic-gate return (DDI_DMA_DONE); 2427*7c478bd9Sstevel@tonic-gate } 2428*7c478bd9Sstevel@tonic-gate /* check if segment is really in window */ 2429*7c478bd9Sstevel@tonic-gate ASSERT((sp->dmais_flags & DMAIS_WINSTRT) && sp == wp || 2430*7c478bd9Sstevel@tonic-gate !(sp->dmais_flags & DMAIS_WINSTRT) && 2431*7c478bd9Sstevel@tonic-gate sp->_win._dmais_cur == wp); 2432*7c478bd9Sstevel@tonic-gate *objpp = (caddr_t)sp->dmais_link; 2433*7c478bd9Sstevel@tonic-gate } 2434*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxseg: new seg %p\n", (void *)*objpp)); 2435*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2436*7c478bd9Sstevel@tonic-gate 2437*7c478bd9Sstevel@tonic-gate case DDI_DMA_NEXTWIN: /* get next DMA window */ 2438*7c478bd9Sstevel@tonic-gate if (hp->dmai_wins && hp->dmai_ibufp) 2439*7c478bd9Sstevel@tonic-gate /* 2440*7c478bd9Sstevel@tonic-gate * do implied sync on current window 2441*7c478bd9Sstevel@tonic-gate */ 2442*7c478bd9Sstevel@tonic-gate (void) rootnex_io_rdsync(hp); 2443*7c478bd9Sstevel@tonic-gate if (!wp) { 2444*7c478bd9Sstevel@tonic-gate /* 2445*7c478bd9Sstevel@tonic-gate * reset to (first segment of) first window 2446*7c478bd9Sstevel@tonic-gate */ 2447*7c478bd9Sstevel@tonic-gate *objpp = (caddr_t)hp->dmai_hds; 2448*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxwin: first win %p\n", (void *)*objpp)); 2449*7c478bd9Sstevel@tonic-gate } else { 2450*7c478bd9Sstevel@tonic-gate ASSERT(wp->dmais_flags & DMAIS_WINSTRT); 2451*7c478bd9Sstevel@tonic-gate if (wp != hp->dmai_wins) { 2452*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxwin: win %p not current\n", 2453*7c478bd9Sstevel@tonic-gate (void *)wp)); 2454*7c478bd9Sstevel@tonic-gate return (DDI_DMA_STALE); 2455*7c478bd9Sstevel@tonic-gate } 2456*7c478bd9Sstevel@tonic-gate if (wp->_win._dmais_nex == 0) { 2457*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxwin: win %p end\n", (void *)wp)); 2458*7c478bd9Sstevel@tonic-gate return (DDI_DMA_DONE); 2459*7c478bd9Sstevel@tonic-gate } 2460*7c478bd9Sstevel@tonic-gate *objpp = (caddr_t)wp->_win._dmais_nex; 2461*7c478bd9Sstevel@tonic-gate DMAPRINT(("nxwin: new win %p\n", (void *)*objpp)); 2462*7c478bd9Sstevel@tonic-gate } 2463*7c478bd9Sstevel@tonic-gate hp->dmai_wins = (impl_dma_segment_t *)*objpp; 2464*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) 2465*7c478bd9Sstevel@tonic-gate return (rootnex_io_wtsync(hp, MAP)); 2466*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2467*7c478bd9Sstevel@tonic-gate 2468*7c478bd9Sstevel@tonic-gate case DDI_DMA_FREE: 2469*7c478bd9Sstevel@tonic-gate DMAPRINT(("free handle\n")); 2470*7c478bd9Sstevel@tonic-gate if (hp->dmai_ibufp) { 2471*7c478bd9Sstevel@tonic-gate rval = rootnex_io_rdsync(hp); 2472*7c478bd9Sstevel@tonic-gate ddi_mem_free(hp->dmai_ibufp); 2473*7c478bd9Sstevel@tonic-gate } 2474*7c478bd9Sstevel@tonic-gate if (hp->dmai_kaddr) 2475*7c478bd9Sstevel@tonic-gate vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE); 2476*7c478bd9Sstevel@tonic-gate kmem_free(hp, hp->dmai_kmsize); 2477*7c478bd9Sstevel@tonic-gate if (dvma_call_list_id) 2478*7c478bd9Sstevel@tonic-gate ddi_run_callback(&dvma_call_list_id); 2479*7c478bd9Sstevel@tonic-gate break; 2480*7c478bd9Sstevel@tonic-gate 2481*7c478bd9Sstevel@tonic-gate case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 2482*7c478bd9Sstevel@tonic-gate DMAPRINT(("iopb alloc\n")); 2483*7c478bd9Sstevel@tonic-gate rval = i_ddi_mem_alloc_lim(rdip, (ddi_dma_lim_t *)offp, 2484*7c478bd9Sstevel@tonic-gate *lenp, 0, 0, 0, objpp, NULL, NULL); 2485*7c478bd9Sstevel@tonic-gate break; 2486*7c478bd9Sstevel@tonic-gate 2487*7c478bd9Sstevel@tonic-gate case DDI_DMA_SMEM_ALLOC: /* get contiguous DMA-able memory */ 2488*7c478bd9Sstevel@tonic-gate DMAPRINT(("mem alloc\n")); 2489*7c478bd9Sstevel@tonic-gate rval = i_ddi_mem_alloc_lim(rdip, (ddi_dma_lim_t *)offp, 2490*7c478bd9Sstevel@tonic-gate *lenp, cache_flags, 1, 0, objpp, (uint_t *)handle, NULL); 2491*7c478bd9Sstevel@tonic-gate break; 2492*7c478bd9Sstevel@tonic-gate 2493*7c478bd9Sstevel@tonic-gate case DDI_DMA_KVADDR: 2494*7c478bd9Sstevel@tonic-gate DMAPRINT(("kvaddr of phys mapping\n")); 2495*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2496*7c478bd9Sstevel@tonic-gate 2497*7c478bd9Sstevel@tonic-gate case DDI_DMA_GETERR: 2498*7c478bd9Sstevel@tonic-gate DMAPRINT(("geterr\n")); 2499*7c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 2500*7c478bd9Sstevel@tonic-gate break; 2501*7c478bd9Sstevel@tonic-gate 2502*7c478bd9Sstevel@tonic-gate case DDI_DMA_COFF: 2503*7c478bd9Sstevel@tonic-gate DMAPRINT(("coff off %p mapping %llx size %lx\n", 2504*7c478bd9Sstevel@tonic-gate (void *)*objpp, 2505*7c478bd9Sstevel@tonic-gate (unsigned long long)hp->dmai_wins->_pdmu._dmais_lpd, 2506*7c478bd9Sstevel@tonic-gate hp->dmai_wins->dmais_size)); 2507*7c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 2508*7c478bd9Sstevel@tonic-gate break; 2509*7c478bd9Sstevel@tonic-gate 2510*7c478bd9Sstevel@tonic-gate default: 2511*7c478bd9Sstevel@tonic-gate DMAPRINT(("unknown 0x%x\n", request)); 2512*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2513*7c478bd9Sstevel@tonic-gate } 2514*7c478bd9Sstevel@tonic-gate return (rval); 2515*7c478bd9Sstevel@tonic-gate } 2516*7c478bd9Sstevel@tonic-gate 2517*7c478bd9Sstevel@tonic-gate /* 2518*7c478bd9Sstevel@tonic-gate * Root nexus ctl functions 2519*7c478bd9Sstevel@tonic-gate */ 2520*7c478bd9Sstevel@tonic-gate #define REPORTDEV_BUFSIZE 1024 2521*7c478bd9Sstevel@tonic-gate 2522*7c478bd9Sstevel@tonic-gate static int 2523*7c478bd9Sstevel@tonic-gate rootnex_ctl_reportdev(dev_info_t *dev) 2524*7c478bd9Sstevel@tonic-gate { 2525*7c478bd9Sstevel@tonic-gate int i, n, len, f_len = 0; 2526*7c478bd9Sstevel@tonic-gate char *buf; 2527*7c478bd9Sstevel@tonic-gate 2528*7c478bd9Sstevel@tonic-gate buf = kmem_alloc(REPORTDEV_BUFSIZE, KM_SLEEP); 2529*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf, REPORTDEV_BUFSIZE, 2530*7c478bd9Sstevel@tonic-gate "%s%d at root", ddi_driver_name(dev), ddi_get_instance(dev)); 2531*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2532*7c478bd9Sstevel@tonic-gate 2533*7c478bd9Sstevel@tonic-gate for (i = 0; i < sparc_pd_getnreg(dev); i++) { 2534*7c478bd9Sstevel@tonic-gate 2535*7c478bd9Sstevel@tonic-gate struct regspec *rp = sparc_pd_getreg(dev, i); 2536*7c478bd9Sstevel@tonic-gate 2537*7c478bd9Sstevel@tonic-gate if (i == 0) 2538*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2539*7c478bd9Sstevel@tonic-gate ": "); 2540*7c478bd9Sstevel@tonic-gate else 2541*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2542*7c478bd9Sstevel@tonic-gate " and "); 2543*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2544*7c478bd9Sstevel@tonic-gate 2545*7c478bd9Sstevel@tonic-gate switch (rp->regspec_bustype) { 2546*7c478bd9Sstevel@tonic-gate 2547*7c478bd9Sstevel@tonic-gate case BTEISA: 2548*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2549*7c478bd9Sstevel@tonic-gate "%s 0x%x", DEVI_EISA_NEXNAME, rp->regspec_addr); 2550*7c478bd9Sstevel@tonic-gate break; 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate case BTISA: 2553*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2554*7c478bd9Sstevel@tonic-gate "%s 0x%x", DEVI_ISA_NEXNAME, rp->regspec_addr); 2555*7c478bd9Sstevel@tonic-gate break; 2556*7c478bd9Sstevel@tonic-gate 2557*7c478bd9Sstevel@tonic-gate default: 2558*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2559*7c478bd9Sstevel@tonic-gate "space %x offset %x", 2560*7c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr); 2561*7c478bd9Sstevel@tonic-gate break; 2562*7c478bd9Sstevel@tonic-gate } 2563*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2564*7c478bd9Sstevel@tonic-gate } 2565*7c478bd9Sstevel@tonic-gate for (i = 0, n = sparc_pd_getnintr(dev); i < n; i++) { 2566*7c478bd9Sstevel@tonic-gate int pri; 2567*7c478bd9Sstevel@tonic-gate 2568*7c478bd9Sstevel@tonic-gate if (i != 0) { 2569*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2570*7c478bd9Sstevel@tonic-gate ","); 2571*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2572*7c478bd9Sstevel@tonic-gate } 2573*7c478bd9Sstevel@tonic-gate pri = INT_IPL(sparc_pd_getintr(dev, i)->intrspec_pri); 2574*7c478bd9Sstevel@tonic-gate f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len, 2575*7c478bd9Sstevel@tonic-gate " sparc ipl %d", pri); 2576*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2577*7c478bd9Sstevel@tonic-gate } 2578*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2579*7c478bd9Sstevel@tonic-gate if (f_len + 1 >= REPORTDEV_BUFSIZE) { 2580*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "next message is truncated: " 2581*7c478bd9Sstevel@tonic-gate "printed length 1024, real length %d", f_len); 2582*7c478bd9Sstevel@tonic-gate } 2583*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2584*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s\n", buf); 2585*7c478bd9Sstevel@tonic-gate kmem_free(buf, REPORTDEV_BUFSIZE); 2586*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2587*7c478bd9Sstevel@tonic-gate } 2588*7c478bd9Sstevel@tonic-gate 2589*7c478bd9Sstevel@tonic-gate /* 2590*7c478bd9Sstevel@tonic-gate * For the x86 rootnexus, we're prepared to claim that the interrupt string 2591*7c478bd9Sstevel@tonic-gate * is in the form of a list of <ipl,vec> specifications. 2592*7c478bd9Sstevel@tonic-gate */ 2593*7c478bd9Sstevel@tonic-gate 2594*7c478bd9Sstevel@tonic-gate #define VEC_MIN 1 2595*7c478bd9Sstevel@tonic-gate #define VEC_MAX 255 2596*7c478bd9Sstevel@tonic-gate static int 2597*7c478bd9Sstevel@tonic-gate rootnex_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, int *in, 2598*7c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr) 2599*7c478bd9Sstevel@tonic-gate { 2600*7c478bd9Sstevel@tonic-gate size_t size; 2601*7c478bd9Sstevel@tonic-gate int n; 2602*7c478bd9Sstevel@tonic-gate struct intrspec *new; 2603*7c478bd9Sstevel@tonic-gate caddr_t got_prop; 2604*7c478bd9Sstevel@tonic-gate int *inpri; 2605*7c478bd9Sstevel@tonic-gate int got_len; 2606*7c478bd9Sstevel@tonic-gate extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 2607*7c478bd9Sstevel@tonic-gate 2608*7c478bd9Sstevel@tonic-gate static char bad_intr_fmt[] = 2609*7c478bd9Sstevel@tonic-gate "rootnex: bad interrupt spec from %s%d - ipl %d, irq %d\n"; 2610*7c478bd9Sstevel@tonic-gate 2611*7c478bd9Sstevel@tonic-gate #ifdef lint 2612*7c478bd9Sstevel@tonic-gate dip = dip; 2613*7c478bd9Sstevel@tonic-gate #endif 2614*7c478bd9Sstevel@tonic-gate /* 2615*7c478bd9Sstevel@tonic-gate * determine if the driver is expecting the new style "interrupts" 2616*7c478bd9Sstevel@tonic-gate * property which just contains the IRQ, or the old style which 2617*7c478bd9Sstevel@tonic-gate * contains pairs of <IPL,IRQ>. if it is the new style, we always 2618*7c478bd9Sstevel@tonic-gate * assign IPL 5 unless an "interrupt-priorities" property exists. 2619*7c478bd9Sstevel@tonic-gate * in that case, the "interrupt-priorities" property contains the 2620*7c478bd9Sstevel@tonic-gate * IPL values that match, one for one, the IRQ values in the 2621*7c478bd9Sstevel@tonic-gate * "interrupts" property. 2622*7c478bd9Sstevel@tonic-gate */ 2623*7c478bd9Sstevel@tonic-gate inpri = NULL; 2624*7c478bd9Sstevel@tonic-gate if ((ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 2625*7c478bd9Sstevel@tonic-gate "ignore-hardware-nodes", -1) != -1) || 2626*7c478bd9Sstevel@tonic-gate ignore_hardware_nodes) { 2627*7c478bd9Sstevel@tonic-gate /* the old style "interrupts" property... */ 2628*7c478bd9Sstevel@tonic-gate 2629*7c478bd9Sstevel@tonic-gate /* 2630*7c478bd9Sstevel@tonic-gate * The list consists of <ipl,vec> elements 2631*7c478bd9Sstevel@tonic-gate */ 2632*7c478bd9Sstevel@tonic-gate if ((n = (*in++ >> 1)) < 1) 2633*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2634*7c478bd9Sstevel@tonic-gate 2635*7c478bd9Sstevel@tonic-gate pdptr->par_nintr = n; 2636*7c478bd9Sstevel@tonic-gate size = n * sizeof (struct intrspec); 2637*7c478bd9Sstevel@tonic-gate new = pdptr->par_intr = kmem_zalloc(size, KM_SLEEP); 2638*7c478bd9Sstevel@tonic-gate 2639*7c478bd9Sstevel@tonic-gate while (n--) { 2640*7c478bd9Sstevel@tonic-gate int level = *in++; 2641*7c478bd9Sstevel@tonic-gate int vec = *in++; 2642*7c478bd9Sstevel@tonic-gate 2643*7c478bd9Sstevel@tonic-gate if (level < 1 || level > MAXIPL || 2644*7c478bd9Sstevel@tonic-gate vec < VEC_MIN || vec > VEC_MAX) { 2645*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, bad_intr_fmt, 2646*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_name, 2647*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_instance, level, vec); 2648*7c478bd9Sstevel@tonic-gate goto broken; 2649*7c478bd9Sstevel@tonic-gate } 2650*7c478bd9Sstevel@tonic-gate new->intrspec_pri = level; 2651*7c478bd9Sstevel@tonic-gate if (vec != 2) 2652*7c478bd9Sstevel@tonic-gate new->intrspec_vec = vec; 2653*7c478bd9Sstevel@tonic-gate else 2654*7c478bd9Sstevel@tonic-gate /* 2655*7c478bd9Sstevel@tonic-gate * irq 2 on the PC bus is tied to irq 9 2656*7c478bd9Sstevel@tonic-gate * on ISA, EISA and MicroChannel 2657*7c478bd9Sstevel@tonic-gate */ 2658*7c478bd9Sstevel@tonic-gate new->intrspec_vec = 9; 2659*7c478bd9Sstevel@tonic-gate new++; 2660*7c478bd9Sstevel@tonic-gate } 2661*7c478bd9Sstevel@tonic-gate 2662*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2663*7c478bd9Sstevel@tonic-gate } else { 2664*7c478bd9Sstevel@tonic-gate /* the new style "interrupts" property... */ 2665*7c478bd9Sstevel@tonic-gate 2666*7c478bd9Sstevel@tonic-gate /* 2667*7c478bd9Sstevel@tonic-gate * The list consists of <vec> elements 2668*7c478bd9Sstevel@tonic-gate */ 2669*7c478bd9Sstevel@tonic-gate if ((n = (*in++)) < 1) 2670*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2671*7c478bd9Sstevel@tonic-gate 2672*7c478bd9Sstevel@tonic-gate pdptr->par_nintr = n; 2673*7c478bd9Sstevel@tonic-gate size = n * sizeof (struct intrspec); 2674*7c478bd9Sstevel@tonic-gate new = pdptr->par_intr = kmem_zalloc(size, KM_SLEEP); 2675*7c478bd9Sstevel@tonic-gate 2676*7c478bd9Sstevel@tonic-gate /* XXX check for "interrupt-priorities" property... */ 2677*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 2678*7c478bd9Sstevel@tonic-gate "interrupt-priorities", (caddr_t)&got_prop, &got_len) 2679*7c478bd9Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 2680*7c478bd9Sstevel@tonic-gate if (n != (got_len / sizeof (int))) { 2681*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 2682*7c478bd9Sstevel@tonic-gate "rootnex: bad interrupt-priorities length" 2683*7c478bd9Sstevel@tonic-gate " from %s%d: expected %d, got %d\n", 2684*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_name, 2685*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_instance, n, 2686*7c478bd9Sstevel@tonic-gate (int)(got_len / sizeof (int))); 2687*7c478bd9Sstevel@tonic-gate goto broken; 2688*7c478bd9Sstevel@tonic-gate } 2689*7c478bd9Sstevel@tonic-gate inpri = (int *)got_prop; 2690*7c478bd9Sstevel@tonic-gate } 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate while (n--) { 2693*7c478bd9Sstevel@tonic-gate int level; 2694*7c478bd9Sstevel@tonic-gate int vec = *in++; 2695*7c478bd9Sstevel@tonic-gate 2696*7c478bd9Sstevel@tonic-gate if (inpri == NULL) 2697*7c478bd9Sstevel@tonic-gate level = 5; 2698*7c478bd9Sstevel@tonic-gate else 2699*7c478bd9Sstevel@tonic-gate level = *inpri++; 2700*7c478bd9Sstevel@tonic-gate 2701*7c478bd9Sstevel@tonic-gate if (level < 1 || level > MAXIPL || 2702*7c478bd9Sstevel@tonic-gate vec < VEC_MIN || vec > VEC_MAX) { 2703*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, bad_intr_fmt, 2704*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_name, 2705*7c478bd9Sstevel@tonic-gate DEVI(rdip)->devi_instance, level, vec); 2706*7c478bd9Sstevel@tonic-gate goto broken; 2707*7c478bd9Sstevel@tonic-gate } 2708*7c478bd9Sstevel@tonic-gate new->intrspec_pri = level; 2709*7c478bd9Sstevel@tonic-gate if (vec != 2) 2710*7c478bd9Sstevel@tonic-gate new->intrspec_vec = vec; 2711*7c478bd9Sstevel@tonic-gate else 2712*7c478bd9Sstevel@tonic-gate /* 2713*7c478bd9Sstevel@tonic-gate * irq 2 on the PC bus is tied to irq 9 2714*7c478bd9Sstevel@tonic-gate * on ISA, EISA and MicroChannel 2715*7c478bd9Sstevel@tonic-gate */ 2716*7c478bd9Sstevel@tonic-gate new->intrspec_vec = 9; 2717*7c478bd9Sstevel@tonic-gate new++; 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate 2720*7c478bd9Sstevel@tonic-gate if (inpri != NULL) 2721*7c478bd9Sstevel@tonic-gate kmem_free(got_prop, got_len); 2722*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2723*7c478bd9Sstevel@tonic-gate } 2724*7c478bd9Sstevel@tonic-gate 2725*7c478bd9Sstevel@tonic-gate broken: 2726*7c478bd9Sstevel@tonic-gate kmem_free(pdptr->par_intr, size); 2727*7c478bd9Sstevel@tonic-gate pdptr->par_intr = NULL; 2728*7c478bd9Sstevel@tonic-gate pdptr->par_nintr = 0; 2729*7c478bd9Sstevel@tonic-gate if (inpri != NULL) 2730*7c478bd9Sstevel@tonic-gate kmem_free(got_prop, got_len); 2731*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2732*7c478bd9Sstevel@tonic-gate } 2733*7c478bd9Sstevel@tonic-gate 2734*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2735*7c478bd9Sstevel@tonic-gate static int 2736*7c478bd9Sstevel@tonic-gate rootnex_ctl_children(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 2737*7c478bd9Sstevel@tonic-gate dev_info_t *child) 2738*7c478bd9Sstevel@tonic-gate { 2739*7c478bd9Sstevel@tonic-gate extern int impl_ddi_sunbus_initchild(dev_info_t *); 2740*7c478bd9Sstevel@tonic-gate extern void impl_ddi_sunbus_removechild(dev_info_t *); 2741*7c478bd9Sstevel@tonic-gate 2742*7c478bd9Sstevel@tonic-gate switch (ctlop) { 2743*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 2744*7c478bd9Sstevel@tonic-gate return (impl_ddi_sunbus_initchild(child)); 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 2747*7c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 2748*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2749*7c478bd9Sstevel@tonic-gate default: 2750*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2751*7c478bd9Sstevel@tonic-gate } 2752*7c478bd9Sstevel@tonic-gate } 2753*7c478bd9Sstevel@tonic-gate 2754*7c478bd9Sstevel@tonic-gate 2755*7c478bd9Sstevel@tonic-gate static int 2756*7c478bd9Sstevel@tonic-gate rootnex_ctlops_poke(peekpoke_ctlops_t *in_args) 2757*7c478bd9Sstevel@tonic-gate { 2758*7c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 2759*7c478bd9Sstevel@tonic-gate on_trap_data_t otd; 2760*7c478bd9Sstevel@tonic-gate 2761*7c478bd9Sstevel@tonic-gate /* Cautious access not supported. */ 2762*7c478bd9Sstevel@tonic-gate if (in_args->handle != NULL) 2763*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2764*7c478bd9Sstevel@tonic-gate 2765*7c478bd9Sstevel@tonic-gate mutex_enter(&pokefault_mutex); 2766*7c478bd9Sstevel@tonic-gate pokefault = -1; 2767*7c478bd9Sstevel@tonic-gate 2768*7c478bd9Sstevel@tonic-gate /* Set up protected environment. */ 2769*7c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 2770*7c478bd9Sstevel@tonic-gate switch (in_args->size) { 2771*7c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 2772*7c478bd9Sstevel@tonic-gate *(uint8_t *)in_args->dev_addr = 2773*7c478bd9Sstevel@tonic-gate *(uint8_t *)in_args->host_addr; 2774*7c478bd9Sstevel@tonic-gate break; 2775*7c478bd9Sstevel@tonic-gate 2776*7c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 2777*7c478bd9Sstevel@tonic-gate *(uint16_t *)in_args->dev_addr = 2778*7c478bd9Sstevel@tonic-gate *(uint16_t *)in_args->host_addr; 2779*7c478bd9Sstevel@tonic-gate break; 2780*7c478bd9Sstevel@tonic-gate 2781*7c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 2782*7c478bd9Sstevel@tonic-gate *(uint32_t *)in_args->dev_addr = 2783*7c478bd9Sstevel@tonic-gate *(uint32_t *)in_args->host_addr; 2784*7c478bd9Sstevel@tonic-gate break; 2785*7c478bd9Sstevel@tonic-gate 2786*7c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 2787*7c478bd9Sstevel@tonic-gate *(uint64_t *)in_args->dev_addr = 2788*7c478bd9Sstevel@tonic-gate *(uint64_t *)in_args->host_addr; 2789*7c478bd9Sstevel@tonic-gate break; 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate default: 2792*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 2793*7c478bd9Sstevel@tonic-gate break; 2794*7c478bd9Sstevel@tonic-gate } 2795*7c478bd9Sstevel@tonic-gate } else 2796*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate /* Take down protected environment. */ 2799*7c478bd9Sstevel@tonic-gate no_trap(); 2800*7c478bd9Sstevel@tonic-gate 2801*7c478bd9Sstevel@tonic-gate pokefault = 0; 2802*7c478bd9Sstevel@tonic-gate mutex_exit(&pokefault_mutex); 2803*7c478bd9Sstevel@tonic-gate 2804*7c478bd9Sstevel@tonic-gate return (err); 2805*7c478bd9Sstevel@tonic-gate } 2806*7c478bd9Sstevel@tonic-gate 2807*7c478bd9Sstevel@tonic-gate 2808*7c478bd9Sstevel@tonic-gate static int 2809*7c478bd9Sstevel@tonic-gate rootnex_ctlops_peek(peekpoke_ctlops_t *in_args, void *result) 2810*7c478bd9Sstevel@tonic-gate { 2811*7c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 2812*7c478bd9Sstevel@tonic-gate on_trap_data_t otd; 2813*7c478bd9Sstevel@tonic-gate 2814*7c478bd9Sstevel@tonic-gate /* Cautious access not supported. */ 2815*7c478bd9Sstevel@tonic-gate if (in_args->handle != NULL) 2816*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2817*7c478bd9Sstevel@tonic-gate 2818*7c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 2819*7c478bd9Sstevel@tonic-gate switch (in_args->size) { 2820*7c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 2821*7c478bd9Sstevel@tonic-gate *(uint8_t *)in_args->host_addr = 2822*7c478bd9Sstevel@tonic-gate *(uint8_t *)in_args->dev_addr; 2823*7c478bd9Sstevel@tonic-gate break; 2824*7c478bd9Sstevel@tonic-gate 2825*7c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 2826*7c478bd9Sstevel@tonic-gate *(uint16_t *)in_args->host_addr = 2827*7c478bd9Sstevel@tonic-gate *(uint16_t *)in_args->dev_addr; 2828*7c478bd9Sstevel@tonic-gate break; 2829*7c478bd9Sstevel@tonic-gate 2830*7c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 2831*7c478bd9Sstevel@tonic-gate *(uint32_t *)in_args->host_addr = 2832*7c478bd9Sstevel@tonic-gate *(uint32_t *)in_args->dev_addr; 2833*7c478bd9Sstevel@tonic-gate break; 2834*7c478bd9Sstevel@tonic-gate 2835*7c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 2836*7c478bd9Sstevel@tonic-gate *(uint64_t *)in_args->host_addr = 2837*7c478bd9Sstevel@tonic-gate *(uint64_t *)in_args->dev_addr; 2838*7c478bd9Sstevel@tonic-gate break; 2839*7c478bd9Sstevel@tonic-gate 2840*7c478bd9Sstevel@tonic-gate default: 2841*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 2842*7c478bd9Sstevel@tonic-gate break; 2843*7c478bd9Sstevel@tonic-gate } 2844*7c478bd9Sstevel@tonic-gate result = (void *)in_args->host_addr; 2845*7c478bd9Sstevel@tonic-gate } else 2846*7c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 2847*7c478bd9Sstevel@tonic-gate 2848*7c478bd9Sstevel@tonic-gate no_trap(); 2849*7c478bd9Sstevel@tonic-gate return (err); 2850*7c478bd9Sstevel@tonic-gate } 2851*7c478bd9Sstevel@tonic-gate 2852*7c478bd9Sstevel@tonic-gate static int 2853*7c478bd9Sstevel@tonic-gate rootnex_ctlops(dev_info_t *dip, dev_info_t *rdip, 2854*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 2855*7c478bd9Sstevel@tonic-gate { 2856*7c478bd9Sstevel@tonic-gate int n, *ptr; 2857*7c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdp; 2858*7c478bd9Sstevel@tonic-gate 2859*7c478bd9Sstevel@tonic-gate static boolean_t reserved_msg_printed = B_FALSE; 2860*7c478bd9Sstevel@tonic-gate 2861*7c478bd9Sstevel@tonic-gate switch (ctlop) { 2862*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC: 2863*7c478bd9Sstevel@tonic-gate /* 2864*7c478bd9Sstevel@tonic-gate * Return 'partial' to indicate that dma mapping 2865*7c478bd9Sstevel@tonic-gate * has to be done in the main MMU. 2866*7c478bd9Sstevel@tonic-gate */ 2867*7c478bd9Sstevel@tonic-gate return (DDI_DMA_PARTIAL); 2868*7c478bd9Sstevel@tonic-gate 2869*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_BTOP: 2870*7c478bd9Sstevel@tonic-gate /* 2871*7c478bd9Sstevel@tonic-gate * Convert byte count input to physical page units. 2872*7c478bd9Sstevel@tonic-gate * (byte counts that are not a page-size multiple 2873*7c478bd9Sstevel@tonic-gate * are rounded down) 2874*7c478bd9Sstevel@tonic-gate */ 2875*7c478bd9Sstevel@tonic-gate *(ulong_t *)result = btop(*(ulong_t *)arg); 2876*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2877*7c478bd9Sstevel@tonic-gate 2878*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PTOB: 2879*7c478bd9Sstevel@tonic-gate /* 2880*7c478bd9Sstevel@tonic-gate * Convert size in physical pages to bytes 2881*7c478bd9Sstevel@tonic-gate */ 2882*7c478bd9Sstevel@tonic-gate *(ulong_t *)result = ptob(*(ulong_t *)arg); 2883*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2884*7c478bd9Sstevel@tonic-gate 2885*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_BTOPR: 2886*7c478bd9Sstevel@tonic-gate /* 2887*7c478bd9Sstevel@tonic-gate * Convert byte count input to physical page units 2888*7c478bd9Sstevel@tonic-gate * (byte counts that are not a page-size multiple 2889*7c478bd9Sstevel@tonic-gate * are rounded up) 2890*7c478bd9Sstevel@tonic-gate */ 2891*7c478bd9Sstevel@tonic-gate *(ulong_t *)result = btopr(*(ulong_t *)arg); 2892*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2893*7c478bd9Sstevel@tonic-gate 2894*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POKE: 2895*7c478bd9Sstevel@tonic-gate return (rootnex_ctlops_poke((peekpoke_ctlops_t *)arg)); 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 2898*7c478bd9Sstevel@tonic-gate return (rootnex_ctlops_peek((peekpoke_ctlops_t *)arg, result)); 2899*7c478bd9Sstevel@tonic-gate 2900*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 2901*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 2902*7c478bd9Sstevel@tonic-gate return (rootnex_ctl_children(dip, rdip, ctlop, arg)); 2903*7c478bd9Sstevel@tonic-gate 2904*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 2905*7c478bd9Sstevel@tonic-gate return (rootnex_ctl_reportdev(rdip)); 2906*7c478bd9Sstevel@tonic-gate 2907*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: 2908*7c478bd9Sstevel@tonic-gate /* 2909*7c478bd9Sstevel@tonic-gate * Nothing to do here but reflect back.. 2910*7c478bd9Sstevel@tonic-gate */ 2911*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2912*7c478bd9Sstevel@tonic-gate 2913*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 2914*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 2915*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NINTRS: 2916*7c478bd9Sstevel@tonic-gate break; 2917*7c478bd9Sstevel@tonic-gate 2918*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 2919*7c478bd9Sstevel@tonic-gate if (ndi_dev_is_prom_node(rdip)) 2920*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2921*7c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(rdip)) 2922*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2923*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2924*7c478bd9Sstevel@tonic-gate 2925*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INTR_HILEVEL: 2926*7c478bd9Sstevel@tonic-gate /* 2927*7c478bd9Sstevel@tonic-gate * Indicate whether the interrupt specified is to be handled 2928*7c478bd9Sstevel@tonic-gate * above lock level. In other words, above the level that 2929*7c478bd9Sstevel@tonic-gate * cv_signal and default type mutexes can be used. 2930*7c478bd9Sstevel@tonic-gate */ 2931*7c478bd9Sstevel@tonic-gate *(int *)result = 2932*7c478bd9Sstevel@tonic-gate (INT_IPL(((struct intrspec *)arg)->intrspec_pri) 2933*7c478bd9Sstevel@tonic-gate > LOCK_LEVEL); 2934*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2935*7c478bd9Sstevel@tonic-gate 2936*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_XLATE_INTRS: 2937*7c478bd9Sstevel@tonic-gate return (rootnex_xlate_intrs(dip, rdip, arg, result)); 2938*7c478bd9Sstevel@tonic-gate 2939*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POWER: 2940*7c478bd9Sstevel@tonic-gate return ((*pm_platform_power)((power_req_t *)arg)); 2941*7c478bd9Sstevel@tonic-gate 2942*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_RESERVED1: /* Was DDI_CTLOPS_POKE_INIT, obsolete */ 2943*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_RESERVED2: /* Was DDI_CTLOPS_POKE_FLUSH, obsolete */ 2944*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_RESERVED3: /* Was DDI_CTLOPS_POKE_FINI, obsolete */ 2945*7c478bd9Sstevel@tonic-gate if (!reserved_msg_printed) { 2946*7c478bd9Sstevel@tonic-gate reserved_msg_printed = B_TRUE; 2947*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Failing ddi_ctlops call(s) for " 2948*7c478bd9Sstevel@tonic-gate "1 or more reserved/obsolete operations."); 2949*7c478bd9Sstevel@tonic-gate } 2950*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2951*7c478bd9Sstevel@tonic-gate 2952*7c478bd9Sstevel@tonic-gate default: 2953*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2954*7c478bd9Sstevel@tonic-gate } 2955*7c478bd9Sstevel@tonic-gate /* 2956*7c478bd9Sstevel@tonic-gate * The rest are for "hardware" properties 2957*7c478bd9Sstevel@tonic-gate */ 2958*7c478bd9Sstevel@tonic-gate if ((pdp = ddi_get_parent_data(rdip)) == NULL) 2959*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2960*7c478bd9Sstevel@tonic-gate 2961*7c478bd9Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) { 2962*7c478bd9Sstevel@tonic-gate ptr = (int *)result; 2963*7c478bd9Sstevel@tonic-gate *ptr = pdp->par_nreg; 2964*7c478bd9Sstevel@tonic-gate } else if (ctlop == DDI_CTLOPS_NINTRS) { 2965*7c478bd9Sstevel@tonic-gate ptr = (int *)result; 2966*7c478bd9Sstevel@tonic-gate *ptr = pdp->par_nintr; 2967*7c478bd9Sstevel@tonic-gate } else { 2968*7c478bd9Sstevel@tonic-gate off_t *size = (off_t *)result; 2969*7c478bd9Sstevel@tonic-gate 2970*7c478bd9Sstevel@tonic-gate ptr = (int *)arg; 2971*7c478bd9Sstevel@tonic-gate n = *ptr; 2972*7c478bd9Sstevel@tonic-gate if (n >= pdp->par_nreg) { 2973*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2974*7c478bd9Sstevel@tonic-gate } 2975*7c478bd9Sstevel@tonic-gate *size = (off_t)pdp->par_reg[n].regspec_size; 2976*7c478bd9Sstevel@tonic-gate } 2977*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2978*7c478bd9Sstevel@tonic-gate } 2979*7c478bd9Sstevel@tonic-gate 2980*7c478bd9Sstevel@tonic-gate /* 2981*7c478bd9Sstevel@tonic-gate * rootnex_get_ispec: 2982*7c478bd9Sstevel@tonic-gate * convert an interrupt number to an interrupt specification. 2983*7c478bd9Sstevel@tonic-gate * The interrupt number determines which interrupt spec will be 2984*7c478bd9Sstevel@tonic-gate * returned if more than one exists. 2985*7c478bd9Sstevel@tonic-gate * 2986*7c478bd9Sstevel@tonic-gate * Look into the parent private data area of the 'rdip' to find out 2987*7c478bd9Sstevel@tonic-gate * the interrupt specification. First check to make sure there is 2988*7c478bd9Sstevel@tonic-gate * one that matchs "inumber" and then return a pointer to it. 2989*7c478bd9Sstevel@tonic-gate * 2990*7c478bd9Sstevel@tonic-gate * Return NULL if one could not be found. 2991*7c478bd9Sstevel@tonic-gate * 2992*7c478bd9Sstevel@tonic-gate * NOTE: This is needed for rootnex_intr_ops() 2993*7c478bd9Sstevel@tonic-gate */ 2994*7c478bd9Sstevel@tonic-gate static struct intrspec * 2995*7c478bd9Sstevel@tonic-gate rootnex_get_ispec(dev_info_t *rdip, int inum) 2996*7c478bd9Sstevel@tonic-gate { 2997*7c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip); 2998*7c478bd9Sstevel@tonic-gate 2999*7c478bd9Sstevel@tonic-gate /* 3000*7c478bd9Sstevel@tonic-gate * Special case handling for drivers that provide their own 3001*7c478bd9Sstevel@tonic-gate * intrspec structures instead of relying on the DDI framework. 3002*7c478bd9Sstevel@tonic-gate * 3003*7c478bd9Sstevel@tonic-gate * A broken hardware driver in ON could potentially provide its 3004*7c478bd9Sstevel@tonic-gate * own intrspec structure, instead of relying on the hardware. 3005*7c478bd9Sstevel@tonic-gate * If these drivers are children of 'rootnex' then we need to 3006*7c478bd9Sstevel@tonic-gate * continue to provide backward compatibility to them here. 3007*7c478bd9Sstevel@tonic-gate * 3008*7c478bd9Sstevel@tonic-gate * Following check is a special case for 'pcic' driver which 3009*7c478bd9Sstevel@tonic-gate * was found to have broken hardwre andby provides its own intrspec. 3010*7c478bd9Sstevel@tonic-gate * 3011*7c478bd9Sstevel@tonic-gate * Verbatim comments from this driver are shown here: 3012*7c478bd9Sstevel@tonic-gate * "Don't use the ddi_add_intr since we don't have a 3013*7c478bd9Sstevel@tonic-gate * default intrspec in all cases." 3014*7c478bd9Sstevel@tonic-gate * 3015*7c478bd9Sstevel@tonic-gate * Since an 'ispec' may not be always created for it, 3016*7c478bd9Sstevel@tonic-gate * check for that and create one if so. 3017*7c478bd9Sstevel@tonic-gate * 3018*7c478bd9Sstevel@tonic-gate * NOTE: Currently 'pcic' is the only driver found to do this. 3019*7c478bd9Sstevel@tonic-gate */ 3020*7c478bd9Sstevel@tonic-gate if (!pdp->par_intr && strcmp(ddi_get_name(rdip), "pcic") == 0) { 3021*7c478bd9Sstevel@tonic-gate pdp->par_nintr = 1; 3022*7c478bd9Sstevel@tonic-gate pdp->par_intr = kmem_zalloc(sizeof (struct intrspec) * 3023*7c478bd9Sstevel@tonic-gate pdp->par_nintr, KM_SLEEP); 3024*7c478bd9Sstevel@tonic-gate } 3025*7c478bd9Sstevel@tonic-gate 3026*7c478bd9Sstevel@tonic-gate /* Validate the interrupt number */ 3027*7c478bd9Sstevel@tonic-gate if (inum >= pdp->par_nintr) 3028*7c478bd9Sstevel@tonic-gate return (NULL); 3029*7c478bd9Sstevel@tonic-gate 3030*7c478bd9Sstevel@tonic-gate /* Get the interrupt structure pointer and return that */ 3031*7c478bd9Sstevel@tonic-gate return ((struct intrspec *)&pdp->par_intr[inum]); 3032*7c478bd9Sstevel@tonic-gate } 3033*7c478bd9Sstevel@tonic-gate 3034*7c478bd9Sstevel@tonic-gate 3035*7c478bd9Sstevel@tonic-gate /* 3036*7c478bd9Sstevel@tonic-gate * rootnex_intr_ops: 3037*7c478bd9Sstevel@tonic-gate * bus_intr_op() function for interrupt support 3038*7c478bd9Sstevel@tonic-gate */ 3039*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3040*7c478bd9Sstevel@tonic-gate static int 3041*7c478bd9Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 3042*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 3043*7c478bd9Sstevel@tonic-gate { 3044*7c478bd9Sstevel@tonic-gate struct intrspec *ispec; 3045*7c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdp; 3046*7c478bd9Sstevel@tonic-gate 3047*7c478bd9Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, 3048*7c478bd9Sstevel@tonic-gate "rootnex_intr_ops: pdip = %p, rdip = %p, intr_op = %x, hdlp = %p\n", 3049*7c478bd9Sstevel@tonic-gate (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 3050*7c478bd9Sstevel@tonic-gate 3051*7c478bd9Sstevel@tonic-gate /* Process the interrupt operation */ 3052*7c478bd9Sstevel@tonic-gate switch (intr_op) { 3053*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 3054*7c478bd9Sstevel@tonic-gate /* First check with pcplusmp */ 3055*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3056*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3057*7c478bd9Sstevel@tonic-gate 3058*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) { 3059*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 3060*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3061*7c478bd9Sstevel@tonic-gate } 3062*7c478bd9Sstevel@tonic-gate break; 3063*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 3064*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3065*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) 3068*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3069*7c478bd9Sstevel@tonic-gate break; 3070*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 3071*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3072*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3073*7c478bd9Sstevel@tonic-gate hdlp->ih_pri = ispec->intrspec_pri; 3074*7c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 3075*7c478bd9Sstevel@tonic-gate break; 3076*7c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 3077*7c478bd9Sstevel@tonic-gate pdp = ddi_get_parent_data(rdip); 3078*7c478bd9Sstevel@tonic-gate /* 3079*7c478bd9Sstevel@tonic-gate * Special case for 'pcic' driver' only. 3080*7c478bd9Sstevel@tonic-gate * If an intrspec was created for it, clean it up here 3081*7c478bd9Sstevel@tonic-gate * See detailed comments on this in the function 3082*7c478bd9Sstevel@tonic-gate * rootnex_get_ispec(). 3083*7c478bd9Sstevel@tonic-gate */ 3084*7c478bd9Sstevel@tonic-gate if (pdp->par_intr && strcmp(ddi_get_name(rdip), "pcic") == 0) { 3085*7c478bd9Sstevel@tonic-gate kmem_free(pdp->par_intr, sizeof (struct intrspec) * 3086*7c478bd9Sstevel@tonic-gate pdp->par_nintr); 3087*7c478bd9Sstevel@tonic-gate /* 3088*7c478bd9Sstevel@tonic-gate * Set it to zero; so that 3089*7c478bd9Sstevel@tonic-gate * DDI framework doesn't free it again 3090*7c478bd9Sstevel@tonic-gate */ 3091*7c478bd9Sstevel@tonic-gate pdp->par_intr = NULL; 3092*7c478bd9Sstevel@tonic-gate pdp->par_nintr = 0; 3093*7c478bd9Sstevel@tonic-gate } 3094*7c478bd9Sstevel@tonic-gate break; 3095*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 3096*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3097*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3098*7c478bd9Sstevel@tonic-gate *(int *)result = ispec->intrspec_pri; 3099*7c478bd9Sstevel@tonic-gate break; 3100*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 3101*7c478bd9Sstevel@tonic-gate /* Validate the interrupt priority passed to us */ 3102*7c478bd9Sstevel@tonic-gate if (*(int *)result > LOCK_LEVEL) 3103*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3104*7c478bd9Sstevel@tonic-gate 3105*7c478bd9Sstevel@tonic-gate /* Ensure that PSM is all initialized and ispec is ok */ 3106*7c478bd9Sstevel@tonic-gate if ((psm_intr_ops == NULL) || 3107*7c478bd9Sstevel@tonic-gate ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)) 3108*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3109*7c478bd9Sstevel@tonic-gate 3110*7c478bd9Sstevel@tonic-gate /* Change the priority */ 3111*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 3112*7c478bd9Sstevel@tonic-gate PSM_FAILURE) 3113*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3114*7c478bd9Sstevel@tonic-gate 3115*7c478bd9Sstevel@tonic-gate /* update the ispec with the new priority */ 3116*7c478bd9Sstevel@tonic-gate ispec->intrspec_pri = *(int *)result; 3117*7c478bd9Sstevel@tonic-gate break; 3118*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 3119*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3120*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3121*7c478bd9Sstevel@tonic-gate ispec->intrspec_func = hdlp->ih_cb_func; 3122*7c478bd9Sstevel@tonic-gate break; 3123*7c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 3124*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3125*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3126*7c478bd9Sstevel@tonic-gate ispec->intrspec_func = (uint_t (*)()) 0; 3127*7c478bd9Sstevel@tonic-gate break; 3128*7c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 3129*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3130*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3131*7c478bd9Sstevel@tonic-gate 3132*7c478bd9Sstevel@tonic-gate /* Call psmi to translate irq with the dip */ 3133*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3134*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3135*7c478bd9Sstevel@tonic-gate 3136*7c478bd9Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 3137*7c478bd9Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, 3138*7c478bd9Sstevel@tonic-gate (int *)&hdlp->ih_vector); 3139*7c478bd9Sstevel@tonic-gate 3140*7c478bd9Sstevel@tonic-gate /* Add the interrupt handler */ 3141*7c478bd9Sstevel@tonic-gate if (!add_avintr((void *)hdlp, ispec->intrspec_pri, 3142*7c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector, 3143*7c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rdip)) 3144*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3145*7c478bd9Sstevel@tonic-gate break; 3146*7c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 3147*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3148*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3149*7c478bd9Sstevel@tonic-gate 3150*7c478bd9Sstevel@tonic-gate /* Call psm_ops() to translate irq with the dip */ 3151*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3152*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3153*7c478bd9Sstevel@tonic-gate 3154*7c478bd9Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 3155*7c478bd9Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 3156*7c478bd9Sstevel@tonic-gate PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector); 3157*7c478bd9Sstevel@tonic-gate 3158*7c478bd9Sstevel@tonic-gate /* Remove the interrupt handler */ 3159*7c478bd9Sstevel@tonic-gate rem_avintr((void *)hdlp, ispec->intrspec_pri, 3160*7c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_vector); 3161*7c478bd9Sstevel@tonic-gate break; 3162*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 3163*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3164*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3165*7c478bd9Sstevel@tonic-gate 3166*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL)) 3167*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3168*7c478bd9Sstevel@tonic-gate break; 3169*7c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 3170*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3171*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3172*7c478bd9Sstevel@tonic-gate 3173*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL)) 3174*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3175*7c478bd9Sstevel@tonic-gate break; 3176*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 3177*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) 3178*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3179*7c478bd9Sstevel@tonic-gate 3180*7c478bd9Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING, 3181*7c478bd9Sstevel@tonic-gate result)) { 3182*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 3183*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3184*7c478bd9Sstevel@tonic-gate } 3185*7c478bd9Sstevel@tonic-gate break; 3186*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 3187*7c478bd9Sstevel@tonic-gate if ((pdp = ddi_get_parent_data(rdip)) == NULL) 3188*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3189*7c478bd9Sstevel@tonic-gate *(int *)result = pdp->par_nintr; 3190*7c478bd9Sstevel@tonic-gate if (pdp->par_nintr == 0) { 3191*7c478bd9Sstevel@tonic-gate /* 3192*7c478bd9Sstevel@tonic-gate * Special case for 'pcic' driver' only. This driver 3193*7c478bd9Sstevel@tonic-gate * driver is a child of 'isa' and 'rootnex' drivers. 3194*7c478bd9Sstevel@tonic-gate * 3195*7c478bd9Sstevel@tonic-gate * See detailed comments on this in the function 3196*7c478bd9Sstevel@tonic-gate * rootnex_get_ispec(). 3197*7c478bd9Sstevel@tonic-gate * 3198*7c478bd9Sstevel@tonic-gate * Children of 'pcic' send 'NINITR' request all the 3199*7c478bd9Sstevel@tonic-gate * way to rootnex driver. But, the 'pdp->par_nintr' 3200*7c478bd9Sstevel@tonic-gate * field may not initialized. So, we fake it here 3201*7c478bd9Sstevel@tonic-gate * to return 1 (a la what PCMCIA nexus does). 3202*7c478bd9Sstevel@tonic-gate */ 3203*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(rdip), "pcic") == 0) 3204*7c478bd9Sstevel@tonic-gate *(int *)result = 1; 3205*7c478bd9Sstevel@tonic-gate } 3206*7c478bd9Sstevel@tonic-gate break; 3207*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 3208*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 3209*7c478bd9Sstevel@tonic-gate *(int *)result |= DDI_INTR_TYPE_FIXED; /* Always ... */ 3210*7c478bd9Sstevel@tonic-gate break; 3211*7c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 3212*7c478bd9Sstevel@tonic-gate if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL) 3213*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3214*7c478bd9Sstevel@tonic-gate 3215*7c478bd9Sstevel@tonic-gate if (psm_intr_ops == NULL) { 3216*7c478bd9Sstevel@tonic-gate *(int *)result = 1; 3217*7c478bd9Sstevel@tonic-gate break; 3218*7c478bd9Sstevel@tonic-gate } 3219*7c478bd9Sstevel@tonic-gate 3220*7c478bd9Sstevel@tonic-gate /* Priority in the handle not initialized yet */ 3221*7c478bd9Sstevel@tonic-gate hdlp->ih_pri = ispec->intrspec_pri; 3222*7c478bd9Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 3223*7c478bd9Sstevel@tonic-gate PSM_INTR_OP_NAVAIL_VECTORS, result); 3224*7c478bd9Sstevel@tonic-gate break; 3225*7c478bd9Sstevel@tonic-gate default: 3226*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3227*7c478bd9Sstevel@tonic-gate } 3228*7c478bd9Sstevel@tonic-gate 3229*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3230*7c478bd9Sstevel@tonic-gate } 3231*7c478bd9Sstevel@tonic-gate 3232*7c478bd9Sstevel@tonic-gate 3233*7c478bd9Sstevel@tonic-gate /* 3234*7c478bd9Sstevel@tonic-gate * Get the physical address of an object described by "dmareq". 3235*7c478bd9Sstevel@tonic-gate * A "segsize" of zero is used to initialize the priv_handle *php. 3236*7c478bd9Sstevel@tonic-gate * Subsequent calls with a non zero "segsize" would get the corresponding 3237*7c478bd9Sstevel@tonic-gate * physical address of the dma object. 3238*7c478bd9Sstevel@tonic-gate * The function returns a 64 bit physical address. 3239*7c478bd9Sstevel@tonic-gate */ 3240*7c478bd9Sstevel@tonic-gate uint64_t 3241*7c478bd9Sstevel@tonic-gate rootnex_get_phyaddr(struct ddi_dma_req *dmareq, uint_t segsize, 3242*7c478bd9Sstevel@tonic-gate struct priv_handle *php) 3243*7c478bd9Sstevel@tonic-gate { 3244*7c478bd9Sstevel@tonic-gate size_t offset; 3245*7c478bd9Sstevel@tonic-gate page_t *pp, **pplist; 3246*7c478bd9Sstevel@tonic-gate caddr_t vaddr, bvaddr; 3247*7c478bd9Sstevel@tonic-gate struct as *asp; 3248*7c478bd9Sstevel@tonic-gate int index; 3249*7c478bd9Sstevel@tonic-gate uint64_t segmentpadr; 3250*7c478bd9Sstevel@tonic-gate 3251*7c478bd9Sstevel@tonic-gate switch (dmareq->dmar_object.dmao_type) { 3252*7c478bd9Sstevel@tonic-gate case DMA_OTYP_PAGES: 3253*7c478bd9Sstevel@tonic-gate if (segsize) { 3254*7c478bd9Sstevel@tonic-gate pp = php->ph_u.pp; 3255*7c478bd9Sstevel@tonic-gate vaddr = php->ph_vaddr; 3256*7c478bd9Sstevel@tonic-gate offset = (uintptr_t)vaddr & MMU_PAGEOFFSET; 3257*7c478bd9Sstevel@tonic-gate vaddr += segsize; 3258*7c478bd9Sstevel@tonic-gate if ((offset += segsize) >= MMU_PAGESIZE) { 3259*7c478bd9Sstevel@tonic-gate /* 3260*7c478bd9Sstevel@tonic-gate * crossed page boundary, get to the next page. 3261*7c478bd9Sstevel@tonic-gate */ 3262*7c478bd9Sstevel@tonic-gate offset &= MMU_PAGEOFFSET; 3263*7c478bd9Sstevel@tonic-gate pp = pp->p_next; 3264*7c478bd9Sstevel@tonic-gate } 3265*7c478bd9Sstevel@tonic-gate } else { 3266*7c478bd9Sstevel@tonic-gate /* 3267*7c478bd9Sstevel@tonic-gate * Initialize the priv_handle structure. 3268*7c478bd9Sstevel@tonic-gate */ 3269*7c478bd9Sstevel@tonic-gate pp = dmareq->dmar_object.dmao_obj.pp_obj.pp_pp; 3270*7c478bd9Sstevel@tonic-gate offset = dmareq->dmar_object.dmao_obj.pp_obj.pp_offset; 3271*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)offset; 3272*7c478bd9Sstevel@tonic-gate php->ph_mapinfo = DMAMI_PAGES; 3273*7c478bd9Sstevel@tonic-gate } 3274*7c478bd9Sstevel@tonic-gate php->ph_u.pp = pp; 3275*7c478bd9Sstevel@tonic-gate php->ph_vaddr = vaddr; 3276*7c478bd9Sstevel@tonic-gate segmentpadr = (uint64_t)offset + ptob64(page_pptonum(pp)); 3277*7c478bd9Sstevel@tonic-gate break; 3278*7c478bd9Sstevel@tonic-gate case DMA_OTYP_VADDR: 3279*7c478bd9Sstevel@tonic-gate case DMA_OTYP_BUFVADDR: 3280*7c478bd9Sstevel@tonic-gate if (segsize) { 3281*7c478bd9Sstevel@tonic-gate asp = php->ph_u.asp; 3282*7c478bd9Sstevel@tonic-gate vaddr = php->ph_vaddr; 3283*7c478bd9Sstevel@tonic-gate vaddr += segsize; 3284*7c478bd9Sstevel@tonic-gate } else { 3285*7c478bd9Sstevel@tonic-gate /* 3286*7c478bd9Sstevel@tonic-gate * Initialize the priv_handle structure. 3287*7c478bd9Sstevel@tonic-gate */ 3288*7c478bd9Sstevel@tonic-gate vaddr = dmareq->dmar_object.dmao_obj.virt_obj.v_addr; 3289*7c478bd9Sstevel@tonic-gate asp = dmareq->dmar_object.dmao_obj.virt_obj.v_as; 3290*7c478bd9Sstevel@tonic-gate if (asp == NULL) { 3291*7c478bd9Sstevel@tonic-gate php->ph_mapinfo = DMAMI_KVADR; 3292*7c478bd9Sstevel@tonic-gate asp = &kas; 3293*7c478bd9Sstevel@tonic-gate } else { 3294*7c478bd9Sstevel@tonic-gate php->ph_mapinfo = DMAMI_UVADR; 3295*7c478bd9Sstevel@tonic-gate } 3296*7c478bd9Sstevel@tonic-gate php->ph_u.asp = asp; 3297*7c478bd9Sstevel@tonic-gate } 3298*7c478bd9Sstevel@tonic-gate pplist = dmareq->dmar_object.dmao_obj.virt_obj.v_priv; 3299*7c478bd9Sstevel@tonic-gate offset = (uintptr_t)vaddr & MMU_PAGEOFFSET; 3300*7c478bd9Sstevel@tonic-gate if (pplist == NULL) { 3301*7c478bd9Sstevel@tonic-gate segmentpadr = (uint64_t)offset + 3302*7c478bd9Sstevel@tonic-gate ptob64(hat_getpfnum(asp->a_hat, vaddr)); 3303*7c478bd9Sstevel@tonic-gate } else { 3304*7c478bd9Sstevel@tonic-gate bvaddr = dmareq->dmar_object.dmao_obj.virt_obj.v_addr; 3305*7c478bd9Sstevel@tonic-gate index = btop(((ulong_t)bvaddr & MMU_PAGEOFFSET) + 3306*7c478bd9Sstevel@tonic-gate vaddr - bvaddr); 3307*7c478bd9Sstevel@tonic-gate segmentpadr = (uint64_t)offset + 3308*7c478bd9Sstevel@tonic-gate ptob64(page_pptonum(pplist[index])); 3309*7c478bd9Sstevel@tonic-gate } 3310*7c478bd9Sstevel@tonic-gate php->ph_vaddr = vaddr; 3311*7c478bd9Sstevel@tonic-gate break; 3312*7c478bd9Sstevel@tonic-gate default: 3313*7c478bd9Sstevel@tonic-gate panic("rootnex_get_phyaddr"); 3314*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3315*7c478bd9Sstevel@tonic-gate } 3316*7c478bd9Sstevel@tonic-gate return (segmentpadr); 3317*7c478bd9Sstevel@tonic-gate } 3318