1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Helpers for IOMMU drivers implementing SVA 4 */ 5#include <linux/mutex.h> 6#include <linux/sched/mm.h> 7 8#include "iommu-sva-lib.h" 9 10static DEFINE_MUTEX(iommu_sva_lock); 11static DECLARE_IOASID_SET(iommu_sva_pasid); 12 13/** 14 * iommu_sva_alloc_pasid - Allocate a PASID for the mm 15 * @mm: the mm 16 * @min: minimum PASID value (inclusive) 17 * @max: maximum PASID value (inclusive) 18 * 19 * Try to allocate a PASID for this mm, or take a reference to the existing one 20 * provided it fits within the [@min, @max] range. On success the PASID is 21 * available in mm->pasid, and must be released with iommu_sva_free_pasid(). 22 * @min must be greater than 0, because 0 indicates an unused mm->pasid. 23 * 24 * Returns 0 on success and < 0 on error. 25 */ 26int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max) 27{ 28 int ret = 0; 29 ioasid_t pasid; 30 31 if (min == INVALID_IOASID || max == INVALID_IOASID || 32 min == 0 || max < min) 33 return -EINVAL; 34 35 mutex_lock(&iommu_sva_lock); 36 if (mm->pasid) { 37 if (mm->pasid >= min && mm->pasid <= max) 38 ioasid_get(mm->pasid); 39 else 40 ret = -EOVERFLOW; 41 } else { 42 pasid = ioasid_alloc(&iommu_sva_pasid, min, max, mm); 43 if (pasid == INVALID_IOASID) 44 ret = -ENOMEM; 45 else 46 mm->pasid = pasid; 47 } 48 mutex_unlock(&iommu_sva_lock); 49 return ret; 50} 51EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid); 52 53/** 54 * iommu_sva_free_pasid - Release the mm's PASID 55 * @mm: the mm 56 * 57 * Drop one reference to a PASID allocated with iommu_sva_alloc_pasid() 58 */ 59void iommu_sva_free_pasid(struct mm_struct *mm) 60{ 61 mutex_lock(&iommu_sva_lock); 62 if (ioasid_put(mm->pasid)) 63 mm->pasid = 0; 64 mutex_unlock(&iommu_sva_lock); 65} 66EXPORT_SYMBOL_GPL(iommu_sva_free_pasid); 67 68/* ioasid_find getter() requires a void * argument */ 69static bool __mmget_not_zero(void *mm) 70{ 71 return mmget_not_zero(mm); 72} 73 74/** 75 * iommu_sva_find() - Find mm associated to the given PASID 76 * @pasid: Process Address Space ID assigned to the mm 77 * 78 * On success a reference to the mm is taken, and must be released with mmput(). 79 * 80 * Returns the mm corresponding to this PASID, or an error if not found. 81 */ 82struct mm_struct *iommu_sva_find(ioasid_t pasid) 83{ 84 return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero); 85} 86EXPORT_SYMBOL_GPL(iommu_sva_find); 87