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

Commit 0659b8dc authored by Eric Auger's avatar Eric Auger Committed by Will Deacon
Browse files

iommu/vt-d: Implement reserved region get/put callbacks



This patch registers the [FEE0_0000h - FEF0_000h] 1MB MSI
range as a reserved region and RMRR regions as direct regions.

This will allow to report those reserved regions in the
iommu-group sysfs.

Signed-off-by: default avatarEric Auger <eric.auger@redhat.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent bc7d12b9
Loading
Loading
Loading
Loading
+74 −18
Original line number Diff line number Diff line
@@ -440,6 +440,7 @@ struct dmar_rmrr_unit {
	u64	end_address;		/* reserved end address */
	struct dmar_dev_scope *devices;	/* target devices */
	int	devices_cnt;		/* target device count */
	struct iommu_resv_region *resv; /* reserved region handle */
};

struct dmar_atsr_unit {
@@ -4246,27 +4247,40 @@ static inline void init_iommu_pm_ops(void) {}
int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
{
	struct acpi_dmar_reserved_memory *rmrr;
	int prot = DMA_PTE_READ|DMA_PTE_WRITE;
	struct dmar_rmrr_unit *rmrru;
	size_t length;

	rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
	if (!rmrru)
		return -ENOMEM;
		goto out;

	rmrru->hdr = header;
	rmrr = (struct acpi_dmar_reserved_memory *)header;
	rmrru->base_address = rmrr->base_address;
	rmrru->end_address = rmrr->end_address;

	length = rmrr->end_address - rmrr->base_address + 1;
	rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot,
					      IOMMU_RESV_DIRECT);
	if (!rmrru->resv)
		goto free_rmrru;

	rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
				((void *)rmrr) + rmrr->header.length,
				&rmrru->devices_cnt);
	if (rmrru->devices_cnt && rmrru->devices == NULL) {
		kfree(rmrru);
		return -ENOMEM;
	}
	if (rmrru->devices_cnt && rmrru->devices == NULL)
		goto free_all;

	list_add(&rmrru->list, &dmar_rmrr_units);

	return 0;
free_all:
	kfree(rmrru->resv);
free_rmrru:
	kfree(rmrru);
out:
	return -ENOMEM;
}

static struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr)
@@ -4480,6 +4494,7 @@ static void intel_iommu_free_dmars(void)
	list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
		list_del(&rmrru->list);
		dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
		kfree(rmrru->resv);
		kfree(rmrru);
	}

@@ -5203,6 +5218,45 @@ static void intel_iommu_remove_device(struct device *dev)
	iommu_device_unlink(iommu->iommu_dev, dev);
}

static void intel_iommu_get_resv_regions(struct device *device,
					 struct list_head *head)
{
	struct iommu_resv_region *reg;
	struct dmar_rmrr_unit *rmrr;
	struct device *i_dev;
	int i;

	rcu_read_lock();
	for_each_rmrr_units(rmrr) {
		for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
					  i, i_dev) {
			if (i_dev != device)
				continue;

			list_add_tail(&rmrr->resv->list, head);
		}
	}
	rcu_read_unlock();

	reg = iommu_alloc_resv_region(IOAPIC_RANGE_START,
				      IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1,
				      0, IOMMU_RESV_RESERVED);
	if (!reg)
		return;
	list_add_tail(&reg->list, head);
}

static void intel_iommu_put_resv_regions(struct device *dev,
					 struct list_head *head)
{
	struct iommu_resv_region *entry, *next;

	list_for_each_entry_safe(entry, next, head, list) {
		if (entry->type == IOMMU_RESV_RESERVED)
			kfree(entry);
	}
}

#ifdef CONFIG_INTEL_IOMMU_SVM
#define MAX_NR_PASID_BITS (20)
static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu)
@@ -5344,6 +5398,8 @@ static const struct iommu_ops intel_iommu_ops = {
	.iova_to_phys		= intel_iommu_iova_to_phys,
	.add_device		= intel_iommu_add_device,
	.remove_device		= intel_iommu_remove_device,
	.get_resv_regions	= intel_iommu_get_resv_regions,
	.put_resv_regions	= intel_iommu_put_resv_regions,
	.device_group		= pci_device_group,
	.pgsize_bitmap		= INTEL_IOMMU_PGSIZES,
};