Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Helpers for IOMMU drivers implementing SVA
0004  */
0005 #include <linux/mutex.h>
0006 #include <linux/sched/mm.h>
0007 
0008 #include "iommu-sva-lib.h"
0009 
0010 static DEFINE_MUTEX(iommu_sva_lock);
0011 static DECLARE_IOASID_SET(iommu_sva_pasid);
0012 
0013 /**
0014  * iommu_sva_alloc_pasid - Allocate a PASID for the mm
0015  * @mm: the mm
0016  * @min: minimum PASID value (inclusive)
0017  * @max: maximum PASID value (inclusive)
0018  *
0019  * Try to allocate a PASID for this mm, or take a reference to the existing one
0020  * provided it fits within the [@min, @max] range. On success the PASID is
0021  * available in mm->pasid and will be available for the lifetime of the mm.
0022  *
0023  * Returns 0 on success and < 0 on error.
0024  */
0025 int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
0026 {
0027     int ret = 0;
0028     ioasid_t pasid;
0029 
0030     if (min == INVALID_IOASID || max == INVALID_IOASID ||
0031         min == 0 || max < min)
0032         return -EINVAL;
0033 
0034     mutex_lock(&iommu_sva_lock);
0035     /* Is a PASID already associated with this mm? */
0036     if (pasid_valid(mm->pasid)) {
0037         if (mm->pasid < min || mm->pasid >= max)
0038             ret = -EOVERFLOW;
0039         goto out;
0040     }
0041 
0042     pasid = ioasid_alloc(&iommu_sva_pasid, min, max, mm);
0043     if (!pasid_valid(pasid))
0044         ret = -ENOMEM;
0045     else
0046         mm_pasid_set(mm, pasid);
0047 out:
0048     mutex_unlock(&iommu_sva_lock);
0049     return ret;
0050 }
0051 EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid);
0052 
0053 /* ioasid_find getter() requires a void * argument */
0054 static bool __mmget_not_zero(void *mm)
0055 {
0056     return mmget_not_zero(mm);
0057 }
0058 
0059 /**
0060  * iommu_sva_find() - Find mm associated to the given PASID
0061  * @pasid: Process Address Space ID assigned to the mm
0062  *
0063  * On success a reference to the mm is taken, and must be released with mmput().
0064  *
0065  * Returns the mm corresponding to this PASID, or an error if not found.
0066  */
0067 struct mm_struct *iommu_sva_find(ioasid_t pasid)
0068 {
0069     return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
0070 }
0071 EXPORT_SYMBOL_GPL(iommu_sva_find);