Message ID | 20211213071407.314309-5-ltykernel@gmail.com |
---|---|
State | New |
Headers | show |
Series | x86/Hyper-V: Add Hyper-V Isolation VM support(Second part) | expand |
> From: Tianyu Lan <ltykernel@gmail.com> > Sent: Sunday, December 12, 2021 11:14 PM > To: KY Srinivasan <kys@microsoft.com>; Haiyang Zhang > <haiyangz@microsoft.com>; Stephen Hemminger <sthemmin@microsoft.com>; > wei.liu@kernel.org; Dexuan Cui <decui@microsoft.com>; tglx@linutronix.de; > mingo@redhat.com; bp@alien8.de; dave.hansen@linux.intel.com; > x86@kernel.org; hpa@zytor.com; davem@davemloft.net; kuba@kernel.org; > jejb@linux.ibm.com; martin.petersen@oracle.com; arnd@arndb.de; > hch@infradead.org; m.szyprowski@samsung.com; robin.murphy@arm.com; > thomas.lendacky@amd.com; Tianyu Lan <Tianyu.Lan@microsoft.com>; Michael > Kelley (LINUX) <mikelley@microsoft.com> > Cc: iommu@lists.linux-foundation.org; linux-arch@vger.kernel.org; linux- > hyperv@vger.kernel.org; linux-kernel@vger.kernel.org; linux- > scsi@vger.kernel.org; netdev@vger.kernel.org; vkuznets > <vkuznets@redhat.com>; brijesh.singh@amd.com; konrad.wilk@oracle.com; > hch@lst.de; joro@8bytes.org; parri.andrea@gmail.com; > dave.hansen@intel.com > Subject: [PATCH V7 4/5] scsi: storvsc: Add Isolation VM support for storvsc driver > > From: Tianyu Lan <Tianyu.Lan@microsoft.com> > > 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. > > 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> Reviewed-by: Long Li <longli@microsoft.com> > --- > drivers/hv/vmbus_drv.c | 4 ++++ > drivers/scsi/storvsc_drv.c | 37 +++++++++++++++++++++---------------- > include/linux/hyperv.h | 1 + > 3 files changed, 26 insertions(+), 16 deletions(-) > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index > 392c1ac4f819..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,8 @@ 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; > + child_device_obj->device.dma_parms = &child_device_obj->dma_parms; > return 0; > > err_kset_unregister: > 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); > } > > 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); > > 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; > > if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { > > @@ -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..650a0574b746 100644 > --- a/include/linux/hyperv.h > +++ b/include/linux/hyperv.h > @@ -1261,6 +1261,7 @@ struct hv_device { > > 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
On Mon, 13 Dec 2021 02:14:05 -0500 Tianyu Lan wrote: > @@ -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); This breaks the x86 clang allmodconfig build as I presume those involved know by now: ../drivers/hv/vmbus_drv.c:2082:29: error: shift count >= width of type [-Werror,-Wshift-count-overflow] static u64 vmbus_dma_mask = DMA_BIT_MASK(64); ^~~~~~~~~~~~~~~~ ../include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK' #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ^ ~~~ 1 error generated. Is there any ETA on getting the fix into Linus's tree?
On Thu, 3 Feb 2022 15:53:51 -0800 Jakub Kicinski wrote: > On Mon, 13 Dec 2021 02:14:05 -0500 Tianyu Lan wrote: > > @@ -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); > > This breaks the x86 clang allmodconfig build as I presume those > involved know by now: > > ../drivers/hv/vmbus_drv.c:2082:29: error: shift count >= width of type [-Werror,-Wshift-count-overflow] > static u64 vmbus_dma_mask = DMA_BIT_MASK(64); > ^~~~~~~~~~~~~~~~ > ../include/linux/dma-mapping.h:76:54: note: expanded from macro 'DMA_BIT_MASK' > #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) > ^ ~~~ > 1 error generated. Looks like a compiler issue actually, found the discussion now: https://lore.kernel.org/llvm/202112181827.o3X7GmHz-lkp@intel.com/
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 392c1ac4f819..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,8 @@ 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; + child_device_obj->device.dma_parms = &child_device_obj->dma_parms; return 0; err_kset_unregister: 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); } 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); 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; if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { @@ -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..650a0574b746 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1261,6 +1261,7 @@ struct hv_device { 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;