Inter-revision diff: patch 4

Comparing v2 (message) to v4 (message)

--- v2
+++ v4
@@ -1,338 +1,142 @@
 From: Tianyu Lan <Tianyu.Lan@microsoft.com>
 
-hyperv 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, all shared memory with host needs to mark visible
+to host via hvcall. vmbus_establish_gpadl() has already done it for
+storvsc rx/tx ring buffer. The page buffer used by vmbus_sendpacket_
+mpb_desc() still needs to be handled. Use DMA API(scsi_dma_map/unmap)
+to map these memory during sending/receiving packet and return swiotlb
+bounce buffer dma address. In Isolation VM, swiotlb  bounce buffer is
+marked to be visible to host and the swiotlb force mode is enabled.
 
-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.
-
-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.
-
-Swiotlb bounce buffer code calls set_memory_decrypted()
-to mark bounce buffer visible to host and map it in extra
-address space via memremap. Populate the shared_gpa_boundary
-(vTOM) via swiotlb_unencrypted_base variable.
-
-The map function memremap() can't work in the early place
-hyperv_iommu_swiotlb_init() and so call swiotlb_update_mem_attributes()
-in the hyperv_iommu_swiotlb_later_init().
-
-Add Hyper-V dma ops and provide alloc/free and vmap/vunmap noncontiguous
-callback to handle request of  allocating and mapping noncontiguous dma
-memory in vmbus device driver. Netvsc driver will use this. Set dma_ops_
-bypass flag for hv device to use dma direct functions during mapping/unmapping
-dma page.
+Set device's dma min align mask to HV_HYP_PAGE_SIZE - 1 in order to
+keep the original data offset in the bounce buffer.
 
 Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
 ---
-Change since v1:
-	* Remove hv isolation check in the sev_setup_arch()
+ drivers/hv/vmbus_drv.c     |  1 +
+ drivers/scsi/storvsc_drv.c | 37 +++++++++++++++++++++----------------
+ include/linux/hyperv.h     |  1 +
+ 3 files changed, 23 insertions(+), 16 deletions(-)
 
- arch/x86/mm/mem_encrypt.c      |   1 +
- arch/x86/xen/pci-swiotlb-xen.c |   3 +-
- drivers/hv/Kconfig             |   1 +
- drivers/hv/vmbus_drv.c         |   6 ++
- drivers/iommu/hyperv-iommu.c   | 164 +++++++++++++++++++++++++++++++++
- include/linux/hyperv.h         |  10 ++
- 6 files changed, 184 insertions(+), 1 deletion(-)
-
-diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
-index 35487305d8af..e48c73b3dd41 100644
---- a/arch/x86/mm/mem_encrypt.c
-+++ b/arch/x86/mm/mem_encrypt.c
-@@ -31,6 +31,7 @@
- #include <asm/processor-flags.h>
- #include <asm/msr.h>
- #include <asm/cmdline.h>
-+#include <asm/mshyperv.h>
- 
- #include "mm_internal.h"
- 
-diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
-index 46df59aeaa06..30fd0600b008 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/Kconfig b/drivers/hv/Kconfig
-index dd12af20e467..d43b4cd88f57 100644
---- a/drivers/hv/Kconfig
-+++ b/drivers/hv/Kconfig
-@@ -9,6 +9,7 @@ config HYPERV
- 	select PARAVIRT
- 	select X86_HV_CALLBACK_VECTOR if X86
- 	select VMAP_PFN
-+	select DMA_OPS_BYPASS
- 	help
- 	  Select this option to run Linux as a Hyper-V client operating
- 	  system.
 diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
-index 392c1ac4f819..32dc193e31cd 100644
+index 0a64ccfafb8b..ae6ec503399a 100644
 --- a/drivers/hv/vmbus_drv.c
 +++ b/drivers/hv/vmbus_drv.c
-@@ -33,6 +33,7 @@
- #include <linux/random.h>
- #include <linux/kernel.h>
- #include <linux/syscore_ops.h>
-+#include <linux/dma-map-ops.h>
- #include <clocksource/hyperv_timer.h>
- #include "hyperv_vmbus.h"
- 
-@@ -2078,6 +2079,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
-  */
-@@ -2118,6 +2120,10 @@ int vmbus_device_register(struct hv_device *child_device_obj)
- 	}
+@@ -2121,6 +2121,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
  	hv_debug_add_dev_dir(child_device_obj);
  
-+	child_device_obj->device.dma_ops_bypass = true;
-+	child_device_obj->device.dma_ops = &hyperv_iommu_dma_ops;
-+	child_device_obj->device.dma_mask = &vmbus_dma_mask;
+ 	child_device_obj->device.dma_mask = &vmbus_dma_mask;
 +	child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
  	return 0;
  
  err_kset_unregister:
-diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c
-index e285a220c913..ebcb628e7e8f 100644
---- a/drivers/iommu/hyperv-iommu.c
-+++ b/drivers/iommu/hyperv-iommu.c
-@@ -13,14 +13,21 @@
- #include <linux/irq.h>
- #include <linux/iommu.h>
- #include <linux/module.h>
-+#include <linux/hyperv.h>
-+#include <linux/io.h>
+diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
+index 20595c0ba0ae..ae293600d799 100644
+--- a/drivers/scsi/storvsc_drv.c
++++ b/drivers/scsi/storvsc_drv.c
+@@ -21,6 +21,8 @@
+ #include <linux/device.h>
+ #include <linux/hyperv.h>
+ #include <linux/blkdev.h>
++#include <linux/dma-mapping.h>
++
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+ #include <scsi/scsi_host.h>
+@@ -1336,6 +1338,7 @@ static void storvsc_on_channel_callback(void *context)
+ 					continue;
+ 				}
+ 				request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd);
++				scsi_dma_unmap(scmnd);
+ 			}
  
- #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>
+ 			storvsc_on_receive(stor_device, packet, request);
+@@ -1749,7 +1752,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 	struct hv_host_device *host_dev = shost_priv(host);
+ 	struct hv_device *dev = host_dev->dev;
+ 	struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd);
+-	int i;
+ 	struct scatterlist *sgl;
+ 	unsigned int sg_count;
+ 	struct vmscsi_request *vm_srb;
+@@ -1831,10 +1833,11 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 	payload_sz = sizeof(cmd_request->mpb);
  
- #include "irq_remapping.h"
+ 	if (sg_count) {
+-		unsigned int hvpgoff, hvpfns_to_add;
+ 		unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset);
+ 		unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length);
+-		u64 hvpfn;
++		struct scatterlist *sg;
++		unsigned long hvpfn, hvpfns_to_add;
++		int j, i = 0;
  
-@@ -337,4 +344,161 @@ static const struct irq_domain_ops hyperv_root_ir_domain_ops = {
- 	.free = hyperv_root_irq_remapping_free,
- };
+ 		if (hvpg_count > MAX_PAGE_BUFFER_COUNT) {
  
-+static void __init hyperv_iommu_swiotlb_init(void)
-+{
-+	unsigned long hyperv_io_tlb_size;
-+	void *hyperv_io_tlb_start;
-+
-+	/*
-+	 * Allocate Hyper-V swiotlb bounce buffer at early place
-+	 * to reserve large contiguous memory.
-+	 */
-+	hyperv_io_tlb_size = swiotlb_size_or_default();
-+	hyperv_io_tlb_start = memblock_alloc(hyperv_io_tlb_size, PAGE_SIZE);
-+
-+	if (!hyperv_io_tlb_start)
-+		pr_warn("Fail to allocate Hyper-V swiotlb buffer.\n");
-+
-+	swiotlb_init_with_tbl(hyperv_io_tlb_start,
-+			      hyperv_io_tlb_size >> IO_TLB_SHIFT, true);
-+}
-+
-+int __init hyperv_swiotlb_detect(void)
-+{
-+	if (!hypervisor_is_type(X86_HYPER_MS_HYPERV))
-+		return 0;
-+
-+	if (!hv_is_isolation_supported())
-+		return 0;
-+
-+	/*
-+	 * Enable swiotlb force mode in Isolation VM to
-+	 * use swiotlb bounce buffer for dma transaction.
-+	 */
-+	if (hv_isolation_type_snp())
-+		swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary;
-+	swiotlb_force = SWIOTLB_FORCE;
-+	return 1;
-+}
-+
-+static void __init hyperv_iommu_swiotlb_later_init(void)
-+{
-+	/*
-+	 * Swiotlb bounce buffer needs to be mapped in extra address
-+	 * space. Map function doesn't work in the early place and so
-+	 * call swiotlb_update_mem_attributes() here.
-+	 */
-+	swiotlb_update_mem_attributes();
-+}
-+
-+IOMMU_INIT_FINISH(hyperv_swiotlb_detect,
-+		  NULL, hyperv_iommu_swiotlb_init,
-+		  hyperv_iommu_swiotlb_later_init);
-+
-+static struct sg_table *hyperv_dma_alloc_noncontiguous(struct device *dev,
-+		size_t size, enum dma_data_direction dir, gfp_t gfp,
-+		unsigned long attrs)
-+{
-+	struct dma_sgt_handle *sh;
-+	struct page **pages;
-+	int num_pages = size >> PAGE_SHIFT;
-+	void *vaddr, *ptr;
-+	int rc, i;
-+
-+	if (!hv_isolation_type_snp())
-+		return NULL;
-+
-+	sh = kmalloc(sizeof(*sh), gfp);
-+	if (!sh)
-+		return NULL;
-+
-+	vaddr = vmalloc(size);
-+	if (!vaddr)
-+		goto free_sgt;
-+
-+	pages = kvmalloc_array(num_pages, sizeof(struct page *),
-+				    GFP_KERNEL | __GFP_ZERO);
-+	if (!pages)
-+		goto free_mem;
-+
-+	for (i = 0, ptr = vaddr; i < num_pages; ++i, ptr += PAGE_SIZE)
-+		pages[i] = vmalloc_to_page(ptr);
-+
-+	rc = sg_alloc_table_from_pages(&sh->sgt, pages, num_pages, 0, size, GFP_KERNEL);
-+	if (rc)
-+		goto free_pages;
-+
-+	sh->sgt.sgl->dma_address = (dma_addr_t)vaddr;
-+	sh->sgt.sgl->dma_length = size;
-+	sh->pages = pages;
-+
-+	return &sh->sgt;
-+
-+free_pages:
-+	kvfree(pages);
-+free_mem:
-+	vfree(vaddr);
-+free_sgt:
-+	kfree(sh);
-+	return NULL;
-+}
-+
-+static void hyperv_dma_free_noncontiguous(struct device *dev, size_t size,
-+		struct sg_table *sgt, enum dma_data_direction dir)
-+{
-+	struct dma_sgt_handle *sh = sgt_handle(sgt);
-+
-+	if (!hv_isolation_type_snp())
-+		return;
-+
-+	vfree((void *)sh->sgt.sgl->dma_address);
-+	sg_free_table(&sh->sgt);
-+	kvfree(sh->pages);
-+	kfree(sh);
-+}
-+
-+static void *hyperv_dma_vmap_noncontiguous(struct device *dev, size_t size,
-+			struct sg_table *sgt)
-+{
-+	int pg_count = size >> PAGE_SHIFT;
-+	unsigned long *pfns;
-+	struct page **pages = sgt_handle(sgt)->pages;
-+	void *vaddr = NULL;
-+	int i;
-+
-+	if (!hv_isolation_type_snp())
-+		return NULL;
-+
-+	if (!pages)
-+		return NULL;
-+
-+	pfns = kcalloc(pg_count, sizeof(*pfns), GFP_KERNEL);
-+	if (!pfns)
-+		return NULL;
-+
-+	for (i = 0; i < pg_count; i++)
-+		pfns[i] = page_to_pfn(pages[i]) +
-+			(ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT);
-+
-+	vaddr = vmap_pfn(pfns, pg_count, PAGE_KERNEL);
-+	kfree(pfns);
-+	return vaddr;
-+
-+}
-+
-+static void hyperv_dma_vunmap_noncontiguous(struct device *dev, void *addr)
-+{
-+	if (!hv_isolation_type_snp())
-+		return;
-+	vunmap(addr);
-+}
-+
-+const struct dma_map_ops hyperv_iommu_dma_ops = {
-+		.alloc_noncontiguous = hyperv_dma_alloc_noncontiguous,
-+		.free_noncontiguous = hyperv_dma_free_noncontiguous,
-+		.vmap_noncontiguous = hyperv_dma_vmap_noncontiguous,
-+		.vunmap_noncontiguous = hyperv_dma_vunmap_noncontiguous,
-+};
-+EXPORT_SYMBOL_GPL(hyperv_iommu_dma_ops);
-+
- #endif
+@@ -1848,21 +1851,22 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 		payload->range.len = length;
+ 		payload->range.offset = offset_in_hvpg;
+ 
++		sg_count = scsi_dma_map(scmnd);
++		if (sg_count < 0)
++			return SCSI_MLQUEUE_DEVICE_BUSY;
+ 
+-		for (i = 0; sgl != NULL; sgl = sg_next(sgl)) {
++		for_each_sg(sgl, sg, sg_count, j) {
+ 			/*
+-			 * Init values for the current sgl entry. hvpgoff
+-			 * and hvpfns_to_add are in units of Hyper-V size
+-			 * pages. Handling the PAGE_SIZE != HV_HYP_PAGE_SIZE
+-			 * case also handles values of sgl->offset that are
+-			 * larger than PAGE_SIZE. Such offsets are handled
+-			 * even on other than the first sgl entry, provided
+-			 * they are a multiple of PAGE_SIZE.
++			 * Init values for the current sgl entry. hvpfns_to_add
++			 * is in units of Hyper-V size pages. Handling the
++			 * PAGE_SIZE != HV_HYP_PAGE_SIZE case also handles
++			 * values of sgl->offset that are larger than PAGE_SIZE.
++			 * Such offsets are handled even on other than the first
++			 * sgl entry, provided they are a multiple of PAGE_SIZE.
+ 			 */
+-			hvpgoff = HVPFN_DOWN(sgl->offset);
+-			hvpfn = page_to_hvpfn(sg_page(sgl)) + hvpgoff;
+-			hvpfns_to_add =	HVPFN_UP(sgl->offset + sgl->length) -
+-						hvpgoff;
++			hvpfn = HVPFN_DOWN(sg_dma_address(sg));
++			hvpfns_to_add = HVPFN_UP(sg_dma_address(sg) +
++						 sg_dma_len(sg)) - hvpfn;
+ 
+ 			/*
+ 			 * Fill the next portion of the PFN array with
+@@ -1872,7 +1876,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 			 * the PFN array is filled.
+ 			 */
+ 			while (hvpfns_to_add--)
+-				payload->range.pfn_array[i++] =	hvpfn++;
++				payload->range.pfn_array[i++] = hvpfn++;
+ 		}
+ 	}
+ 
+@@ -2016,6 +2020,7 @@ static int storvsc_probe(struct hv_device *device,
+ 	stor_device->vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
+ 	spin_lock_init(&stor_device->lock);
+ 	hv_set_drvdata(device, stor_device);
++	dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1);
+ 
+ 	stor_device->port_number = host->host_no;
+ 	ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
 diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
-index b823311eac79..4d44fb3b3f1c 100644
+index 1f037e114dc8..74f5e92f91a0 100644
 --- a/include/linux/hyperv.h
 +++ b/include/linux/hyperv.h
-@@ -1726,6 +1726,16 @@ 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));
-+#ifdef CONFIG_HYPERV
-+int __init hyperv_swiotlb_detect(void);
-+#else
-+static inline int __init hyperv_swiotlb_detect(void)
-+{
-+	return 0;
-+}
-+#endif
-+
-+extern const struct dma_map_ops hyperv_iommu_dma_ops;
+@@ -1261,6 +1261,7 @@ struct hv_device {
  
- struct hyperv_pci_block_ops {
- 	int (*read_block)(struct pci_dev *dev, void *buf, unsigned int buf_len,
+ 	struct vmbus_channel *channel;
+ 	struct kset	     *channels_kset;
++	struct device_dma_parameters dma_parms;
+ 
+ 	/* place holder to keep track of the dir for hv device in debugfs */
+ 	struct dentry *debug_dir;
 -- 
 2.25.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help