Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 741669c7 authored by Joerg Roedel's avatar Joerg Roedel
Browse files

iommu/amd: Convert IOMMUv2 state_table into state_list



The state_table consumes 512kb of memory and is only sparsly
populated. Convert it into a list to save memory. There
should be no measurable performance impact.

Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
Tested-by: default avatarJay Cornwall <Jay.Cornwall@amd.com>
parent b87d2d7c
Loading
Loading
Loading
Loading
+18 −21
Original line number Original line Diff line number Diff line
@@ -56,6 +56,8 @@ struct pasid_state {
};
};


struct device_state {
struct device_state {
	struct list_head list;
	u16 devid;
	atomic_t count;
	atomic_t count;
	struct pci_dev *pdev;
	struct pci_dev *pdev;
	struct pasid_state **states;
	struct pasid_state **states;
@@ -81,7 +83,7 @@ struct fault {
	u16 flags;
	u16 flags;
};
};


static struct device_state **state_table;
static LIST_HEAD(state_list);
static spinlock_t state_lock;
static spinlock_t state_lock;


/* List and lock for all pasid_states */
/* List and lock for all pasid_states */
@@ -113,7 +115,14 @@ static u16 device_id(struct pci_dev *pdev)


static struct device_state *__get_device_state(u16 devid)
static struct device_state *__get_device_state(u16 devid)
{
{
	return state_table[devid];
	struct device_state *dev_state;

	list_for_each_entry(dev_state, &state_list, list) {
		if (dev_state->devid == devid)
			return dev_state;
	}

	return NULL;
}
}


static struct device_state *get_device_state(u16 devid)
static struct device_state *get_device_state(u16 devid)
@@ -779,6 +788,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
	spin_lock_init(&dev_state->lock);
	spin_lock_init(&dev_state->lock);
	init_waitqueue_head(&dev_state->wq);
	init_waitqueue_head(&dev_state->wq);
	dev_state->pdev  = pdev;
	dev_state->pdev  = pdev;
	dev_state->devid = devid;


	tmp = pasids;
	tmp = pasids;
	for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
	for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
@@ -808,13 +818,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)


	spin_lock_irqsave(&state_lock, flags);
	spin_lock_irqsave(&state_lock, flags);


	if (state_table[devid] != NULL) {
	if (__get_device_state(devid) != NULL) {
		spin_unlock_irqrestore(&state_lock, flags);
		spin_unlock_irqrestore(&state_lock, flags);
		ret = -EBUSY;
		ret = -EBUSY;
		goto out_free_domain;
		goto out_free_domain;
	}
	}


	state_table[devid] = dev_state;
	list_add_tail(&dev_state->list, &state_list);


	spin_unlock_irqrestore(&state_lock, flags);
	spin_unlock_irqrestore(&state_lock, flags);


@@ -852,7 +862,7 @@ void amd_iommu_free_device(struct pci_dev *pdev)
		return;
		return;
	}
	}


	state_table[devid] = NULL;
	list_del(&dev_state->list);


	spin_unlock_irqrestore(&state_lock, flags);
	spin_unlock_irqrestore(&state_lock, flags);


@@ -927,7 +937,6 @@ EXPORT_SYMBOL(amd_iommu_set_invalidate_ctx_cb);


static int __init amd_iommu_v2_init(void)
static int __init amd_iommu_v2_init(void)
{
{
	size_t state_table_size;
	int ret;
	int ret;


	pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n");
	pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n");
@@ -943,16 +952,10 @@ static int __init amd_iommu_v2_init(void)


	spin_lock_init(&state_lock);
	spin_lock_init(&state_lock);


	state_table_size = MAX_DEVICES * sizeof(struct device_state *);
	state_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
					       get_order(state_table_size));
	if (state_table == NULL)
		return -ENOMEM;

	ret = -ENOMEM;
	ret = -ENOMEM;
	iommu_wq = create_workqueue("amd_iommu_v2");
	iommu_wq = create_workqueue("amd_iommu_v2");
	if (iommu_wq == NULL)
	if (iommu_wq == NULL)
		goto out_free;
		goto out;


	ret = -ENOMEM;
	ret = -ENOMEM;
	empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL);
	empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL);
@@ -967,16 +970,13 @@ static int __init amd_iommu_v2_init(void)
out_destroy_wq:
out_destroy_wq:
	destroy_workqueue(iommu_wq);
	destroy_workqueue(iommu_wq);


out_free:
out:
	free_pages((unsigned long)state_table, get_order(state_table_size));

	return ret;
	return ret;
}
}


static void __exit amd_iommu_v2_exit(void)
static void __exit amd_iommu_v2_exit(void)
{
{
	struct device_state *dev_state;
	struct device_state *dev_state;
	size_t state_table_size;
	int i;
	int i;


	if (!amd_iommu_v2_supported())
	if (!amd_iommu_v2_supported())
@@ -1005,9 +1005,6 @@ static void __exit amd_iommu_v2_exit(void)


	destroy_workqueue(iommu_wq);
	destroy_workqueue(iommu_wq);


	state_table_size = MAX_DEVICES * sizeof(struct device_state *);
	free_pages((unsigned long)state_table, get_order(state_table_size));

	free_page((unsigned long)empty_page_table);
	free_page((unsigned long)empty_page_table);
}
}