David Woodhouse
2016-10-30 19:14:49 UTC
The Intel IOMMU code registers a notifier and plays nasty tricks to fill
device pointers in with its DMAR scope tables when devices are detected,
then later compares the device pointers in those tables when it needs to
find the IOMMU unit for a given device.
If we let it use arch_setup_dma_ops() to match the device to an IOMMU
unit at device_register() time, this gets a whole lot saner.
Signed-off-by: David Woodhouse <***@infradead.org>
---
Of course it's still not actually *sane*. We have per-device DMA ops,
but per-bus IOMMU ops. What we actually want to do is ditch the DMA ops
entirely and simply do it all through the IOMMU ops, like ARM does in
its arch/arm/mm/dma-mapping.c. I think we can do an iova-dma-mapping.c
with just an additional flag in the IOMMU domain which says that it can
do lazy unmaps.Â
And IOMMU ops should be per-device of course, not per-bus. But this is
a start...
 arch/x86/include/asm/dma-mapping.h | 2 ++
 arch/x86/include/asm/x86_init.h    | 3 +++
 arch/x86/kernel/x86_init.c         | 3 +++
 3 files changed, 8 insertions(+)
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 4446162..b3888a0 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -42,6 +42,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp);
 #define arch_dma_alloc_attrs arch_dma_alloc_attrs
Â
+#define arch_setup_dma_ops x86_platform.iommu_setup_dma_ops
+
 #define HAVE_ARCH_DMA_SUPPORTED 1
 extern int dma_supported(struct device *hwdev, u64 mask);
Â
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 6ba7931..6872dcc 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -7,6 +7,7 @@ struct mpc_bus;
 struct mpc_cpu;
 struct mpc_table;
 struct cpuinfo_x86;
+struct iommu_ops;
Â
 /**
 * struct x86_init_mpparse - platform specific mpparse ops
@@ -207,6 +208,8 @@ struct x86_platform_ops {
 void (*get_wallclock)(struct timespec *ts);
 int (*set_wallclock)(const struct timespec *ts);
 void (*iommu_shutdown)(void);
+ void (*iommu_setup_dma_ops)(struct device *dev, u64 dma_base, u64 size,
+ Â Â Â Â const struct iommu_ops *iommu, bool coherent);
 bool (*is_untracked_pat_range)(u64 start, u64 end);
 void (*nmi_init)(void);
 unsigned char (*get_nmi_reason)(void);
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 0bd9f12..5e54a72 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -28,6 +28,8 @@ void x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
+void iommu_setup_dma_ops_noop(struct device *dev, u64 dma_base, u64 size,
+ Â Â Â Â Â Â const struct iommu_ops *iommu, bool coherent) { }
Â
 /*
 * The platform setup functions are preset with the default functions
@@ -97,6 +99,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
 .get_wallclock = mach_get_cmos_time,
 .set_wallclock = mach_set_rtc_mmss,
 .iommu_shutdown = iommu_shutdown_noop,
+ .iommu_setup_dma_ops = iommu_setup_dma_ops_noop,
 .is_untracked_pat_range = is_ISA_range,
 .nmi_init = default_nmi_init,
 .get_nmi_reason = default_get_nmi_reason,
--Â
2.5.5
device pointers in with its DMAR scope tables when devices are detected,
then later compares the device pointers in those tables when it needs to
find the IOMMU unit for a given device.
If we let it use arch_setup_dma_ops() to match the device to an IOMMU
unit at device_register() time, this gets a whole lot saner.
Signed-off-by: David Woodhouse <***@infradead.org>
---
Of course it's still not actually *sane*. We have per-device DMA ops,
but per-bus IOMMU ops. What we actually want to do is ditch the DMA ops
entirely and simply do it all through the IOMMU ops, like ARM does in
its arch/arm/mm/dma-mapping.c. I think we can do an iova-dma-mapping.c
with just an additional flag in the IOMMU domain which says that it can
do lazy unmaps.Â
And IOMMU ops should be per-device of course, not per-bus. But this is
a start...
 arch/x86/include/asm/dma-mapping.h | 2 ++
 arch/x86/include/asm/x86_init.h    | 3 +++
 arch/x86/kernel/x86_init.c         | 3 +++
 3 files changed, 8 insertions(+)
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 4446162..b3888a0 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -42,6 +42,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp);
 #define arch_dma_alloc_attrs arch_dma_alloc_attrs
Â
+#define arch_setup_dma_ops x86_platform.iommu_setup_dma_ops
+
 #define HAVE_ARCH_DMA_SUPPORTED 1
 extern int dma_supported(struct device *hwdev, u64 mask);
Â
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 6ba7931..6872dcc 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -7,6 +7,7 @@ struct mpc_bus;
 struct mpc_cpu;
 struct mpc_table;
 struct cpuinfo_x86;
+struct iommu_ops;
Â
 /**
 * struct x86_init_mpparse - platform specific mpparse ops
@@ -207,6 +208,8 @@ struct x86_platform_ops {
 void (*get_wallclock)(struct timespec *ts);
 int (*set_wallclock)(const struct timespec *ts);
 void (*iommu_shutdown)(void);
+ void (*iommu_setup_dma_ops)(struct device *dev, u64 dma_base, u64 size,
+ Â Â Â Â const struct iommu_ops *iommu, bool coherent);
 bool (*is_untracked_pat_range)(u64 start, u64 end);
 void (*nmi_init)(void);
 unsigned char (*get_nmi_reason)(void);
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 0bd9f12..5e54a72 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -28,6 +28,8 @@ void x86_init_noop(void) { }
 void __init x86_init_uint_noop(unsigned int unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
+void iommu_setup_dma_ops_noop(struct device *dev, u64 dma_base, u64 size,
+ Â Â Â Â Â Â const struct iommu_ops *iommu, bool coherent) { }
Â
 /*
 * The platform setup functions are preset with the default functions
@@ -97,6 +99,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
 .get_wallclock = mach_get_cmos_time,
 .set_wallclock = mach_set_rtc_mmss,
 .iommu_shutdown = iommu_shutdown_noop,
+ .iommu_setup_dma_ops = iommu_setup_dma_ops_noop,
 .is_untracked_pat_range = is_ISA_range,
 .nmi_init = default_nmi_init,
 .get_nmi_reason = default_get_nmi_reason,
--Â
2.5.5