--- v1
+++ v4
@@ -1,86 +1,195 @@
From: Tianyu Lan <Tianyu.Lan@microsoft.com>
-In Hyper-V Isolation VM with AMD SEV, swiotlb boucne buffer
-needs to be mapped into address space above vTOM and so
-introduce dma_map_decrypted/dma_unmap_encrypted() to map/unmap
-bounce buffer memory. The platform can populate man/unmap callback
-in the dma memory decrypted ops.
+Hyper-V Isolation VM requires bounce buffer support to copy
+data from/to encrypted memory and so enable swiotlb force
+mode to use swiotlb bounce buffer for DMA transaction.
+
+In Isolation VM with AMD SEV, the bounce buffer needs to be
+accessed via extra address space which is above shared_gpa_boundary
+(E.G 39 bit address line) reported by Hyper-V CPUID ISOLATION_CONFIG.
+The access physical address will be original physical address +
+shared_gpa_boundary. The shared_gpa_boundary in the AMD SEV SNP
+spec is called virtual top of memory(vTOM). Memory addresses below
+vTOM are automatically treated as private while memory above
+vTOM is treated as shared.
+
+Swiotlb bounce buffer code calls set_memory_decrypted_map()
+to mark bounce buffer visible to host and map it in extra
+address space.
+
+Hyper-V initalizes swiotlb bounce buffer and default swiotlb
+needs to be disabled. pci_swiotlb_detect_override() and
+pci_swiotlb_detect_4gb() enable the default one. To override
+the setting, hyperv_swiotlb_detect() needs to run before
+these detect functions which depends on the pci_xen_swiotlb_
+init(). Make pci_xen_swiotlb_init() depends on the hyperv_swiotlb
+_detect() to keep the order.
+
+The map function vmap_pfn() can't work in the early place
+hyperv_iommu_swiotlb_init() and so initialize swiotlb bounce
+buffer in the hyperv_iommu_swiotlb_later_init().
Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
---
- include/linux/dma-map-ops.h | 9 +++++++++
- kernel/dma/mapping.c | 22 ++++++++++++++++++++++
- 2 files changed, 31 insertions(+)
+ arch/x86/xen/pci-swiotlb-xen.c | 3 +-
+ drivers/hv/vmbus_drv.c | 3 ++
+ drivers/iommu/hyperv-iommu.c | 62 ++++++++++++++++++++++++++++++++++
+ include/linux/hyperv.h | 1 +
+ 4 files changed, 68 insertions(+), 1 deletion(-)
-diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
-index 0d53a96a3d64..01d60a024e45 100644
---- a/include/linux/dma-map-ops.h
-+++ b/include/linux/dma-map-ops.h
-@@ -71,6 +71,11 @@ struct dma_map_ops {
- unsigned long (*get_merge_boundary)(struct device *dev);
+diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
+index 54f9aa7e8457..43bd031aa332 100644
+--- a/arch/x86/xen/pci-swiotlb-xen.c
++++ b/arch/x86/xen/pci-swiotlb-xen.c
+@@ -4,6 +4,7 @@
+
+ #include <linux/dma-map-ops.h>
+ #include <linux/pci.h>
++#include <linux/hyperv.h>
+ #include <xen/swiotlb-xen.h>
+
+ #include <asm/xen/hypervisor.h>
+@@ -91,6 +92,6 @@ int pci_xen_swiotlb_init_late(void)
+ EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late);
+
+ IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
+- NULL,
++ hyperv_swiotlb_detect,
+ pci_xen_swiotlb_init,
+ NULL);
+diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
+index 92cb3f7d21d9..5e3bb76d4dee 100644
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -23,6 +23,7 @@
+ #include <linux/cpu.h>
+ #include <linux/sched/task_stack.h>
+
++#include <linux/dma-map-ops.h>
+ #include <linux/delay.h>
+ #include <linux/notifier.h>
+ #include <linux/ptrace.h>
+@@ -2080,6 +2081,7 @@ struct hv_device *vmbus_device_create(const guid_t *type,
+ return child_device_obj;
+ }
+
++static u64 vmbus_dma_mask = DMA_BIT_MASK(64);
+ /*
+ * vmbus_device_register - Register the child device
+ */
+@@ -2120,6 +2122,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
+ }
+ hv_debug_add_dev_dir(child_device_obj);
+
++ child_device_obj->device.dma_mask = &vmbus_dma_mask;
+ return 0;
+
+ err_kset_unregister:
+diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c
+index e285a220c913..d7ea8e05b991 100644
+--- a/drivers/iommu/hyperv-iommu.c
++++ b/drivers/iommu/hyperv-iommu.c
+@@ -13,14 +13,22 @@
+ #include <linux/irq.h>
+ #include <linux/iommu.h>
+ #include <linux/module.h>
++#include <linux/hyperv.h>
++#include <linux/io.h>
+
+ #include <asm/apic.h>
+ #include <asm/cpu.h>
+ #include <asm/hw_irq.h>
+ #include <asm/io_apic.h>
++#include <asm/iommu.h>
++#include <asm/iommu_table.h>
+ #include <asm/irq_remapping.h>
+ #include <asm/hypervisor.h>
+ #include <asm/mshyperv.h>
++#include <asm/swiotlb.h>
++#include <linux/dma-map-ops.h>
++#include <linux/dma-direct.h>
++#include <linux/set_memory.h>
+
+ #include "irq_remapping.h"
+
+@@ -36,6 +44,8 @@
+ static cpumask_t ioapic_max_cpumask = { CPU_BITS_NONE };
+ static struct irq_domain *ioapic_ir_domain;
+
++static unsigned long hyperv_io_tlb_start, hyperv_io_tlb_size;
++
+ static int hyperv_ir_set_affinity(struct irq_data *data,
+ const struct cpumask *mask, bool force)
+ {
+@@ -337,4 +347,56 @@ static const struct irq_domain_ops hyperv_root_ir_domain_ops = {
+ .free = hyperv_root_irq_remapping_free,
};
-+struct dma_memory_decrypted_ops {
-+ void *(*map)(void *addr, unsigned long size);
-+ void (*unmap)(void *addr);
-+};
++void __init hyperv_iommu_swiotlb_init(void)
++{
++ unsigned long bytes;
++ void *vstart;
+
- #ifdef CONFIG_DMA_OPS
- #include <asm/dma-mapping.h>
-
-@@ -374,6 +379,10 @@ static inline void debug_dma_dump_mappings(struct device *dev)
- }
- #endif /* CONFIG_DMA_API_DEBUG */
-
-+void *dma_map_decrypted(void *addr, unsigned long size);
-+int dma_unmap_decrypted(void *addr, unsigned long size);
++ /*
++ * Allocate Hyper-V swiotlb bounce buffer at early place
++ * to reserve large contiguous memory.
++ */
++ hyperv_io_tlb_size = 200 * 1024 * 1024;
++ hyperv_io_tlb_start = memblock_alloc_low(PAGE_ALIGN(hyperv_io_tlb_size),
++ HV_HYP_PAGE_SIZE);
+
- extern const struct dma_map_ops dma_dummy_ops;
-+extern struct dma_memory_decrypted_ops dma_memory_generic_decrypted_ops;
-
- #endif /* _LINUX_DMA_MAP_OPS_H */
-diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
-index 2b06a809d0b9..6fb150dc1750 100644
---- a/kernel/dma/mapping.c
-+++ b/kernel/dma/mapping.c
-@@ -13,11 +13,13 @@
- #include <linux/of_device.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
-+#include <asm/set_memory.h>
- #include "debug.h"
- #include "direct.h"
-
- bool dma_default_coherent;
-
-+struct dma_memory_decrypted_ops dma_memory_generic_decrypted_ops;
- /*
- * Managed DMA API
- */
-@@ -736,3 +738,23 @@ unsigned long dma_get_merge_boundary(struct device *dev)
- return ops->get_merge_boundary(dev);
- }
- EXPORT_SYMBOL_GPL(dma_get_merge_boundary);
-+
-+void *dma_map_decrypted(void *addr, unsigned long size)
-+{
-+ if (set_memory_decrypted((unsigned long)addr,
-+ size / PAGE_SIZE))
-+ return NULL;
-+
-+ if (dma_memory_generic_decrypted_ops.map)
-+ return dma_memory_generic_decrypted_ops.map(addr, size);
-+ else
-+ return addr;
++ if (!hyperv_io_tlb_start) {
++ pr_warn("Fail to allocate Hyper-V swiotlb buffer.\n");
++ return;
++ }
+}
+
-+int dma_unmap_encrypted(void *addr, unsigned long size)
++int __init hyperv_swiotlb_detect(void)
+{
-+ if (dma_memory_generic_decrypted_ops.unmap)
-+ dma_memory_generic_decrypted_ops.unmap(addr);
++ if (hypervisor_is_type(X86_HYPER_MS_HYPERV)
++ && hv_is_isolation_supported()) {
++ /*
++ * Enable swiotlb force mode in Isolation VM to
++ * use swiotlb bounce buffer for dma transaction.
++ */
++ swiotlb_force = SWIOTLB_FORCE;
++ return 1;
++ }
+
-+ return set_memory_encrypted((unsigned long)addr, size / PAGE_SIZE);
++ return 0;
+}
++
++void __init hyperv_iommu_swiotlb_later_init(void)
++{
++ void *hyperv_io_tlb_remap;
++ int ret;
++
++ /*
++ * Swiotlb bounce buffer needs to be mapped in extra address
++ * space. Map function doesn't work in the early place and so
++ * call swiotlb_late_init_with_tbl() here.
++ */
++ swiotlb_late_init_with_tbl(hyperv_io_tlb_start,
++ hyperv_io_tlb_size >> IO_TLB_SHIFT);
++}
++
++IOMMU_INIT_FINISH(hyperv_swiotlb_detect,
++ NULL, hyperv_iommu_swiotlb_init,
++ hyperv_iommu_swiotlb_later_init);
++
+ #endif
+diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
+index 06eccaba10c5..babbe19f57e2 100644
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -1759,6 +1759,7 @@ int hyperv_write_cfg_blk(struct pci_dev *dev, void *buf, unsigned int len,
+ int hyperv_reg_block_invalidate(struct pci_dev *dev, void *context,
+ void (*block_invalidate)(void *context,
+ u64 block_mask));
++int __init hyperv_swiotlb_detect(void);
+
+ struct hyperv_pci_block_ops {
+ int (*read_block)(struct pci_dev *dev, void *buf, unsigned int buf_len,
--
2.25.1