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 41667ce33eSRob Clark void 42667ce33eSRob Clark msm_gem_unmap_vma(struct msm_gem_address_space *aspace, 4370dc51b4SJordan Crouse struct msm_gem_vma *vma) 44667ce33eSRob Clark { 4579687057SHans Verkuil if (!aspace || !vma->iova) 46667ce33eSRob Clark return; 47667ce33eSRob Clark 48667ce33eSRob Clark if (aspace->mmu) { 49667ce33eSRob Clark unsigned size = vma->node.size << PAGE_SHIFT; 5070dc51b4SJordan Crouse aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, size); 51667ce33eSRob Clark } 52667ce33eSRob Clark 530e08270aSSushmita Susheelendra spin_lock(&aspace->lock); 54667ce33eSRob Clark drm_mm_remove_node(&vma->node); 550e08270aSSushmita Susheelendra spin_unlock(&aspace->lock); 56667ce33eSRob Clark 57667ce33eSRob Clark vma->iova = 0; 58c0ee9794SJordan Crouse vma->mapped = false; 59ee546cd3SJordan Crouse 60ee546cd3SJordan Crouse msm_gem_address_space_put(aspace); 61667ce33eSRob Clark } 62667ce33eSRob Clark 63667ce33eSRob Clark int 64667ce33eSRob Clark msm_gem_map_vma(struct msm_gem_address_space *aspace, 65667ce33eSRob Clark struct msm_gem_vma *vma, struct sg_table *sgt, int npages) 66667ce33eSRob Clark { 67c0ee9794SJordan Crouse unsigned size = npages << PAGE_SHIFT; 68c0ee9794SJordan Crouse int ret = 0; 69667ce33eSRob Clark 70c0ee9794SJordan Crouse if (WARN_ON(!vma->iova)) 71c0ee9794SJordan Crouse return -EINVAL; 72c0ee9794SJordan Crouse 73c0ee9794SJordan Crouse if (vma->mapped) 74667ce33eSRob Clark return 0; 75c0ee9794SJordan Crouse 76c0ee9794SJordan Crouse vma->mapped = true; 77c0ee9794SJordan Crouse 78c0ee9794SJordan Crouse if (aspace->mmu) 79c0ee9794SJordan Crouse ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, 80c0ee9794SJordan Crouse size, IOMMU_READ | IOMMU_WRITE); 81c0ee9794SJordan Crouse 82c0ee9794SJordan Crouse if (ret) 83c0ee9794SJordan Crouse vma->mapped = false; 84c0ee9794SJordan Crouse 85c0ee9794SJordan Crouse return ret; 860e08270aSSushmita Susheelendra } 87667ce33eSRob Clark 88c0ee9794SJordan Crouse /* Initialize a new vma and allocate an iova for it */ 89c0ee9794SJordan Crouse int msm_gem_init_vma(struct msm_gem_address_space *aspace, 90c0ee9794SJordan Crouse struct msm_gem_vma *vma, int npages) 91c0ee9794SJordan Crouse { 92c0ee9794SJordan Crouse int ret; 93c0ee9794SJordan Crouse 94c0ee9794SJordan Crouse if (WARN_ON(vma->iova)) 95c0ee9794SJordan Crouse return -EBUSY; 96c0ee9794SJordan Crouse 97c0ee9794SJordan Crouse spin_lock(&aspace->lock); 984e64e553SChris Wilson ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); 990e08270aSSushmita Susheelendra spin_unlock(&aspace->lock); 1000e08270aSSushmita Susheelendra 101667ce33eSRob Clark if (ret) 102667ce33eSRob Clark return ret; 103667ce33eSRob Clark 104667ce33eSRob Clark vma->iova = vma->node.start << PAGE_SHIFT; 105c0ee9794SJordan Crouse vma->mapped = false; 106667ce33eSRob Clark 107ee546cd3SJordan Crouse kref_get(&aspace->kref); 108667ce33eSRob Clark 109c0ee9794SJordan Crouse return 0; 110667ce33eSRob Clark } 111667ce33eSRob Clark 112667ce33eSRob Clark struct msm_gem_address_space * 113667ce33eSRob Clark msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, 114667ce33eSRob Clark const char *name) 115667ce33eSRob Clark { 116667ce33eSRob Clark struct msm_gem_address_space *aspace; 117edf5ceacSJordan Crouse u64 size = domain->geometry.aperture_end - 118edf5ceacSJordan Crouse domain->geometry.aperture_start; 119667ce33eSRob Clark 120667ce33eSRob Clark aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); 121667ce33eSRob Clark if (!aspace) 122667ce33eSRob Clark return ERR_PTR(-ENOMEM); 123667ce33eSRob Clark 1240e08270aSSushmita Susheelendra spin_lock_init(&aspace->lock); 125667ce33eSRob Clark aspace->name = name; 126667ce33eSRob Clark aspace->mmu = msm_iommu_new(dev, domain); 127667ce33eSRob Clark 128667ce33eSRob Clark drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), 129edf5ceacSJordan Crouse size >> PAGE_SHIFT); 130667ce33eSRob Clark 131ee546cd3SJordan Crouse kref_init(&aspace->kref); 132ee546cd3SJordan Crouse 133667ce33eSRob Clark return aspace; 134667ce33eSRob Clark } 135