Skip to content

Commit 9ad1b03

Browse files
committed
iommu: Handle translated device firmware mappings
Signed-off-by: Janne Grunau <[email protected]>
1 parent 6d716ae commit 9ad1b03

2 files changed

Lines changed: 28 additions & 5 deletions

File tree

drivers/iommu/iommu.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,35 +1143,43 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain,
11431143

11441144
/* We need to consider overlapping regions for different devices */
11451145
list_for_each_entry(entry, &mappings, list) {
1146-
dma_addr_t start, end, addr;
1146+
dma_addr_t start, end, addr, iova;
11471147
size_t map_size = 0;
11481148

11491149
if (entry->type == IOMMU_RESV_DIRECT)
11501150
dev->iommu->require_direct = 1;
1151+
if (entry->type == IOMMU_RESV_TRANSLATED)
1152+
dev->iommu->require_translated = 1;
11511153

11521154
if ((entry->type != IOMMU_RESV_DIRECT &&
1153-
entry->type != IOMMU_RESV_DIRECT_RELAXABLE) ||
1155+
entry->type != IOMMU_RESV_DIRECT_RELAXABLE &&
1156+
entry->type != IOMMU_RESV_TRANSLATED) ||
11541157
!iommu_is_dma_domain(domain))
11551158
continue;
11561159

11571160
start = ALIGN(entry->start, pg_size);
11581161
end = ALIGN(entry->start + entry->length, pg_size);
11591162

1160-
for (addr = start; addr <= end; addr += pg_size) {
1163+
if (entry->type == IOMMU_RESV_TRANSLATED)
1164+
iova = ALIGN(entry->dva, pg_size);
1165+
else
1166+
iova = start;
1167+
1168+
for (addr = start; addr <= end; addr += pg_size, iova += pg_size) {
11611169
phys_addr_t phys_addr;
11621170

11631171
if (addr == end)
11641172
goto map_end;
11651173

1166-
phys_addr = iommu_iova_to_phys(domain, addr);
1174+
phys_addr = iommu_iova_to_phys(domain, iova);
11671175
if (!phys_addr) {
11681176
map_size += pg_size;
11691177
continue;
11701178
}
11711179

11721180
map_end:
11731181
if (map_size) {
1174-
ret = iommu_map(domain, addr - map_size,
1182+
ret = iommu_map(domain, iova - map_size,
11751183
addr - map_size, map_size,
11761184
entry->prot, GFP_KERNEL);
11771185
if (ret)
@@ -2266,6 +2274,19 @@ static int __iommu_device_set_domain(struct iommu_group *group,
22662274
"Firmware has requested this device have a 1:1 IOMMU mapping, rejecting configuring the device without a 1:1 mapping. Contact your platform vendor.\n");
22672275
return -EINVAL;
22682276
}
2277+
/*
2278+
* If the device requires IOMMU_RESV_TRANSLATED then we cannot allow
2279+
* the identy or blocking domain to be attached as it does not contain
2280+
* the required translated mapping.
2281+
*/
2282+
if (dev->iommu->require_translated &&
2283+
(new_domain->type == IOMMU_DOMAIN_IDENTITY ||
2284+
new_domain->type == IOMMU_DOMAIN_BLOCKED ||
2285+
new_domain == group->blocking_domain)) {
2286+
dev_warn(dev,
2287+
"Firmware has requested this device have a translated IOMMU mapping, rejecting configuring the device without a translated mapping. Contact your platform vendor.\n");
2288+
return -EINVAL;
2289+
}
22692290

22702291
if (dev->iommu->attach_deferred) {
22712292
if (new_domain == group->default_domain)

include/linux/iommu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ struct iommu_fault_param {
804804
* @pci_32bit_workaround: Limit DMA allocations to 32-bit IOVAs
805805
* @require_direct: device requires IOMMU_RESV_DIRECT regions
806806
* @shadow_on_flush: IOTLB flushes are used to sync shadow tables
807+
* @require_translated: device requires IOMMU_RESV_TRANSLATED regions
807808
*
808809
* TODO: migrate other per device data pointers under iommu_dev_data, e.g.
809810
* struct iommu_group *iommu_group;
@@ -819,6 +820,7 @@ struct dev_iommu {
819820
u32 pci_32bit_workaround:1;
820821
u32 require_direct:1;
821822
u32 shadow_on_flush:1;
823+
u32 require_translated:1;
822824
};
823825

824826
int iommu_device_register(struct iommu_device *iommu,

0 commit comments

Comments
 (0)