17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4ab75253Smrj * Common Development and Distribution License (the "License"). 6*4ab75253Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*4ab75253Smrj 227c478bd9Sstevel@tonic-gate /* 23*4ab75253Smrj * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/systm.h> 327c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 337c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 367c478bd9Sstevel@tonic-gate #include <sys/pte.h> 377c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 387c478bd9Sstevel@tonic-gate #include <sys/mmu.h> 397c478bd9Sstevel@tonic-gate #include <sys/dvma.h> 407c478bd9Sstevel@tonic-gate #include <sys/debug.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define HD ((ddi_dma_impl_t *)h)->dmai_rdip 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate unsigned long 457c478bd9Sstevel@tonic-gate dvma_pagesize(dev_info_t *dip) 467c478bd9Sstevel@tonic-gate { 477c478bd9Sstevel@tonic-gate auto unsigned long dvmapgsz; 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate (void) ddi_ctlops(dip, dip, DDI_CTLOPS_DVMAPAGESIZE, 507c478bd9Sstevel@tonic-gate NULL, (void *) &dvmapgsz); 517c478bd9Sstevel@tonic-gate return (dvmapgsz); 527c478bd9Sstevel@tonic-gate } 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate int 557c478bd9Sstevel@tonic-gate dvma_reserve(dev_info_t *dip, ddi_dma_lim_t *limp, uint_t pages, 567c478bd9Sstevel@tonic-gate ddi_dma_handle_t *handlep) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate auto ddi_dma_lim_t dma_lim; 597c478bd9Sstevel@tonic-gate auto ddi_dma_impl_t implhdl; 607c478bd9Sstevel@tonic-gate struct ddi_dma_req dmareq; 617c478bd9Sstevel@tonic-gate ddi_dma_handle_t reqhdl; 627c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 637c478bd9Sstevel@tonic-gate int ret; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate if (limp == (ddi_dma_lim_t *)0) { 667c478bd9Sstevel@tonic-gate return (DDI_DMA_BADLIMITS); 677c478bd9Sstevel@tonic-gate } else { 687c478bd9Sstevel@tonic-gate dma_lim = *limp; 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate bzero(&dmareq, sizeof (dmareq)); 717c478bd9Sstevel@tonic-gate dmareq.dmar_fp = DDI_DMA_DONTWAIT; 727c478bd9Sstevel@tonic-gate dmareq.dmar_flags = DDI_DMA_RDWR | DDI_DMA_STREAMING; 737c478bd9Sstevel@tonic-gate dmareq.dmar_limits = &dma_lim; 747c478bd9Sstevel@tonic-gate dmareq.dmar_object.dmao_size = pages; 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * pass in a dummy handle. This avoids the problem when 777c478bd9Sstevel@tonic-gate * somebody is dereferencing the handle before checking 787c478bd9Sstevel@tonic-gate * the operation. This can be avoided once we separate 797c478bd9Sstevel@tonic-gate * handle allocation and actual operation. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate bzero((caddr_t)&implhdl, sizeof (ddi_dma_impl_t)); 827c478bd9Sstevel@tonic-gate reqhdl = (ddi_dma_handle_t)&implhdl; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate ret = ddi_dma_mctl(dip, dip, reqhdl, DDI_DMA_RESERVE, (off_t *)&dmareq, 857c478bd9Sstevel@tonic-gate 0, (caddr_t *)handlep, 0); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 887c478bd9Sstevel@tonic-gate mp = (ddi_dma_impl_t *)(*handlep); 897c478bd9Sstevel@tonic-gate if (!(mp->dmai_rflags & DMP_BYPASSNEXUS)) { 907c478bd9Sstevel@tonic-gate uint_t np = mp->dmai_ndvmapages; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate mp->dmai_mapping = (ulong_t)kmem_alloc( 937c478bd9Sstevel@tonic-gate sizeof (ddi_dma_lim_t), KM_SLEEP); 947c478bd9Sstevel@tonic-gate bcopy((char *)&dma_lim, (char *)mp->dmai_mapping, 957c478bd9Sstevel@tonic-gate sizeof (ddi_dma_lim_t)); 967c478bd9Sstevel@tonic-gate mp->dmai_minfo = kmem_alloc( 977c478bd9Sstevel@tonic-gate np * sizeof (ddi_dma_handle_t), KM_SLEEP); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate return (ret); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate void 1047c478bd9Sstevel@tonic-gate dvma_release(ddi_dma_handle_t h) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1077c478bd9Sstevel@tonic-gate uint_t np = mp->dmai_ndvmapages; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate if (!(mp->dmai_rflags & DMP_BYPASSNEXUS)) { 1107c478bd9Sstevel@tonic-gate kmem_free((void *)mp->dmai_mapping, sizeof (ddi_dma_lim_t)); 1117c478bd9Sstevel@tonic-gate kmem_free(mp->dmai_minfo, np * sizeof (ddi_dma_handle_t)); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate (void) ddi_dma_mctl(HD, HD, h, DDI_DMA_RELEASE, 0, 0, 0, 0); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate void 1187c478bd9Sstevel@tonic-gate dvma_kaddr_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, 1197c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cp) 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1227c478bd9Sstevel@tonic-gate struct fast_dvma *nexus_private; 1237c478bd9Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 124*4ab75253Smrj ddi_dma_attr_t dma_attr; 125*4ab75253Smrj uint_t ccnt; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1287c478bd9Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1297c478bd9Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1307c478bd9Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_kaddr_load)(h, a, len, index, cp); 1317c478bd9Sstevel@tonic-gate } else { 1327c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 1337c478bd9Sstevel@tonic-gate ddi_dma_lim_t *limp; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate limp = (ddi_dma_lim_t *)mp->dmai_mapping; 136*4ab75253Smrj dma_attr.dma_attr_version = DMA_ATTR_V0; 137*4ab75253Smrj dma_attr.dma_attr_addr_lo = limp->dlim_addr_lo; 138*4ab75253Smrj dma_attr.dma_attr_addr_hi = limp->dlim_addr_hi; 139*4ab75253Smrj dma_attr.dma_attr_count_max = limp->dlim_cntr_max; 140*4ab75253Smrj dma_attr.dma_attr_align = 1; 141*4ab75253Smrj dma_attr.dma_attr_burstsizes = limp->dlim_burstsizes; 142*4ab75253Smrj dma_attr.dma_attr_minxfer = limp->dlim_minxfer; 143*4ab75253Smrj dma_attr.dma_attr_maxxfer = 0xFFFFFFFFull; 144*4ab75253Smrj dma_attr.dma_attr_seg = 0xFFFFFFFFull; 145*4ab75253Smrj dma_attr.dma_attr_sgllen = 1; 146*4ab75253Smrj dma_attr.dma_attr_granular = 1; 147*4ab75253Smrj dma_attr.dma_attr_flags = 0; 148*4ab75253Smrj (void) ddi_dma_alloc_handle(HD, &dma_attr, DDI_DMA_SLEEP, NULL, 149*4ab75253Smrj &handle); 150*4ab75253Smrj (void) ddi_dma_addr_bind_handle(handle, NULL, a, len, 151*4ab75253Smrj DDI_DMA_RDWR, DDI_DMA_SLEEP, NULL, cp, &ccnt); 1527c478bd9Sstevel@tonic-gate ((ddi_dma_handle_t *)mp->dmai_minfo)[index] = handle; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1577c478bd9Sstevel@tonic-gate void 1587c478bd9Sstevel@tonic-gate dvma_unload(ddi_dma_handle_t h, uint_t objindex, uint_t type) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1617c478bd9Sstevel@tonic-gate struct fast_dvma *nexus_private; 1627c478bd9Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1657c478bd9Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1667c478bd9Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1677c478bd9Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_unload)(h, objindex, type); 1687c478bd9Sstevel@tonic-gate } else { 1697c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate handle = ((ddi_dma_handle_t *)mp->dmai_minfo)[objindex]; 172*4ab75253Smrj (void) ddi_dma_unbind_handle(handle); 173*4ab75253Smrj (void) ddi_dma_free_handle(&handle); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate void 1787c478bd9Sstevel@tonic-gate dvma_sync(ddi_dma_handle_t h, uint_t objindex, uint_t type) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate register ddi_dma_impl_t *mp = (ddi_dma_impl_t *)h; 1817c478bd9Sstevel@tonic-gate struct fast_dvma *nexus_private; 1827c478bd9Sstevel@tonic-gate struct dvma_ops *nexus_funcptr; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 1857c478bd9Sstevel@tonic-gate nexus_private = (struct fast_dvma *)mp->dmai_nexus_private; 1867c478bd9Sstevel@tonic-gate nexus_funcptr = (struct dvma_ops *)nexus_private->ops; 1877c478bd9Sstevel@tonic-gate (void) (*nexus_funcptr->dvma_sync)(h, objindex, type); 1887c478bd9Sstevel@tonic-gate } else { 1897c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate handle = ((ddi_dma_handle_t *)mp->dmai_minfo)[objindex]; 1927c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(handle, 0, 0, type); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate } 195