10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1106Smrj * Common Development and Distribution License (the "License"). 6*1106Smrj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*1106Smrj 220Sstevel@tonic-gate /* 23*1106Smrj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/param.h> 310Sstevel@tonic-gate #include <sys/systm.h> 320Sstevel@tonic-gate #include <sys/kmem.h> 330Sstevel@tonic-gate #include <sys/cpu.h> 340Sstevel@tonic-gate #include <sys/sunddi.h> 350Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 360Sstevel@tonic-gate #include <sys/pte.h> 370Sstevel@tonic-gate #include <sys/machsystm.h> 380Sstevel@tonic-gate #include <sys/mmu.h> 390Sstevel@tonic-gate #include <sys/dvma.h> 400Sstevel@tonic-gate #include <sys/debug.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define HD ((ddi_dma_impl_t *)h)->dmai_rdip 430Sstevel@tonic-gate 440Sstevel@tonic-gate unsigned long 450Sstevel@tonic-gate dvma_pagesize(dev_info_t *dip) 460Sstevel@tonic-gate { 470Sstevel@tonic-gate auto unsigned long dvmapgsz; 480Sstevel@tonic-gate 490Sstevel@tonic-gate (void) ddi_ctlops(dip, dip, DDI_CTLOPS_DVMAPAGESIZE, 500Sstevel@tonic-gate NULL, (void *) &dvmapgsz); 510Sstevel@tonic-gate return (dvmapgsz); 520Sstevel@tonic-gate } 530Sstevel@tonic-gate 540Sstevel@tonic-gate int 550Sstevel@tonic-gate dvma_reserve(dev_info_t *dip, ddi_dma_lim_t *limp, uint_t pages, 560Sstevel@tonic-gate ddi_dma_handle_t *handlep) 570Sstevel@tonic-gate { 580Sstevel@tonic-gate auto ddi_dma_lim_t dma_lim; 590Sstevel@tonic-gate auto ddi_dma_impl_t implhdl; 600Sstevel@tonic-gate struct ddi_dma_req dmareq; 610Sstevel@tonic-gate ddi_dma_handle_t reqhdl; 620Sstevel@tonic-gate ddi_dma_impl_t *mp; 630Sstevel@tonic-gate int ret; 640Sstevel@tonic-gate 650Sstevel@tonic-gate if (limp == (ddi_dma_lim_t *)0) { 660Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 670Sstevel@tonic-gate } else { 680Sstevel@tonic-gate dma_lim = *limp; 690Sstevel@tonic-gate } 700Sstevel@tonic-gate bzero(&dmareq, sizeof (dmareq)); 710Sstevel@tonic-gate dmareq.dmar_fp = DDI_DMA_DONTWAIT; 720Sstevel@tonic-gate dmareq.dmar_flags = DDI_DMA_RDWR | DDI_DMA_STREAMING; 730Sstevel@tonic-gate dmareq.dmar_limits = &dma_lim; 740Sstevel@tonic-gate dmareq.dmar_object.dmao_size = pages; 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * pass in a dummy handle. This avoids the problem when 770Sstevel@tonic-gate * somebody is dereferencing the handle before checking 780Sstevel@tonic-gate * the operation. This can be avoided once we separate 790Sstevel@tonic-gate * handle allocation and actual operation. 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate bzero((caddr_t)&implhdl, sizeof (ddi_dma_impl_t)); 820Sstevel@tonic-gate reqhdl = (ddi_dma_handle_t)&implhdl; 830Sstevel@tonic-gate 840Sstevel@tonic-gate ret = ddi_dma_mctl(dip, dip, reqhdl, DDI_DMA_RESERVE, (off_t *)&dmareq, 850Sstevel@tonic-gate 0, (caddr_t *)handlep, 0); 860Sstevel@tonic-gate 870Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 880Sstevel@tonic-gate mp = (ddi_dma_impl_t *)(*handlep); 890Sstevel@tonic-gate if (!(mp->dmai_rflags & DMP_BYPASSNEXUS)) { 900Sstevel@tonic-gate uint_t np = mp->dmai_ndvmapages; 910Sstevel@tonic-gate 920Sstevel@tonic-gate mp->dmai_mapping = (ulong_t)kmem_alloc( 930Sstevel@tonic-gate sizeof (ddi_dma_lim_t), KM_SLEEP); 940Sstevel@tonic-gate bcopy((char *)&dma_lim, (char *)mp->dmai_mapping, 950Sstevel@tonic-gate sizeof (ddi_dma_lim_t)); 960Sstevel@tonic-gate mp->dmai_minfo = kmem_alloc( 970Sstevel@tonic-gate np * sizeof (ddi_dma_handle_t), KM_SLEEP); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate return (ret); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate void 1040Sstevel@tonic-gate dvma_release(ddi_dma_handle_t h) 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1070Sstevel@tonic-gate uint_t np = mp->dmai_ndvmapages; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate if (!(mp->dmai_rflags & DMP_BYPASSNEXUS)) { 1100Sstevel@tonic-gate kmem_free((void *)mp->dmai_mapping, sizeof (ddi_dma_lim_t)); 1110Sstevel@tonic-gate kmem_free(mp->dmai_minfo, np * sizeof (ddi_dma_handle_t)); 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate (void) ddi_dma_mctl(HD, HD, h, DDI_DMA_RELEASE, 0, 0, 0, 0); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate void 1180Sstevel@tonic-gate dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, 1190Sstevel@tonic-gate ddi_dma_cookie_t *cp) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1220Sstevel@tonic-gate struct fast_dvma *nexus_private; 1230Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 124*1106Smrj ddi_dma_attr_t dma_attr; 125*1106Smrj uint_t ccnt; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1280Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1290Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1300Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_kaddr_load)(h, a, len, index, cp); 1310Sstevel@tonic-gate } else { 1320Sstevel@tonic-gate ddi_dma_handle_t handle; 1330Sstevel@tonic-gate ddi_dma_lim_t *limp; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate limp = (ddi_dma_lim_t *)mp->dmai_mapping; 136*1106Smrj dma_attr.dma_attr_version = DMA_ATTR_V0; 137*1106Smrj dma_attr.dma_attr_addr_lo = limp->dlim_addr_lo; 138*1106Smrj dma_attr.dma_attr_addr_hi = limp->dlim_addr_hi; 139*1106Smrj dma_attr.dma_attr_count_max = limp->dlim_cntr_max; 140*1106Smrj dma_attr.dma_attr_align = 1; 141*1106Smrj dma_attr.dma_attr_burstsizes = limp->dlim_burstsizes; 142*1106Smrj dma_attr.dma_attr_minxfer = limp->dlim_minxfer; 143*1106Smrj dma_attr.dma_attr_maxxfer = 0xFFFFFFFFull; 144*1106Smrj dma_attr.dma_attr_seg = 0xFFFFFFFFull; 145*1106Smrj dma_attr.dma_attr_sgllen = 1; 146*1106Smrj dma_attr.dma_attr_granular = 1; 147*1106Smrj dma_attr.dma_attr_flags = 0; 148*1106Smrj (void) ddi_dma_alloc_handle(HD, &dma_attr, DDI_DMA_SLEEP, NULL, 149*1106Smrj &handle); 150*1106Smrj (void) ddi_dma_addr_bind_handle(handle, NULL, a, len, 151*1106Smrj DDI_DMA_RDWR, DDI_DMA_SLEEP, NULL, cp, &ccnt); 1520Sstevel@tonic-gate ((ddi_dma_handle_t *)mp->dmai_minfo)[index] = handle; 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /*ARGSUSED*/ 1570Sstevel@tonic-gate void 1580Sstevel@tonic-gate dvma_unload(ddi_dma_handle_t h, uint_t objindex, uint_t type) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1610Sstevel@tonic-gate struct fast_dvma *nexus_private; 1620Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1650Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1660Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1670Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_unload)(h, objindex, type); 1680Sstevel@tonic-gate } else { 1690Sstevel@tonic-gate ddi_dma_handle_t handle; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate handle = ((ddi_dma_handle_t *)mp->dmai_minfo)[objindex]; 172*1106Smrj (void) ddi_dma_unbind_handle(handle); 173*1106Smrj (void) ddi_dma_free_handle(&handle); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate void 1780Sstevel@tonic-gate dvma_sync(ddi_dma_handle_t h, uint_t objindex, uint_t type) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1810Sstevel@tonic-gate struct fast_dvma *nexus_private; 1820Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1850Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1860Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1870Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_sync)(h, objindex, type); 1880Sstevel@tonic-gate } else { 1890Sstevel@tonic-gate ddi_dma_handle_t handle; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate handle = ((ddi_dma_handle_t *)mp->dmai_minfo)[objindex]; 1920Sstevel@tonic-gate (void) ddi_dma_sync(handle, 0, 0, type); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate } 195