Inter-revision diff: patch 9

Comparing rfc (message) to v4 (message)

--- vrfc
+++ v4
@@ -1,224 +1,195 @@
 From: Tianyu Lan <Tianyu.Lan@microsoft.com>
 
-Add new parameter io_type and struct bounce_pkt for vmbus_sendpacket_pagebuffer()
-and vmbus_sendpacket_mpb_desc() in order to add bounce buffer support
-later.
+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.
 
-Signed-off-by: Sunil Muthuswamy <sunilmut@microsoft.com>
-Co-Developed-by: Sunil Muthuswamy <sunilmut@microsoft.com>
+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>
 ---
- drivers/hv/channel.c            |  7 +++++--
- drivers/hv/hyperv_vmbus.h       | 12 ++++++++++++
- drivers/net/hyperv/hyperv_net.h |  1 +
- drivers/net/hyperv/netvsc.c     |  5 ++++-
- drivers/scsi/storvsc_drv.c      | 23 +++++++++++++++++------
- include/linux/hyperv.h          | 16 ++++++++++++++--
- 6 files changed, 53 insertions(+), 11 deletions(-)
+ 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/drivers/hv/channel.c b/drivers/hv/channel.c
-index 4c05b1488649..976ef99dda28 100644
---- a/drivers/hv/channel.c
-+++ b/drivers/hv/channel.c
-@@ -1044,7 +1044,8 @@ EXPORT_SYMBOL(vmbus_sendpacket);
- int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
- 				struct hv_page_buffer pagebuffers[],
- 				u32 pagecount, void *buffer, u32 bufferlen,
--				u64 requestid)
-+				u64 requestid, u8 io_type,
-+				struct hv_bounce_pkt **bounce_pkt)
+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)
  {
- 	int i;
- 	struct vmbus_channel_packet_page_buffer desc;
-@@ -1101,7 +1102,9 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
- int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
- 			      struct vmbus_packet_mpb_array *desc,
- 			      u32 desc_size,
--			      void *buffer, u32 bufferlen, u64 requestid)
-+			      void *buffer, u32 bufferlen, u64 requestid,
-+			      u32 pfn_count, u8 io_type,
-+			      struct hv_bounce_pkt **bounce_pkt)
- {
- 	u32 packetlen;
- 	u32 packetlen_aligned;
-diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
-index 7edf2be60d2c..7677f083d33a 100644
---- a/drivers/hv/hyperv_vmbus.h
-+++ b/drivers/hv/hyperv_vmbus.h
-@@ -57,6 +57,18 @@ union hv_monitor_trigger_state {
- 	};
+@@ -337,4 +347,56 @@ static const struct irq_domain_ops hyperv_root_ir_domain_ops = {
+ 	.free = hyperv_root_irq_remapping_free,
  };
  
-+/*
-+ * Hyper-V bounce packet. Each in-use bounce packet is mapped to a vmbus
-+ * transaction and contains a list of bounce pages for that transaction.
-+ */
-+struct hv_bounce_pkt {
-+	/* Link to the next bounce packet, when it is in the free list */
-+	struct list_head link;
-+	struct list_head bounce_page_head;
-+	u32 flags;
-+};
++void __init hyperv_iommu_swiotlb_init(void)
++{
++	unsigned long bytes;
++	void *vstart;
 +
++	/*
++	 * 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);
 +
- /*
-  * All vmbus channels initially start with zero bounce pages and are required
-  * to set any non-zero size, if needed.
-diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
-index b3a43c4ec8ab..11266b92bcf0 100644
---- a/drivers/net/hyperv/hyperv_net.h
-+++ b/drivers/net/hyperv/hyperv_net.h
-@@ -130,6 +130,7 @@ struct hv_netvsc_packet {
- 	u32 total_bytes;
- 	u32 send_buf_index;
- 	u32 total_data_buflen;
-+	struct hv_bounce_pkt *bounce_pkt;
- };
- 
- #define NETVSC_HASH_KEYLEN 40
-diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
-index 08d73401bb28..77657c5acc65 100644
---- a/drivers/net/hyperv/netvsc.c
-+++ b/drivers/net/hyperv/netvsc.c
-@@ -926,14 +926,17 @@ static inline int netvsc_send_pkt(
- 
- 	trace_nvsp_send_pkt(ndev, out_channel, rpkt);
- 
-+	packet->bounce_pkt = NULL;
- 	if (packet->page_buf_cnt) {
- 		if (packet->cp_partial)
- 			pb += packet->rmsg_pgcnt;
- 
-+		/* The I/O type is always 'write' for netvsc */
- 		ret = vmbus_sendpacket_pagebuffer(out_channel,
- 						  pb, packet->page_buf_cnt,
- 						  &nvmsg, sizeof(nvmsg),
--						  req_id);
-+						  req_id, IO_TYPE_WRITE,
-+						  &packet->bounce_pkt);
- 	} else {
- 		ret = vmbus_sendpacket(out_channel,
- 				       &nvmsg, sizeof(nvmsg),
-diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
-index 2e4fa77445fd..c5b4974eb41f 100644
---- a/drivers/scsi/storvsc_drv.c
-+++ b/drivers/scsi/storvsc_drv.c
-@@ -31,6 +31,7 @@
- #include <scsi/scsi_dbg.h>
- #include <scsi/scsi_transport_fc.h>
- #include <scsi/scsi_transport.h>
-+#include <asm/mshyperv.h>
- 
- /*
-  * All wire protocol details (storage protocol between the guest and the host)
-@@ -427,6 +428,7 @@ struct storvsc_cmd_request {
- 	u32 payload_sz;
- 
- 	struct vstor_packet vstor_packet;
-+	struct hv_bounce_pkt *bounce_pkt;
- };
- 
- 
-@@ -1390,7 +1392,8 @@ static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device,
- 
- 
- static int storvsc_do_io(struct hv_device *device,
--			 struct storvsc_cmd_request *request, u16 q_num)
-+			 struct storvsc_cmd_request *request, u16 q_num,
-+			 u32 pfn_count)
- {
- 	struct storvsc_device *stor_device;
- 	struct vstor_packet *vstor_packet;
-@@ -1493,14 +1496,18 @@ static int storvsc_do_io(struct hv_device *device,
- 
- 	vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
- 
-+	request->bounce_pkt = NULL;
- 	if (request->payload->range.len) {
-+		struct vmscsi_request *vm_srb = &request->vstor_packet.vm_srb;
- 
- 		ret = vmbus_sendpacket_mpb_desc(outgoing_channel,
- 				request->payload, request->payload_sz,
- 				vstor_packet,
- 				(sizeof(struct vstor_packet) -
- 				vmscsi_size_delta),
--				(unsigned long)request);
-+				(unsigned long)request,
-+				pfn_count,
-+				vm_srb->data_in, &request->bounce_pkt);
- 	} else {
- 		ret = vmbus_sendpacket(outgoing_channel, vstor_packet,
- 			       (sizeof(struct vstor_packet) -
-@@ -1510,8 +1517,10 @@ static int storvsc_do_io(struct hv_device *device,
- 			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- 	}
- 
--	if (ret != 0)
-+	if (ret != 0) {
-+		request->bounce_pkt = NULL;
- 		return ret;
++	if (!hyperv_io_tlb_start) {
++		pr_warn("Fail to allocate Hyper-V swiotlb buffer.\n");
++		return;
 +	}
- 
- 	atomic_inc(&stor_device->num_outstanding_req);
- 
-@@ -1825,14 +1834,16 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
- 	cmd_request->payload_sz = payload_sz;
- 
- 	/* Invokes the vsc to start an IO */
--	ret = storvsc_do_io(dev, cmd_request, get_cpu());
-+	ret = storvsc_do_io(dev, cmd_request, get_cpu(), sg_count);
- 	put_cpu();
- 
--	if (ret == -EAGAIN) {
-+	if (ret) {
- 		if (payload_sz > sizeof(cmd_request->mpb))
- 			kfree(payload);
- 		/* no more space */
--		return SCSI_MLQUEUE_DEVICE_BUSY;
-+		if (ret == -EAGAIN || ret == -ENOSPC)
-+			return SCSI_MLQUEUE_DEVICE_BUSY;
-+		return ret;
- 	}
- 
- 	return 0;
++}
++
++int __init hyperv_swiotlb_detect(void)
++{
++	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 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 d518aba17565..d1a936091665 100644
+index 06eccaba10c5..babbe19f57e2 100644
 --- a/include/linux/hyperv.h
 +++ b/include/linux/hyperv.h
-@@ -1184,19 +1184,31 @@ extern int vmbus_sendpacket(struct vmbus_channel *channel,
- 				  enum vmbus_packet_type type,
- 				  u32 flags);
+@@ -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);
  
-+#define IO_TYPE_WRITE	0
-+#define IO_TYPE_READ	1
-+#define IO_TYPE_UNKNOWN 2
-+
-+struct hv_bounce_pkt;
-+
- extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
- 					    struct hv_page_buffer pagebuffers[],
- 					    u32 pagecount,
- 					    void *buffer,
- 					    u32 bufferlen,
--					    u64 requestid);
-+					    u64 requestid,
-+					    u8 io_type,
-+					    struct hv_bounce_pkt **bounce_pkt);
- 
- extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
- 				     struct vmbus_packet_mpb_array *mpb,
- 				     u32 desc_size,
- 				     void *buffer,
- 				     u32 bufferlen,
--				     u64 requestid);
-+				     u64 requestid,
-+				     u32 pfn_count,
-+				     u8 io_type,
-+				     struct hv_bounce_pkt **bounce_pkt);
-+
- 
- extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
- 				      void *kbuffer,
+ struct hyperv_pci_block_ops {
+ 	int (*read_block)(struct pci_dev *dev, void *buf, unsigned int buf_len,
 -- 
 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