Commit 2fcab2de authored by Vasant Hegde's avatar Vasant Hegde Committed by Joerg Roedel
Browse files

iommu/amd: Use ida interface to manage protection domain ID



Replace custom domain ID allocator with IDA interface.

Signed-off-by: default avatarVasant Hegde <vasant.hegde@amd.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/20241030063556.6104-3-vasant.hegde@amd.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 01699160
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -912,14 +912,14 @@ struct unity_map_entry {
/* size of the dma_ops aperture as power of 2 */
extern unsigned amd_iommu_aperture_order;

/* allocation bitmap for domain ids */
extern unsigned long *amd_iommu_pd_alloc_bitmap;

extern bool amd_iommu_force_isolation;

/* Max levels of glxval supported */
extern int amd_iommu_max_glx_val;

/* IDA to track protection domain IDs */
extern struct ida pdom_ids;

/* Global EFR and EFR2 registers */
extern u64 amd_iommu_efr;
extern u64 amd_iommu_efr2;
+7 −24
Original line number Diff line number Diff line
@@ -194,12 +194,6 @@ bool amd_iommu_force_isolation __read_mostly;

unsigned long amd_iommu_pgsize_bitmap __ro_after_init = AMD_IOMMU_PGSIZES;

/*
 * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
 * to know which ones are already in use.
 */
unsigned long *amd_iommu_pd_alloc_bitmap;

enum iommu_init_state {
	IOMMU_START_STATE,
	IOMMU_IVRS_DETECTED,
@@ -1082,7 +1076,12 @@ static bool __copy_device_table(struct amd_iommu *iommu)
		if (dte_v && dom_id) {
			pci_seg->old_dev_tbl_cpy[devid].data[0] = old_devtb[devid].data[0];
			pci_seg->old_dev_tbl_cpy[devid].data[1] = old_devtb[devid].data[1];
			__set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
			/* Reserve the Domain IDs used by previous kernel */
			if (ida_alloc_range(&pdom_ids, dom_id, dom_id, GFP_ATOMIC) != dom_id) {
				pr_err("Failed to reserve domain ID 0x%x\n", dom_id);
				memunmap(old_devtb);
				return false;
			}
			/* If gcr3 table existed, mask it out */
			if (old_devtb[devid].data[0] & DTE_FLAG_GV) {
				tmp = DTE_GCR3_VAL_B(~0ULL) << DTE_GCR3_SHIFT_B;
@@ -2985,9 +2984,7 @@ static bool __init check_ioapic_information(void)

static void __init free_dma_resources(void)
{
	iommu_free_pages(amd_iommu_pd_alloc_bitmap,
			 get_order(MAX_DOMAIN_ID / 8));
	amd_iommu_pd_alloc_bitmap = NULL;
	ida_destroy(&pdom_ids);

	free_unity_maps();
}
@@ -3055,20 +3052,6 @@ static int __init early_amd_iommu_init(void)
	amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base);
	DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type);

	/* Device table - directly used by all IOMMUs */
	ret = -ENOMEM;

	amd_iommu_pd_alloc_bitmap = iommu_alloc_pages(GFP_KERNEL,
						      get_order(MAX_DOMAIN_ID / 8));
	if (amd_iommu_pd_alloc_bitmap == NULL)
		goto out;

	/*
	 * never allocate domain 0 because its used as the non-allocated and
	 * error value placeholder
	 */
	__set_bit(0, amd_iommu_pd_alloc_bitmap);

	/*
	 * now the data structures are allocated and basically initialized
	 * start the real acpi table scan
+25 −31
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/scatterlist.h>
#include <linux/dma-map-ops.h>
#include <linux/dma-direct.h>
#include <linux/idr.h>
#include <linux/iommu-helper.h>
#include <linux/delay.h>
#include <linux/amd-iommu.h>
@@ -52,8 +53,6 @@
#define HT_RANGE_START		(0xfd00000000ULL)
#define HT_RANGE_END		(0xffffffffffULL)

static DEFINE_SPINLOCK(pd_bitmap_lock);

LIST_HEAD(ioapic_map);
LIST_HEAD(hpet_map);
LIST_HEAD(acpihid_map);
@@ -70,6 +69,12 @@ struct iommu_cmd {
	u32 data[4];
};

/*
 * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
 * to know which ones are already in use.
 */
DEFINE_IDA(pdom_ids);

struct kmem_cache *amd_iommu_irq_cache;

static void detach_device(struct device *dev);
@@ -1643,31 +1648,14 @@ int amd_iommu_complete_ppr(struct device *dev, u32 pasid, int status, int tag)
 *
 ****************************************************************************/

static u16 domain_id_alloc(void)
static int pdom_id_alloc(void)
{
	unsigned long flags;
	int id;

	spin_lock_irqsave(&pd_bitmap_lock, flags);
	id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID);
	BUG_ON(id == 0);
	if (id > 0 && id < MAX_DOMAIN_ID)
		__set_bit(id, amd_iommu_pd_alloc_bitmap);
	else
		id = 0;
	spin_unlock_irqrestore(&pd_bitmap_lock, flags);

	return id;
	return ida_alloc_range(&pdom_ids, 1, MAX_DOMAIN_ID - 1, GFP_ATOMIC);
}

static void domain_id_free(int id)
static void pdom_id_free(int id)
{
	unsigned long flags;

	spin_lock_irqsave(&pd_bitmap_lock, flags);
	if (id > 0 && id < MAX_DOMAIN_ID)
		__clear_bit(id, amd_iommu_pd_alloc_bitmap);
	spin_unlock_irqrestore(&pd_bitmap_lock, flags);
	ida_free(&pdom_ids, id);
}

static void free_gcr3_tbl_level1(u64 *tbl)
@@ -1712,7 +1700,7 @@ static void free_gcr3_table(struct gcr3_tbl_info *gcr3_info)
	gcr3_info->glx = 0;

	/* Free per device domain ID */
	domain_id_free(gcr3_info->domid);
	pdom_id_free(gcr3_info->domid);

	iommu_free_page(gcr3_info->gcr3_tbl);
	gcr3_info->gcr3_tbl = NULL;
@@ -1739,6 +1727,7 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info,
{
	int levels = get_gcr3_levels(pasids);
	int nid = iommu ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE;
	int domid;

	if (levels > amd_iommu_max_glx_val)
		return -EINVAL;
@@ -1747,11 +1736,14 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info,
		return -EBUSY;

	/* Allocate per device domain ID */
	gcr3_info->domid = domain_id_alloc();
	domid = pdom_id_alloc();
	if (domid <= 0)
		return -ENOSPC;
	gcr3_info->domid = domid;

	gcr3_info->gcr3_tbl = iommu_alloc_page_node(nid, GFP_ATOMIC);
	if (gcr3_info->gcr3_tbl == NULL) {
		domain_id_free(gcr3_info->domid);
		pdom_id_free(domid);
		return -ENOMEM;
	}

@@ -2262,7 +2254,7 @@ void protection_domain_free(struct protection_domain *domain)
	WARN_ON(!list_empty(&domain->dev_list));
	if (domain->domain.type & __IOMMU_DOMAIN_PAGING)
		free_io_pgtable_ops(&domain->iop.pgtbl.ops);
	domain_id_free(domain->id);
	pdom_id_free(domain->id);
	kfree(domain);
}

@@ -2277,16 +2269,18 @@ static void protection_domain_init(struct protection_domain *domain, int nid)
struct protection_domain *protection_domain_alloc(unsigned int type, int nid)
{
	struct protection_domain *domain;
	int domid;

	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
	if (!domain)
		return NULL;

	domain->id = domain_id_alloc();
	if (!domain->id) {
	domid = pdom_id_alloc();
	if (domid <= 0) {
		kfree(domain);
		return NULL;
	}
	domain->id = domid;

	protection_domain_init(domain, nid);

@@ -2361,7 +2355,7 @@ static struct iommu_domain *do_iommu_domain_alloc(unsigned int type,

	ret = pdom_setup_pgtable(domain, type, pgtable);
	if (ret) {
		domain_id_free(domain->id);
		pdom_id_free(domain->id);
		kfree(domain);
		return ERR_PTR(ret);
	}
@@ -2493,7 +2487,7 @@ void amd_iommu_init_identity_domain(void)
	domain->ops = &identity_domain_ops;
	domain->owner = &amd_iommu_ops;

	identity_domain.id = domain_id_alloc();
	identity_domain.id = pdom_id_alloc();

	protection_domain_init(&identity_domain, NUMA_NO_NODE);
}