forked from Minki/linux
701fac4038
PASIDs are process-wide. It was attempted to use refcounted PASIDs to free them when the last thread drops the refcount. This turned out to be complex and error prone. Given the fact that the PASID space is 20 bits, which allows up to 1M processes to have a PASID associated concurrently, PASID resource exhaustion is not a realistic concern. Therefore, it was decided to simplify the approach and stick with lazy on demand PASID allocation, but drop the eager free approach and make an allocated PASID's lifetime bound to the lifetime of the process. Get rid of the refcounting mechanisms and replace/rename the interfaces to reflect this new approach. [ bp: Massage commit message. ] Suggested-by: Dave Hansen <dave.hansen@linux.intel.com> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Tony Luck <tony.luck@intel.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Jacob Pan <jacob.jun.pan@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Joerg Roedel <jroedel@suse.de> Link: https://lore.kernel.org/r/20220207230254.3342514-6-fenghua.yu@intel.com
72 lines
1.8 KiB
C
72 lines
1.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Helpers for IOMMU drivers implementing SVA
|
|
*/
|
|
#include <linux/mutex.h>
|
|
#include <linux/sched/mm.h>
|
|
|
|
#include "iommu-sva-lib.h"
|
|
|
|
static DEFINE_MUTEX(iommu_sva_lock);
|
|
static DECLARE_IOASID_SET(iommu_sva_pasid);
|
|
|
|
/**
|
|
* iommu_sva_alloc_pasid - Allocate a PASID for the mm
|
|
* @mm: the mm
|
|
* @min: minimum PASID value (inclusive)
|
|
* @max: maximum PASID value (inclusive)
|
|
*
|
|
* Try to allocate a PASID for this mm, or take a reference to the existing one
|
|
* provided it fits within the [@min, @max] range. On success the PASID is
|
|
* available in mm->pasid and will be available for the lifetime of the mm.
|
|
*
|
|
* Returns 0 on success and < 0 on error.
|
|
*/
|
|
int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
|
|
{
|
|
int ret = 0;
|
|
ioasid_t pasid;
|
|
|
|
if (min == INVALID_IOASID || max == INVALID_IOASID ||
|
|
min == 0 || max < min)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&iommu_sva_lock);
|
|
/* Is a PASID already associated with this mm? */
|
|
if (pasid_valid(mm->pasid)) {
|
|
if (mm->pasid < min || mm->pasid >= max)
|
|
ret = -EOVERFLOW;
|
|
goto out;
|
|
}
|
|
|
|
pasid = ioasid_alloc(&iommu_sva_pasid, min, max, mm);
|
|
if (!pasid_valid(pasid))
|
|
ret = -ENOMEM;
|
|
else
|
|
mm_pasid_set(mm, pasid);
|
|
out:
|
|
mutex_unlock(&iommu_sva_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid);
|
|
|
|
/* ioasid_find getter() requires a void * argument */
|
|
static bool __mmget_not_zero(void *mm)
|
|
{
|
|
return mmget_not_zero(mm);
|
|
}
|
|
|
|
/**
|
|
* iommu_sva_find() - Find mm associated to the given PASID
|
|
* @pasid: Process Address Space ID assigned to the mm
|
|
*
|
|
* On success a reference to the mm is taken, and must be released with mmput().
|
|
*
|
|
* Returns the mm corresponding to this PASID, or an error if not found.
|
|
*/
|
|
struct mm_struct *iommu_sva_find(ioasid_t pasid)
|
|
{
|
|
return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
|
|
}
|
|
EXPORT_SYMBOL_GPL(iommu_sva_find);
|