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: Eric Auger <eric.auger@redhat.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
bc7d12b91b
commit
0659b8dc45
@ -440,6 +440,7 @@ struct dmar_rmrr_unit {
|
|||||||
u64 end_address; /* reserved end address */
|
u64 end_address; /* reserved end address */
|
||||||
struct dmar_dev_scope *devices; /* target devices */
|
struct dmar_dev_scope *devices; /* target devices */
|
||||||
int devices_cnt; /* target device count */
|
int devices_cnt; /* target device count */
|
||||||
|
struct iommu_resv_region *resv; /* reserved region handle */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dmar_atsr_unit {
|
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)
|
int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
|
||||||
{
|
{
|
||||||
struct acpi_dmar_reserved_memory *rmrr;
|
struct acpi_dmar_reserved_memory *rmrr;
|
||||||
|
int prot = DMA_PTE_READ|DMA_PTE_WRITE;
|
||||||
struct dmar_rmrr_unit *rmrru;
|
struct dmar_rmrr_unit *rmrru;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
|
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
|
||||||
if (!rmrru)
|
if (!rmrru)
|
||||||
return -ENOMEM;
|
goto out;
|
||||||
|
|
||||||
rmrru->hdr = header;
|
rmrru->hdr = header;
|
||||||
rmrr = (struct acpi_dmar_reserved_memory *)header;
|
rmrr = (struct acpi_dmar_reserved_memory *)header;
|
||||||
rmrru->base_address = rmrr->base_address;
|
rmrru->base_address = rmrr->base_address;
|
||||||
rmrru->end_address = rmrr->end_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),
|
rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
|
||||||
((void *)rmrr) + rmrr->header.length,
|
((void *)rmrr) + rmrr->header.length,
|
||||||
&rmrru->devices_cnt);
|
&rmrru->devices_cnt);
|
||||||
if (rmrru->devices_cnt && rmrru->devices == NULL) {
|
if (rmrru->devices_cnt && rmrru->devices == NULL)
|
||||||
kfree(rmrru);
|
goto free_all;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_add(&rmrru->list, &dmar_rmrr_units);
|
list_add(&rmrru->list, &dmar_rmrr_units);
|
||||||
|
|
||||||
return 0;
|
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)
|
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_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
|
||||||
list_del(&rmrru->list);
|
list_del(&rmrru->list);
|
||||||
dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
|
dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
|
||||||
|
kfree(rmrru->resv);
|
||||||
kfree(rmrru);
|
kfree(rmrru);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5203,6 +5218,45 @@ static void intel_iommu_remove_device(struct device *dev)
|
|||||||
iommu_device_unlink(iommu->iommu_dev, 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(®->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
|
#ifdef CONFIG_INTEL_IOMMU_SVM
|
||||||
#define MAX_NR_PASID_BITS (20)
|
#define MAX_NR_PASID_BITS (20)
|
||||||
static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu)
|
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,
|
.iova_to_phys = intel_iommu_iova_to_phys,
|
||||||
.add_device = intel_iommu_add_device,
|
.add_device = intel_iommu_add_device,
|
||||||
.remove_device = intel_iommu_remove_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,
|
.device_group = pci_device_group,
|
||||||
.pgsize_bitmap = INTEL_IOMMU_PGSIZES,
|
.pgsize_bitmap = INTEL_IOMMU_PGSIZES,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user