--- v2
+++ v4
@@ -1,138 +1,159 @@
From: Tianyu Lan <Tianyu.Lan@microsoft.com>
-In Isolation VM with AMD SEV, 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.
-
-Use dma_map_decrypted() in the swiotlb code, store remap address returned
-and use the remap address to copy data from/to swiotlb bounce buffer.
+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 need to handle. Use DMA API to map/umap these
+memory during sending/receiving packet and Hyper-V DMA ops callback
+will use swiotlb function to allocate bounce buffer and copy data
+from/to bounce buffer.
Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
---
-Change since v1:
- * Make swiotlb_init_io_tlb_mem() return error code and return
- error when dma_map_decrypted() fails.
+ drivers/scsi/storvsc_drv.c | 68 +++++++++++++++++++++++++++++++++++---
+ 1 file changed, 63 insertions(+), 5 deletions(-)
-Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
----
- include/linux/swiotlb.h | 4 ++++
- kernel/dma/swiotlb.c | 32 ++++++++++++++++++++++++--------
- 2 files changed, 28 insertions(+), 8 deletions(-)
-
-diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
-index f507e3eacbea..584560ecaa8e 100644
---- a/include/linux/swiotlb.h
-+++ b/include/linux/swiotlb.h
-@@ -72,6 +72,9 @@ extern enum swiotlb_force swiotlb_force;
- * @end: The end address of the swiotlb memory pool. Used to do a quick
- * range check to see if the memory was in fact allocated by this
- * API.
-+ * @vaddr: The vaddr of the swiotlb memory pool. The swiotlb
-+ * memory pool may be remapped in the memory encrypted case and store
-+ * virtual address for bounce buffer operation.
- * @nslabs: The number of IO TLB blocks (in groups of 64) between @start and
- * @end. For default swiotlb, this is command line adjustable via
- * setup_io_tlb_npages.
-@@ -89,6 +92,7 @@ extern enum swiotlb_force swiotlb_force;
- struct io_tlb_mem {
- phys_addr_t start;
- phys_addr_t end;
-+ void *vaddr;
- unsigned long nslabs;
- unsigned long used;
- unsigned int index;
-diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
-index 1fa81c096c1d..29b6d888ef3b 100644
---- a/kernel/dma/swiotlb.c
-+++ b/kernel/dma/swiotlb.c
-@@ -176,7 +176,7 @@ void __init swiotlb_update_mem_attributes(void)
- memset(vaddr, 0, bytes);
+diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
+index 403753929320..cc9cb32f6621 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/io.h>
++#include <linux/dma-mapping.h>
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_cmnd.h>
+ #include <scsi/scsi_host.h>
+@@ -427,6 +429,8 @@ struct storvsc_cmd_request {
+ u32 payload_sz;
+
+ struct vstor_packet vstor_packet;
++ u32 hvpg_count;
++ struct hv_dma_range *dma_range;
+ };
+
+
+@@ -509,6 +513,14 @@ struct storvsc_scan_work {
+ u8 tgt_id;
+ };
+
++#define storvsc_dma_map(dev, page, offset, size, dir) \
++ dma_map_page(dev, page, offset, size, dir)
++
++#define storvsc_dma_unmap(dev, dma_range, dir) \
++ dma_unmap_page(dev, dma_range.dma, \
++ dma_range.mapping_size, \
++ dir ? DMA_FROM_DEVICE : DMA_TO_DEVICE)
++
+ static void storvsc_device_scan(struct work_struct *work)
+ {
+ struct storvsc_scan_work *wrk;
+@@ -1267,6 +1279,7 @@ static void storvsc_on_channel_callback(void *context)
+ struct hv_device *device;
+ struct storvsc_device *stor_device;
+ struct Scsi_Host *shost;
++ int i;
+
+ if (channel->primary_channel != NULL)
+ device = channel->primary_channel->device_obj;
+@@ -1321,6 +1334,15 @@ static void storvsc_on_channel_callback(void *context)
+ request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd);
+ }
+
++ if (request->dma_range) {
++ for (i = 0; i < request->hvpg_count; i++)
++ storvsc_dma_unmap(&device->device,
++ request->dma_range[i],
++ request->vstor_packet.vm_srb.data_in == READ_TYPE);
++
++ kfree(request->dma_range);
++ }
++
+ storvsc_on_receive(stor_device, packet, request);
+ continue;
+ }
+@@ -1817,7 +1839,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ 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);
++ dma_addr_t dma;
+ u64 hvpfn;
++ u32 size;
+
+ if (hvpg_count > MAX_PAGE_BUFFER_COUNT) {
+
+@@ -1831,6 +1855,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ payload->range.len = length;
+ payload->range.offset = offset_in_hvpg;
+
++ cmd_request->dma_range = kcalloc(hvpg_count,
++ sizeof(*cmd_request->dma_range),
++ GFP_ATOMIC);
++ if (!cmd_request->dma_range) {
++ ret = -ENOMEM;
++ goto free_payload;
++ }
+
+ for (i = 0; sgl != NULL; sgl = sg_next(sgl)) {
+ /*
+@@ -1854,9 +1885,29 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ * last sgl should be reached at the same time that
+ * the PFN array is filled.
+ */
+- while (hvpfns_to_add--)
+- payload->range.pfn_array[i++] = hvpfn++;
++ while (hvpfns_to_add--) {
++ size = min(HV_HYP_PAGE_SIZE - offset_in_hvpg,
++ (unsigned long)length);
++ dma = storvsc_dma_map(&dev->device, pfn_to_page(hvpfn++),
++ offset_in_hvpg, size,
++ scmnd->sc_data_direction);
++ if (dma_mapping_error(&dev->device, dma)) {
++ ret = -ENOMEM;
++ goto free_dma_range;
++ }
++
++ if (offset_in_hvpg) {
++ payload->range.offset = dma & ~HV_HYP_PAGE_MASK;
++ offset_in_hvpg = 0;
++ }
++
++ cmd_request->dma_range[i].dma = dma;
++ cmd_request->dma_range[i].mapping_size = size;
++ payload->range.pfn_array[i++] = dma >> HV_HYP_PAGE_SHIFT;
++ length -= size;
++ }
+ }
++ cmd_request->hvpg_count = hvpg_count;
+ }
+
+ cmd_request->payload = payload;
+@@ -1867,13 +1918,20 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
+ put_cpu();
+
+ if (ret == -EAGAIN) {
+- if (payload_sz > sizeof(cmd_request->mpb))
+- kfree(payload);
+ /* no more space */
+- return SCSI_MLQUEUE_DEVICE_BUSY;
++ ret = SCSI_MLQUEUE_DEVICE_BUSY;
++ goto free_dma_range;
+ }
+
+ return 0;
++
++free_dma_range:
++ kfree(cmd_request->dma_range);
++
++free_payload:
++ if (payload_sz > sizeof(cmd_request->mpb))
++ kfree(payload);
++ return ret;
}
--static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start,
-+static int swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start,
- unsigned long nslabs, bool late_alloc)
- {
- void *vaddr = phys_to_virt(start);
-@@ -194,14 +194,21 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start,
- mem->slots[i].alloc_size = 0;
- }
-
-- set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT);
-- memset(vaddr, 0, bytes);
-+ mem->vaddr = dma_map_decrypted(vaddr, bytes);
-+ if (!mem->vaddr) {
-+ pr_err("Failed to decrypt memory.\n");
-+ return -ENOMEM;
-+ }
-+
-+ memset(mem->vaddr, 0, bytes);
-+ return 0;
- }
-
- int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
- {
- struct io_tlb_mem *mem;
- size_t alloc_size;
-+ int ret;
-
- if (swiotlb_force == SWIOTLB_NO_FORCE)
- return 0;
-@@ -216,7 +223,11 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
- panic("%s: Failed to allocate %zu bytes align=0x%lx\n",
- __func__, alloc_size, PAGE_SIZE);
-
-- swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, false);
-+ ret = swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, false);
-+ if (ret) {
-+ memblock_free(__pa(mem), alloc_size);
-+ return ret;
-+ }
-
- io_tlb_default_mem = mem;
- if (verbose)
-@@ -304,6 +315,8 @@ int
- swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
- {
- struct io_tlb_mem *mem;
-+ int size = get_order(struct_size(mem, slots, nslabs));
-+ int ret;
-
- if (swiotlb_force == SWIOTLB_NO_FORCE)
- return 0;
-@@ -312,12 +325,15 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
- if (WARN_ON_ONCE(io_tlb_default_mem))
- return -ENOMEM;
-
-- mem = (void *)__get_free_pages(GFP_KERNEL,
-- get_order(struct_size(mem, slots, nslabs)));
-+ mem = (void *)__get_free_pages(GFP_KERNEL, size);
- if (!mem)
- return -ENOMEM;
-
-- swiotlb_init_io_tlb_mem(mem, virt_to_phys(tlb), nslabs, true);
-+ ret = swiotlb_init_io_tlb_mem(mem, virt_to_phys(tlb), nslabs, true);
-+ if (ret) {
-+ free_pages((unsigned long)mem, size);
-+ return ret;
-+ }
-
- io_tlb_default_mem = mem;
- swiotlb_print_info();
-@@ -360,7 +376,7 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
- phys_addr_t orig_addr = mem->slots[index].orig_addr;
- size_t alloc_size = mem->slots[index].alloc_size;
- unsigned long pfn = PFN_DOWN(orig_addr);
-- unsigned char *vaddr = phys_to_virt(tlb_addr);
-+ unsigned char *vaddr = mem->vaddr + tlb_addr - mem->start;
- unsigned int tlb_offset;
-
- if (orig_addr == INVALID_PHYS_ADDR)
+ static struct scsi_host_template scsi_driver = {
--
2.25.1