Skip to content

Commit 23e4bc8

Browse files
committed
iommu: Handle translated device firmware mappings
Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 0345a1a commit 23e4bc8

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
@@ -1188,21 +1188,29 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain,
11881188

11891189
/* We need to consider overlapping regions for different devices */
11901190
list_for_each_entry(entry, &mappings, list) {
1191-
dma_addr_t start, end, addr;
1191+
dma_addr_t start, end, addr, iova;
11921192
size_t map_size = 0;
11931193

11941194
if (entry->type == IOMMU_RESV_DIRECT)
11951195
dev->iommu->require_direct = 1;
1196+
if (entry->type == IOMMU_RESV_TRANSLATED)
1197+
dev->iommu->require_translated = 1;
11961198

11971199
if ((entry->type != IOMMU_RESV_DIRECT &&
1198-
entry->type != IOMMU_RESV_DIRECT_RELAXABLE) ||
1200+
entry->type != IOMMU_RESV_DIRECT_RELAXABLE &&
1201+
entry->type != IOMMU_RESV_TRANSLATED) ||
11991202
!iommu_is_dma_domain(domain))
12001203
continue;
12011204

12021205
start = ALIGN(entry->start, pg_size);
12031206
end = ALIGN(entry->start + entry->length, pg_size);
12041207

1205-
for (addr = start; addr <= end; addr += pg_size) {
1208+
if (entry->type == IOMMU_RESV_TRANSLATED)
1209+
iova = ALIGN(entry->dva, pg_size);
1210+
else
1211+
iova = start;
1212+
1213+
for (addr = start; addr <= end; addr += pg_size, iova += pg_size) {
12061214
phys_addr_t phys_addr;
12071215

12081216
if (addr == end)
@@ -1212,15 +1220,15 @@ static int iommu_create_device_fw_mappings(struct iommu_domain *domain,
12121220
* Return address by iommu_iova_to_phys for 0 is
12131221
* ambiguous. Offset to address 1 if addr is 0.
12141222
*/
1215-
phys_addr = iommu_iova_to_phys(domain, addr ? addr : 1);
1223+
phys_addr = iommu_iova_to_phys(domain, iova ? iova : 1);
12161224
if (!phys_addr) {
12171225
map_size += pg_size;
12181226
continue;
12191227
}
12201228

12211229
map_end:
12221230
if (map_size) {
1223-
ret = iommu_map(domain, addr - map_size,
1231+
ret = iommu_map(domain, iova - map_size,
12241232
addr - map_size, map_size,
12251233
entry->prot, GFP_KERNEL);
12261234
if (ret)
@@ -2323,6 +2331,19 @@ static int __iommu_device_set_domain(struct iommu_group *group,
23232331
"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");
23242332
return -EINVAL;
23252333
}
2334+
/*
2335+
* If the device requires IOMMU_RESV_TRANSLATED then we cannot allow
2336+
* the identy or blocking domain to be attached as it does not contain
2337+
* the required translated mapping.
2338+
*/
2339+
if (dev->iommu->require_translated &&
2340+
(new_domain->type == IOMMU_DOMAIN_IDENTITY ||
2341+
new_domain->type == IOMMU_DOMAIN_BLOCKED ||
2342+
new_domain == group->blocking_domain)) {
2343+
dev_warn(dev,
2344+
"Firmware has requested this device have a translated IOMMU mapping, rejecting configuring the device without a translated mapping. Contact your platform vendor.\n");
2345+
return -EINVAL;
2346+
}
23262347

23272348
if (dev->iommu->attach_deferred) {
23282349
if (new_domain == group->default_domain)

include/linux/iommu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ struct iommu_fault_param {
845845
* @pci_32bit_workaround: Limit DMA allocations to 32-bit IOVAs
846846
* @require_direct: device requires IOMMU_RESV_DIRECT regions
847847
* @shadow_on_flush: IOTLB flushes are used to sync shadow tables
848+
* @require_translated: device requires IOMMU_RESV_TRANSLATED regions
848849
*
849850
* TODO: migrate other per device data pointers under iommu_dev_data, e.g.
850851
* struct iommu_group *iommu_group;
@@ -860,6 +861,7 @@ struct dev_iommu {
860861
u32 pci_32bit_workaround:1;
861862
u32 require_direct:1;
862863
u32 shadow_on_flush:1;
864+
u32 require_translated:1;
863865
};
864866

865867
int iommu_device_register(struct iommu_device *iommu,

0 commit comments

Comments
 (0)