// SPDX-License-Identifier: GPL-2.0
/**
- * intel-pasid.c - PASID idr, table and entry manipulation
+ * intel-pasid.c - PASID id, table and entry manipulation
*
* Copyright (C) 2018 Intel Corporation
*
#include <linux/pci.h>
#include <linux/pci-ats.h>
#include <linux/spinlock.h>
+#include <linux/xarray.h>
#include "intel-pasid.h"
/*
* Intel IOMMU system wide PASID name space:
*/
-static DEFINE_SPINLOCK(pasid_lock);
u32 intel_pasid_max_id = PASID_MAX;
-static DEFINE_IDR(pasid_idr);
+static DEFINE_XARRAY_ALLOC1(pasid_ptrs);
int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp)
{
- int ret, min, max;
+ int ret, id;
- min = max_t(int, start, PASID_MIN);
- max = min_t(int, end, intel_pasid_max_id);
+ if (end > intel_pasid_max_id - 1)
+ end = intel_pasid_max_id - 1;
- WARN_ON(in_interrupt());
- idr_preload(gfp);
- spin_lock(&pasid_lock);
- ret = idr_alloc(&pasid_idr, ptr, min, max, GFP_ATOMIC);
- spin_unlock(&pasid_lock);
- idr_preload_end();
+ ret = xa_alloc(&pasid_ptrs, &id, ptr, XA_LIMIT(start, end), gfp);
+ if (ret < 0)
+ return ret;
- return ret;
+ return id;
}
void intel_pasid_free_id(int pasid)
{
- spin_lock(&pasid_lock);
- idr_remove(&pasid_idr, pasid);
- spin_unlock(&pasid_lock);
+ xa_erase(&pasid_ptrs, pasid);
}
void *intel_pasid_lookup_id(int pasid)
{
- void *p;
-
- spin_lock(&pasid_lock);
- p = idr_find(&pasid_idr, pasid);
- spin_unlock(&pasid_lock);
-
- return p;
+ return xa_load(&pasid_ptrs, pasid);
}
/*
dir_index = pasid >> PASID_PDE_SHIFT;
index = pasid & PASID_PTE_MASK;
- spin_lock(&pasid_lock);
+ xa_lock(&pasid_ptrs);
entries = get_pasid_table_from_pde(&dir[dir_index]);
if (!entries) {
entries = alloc_pgtable_page(info->iommu->node);
if (!entries) {
- spin_unlock(&pasid_lock);
+ xa_unlock(&pasid_ptrs);
return NULL;
}
WRITE_ONCE(dir[dir_index].val,
(u64)virt_to_phys(entries) | PASID_PTE_PRESENT);
}
- spin_unlock(&pasid_lock);
+ xa_unlock(&pasid_ptrs);
return &entries[index];
}