前面我们讲了bus_set_iommu 中以此会调用add_device->device_group->domain_alloc->attach_dev,从而会完成smmu 的初始化部分,完成这些后,driver只要调用dma的API,例如dma_alloc_coherent 就可以从buddy system的API申请memory,然后调用smmu的map函数来映射,但是这些driver只限与pci_bus_type/amba_bustype/platform_bus_type .因为只有这三个bus type调用了bus_set_iommu 接口。
#ifdef CONFIG_PCI
if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
pci_request_acs();
ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
if (ret)
return ret;
}
#endif
#ifdef CONFIG_ARM_AMBA
if (amba_bustype.iommu_ops != &arm_smmu_ops) {
ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
if (ret)
return ret;
}
#endif
if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
if (ret)
return ret;
}
不过好在大部分device都属于pci_bus_type/amba_bustype/platform_bus_type 。因此使用smmu很方便.
而/sys/bus 下面有很多的bus,这些bus下的driver要使用iommu的话,就需要根据iommu.h 中的api申请device/domain等
[root@centos bus]# ls
acpi cpu iscsi_flashnode pci_express spi
amba event_source mdio_bus platform usb
clockevents gpio mipi-dsi pnp usb-serial
clocksource hid node scsi virtio
container i2c pci serio workqueue
例如在drivers/vfio/vfio_iommu_type1.c 中vfio_iommu_type1_attach_group函数中,就需要先申请
domain->domain = iommu_domain_alloc(bus);
然后ret = iommu_attach_group(domain->domain, iommu_group);
再然后iommu_attach_group 等步奏使用smmu,详细代码如下:
ret = iommu_attach_group(domain->domain, iommu_group);
1256 if (ret)
1257 goto out_domain;
1258
1259 INIT_LIST_HEAD(&domain->group_list);
1260 list_add(&group->next, &domain->group_list);
1261
1262 if (!allow_unsafe_interrupts &&
1263 !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
1264 pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
1265 __func__);
1266 ret = -EPERM;
1267 goto out_detach;
1268 }
1269
1270 if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
1271 domain->prot |= IOMMU_CACHE;
1272
1273 /*
1274 * Try to match an existing compatible domain. We don't want to
1275 * preclude an IOMMU driver supporting multiple bus_types and being
1276 * able to include different bus_types in the same IOMMU domain, so
1277 * we test whether the domains use the same iommu_ops rather than
1278 * testing if they're on the same bus_type.
1279 */
1280 list_for_each_entry(d, &iommu->domain_list, next) {
1281 if (d->domain->ops == domain->domain->ops &&
1282 d->prot == domain->prot) {
1283 iommu_detach_group(domain->domain, iommu_group);
1284 if (!iommu_attach_group(d->domain, iommu_group)) {
1285 list_add(&group->next, &d->group_list);
1286 iommu_domain_free(domain->domain);
1287 kfree(domain);
1288 mutex_unlock(&iommu->lock);
1289 return 0;
1290 }
1291
1292 ret = iommu_attach_group(domain->domain, iommu_group);
1293 if (ret)
1294 goto out_domain;
1295 }
1296 }
#ifdef CONFIG_PCI
if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
pci_request_acs();
ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
if (ret)
return ret;
}
#endif
#ifdef CONFIG_ARM_AMBA
if (amba_bustype.iommu_ops != &arm_smmu_ops) {
ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
if (ret)
return ret;
}
#endif
if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
if (ret)
return ret;
}
不过好在大部分device都属于pci_bus_type/amba_bustype/platform_bus_type 。因此使用smmu很方便.
而/sys/bus 下面有很多的bus,这些bus下的driver要使用iommu的话,就需要根据iommu.h 中的api申请device/domain等
[root@centos bus]# ls
acpi cpu iscsi_flashnode pci_express spi
amba event_source mdio_bus platform usb
clockevents gpio mipi-dsi pnp usb-serial
clocksource hid node scsi virtio
container i2c pci serio workqueue
例如在drivers/vfio/vfio_iommu_type1.c 中vfio_iommu_type1_attach_group函数中,就需要先申请
domain->domain = iommu_domain_alloc(bus);
然后ret = iommu_attach_group(domain->domain, iommu_group);
再然后iommu_attach_group 等步奏使用smmu,详细代码如下:
ret = iommu_attach_group(domain->domain, iommu_group);
1256 if (ret)
1257 goto out_domain;
1258
1259 INIT_LIST_HEAD(&domain->group_list);
1260 list_add(&group->next, &domain->group_list);
1261
1262 if (!allow_unsafe_interrupts &&
1263 !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
1264 pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
1265 __func__);
1266 ret = -EPERM;
1267 goto out_detach;
1268 }
1269
1270 if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
1271 domain->prot |= IOMMU_CACHE;
1272
1273 /*
1274 * Try to match an existing compatible domain. We don't want to
1275 * preclude an IOMMU driver supporting multiple bus_types and being
1276 * able to include different bus_types in the same IOMMU domain, so
1277 * we test whether the domains use the same iommu_ops rather than
1278 * testing if they're on the same bus_type.
1279 */
1280 list_for_each_entry(d, &iommu->domain_list, next) {
1281 if (d->domain->ops == domain->domain->ops &&
1282 d->prot == domain->prot) {
1283 iommu_detach_group(domain->domain, iommu_group);
1284 if (!iommu_attach_group(d->domain, iommu_group)) {
1285 list_add(&group->next, &d->group_list);
1286 iommu_domain_free(domain->domain);
1287 kfree(domain);
1288 mutex_unlock(&iommu->lock);
1289 return 0;
1290 }
1291
1292 ret = iommu_attach_group(domain->domain, iommu_group);
1293 if (ret)
1294 goto out_domain;
1295 }
1296 }