linux/drivers/iommu/iommu-sva-lib.c
<<
>>
Prefs
   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