1667ce33eSRob Clark /* 2667ce33eSRob Clark * Copyright (C) 2016 Red Hat 3667ce33eSRob Clark * Author: Rob Clark <robdclark@gmail.com> 4667ce33eSRob Clark * 5667ce33eSRob Clark * This program is free software; you can redistribute it and/or modify it 6667ce33eSRob Clark * under the terms of the GNU General Public License version 2 as published by 7667ce33eSRob Clark * the Free Software Foundation. 8667ce33eSRob Clark * 9667ce33eSRob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 10667ce33eSRob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11667ce33eSRob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12667ce33eSRob Clark * more details. 13667ce33eSRob Clark * 14667ce33eSRob Clark * You should have received a copy of the GNU General Public License along with 15667ce33eSRob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 16667ce33eSRob Clark */ 17667ce33eSRob Clark 18667ce33eSRob Clark #include "msm_drv.h" 19667ce33eSRob Clark #include "msm_gem.h" 20667ce33eSRob Clark #include "msm_mmu.h" 21667ce33eSRob Clark 22ee546cd3SJordan Crouse static void 23ee546cd3SJordan Crouse msm_gem_address_space_destroy(struct kref *kref) 24ee546cd3SJordan Crouse { 25ee546cd3SJordan Crouse struct msm_gem_address_space *aspace = container_of(kref, 26ee546cd3SJordan Crouse struct msm_gem_address_space, kref); 27ee546cd3SJordan Crouse 28ee546cd3SJordan Crouse drm_mm_takedown(&aspace->mm); 29ee546cd3SJordan Crouse if (aspace->mmu) 30ee546cd3SJordan Crouse aspace->mmu->funcs->destroy(aspace->mmu); 31ee546cd3SJordan Crouse kfree(aspace); 32ee546cd3SJordan Crouse } 33ee546cd3SJordan Crouse 34ee546cd3SJordan Crouse 35ee546cd3SJordan Crouse void msm_gem_address_space_put(struct msm_gem_address_space *aspace) 36ee546cd3SJordan Crouse { 37ee546cd3SJordan Crouse if (aspace) 38ee546cd3SJordan Crouse kref_put(&aspace->kref, msm_gem_address_space_destroy); 39ee546cd3SJordan Crouse } 40ee546cd3SJordan Crouse 417ad0e8cfSJordan Crouse /* Actually unmap memory for the vma */ 427ad0e8cfSJordan Crouse void msm_gem_purge_vma(struct msm_gem_address_space *aspace, 4370dc51b4SJordan Crouse struct msm_gem_vma *vma) 44667ce33eSRob Clark { 457ad0e8cfSJordan Crouse unsigned size = vma->node.size << PAGE_SHIFT; 467ad0e8cfSJordan Crouse 477ad0e8cfSJordan Crouse /* Print a message if we try to purge a vma in use */ 487ad0e8cfSJordan Crouse if (WARN_ON(vma->inuse > 0)) 49667ce33eSRob Clark return; 50667ce33eSRob Clark 517ad0e8cfSJordan Crouse /* Don't do anything if the memory isn't mapped */ 527ad0e8cfSJordan Crouse if (!vma->mapped) 537ad0e8cfSJordan Crouse return; 547ad0e8cfSJordan Crouse 557ad0e8cfSJordan Crouse if (aspace->mmu) 5670dc51b4SJordan Crouse aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, size); 577ad0e8cfSJordan Crouse 587ad0e8cfSJordan Crouse vma->mapped = false; 59667ce33eSRob Clark } 60667ce33eSRob Clark 617ad0e8cfSJordan Crouse /* Remove reference counts for the mapping */ 627ad0e8cfSJordan Crouse void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, 637ad0e8cfSJordan Crouse struct msm_gem_vma *vma) 647ad0e8cfSJordan Crouse { 657ad0e8cfSJordan Crouse if (!WARN_ON(!vma->iova)) 667ad0e8cfSJordan Crouse vma->inuse--; 67667ce33eSRob Clark } 68667ce33eSRob Clark 69667ce33eSRob Clark int 70667ce33eSRob Clark msm_gem_map_vma(struct msm_gem_address_space *aspace, 71bbc2cd07SRob Clark struct msm_gem_vma *vma, int prot, 72bbc2cd07SRob Clark struct sg_table *sgt, int npages) 73667ce33eSRob Clark { 74c0ee9794SJordan Crouse unsigned size = npages << PAGE_SHIFT; 75c0ee9794SJordan Crouse int ret = 0; 76667ce33eSRob Clark 77c0ee9794SJordan Crouse if (WARN_ON(!vma->iova)) 78c0ee9794SJordan Crouse return -EINVAL; 79c0ee9794SJordan Crouse 807ad0e8cfSJordan Crouse /* Increase the usage counter */ 817ad0e8cfSJordan Crouse vma->inuse++; 827ad0e8cfSJordan Crouse 83c0ee9794SJordan Crouse if (vma->mapped) 84667ce33eSRob Clark return 0; 85c0ee9794SJordan Crouse 86c0ee9794SJordan Crouse vma->mapped = true; 87c0ee9794SJordan Crouse 887603df38SLuca Weiss if (aspace && aspace->mmu) 89c0ee9794SJordan Crouse ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, 90bbc2cd07SRob Clark size, prot); 91c0ee9794SJordan Crouse 92c0ee9794SJordan Crouse if (ret) 93c0ee9794SJordan Crouse vma->mapped = false; 94c0ee9794SJordan Crouse 95c0ee9794SJordan Crouse return ret; 960e08270aSSushmita Susheelendra } 97667ce33eSRob Clark 987ad0e8cfSJordan Crouse /* Close an iova. Warn if it is still in use */ 997ad0e8cfSJordan Crouse void msm_gem_close_vma(struct msm_gem_address_space *aspace, 1007ad0e8cfSJordan Crouse struct msm_gem_vma *vma) 1017ad0e8cfSJordan Crouse { 1027ad0e8cfSJordan Crouse if (WARN_ON(vma->inuse > 0 || vma->mapped)) 1037ad0e8cfSJordan Crouse return; 1047ad0e8cfSJordan Crouse 1057ad0e8cfSJordan Crouse spin_lock(&aspace->lock); 1067ad0e8cfSJordan Crouse if (vma->iova) 1077ad0e8cfSJordan Crouse drm_mm_remove_node(&vma->node); 1087ad0e8cfSJordan Crouse spin_unlock(&aspace->lock); 1097ad0e8cfSJordan Crouse 1107ad0e8cfSJordan Crouse vma->iova = 0; 1117ad0e8cfSJordan Crouse 1127ad0e8cfSJordan Crouse msm_gem_address_space_put(aspace); 1137ad0e8cfSJordan Crouse } 1147ad0e8cfSJordan Crouse 115c0ee9794SJordan Crouse /* Initialize a new vma and allocate an iova for it */ 116c0ee9794SJordan Crouse int msm_gem_init_vma(struct msm_gem_address_space *aspace, 117c0ee9794SJordan Crouse struct msm_gem_vma *vma, int npages) 118c0ee9794SJordan Crouse { 119c0ee9794SJordan Crouse int ret; 120c0ee9794SJordan Crouse 121c0ee9794SJordan Crouse if (WARN_ON(vma->iova)) 122c0ee9794SJordan Crouse return -EBUSY; 123c0ee9794SJordan Crouse 124c0ee9794SJordan Crouse spin_lock(&aspace->lock); 1254e64e553SChris Wilson ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); 1260e08270aSSushmita Susheelendra spin_unlock(&aspace->lock); 1270e08270aSSushmita Susheelendra 128667ce33eSRob Clark if (ret) 129667ce33eSRob Clark return ret; 130667ce33eSRob Clark 131667ce33eSRob Clark vma->iova = vma->node.start << PAGE_SHIFT; 132c0ee9794SJordan Crouse vma->mapped = false; 133667ce33eSRob Clark 134ee546cd3SJordan Crouse kref_get(&aspace->kref); 135667ce33eSRob Clark 136c0ee9794SJordan Crouse return 0; 137667ce33eSRob Clark } 138667ce33eSRob Clark 1397ad0e8cfSJordan Crouse 140667ce33eSRob Clark struct msm_gem_address_space * 141667ce33eSRob Clark msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, 142667ce33eSRob Clark const char *name) 143667ce33eSRob Clark { 144667ce33eSRob Clark struct msm_gem_address_space *aspace; 145edf5ceacSJordan Crouse u64 size = domain->geometry.aperture_end - 146edf5ceacSJordan Crouse domain->geometry.aperture_start; 147667ce33eSRob Clark 148667ce33eSRob Clark aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); 149667ce33eSRob Clark if (!aspace) 150667ce33eSRob Clark return ERR_PTR(-ENOMEM); 151667ce33eSRob Clark 1520e08270aSSushmita Susheelendra spin_lock_init(&aspace->lock); 153667ce33eSRob Clark aspace->name = name; 154667ce33eSRob Clark aspace->mmu = msm_iommu_new(dev, domain); 155667ce33eSRob Clark 156667ce33eSRob Clark drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), 157edf5ceacSJordan Crouse size >> PAGE_SHIFT); 158667ce33eSRob Clark 159ee546cd3SJordan Crouse kref_init(&aspace->kref); 160ee546cd3SJordan Crouse 161667ce33eSRob Clark return aspace; 162667ce33eSRob Clark } 163c2052a4eSJonathan Marek 164c2052a4eSJonathan Marek struct msm_gem_address_space * 165c2052a4eSJonathan Marek msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, 166c2052a4eSJonathan Marek const char *name, uint64_t va_start, uint64_t va_end) 167c2052a4eSJonathan Marek { 168c2052a4eSJonathan Marek struct msm_gem_address_space *aspace; 169c2052a4eSJonathan Marek u64 size = va_end - va_start; 170c2052a4eSJonathan Marek 171c2052a4eSJonathan Marek aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); 172c2052a4eSJonathan Marek if (!aspace) 173c2052a4eSJonathan Marek return ERR_PTR(-ENOMEM); 174c2052a4eSJonathan Marek 175c2052a4eSJonathan Marek spin_lock_init(&aspace->lock); 176c2052a4eSJonathan Marek aspace->name = name; 177c2052a4eSJonathan Marek aspace->mmu = msm_gpummu_new(dev, gpu); 178c2052a4eSJonathan Marek 179c2052a4eSJonathan Marek drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT), 180c2052a4eSJonathan Marek size >> PAGE_SHIFT); 181c2052a4eSJonathan Marek 182c2052a4eSJonathan Marek kref_init(&aspace->kref); 183c2052a4eSJonathan Marek 184c2052a4eSJonathan Marek return aspace; 185c2052a4eSJonathan Marek } 186