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*d0662dbfSelowe * Common Development and Distribution License (the "License"). 6*d0662dbfSelowe * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*d0662dbfSelowe * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * PCI nexus DVMA relocation routines. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * These routines handle the interactions with the HAT layer to 327c478bd9Sstevel@tonic-gate * implement page relocation for page(s) which have active DMA handle 337c478bd9Sstevel@tonic-gate * bindings when DVMA is being used for those handles. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * The current modus operandi is as follows: 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Object binding: register the appropriate callback for each page 387c478bd9Sstevel@tonic-gate * of the kernel object while obtaining the PFN for the DVMA page. 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * Object unbinding: unregister the callback for each page of the 417c478bd9Sstevel@tonic-gate * kernel object. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * Relocation request: 447c478bd9Sstevel@tonic-gate * 1) Suspend the bus and sync the caches. 457c478bd9Sstevel@tonic-gate * 2) Remap the DVMA object using the new provided PFN. 467c478bd9Sstevel@tonic-gate * 3) Unsuspend the bus. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * The relocation code runs with CPUs captured (idling in xc_loop()) 497c478bd9Sstevel@tonic-gate * so we can only acquire spinlocks at PIL >= 13 for synchronization 507c478bd9Sstevel@tonic-gate * within those codepaths. 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate #include <sys/types.h> 537c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 547c478bd9Sstevel@tonic-gate #include <sys/async.h> 557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 567c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 587c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 597c478bd9Sstevel@tonic-gate #include <sys/dvma.h> 607c478bd9Sstevel@tonic-gate #include <vm/hat.h> 617c478bd9Sstevel@tonic-gate #include <sys/pci/pci_obj.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate void 667c478bd9Sstevel@tonic-gate pci_dvma_unregister_callbacks(pci_t *pci_p, ddi_dma_impl_t *mp) 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate ddi_dma_obj_t *dobj_p = &mp->dmai_object; 697c478bd9Sstevel@tonic-gate struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as; 707c478bd9Sstevel@tonic-gate page_t **pplist = dobj_p->dmao_obj.virt_obj.v_priv; 717c478bd9Sstevel@tonic-gate caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr; 727c478bd9Sstevel@tonic-gate struct hat *hat_p; 737c478bd9Sstevel@tonic-gate uint32_t offset; 747c478bd9Sstevel@tonic-gate int i; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate if (!PCI_DMA_CANRELOC(mp)) 777c478bd9Sstevel@tonic-gate return; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate hat_p = (as_p == NULL)? kas.a_hat : as_p->a_hat; 807c478bd9Sstevel@tonic-gate ASSERT(hat_p == kas.a_hat); 817c478bd9Sstevel@tonic-gate ASSERT(pplist == NULL); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate offset = mp->dmai_roffset; 84*d0662dbfSelowe hat_delete_callback(vaddr, IOMMU_PAGE_SIZE - offset, mp, HAC_PAGELOCK, 85*d0662dbfSelowe MP_HAT_CB_COOKIE(mp, 0)); 867c478bd9Sstevel@tonic-gate vaddr = (caddr_t)(((uintptr_t)vaddr + IOMMU_PAGE_SIZE) & 877c478bd9Sstevel@tonic-gate IOMMU_PAGE_MASK); 887c478bd9Sstevel@tonic-gate for (i = 1; i < mp->dmai_ndvmapages; i++) { 89*d0662dbfSelowe hat_delete_callback(vaddr, IOMMU_PAGE_SIZE, mp, HAC_PAGELOCK, 90*d0662dbfSelowe MP_HAT_CB_COOKIE(mp, i)); 917c478bd9Sstevel@tonic-gate vaddr += IOMMU_PAGE_SIZE; 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate mp->dmai_flags &= ~DMAI_FLAGS_RELOC; 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate static int 977c478bd9Sstevel@tonic-gate pci_dvma_postrelocator(caddr_t va, uint_t len, uint_t flags, void *mpvoid, 987c478bd9Sstevel@tonic-gate pfn_t newpfn) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)mpvoid; 1017c478bd9Sstevel@tonic-gate dev_info_t *rdip = mp->dmai_rdip; 1027c478bd9Sstevel@tonic-gate ddi_dma_obj_t *dobj_p = &mp->dmai_object; 1037c478bd9Sstevel@tonic-gate page_t **pplist = dobj_p->dmao_obj.virt_obj.v_priv; 1047c478bd9Sstevel@tonic-gate caddr_t baseva = dobj_p->dmao_obj.virt_obj.v_addr; 1057c478bd9Sstevel@tonic-gate int index; 1067c478bd9Sstevel@tonic-gate size_t length = IOMMU_PTOB(1); 1077c478bd9Sstevel@tonic-gate off_t offset; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate DEBUG0(DBG_RELOC, rdip, "postrelocator called\n"); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if (flags == HAT_POSTUNSUSPEND) { 1127c478bd9Sstevel@tonic-gate mutex_enter(&pci_reloc_mutex); 1137c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_thread == curthread); 1147c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_presuspend > 0); 1157c478bd9Sstevel@tonic-gate if (--pci_reloc_presuspend == 0) { 1167c478bd9Sstevel@tonic-gate pci_reloc_thread = NULL; 1177c478bd9Sstevel@tonic-gate cv_broadcast(&pci_reloc_cv); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate mutex_exit(&pci_reloc_mutex); 1207c478bd9Sstevel@tonic-gate return (0); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate ASSERT(flags == HAT_UNSUSPEND); 1247c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_suspend > 0); 1257c478bd9Sstevel@tonic-gate pci_reloc_suspend--; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate ASSERT(len <= length); 1287c478bd9Sstevel@tonic-gate ASSERT(pplist == NULL); /* addr bind handle only */ 1297c478bd9Sstevel@tonic-gate ASSERT(dobj_p->dmao_obj.virt_obj.v_as == &kas || 1307c478bd9Sstevel@tonic-gate dobj_p->dmao_obj.virt_obj.v_as == NULL); 1317c478bd9Sstevel@tonic-gate ASSERT(PCI_DMA_ISDVMA(mp)); 1327c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_thread == curthread); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate offset = va - baseva; 1357c478bd9Sstevel@tonic-gate index = IOMMU_BTOPR(offset); 1367c478bd9Sstevel@tonic-gate ASSERT(index < mp->dmai_ndvmapages); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate DEBUG3(DBG_RELOC, rdip, "index 0x%x, vaddr 0x%llx, baseva 0x%llx\n", 1397c478bd9Sstevel@tonic-gate index, (int64_t)va, (int64_t)baseva); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate if ((mp)->dmai_ndvmapages == 1) { 1427c478bd9Sstevel@tonic-gate DEBUG2(DBG_RELOC, rdip, "pfn remap (1) 0x%x -> 0x%x\n", 1437c478bd9Sstevel@tonic-gate mp->dmai_pfnlst, newpfn); 1447c478bd9Sstevel@tonic-gate mp->dmai_pfnlst = (void *)newpfn; 1457c478bd9Sstevel@tonic-gate } else { 1467c478bd9Sstevel@tonic-gate DEBUG3(DBG_RELOC, rdip, "pfn remap (%d) 0x%x -> 0x%x\n", 1477c478bd9Sstevel@tonic-gate index, ((iopfn_t *)mp->dmai_pfnlst)[index], newpfn); 1487c478bd9Sstevel@tonic-gate ((iopfn_t *)mp->dmai_pfnlst)[index] = (iopfn_t)newpfn; 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate if (ddi_dma_mctl(rdip, rdip, (ddi_dma_handle_t)mp, DDI_DMA_REMAP, 1527c478bd9Sstevel@tonic-gate &offset, &length, NULL, 0) != DDI_SUCCESS) 1537c478bd9Sstevel@tonic-gate return (EIO); 1547c478bd9Sstevel@tonic-gate if (ddi_ctlops(rdip, rdip, DDI_CTLOPS_UNQUIESCE, NULL, NULL) != 1557c478bd9Sstevel@tonic-gate DDI_SUCCESS) 1567c478bd9Sstevel@tonic-gate return (EIO); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate return (0); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * Log a warning message if a callback is still registered on 1637c478bd9Sstevel@tonic-gate * a page which is being freed. This is indicative of a driver 1647c478bd9Sstevel@tonic-gate * bug -- DMA handles are bound, and the memory is being freed by 1657c478bd9Sstevel@tonic-gate * the VM subsystem without an unbind call on the handle first. 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate static int 1687c478bd9Sstevel@tonic-gate pci_dma_relocerr(caddr_t va, uint_t len, uint_t errorcode, void *mpvoid) 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate int errlevel = pci_dma_panic_on_leak? CE_PANIC : CE_WARN; 1717c478bd9Sstevel@tonic-gate if (errorcode == HAT_CB_ERR_LEAKED) { 1727c478bd9Sstevel@tonic-gate cmn_err(errlevel, "object 0x%p has a bound DMA handle 0x%p\n", 1737c478bd9Sstevel@tonic-gate va, mpvoid); 1747c478bd9Sstevel@tonic-gate return (0); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* unknown error code, unhandled so panic */ 1787c478bd9Sstevel@tonic-gate return (EINVAL); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * pci DVMA remap entry points 1837c478bd9Sstevel@tonic-gate * 1847c478bd9Sstevel@tonic-gate * Called in response to a DDI_DMA_REMAP DMA ctlops command. 1857c478bd9Sstevel@tonic-gate * Remaps the region specified in the underlying IOMMU. Safe 1867c478bd9Sstevel@tonic-gate * to assume that the bus was quiesced and ddi_dma_sync() was 1877c478bd9Sstevel@tonic-gate * invoked by the caller before we got to this point. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate pci_dvma_remap(dev_info_t *dip, dev_info_t *rdip, ddi_dma_impl_t *mp, 1917c478bd9Sstevel@tonic-gate off_t offset, size_t length) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 1947c478bd9Sstevel@tonic-gate iommu_t *iommu_p = pci_p->pci_iommu_p; 1957c478bd9Sstevel@tonic-gate dvma_addr_t dvma_pg; 1967c478bd9Sstevel@tonic-gate size_t npgs; 1977c478bd9Sstevel@tonic-gate int idx; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate dvma_pg = IOMMU_BTOP(mp->dmai_mapping); 2007c478bd9Sstevel@tonic-gate idx = IOMMU_BTOPR(offset); 2017c478bd9Sstevel@tonic-gate dvma_pg += idx; 2027c478bd9Sstevel@tonic-gate npgs = IOMMU_BTOPR(length); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate DEBUG3(DBG_RELOC, mp->dmai_rdip, 2057c478bd9Sstevel@tonic-gate "pci_dvma_remap: dvma_pg 0x%llx len 0x%llx idx 0x%x\n", 2067c478bd9Sstevel@tonic-gate dvma_pg, length, idx); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate ASSERT(pci_p->pci_pbm_p->pbm_quiesce_count > 0); 2097c478bd9Sstevel@tonic-gate iommu_remap_pages(iommu_p, mp, dvma_pg, npgs, idx); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate void 2157c478bd9Sstevel@tonic-gate pci_fdvma_remap(ddi_dma_impl_t *mp, caddr_t kvaddr, dvma_addr_t dvma_pg, 2167c478bd9Sstevel@tonic-gate size_t npages, size_t index, pfn_t newpfn) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate fdvma_t *fdvma_p = (fdvma_t *)mp->dmai_fdvma; 2197c478bd9Sstevel@tonic-gate pci_t *pci_p = (pci_t *)fdvma_p->softsp; 2207c478bd9Sstevel@tonic-gate iommu_t *iommu_p = pci_p->pci_iommu_p; 2217c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 2227c478bd9Sstevel@tonic-gate iopfn_t pfn = (iopfn_t)newpfn; 2237c478bd9Sstevel@tonic-gate dvma_addr_t pg_index = dvma_pg - iommu_p->dvma_base_pg; 2247c478bd9Sstevel@tonic-gate int i; 2257c478bd9Sstevel@tonic-gate uint64_t tte; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* make sure we don't exceed reserved boundary */ 2287c478bd9Sstevel@tonic-gate DEBUG3(DBG_FAST_DVMA, dip, "fast remap index=%x: %p, npgs=%x", index, 2297c478bd9Sstevel@tonic-gate kvaddr, npages); 2307c478bd9Sstevel@tonic-gate if (index + npages > mp->dmai_ndvmapages) { 2317c478bd9Sstevel@tonic-gate cmn_err(pci_panic_on_fatal_errors ? CE_PANIC : CE_WARN, 232f47a9c50Smathue "%s%d: fdvma remap index(%lx)+pgs(%lx) exceeds limit\n", 2337c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 2347c478bd9Sstevel@tonic-gate index, npages); 2357c478bd9Sstevel@tonic-gate return; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate for (i = 0; i < npages; i++, kvaddr += IOMMU_PAGE_SIZE) { 2397c478bd9Sstevel@tonic-gate DEBUG3(DBG_FAST_DVMA, dip, "remap dvma_pg %x -> pfn %x," 2407c478bd9Sstevel@tonic-gate " old tte 0x%llx\n", dvma_pg + i, pfn, 2417c478bd9Sstevel@tonic-gate iommu_p->iommu_tsb_vaddr[pg_index + i]); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (pfn == PFN_INVALID) 2447c478bd9Sstevel@tonic-gate goto bad_pfn; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if (i == 0) 2477c478bd9Sstevel@tonic-gate tte = MAKE_TTE_TEMPLATE(pfn, mp); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* XXX assumes iommu and mmu has same page size */ 2507c478bd9Sstevel@tonic-gate iommu_p->iommu_tsb_vaddr[pg_index + i] = tte | IOMMU_PTOB(pfn); 2517c478bd9Sstevel@tonic-gate IOMMU_PAGE_FLUSH(iommu_p, (dvma_pg + i)); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate return; 2547c478bd9Sstevel@tonic-gate bad_pfn: 2557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: fdvma remap can't get page frame for vaddr %p", 2567c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), kvaddr); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate static int 2607c478bd9Sstevel@tonic-gate pci_fdvma_prerelocator(caddr_t va, uint_t len, uint_t flags, void *mpvoid) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)mpvoid; 2637c478bd9Sstevel@tonic-gate fdvma_t *fdvma_p = (fdvma_t *)mp->dmai_fdvma; 2647c478bd9Sstevel@tonic-gate caddr_t baseva, endva; 2657c478bd9Sstevel@tonic-gate int i; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * It isn't safe to do relocation if all of the IOMMU 2697c478bd9Sstevel@tonic-gate * mappings haven't yet been established at this index. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate for (i = 0; i < mp->dmai_ndvmapages; i++) { 2727c478bd9Sstevel@tonic-gate baseva = fdvma_p->kvbase[i]; 2737c478bd9Sstevel@tonic-gate endva = baseva + IOMMU_PTOB(fdvma_p->pagecnt[i]); 2747c478bd9Sstevel@tonic-gate if (va >= baseva && va < endva) 2757c478bd9Sstevel@tonic-gate return (0); /* found a valid index */ 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate return (EAGAIN); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate static int 2817c478bd9Sstevel@tonic-gate pci_fdvma_postrelocator(caddr_t va, uint_t len, uint_t flags, void *mpvoid, 2827c478bd9Sstevel@tonic-gate pfn_t pfn) 2837c478bd9Sstevel@tonic-gate { 2847c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)mpvoid; 2857c478bd9Sstevel@tonic-gate dev_info_t *rdip = mp->dmai_rdip; 2867c478bd9Sstevel@tonic-gate fdvma_t *fdvma_p = (fdvma_t *)mp->dmai_fdvma; 2877c478bd9Sstevel@tonic-gate caddr_t baseva; 2887c478bd9Sstevel@tonic-gate dvma_addr_t dvma_pg; 2897c478bd9Sstevel@tonic-gate size_t length = PAGESIZE; 2907c478bd9Sstevel@tonic-gate int i; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate DEBUG0(DBG_RELOC, rdip, "fdvma postrelocator called\n"); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (flags == HAT_POSTUNSUSPEND) { 2957c478bd9Sstevel@tonic-gate mutex_enter(&pci_reloc_mutex); 2967c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_thread == curthread); 2977c478bd9Sstevel@tonic-gate if (--pci_reloc_presuspend == 0) { 2987c478bd9Sstevel@tonic-gate pci_reloc_thread = NULL; 2997c478bd9Sstevel@tonic-gate cv_broadcast(&pci_reloc_cv); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate mutex_exit(&pci_reloc_mutex); 3027c478bd9Sstevel@tonic-gate return (0); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate pci_reloc_suspend--; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate ASSERT(flags == HAT_UNSUSPEND); 3087c478bd9Sstevel@tonic-gate ASSERT(len <= length); 3097c478bd9Sstevel@tonic-gate ASSERT((mp->dmai_rflags & DMP_BYPASSNEXUS) != 0); 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * This virtual page can have multiple cookies that refer 3137c478bd9Sstevel@tonic-gate * to it within the same handle. We must walk the whole 3147c478bd9Sstevel@tonic-gate * table for this DMA handle finding all the cookies, and 3157c478bd9Sstevel@tonic-gate * update all of them. Sigh. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate for (i = 0; i < mp->dmai_ndvmapages; i++) { 3187c478bd9Sstevel@tonic-gate caddr_t endva; 3197c478bd9Sstevel@tonic-gate int index; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate baseva = fdvma_p->kvbase[i]; 3227c478bd9Sstevel@tonic-gate endva = baseva + IOMMU_PTOB(fdvma_p->pagecnt[i]); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (va >= baseva && va < endva) { 3257c478bd9Sstevel@tonic-gate index = i + IOMMU_BTOP(va - baseva); 3267c478bd9Sstevel@tonic-gate ASSERT(index < mp->dmai_ndvmapages); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate DEBUG4(DBG_RELOC, rdip, "mp %p: index 0x%x, " 3297c478bd9Sstevel@tonic-gate " vaddr 0x%llx, baseva 0x%llx\n", mp, index, 3307c478bd9Sstevel@tonic-gate (int64_t)va, (int64_t)baseva); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate dvma_pg = IOMMU_BTOP(mp->dmai_mapping) + index; 3337c478bd9Sstevel@tonic-gate pci_fdvma_remap(mp, va, dvma_pg, IOMMU_BTOP(length), 3347c478bd9Sstevel@tonic-gate index, pfn); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (ddi_ctlops(rdip, rdip, DDI_CTLOPS_UNQUIESCE, NULL, NULL) != 3397c478bd9Sstevel@tonic-gate DDI_SUCCESS) 3407c478bd9Sstevel@tonic-gate return (EIO); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate return (0); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate void 3467c478bd9Sstevel@tonic-gate pci_fdvma_unregister_callbacks(pci_t *pci_p, fdvma_t *fdvma_p, 3477c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp, uint_t index) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate size_t npgs = fdvma_p->pagecnt[index]; 3507c478bd9Sstevel@tonic-gate caddr_t kva = fdvma_p->kvbase[index]; 3517c478bd9Sstevel@tonic-gate int i; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate ASSERT(index + npgs <= mp->dmai_ndvmapages); 3547c478bd9Sstevel@tonic-gate ASSERT(kva != NULL); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate for (i = 0; i < npgs && pci_dvma_remap_enabled; 3577c478bd9Sstevel@tonic-gate i++, kva += IOMMU_PAGE_SIZE) 358*d0662dbfSelowe hat_delete_callback(kva, IOMMU_PAGE_SIZE, mp, HAC_PAGELOCK, 359*d0662dbfSelowe fdvma_p->cbcookie[index + i]); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate static int 3637c478bd9Sstevel@tonic-gate pci_common_prerelocator(caddr_t va, uint_t len, uint_t flags, void *mpvoid) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)mpvoid; 3667c478bd9Sstevel@tonic-gate ddi_dma_handle_t h = (ddi_dma_handle_t)mpvoid; 3677c478bd9Sstevel@tonic-gate dev_info_t *rdip = mp->dmai_rdip; 3687c478bd9Sstevel@tonic-gate int ret; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate DEBUG0(DBG_RELOC, rdip, "prerelocator called\n"); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (flags == HAT_PRESUSPEND) { 3737c478bd9Sstevel@tonic-gate if (!ddi_prop_exists(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM, 3747c478bd9Sstevel@tonic-gate "dvma-remap-supported")) 3757c478bd9Sstevel@tonic-gate return (ENOTSUP); 3767c478bd9Sstevel@tonic-gate if (!PCI_DMA_ISMAPPED(mp)) 3777c478bd9Sstevel@tonic-gate return (EAGAIN); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (mp->dmai_rflags & DMP_BYPASSNEXUS) { 3807c478bd9Sstevel@tonic-gate ret = pci_fdvma_prerelocator(va, len, flags, mpvoid); 3817c478bd9Sstevel@tonic-gate if (ret != 0) 3827c478bd9Sstevel@tonic-gate return (ret); 3837c478bd9Sstevel@tonic-gate } else if (!PCI_DMA_ISDVMA(mp)) 3847c478bd9Sstevel@tonic-gate return (EINVAL); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Acquire the exclusive right to relocate a PCI DMA page, 3887c478bd9Sstevel@tonic-gate * since we later have to pause CPUs which could otherwise 3897c478bd9Sstevel@tonic-gate * lead to all sorts of synchronization headaches. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate mutex_enter(&pci_reloc_mutex); 3927c478bd9Sstevel@tonic-gate if (pci_reloc_thread != curthread) { 3937c478bd9Sstevel@tonic-gate while (pci_reloc_thread != NULL) { 3947c478bd9Sstevel@tonic-gate cv_wait(&pci_reloc_cv, &pci_reloc_mutex); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate pci_reloc_thread = curthread; 3977c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_suspend == 0); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate mutex_exit(&pci_reloc_mutex); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_thread == curthread); 4027c478bd9Sstevel@tonic-gate pci_reloc_presuspend++; 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate return (0); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate ASSERT(flags == HAT_SUSPEND); 4087c478bd9Sstevel@tonic-gate ASSERT(PCI_DMA_CANRELOC(mp)); 4097c478bd9Sstevel@tonic-gate ASSERT(pci_reloc_thread == curthread); 4107c478bd9Sstevel@tonic-gate pci_reloc_suspend++; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate if (ddi_ctlops(rdip, rdip, DDI_CTLOPS_QUIESCE, NULL, NULL) != 4137c478bd9Sstevel@tonic-gate DDI_SUCCESS) 4147c478bd9Sstevel@tonic-gate return (EIO); 4157c478bd9Sstevel@tonic-gate if (ddi_dma_sync(h, 0, 0, DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) 4167c478bd9Sstevel@tonic-gate return (EIO); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate return (0); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* 4227c478bd9Sstevel@tonic-gate * Register two callback types: one for normal DVMA and the 4237c478bd9Sstevel@tonic-gate * other for fast DVMA, since each method has a different way 4247c478bd9Sstevel@tonic-gate * of tracking the PFNs behind a handle. 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate void 4277c478bd9Sstevel@tonic-gate pci_reloc_init(void) 4287c478bd9Sstevel@tonic-gate { 429*d0662dbfSelowe int key = pci_reloc_getkey(); 430*d0662dbfSelowe 4317c478bd9Sstevel@tonic-gate mutex_init(&pci_reloc_mutex, NULL, MUTEX_DEFAULT, NULL); 4327c478bd9Sstevel@tonic-gate cv_init(&pci_reloc_cv, NULL, CV_DEFAULT, NULL); 433*d0662dbfSelowe pci_dvma_cbid = hat_register_callback( 434*d0662dbfSelowe key + ('D'<<24 | 'V'<<16 | 'M'<<8 | 'A'), 4351bd5c35fSelowe pci_common_prerelocator, pci_dvma_postrelocator, 4361bd5c35fSelowe pci_dma_relocerr, 1); 4371bd5c35fSelowe pci_fast_dvma_cbid = hat_register_callback( 438*d0662dbfSelowe key + ('F'<<24 | 'D'<<16 | 'M'<<8 | 'A'), 439*d0662dbfSelowe pci_common_prerelocator, 4407c478bd9Sstevel@tonic-gate pci_fdvma_postrelocator, pci_dma_relocerr, 1); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate void 4447c478bd9Sstevel@tonic-gate pci_reloc_fini(void) 4457c478bd9Sstevel@tonic-gate { 4467c478bd9Sstevel@tonic-gate cv_destroy(&pci_reloc_cv); 4477c478bd9Sstevel@tonic-gate mutex_destroy(&pci_reloc_mutex); 4487c478bd9Sstevel@tonic-gate } 449