mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-24 05:01:03 +02:00
iommu/ioasid: Add ioasid references
Let IOASID users take references to existing ioasids with ioasid_get(). ioasid_put() drops a reference and only frees the ioasid when its reference number is zero. It returns true if the ioasid was freed. For drivers that don't call ioasid_get(), ioasid_put() is the same as ioasid_free(). Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Link: https://lore.kernel.org/r/20201106155048.997886-2-jean-philippe@linaro.org Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
f8394f232b
commit
cb4789b0d1
@@ -5198,7 +5198,7 @@ static void auxiliary_unlink_device(struct dmar_domain *domain,
|
|||||||
domain->auxd_refcnt--;
|
domain->auxd_refcnt--;
|
||||||
|
|
||||||
if (!domain->auxd_refcnt && domain->default_pasid > 0)
|
if (!domain->auxd_refcnt && domain->default_pasid > 0)
|
||||||
ioasid_free(domain->default_pasid);
|
ioasid_put(domain->default_pasid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aux_domain_add_dev(struct dmar_domain *domain,
|
static int aux_domain_add_dev(struct dmar_domain *domain,
|
||||||
@@ -5259,7 +5259,7 @@ attach_failed:
|
|||||||
spin_unlock(&iommu->lock);
|
spin_unlock(&iommu->lock);
|
||||||
spin_unlock_irqrestore(&device_domain_lock, flags);
|
spin_unlock_irqrestore(&device_domain_lock, flags);
|
||||||
if (!domain->auxd_refcnt && domain->default_pasid > 0)
|
if (!domain->auxd_refcnt && domain->default_pasid > 0)
|
||||||
ioasid_free(domain->default_pasid);
|
ioasid_put(domain->default_pasid);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -598,7 +598,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||||||
if (mm) {
|
if (mm) {
|
||||||
ret = mmu_notifier_register(&svm->notifier, mm);
|
ret = mmu_notifier_register(&svm->notifier, mm);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ioasid_free(svm->pasid);
|
ioasid_put(svm->pasid);
|
||||||
kfree(svm);
|
kfree(svm);
|
||||||
kfree(sdev);
|
kfree(sdev);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -616,7 +616,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
if (mm)
|
if (mm)
|
||||||
mmu_notifier_unregister(&svm->notifier, mm);
|
mmu_notifier_unregister(&svm->notifier, mm);
|
||||||
ioasid_free(svm->pasid);
|
ioasid_put(svm->pasid);
|
||||||
kfree(svm);
|
kfree(svm);
|
||||||
kfree(sdev);
|
kfree(sdev);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -689,7 +689,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
|
|||||||
kfree_rcu(sdev, rcu);
|
kfree_rcu(sdev, rcu);
|
||||||
|
|
||||||
if (list_empty(&svm->devs)) {
|
if (list_empty(&svm->devs)) {
|
||||||
ioasid_free(svm->pasid);
|
ioasid_put(svm->pasid);
|
||||||
if (svm->mm) {
|
if (svm->mm) {
|
||||||
mmu_notifier_unregister(&svm->notifier, svm->mm);
|
mmu_notifier_unregister(&svm->notifier, svm->mm);
|
||||||
/* Clear mm's pasid. */
|
/* Clear mm's pasid. */
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* I/O Address Space ID allocator. There is one global IOASID space, split into
|
* I/O Address Space ID allocator. There is one global IOASID space, split into
|
||||||
* subsets. Users create a subset with DECLARE_IOASID_SET, then allocate and
|
* subsets. Users create a subset with DECLARE_IOASID_SET, then allocate and
|
||||||
* free IOASIDs with ioasid_alloc and ioasid_free.
|
* free IOASIDs with ioasid_alloc and ioasid_put.
|
||||||
*/
|
*/
|
||||||
#include <linux/ioasid.h>
|
#include <linux/ioasid.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -15,6 +15,7 @@ struct ioasid_data {
|
|||||||
struct ioasid_set *set;
|
struct ioasid_set *set;
|
||||||
void *private;
|
void *private;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
refcount_t refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -314,6 +315,7 @@ ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
|
|||||||
|
|
||||||
data->set = set;
|
data->set = set;
|
||||||
data->private = private;
|
data->private = private;
|
||||||
|
refcount_set(&data->refs, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Custom allocator needs allocator data to perform platform specific
|
* Custom allocator needs allocator data to perform platform specific
|
||||||
@@ -346,13 +348,36 @@ exit_free:
|
|||||||
EXPORT_SYMBOL_GPL(ioasid_alloc);
|
EXPORT_SYMBOL_GPL(ioasid_alloc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ioasid_free - Free an IOASID
|
* ioasid_get - obtain a reference to the IOASID
|
||||||
* @ioasid: the ID to remove
|
|
||||||
*/
|
*/
|
||||||
void ioasid_free(ioasid_t ioasid)
|
void ioasid_get(ioasid_t ioasid)
|
||||||
{
|
{
|
||||||
struct ioasid_data *ioasid_data;
|
struct ioasid_data *ioasid_data;
|
||||||
|
|
||||||
|
spin_lock(&ioasid_allocator_lock);
|
||||||
|
ioasid_data = xa_load(&active_allocator->xa, ioasid);
|
||||||
|
if (ioasid_data)
|
||||||
|
refcount_inc(&ioasid_data->refs);
|
||||||
|
else
|
||||||
|
WARN_ON(1);
|
||||||
|
spin_unlock(&ioasid_allocator_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ioasid_get);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ioasid_put - Release a reference to an ioasid
|
||||||
|
* @ioasid: the ID to remove
|
||||||
|
*
|
||||||
|
* Put a reference to the IOASID, free it when the number of references drops to
|
||||||
|
* zero.
|
||||||
|
*
|
||||||
|
* Return: %true if the IOASID was freed, %false otherwise.
|
||||||
|
*/
|
||||||
|
bool ioasid_put(ioasid_t ioasid)
|
||||||
|
{
|
||||||
|
bool free = false;
|
||||||
|
struct ioasid_data *ioasid_data;
|
||||||
|
|
||||||
spin_lock(&ioasid_allocator_lock);
|
spin_lock(&ioasid_allocator_lock);
|
||||||
ioasid_data = xa_load(&active_allocator->xa, ioasid);
|
ioasid_data = xa_load(&active_allocator->xa, ioasid);
|
||||||
if (!ioasid_data) {
|
if (!ioasid_data) {
|
||||||
@@ -360,6 +385,10 @@ void ioasid_free(ioasid_t ioasid)
|
|||||||
goto exit_unlock;
|
goto exit_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free = refcount_dec_and_test(&ioasid_data->refs);
|
||||||
|
if (!free)
|
||||||
|
goto exit_unlock;
|
||||||
|
|
||||||
active_allocator->ops->free(ioasid, active_allocator->ops->pdata);
|
active_allocator->ops->free(ioasid, active_allocator->ops->pdata);
|
||||||
/* Custom allocator needs additional steps to free the xa element */
|
/* Custom allocator needs additional steps to free the xa element */
|
||||||
if (active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) {
|
if (active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) {
|
||||||
@@ -369,8 +398,9 @@ void ioasid_free(ioasid_t ioasid)
|
|||||||
|
|
||||||
exit_unlock:
|
exit_unlock:
|
||||||
spin_unlock(&ioasid_allocator_lock);
|
spin_unlock(&ioasid_allocator_lock);
|
||||||
|
return free;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ioasid_free);
|
EXPORT_SYMBOL_GPL(ioasid_put);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ioasid_find - Find IOASID data
|
* ioasid_find - Find IOASID data
|
||||||
|
@@ -34,7 +34,8 @@ struct ioasid_allocator_ops {
|
|||||||
#if IS_ENABLED(CONFIG_IOASID)
|
#if IS_ENABLED(CONFIG_IOASID)
|
||||||
ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
|
ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max,
|
||||||
void *private);
|
void *private);
|
||||||
void ioasid_free(ioasid_t ioasid);
|
void ioasid_get(ioasid_t ioasid);
|
||||||
|
bool ioasid_put(ioasid_t ioasid);
|
||||||
void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
|
void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
|
||||||
bool (*getter)(void *));
|
bool (*getter)(void *));
|
||||||
int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
|
int ioasid_register_allocator(struct ioasid_allocator_ops *allocator);
|
||||||
@@ -48,10 +49,15 @@ static inline ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min,
|
|||||||
return INVALID_IOASID;
|
return INVALID_IOASID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ioasid_free(ioasid_t ioasid)
|
static inline void ioasid_get(ioasid_t ioasid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool ioasid_put(ioasid_t ioasid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
|
static inline void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid,
|
||||||
bool (*getter)(void *))
|
bool (*getter)(void *))
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user