Skip to content

Commit cf5c1c8

Browse files
svenpeter42joergroedel
authored andcommitted
iommu/dart: Fix apple_dart_device_group for PCI groups
pci_device_group() can return an already existing IOMMU group if the PCI device's pagetables have to be shared with another one due to bus toplogy, isolation features and/or DMA alias quirks. apple_dart_device_group() however assumes that the group has just been created and overwrites its iommudata which will eventually lead to apple_dart_release_group leaving stale entries in sid2group. Fix that by merging the iommudata if the returned group already exists. Fixes: f0b6368 ("iommu/dart: Clear sid2group entry when a group is freed") Signed-off-by: Sven Peter <[email protected]> Reviewed-by: Eric Curtin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent d8bcc87 commit cf5c1c8

File tree

1 file changed

+44
-7
lines changed

1 file changed

+44
-7
lines changed

drivers/iommu/apple-dart.c

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,29 @@ static void apple_dart_release_group(void *iommu_data)
835835
mutex_unlock(&apple_dart_groups_lock);
836836
}
837837

838+
static int apple_dart_merge_master_cfg(struct apple_dart_master_cfg *dst,
839+
struct apple_dart_master_cfg *src)
840+
{
841+
/*
842+
* We know that this function is only called for groups returned from
843+
* pci_device_group and that all Apple Silicon platforms never spread
844+
* PCIe devices from the same bus across multiple DARTs such that we can
845+
* just assume that both src and dst only have the same single DART.
846+
*/
847+
if (src->stream_maps[1].dart)
848+
return -EINVAL;
849+
if (dst->stream_maps[1].dart)
850+
return -EINVAL;
851+
if (src->stream_maps[0].dart != dst->stream_maps[0].dart)
852+
return -EINVAL;
853+
854+
bitmap_or(dst->stream_maps[0].sidmap,
855+
dst->stream_maps[0].sidmap,
856+
src->stream_maps[0].sidmap,
857+
dst->stream_maps[0].dart->num_streams);
858+
return 0;
859+
}
860+
838861
static struct iommu_group *apple_dart_device_group(struct device *dev)
839862
{
840863
int i, sid;
@@ -876,14 +899,28 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
876899
if (!group)
877900
goto out;
878901

879-
group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg), GFP_KERNEL);
880-
if (!group_master_cfg) {
881-
iommu_group_put(group);
882-
goto out;
883-
}
902+
group_master_cfg = iommu_group_get_iommudata(group);
903+
if (group_master_cfg) {
904+
int ret;
884905

885-
iommu_group_set_iommudata(group, group_master_cfg,
886-
apple_dart_release_group);
906+
ret = apple_dart_merge_master_cfg(group_master_cfg, cfg);
907+
if (ret) {
908+
dev_err(dev, "Failed to merge DART IOMMU grups.\n");
909+
iommu_group_put(group);
910+
res = ERR_PTR(ret);
911+
goto out;
912+
}
913+
} else {
914+
group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg),
915+
GFP_KERNEL);
916+
if (!group_master_cfg) {
917+
iommu_group_put(group);
918+
goto out;
919+
}
920+
921+
iommu_group_set_iommudata(group, group_master_cfg,
922+
apple_dart_release_group);
923+
}
887924

888925
for_each_stream_map(i, cfg, stream_map)
889926
for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams)

0 commit comments

Comments
 (0)