git: 48a799af88c0 - releng/14.0 - Hyper-V: vmbus: implementat bus_get_dma_tag in vmbus

From: Wei Hu <whu_at_FreeBSD.org>
Date: Mon, 18 Sep 2023 14:59:56 UTC
The branch releng/14.0 has been updated by whu:

URL: https://cgit.FreeBSD.org/src/commit/?id=48a799af88c0c77963ffb23eba797f85f86751dd

commit 48a799af88c0c77963ffb23eba797f85f86751dd
Author:     Souradeep Chakrabarti <schakrabarti@microsoft.com>
AuthorDate: 2023-09-14 07:11:25 +0000
Commit:     Wei Hu <whu@FreeBSD.org>
CommitDate: 2023-09-18 14:57:57 +0000

    Hyper-V: vmbus: implementat bus_get_dma_tag in vmbus
    
    In ARM64 Hyper-V UFS filesystem is getting corruption and those
    corruptions are consistently happening just after hitting a page
    boundary. It is unable to correctly read disk blocks into buffers
    that are not aligned to 512-byte boundaries.
    
    It happens because storvsc needs physically contiguous memory which
    may not be the case when bus_dma needs to create a bounce buffer.
    This can happen when the destination is not cache-line aligned.
    
    Hyper-V VMs have VMbus synthetic devices and PCI pass-thru devices
    that are added dynamically via the VMbus protocol and are not
    represented in the ACPI DSDT. Only the top level VMbus node exists
    in the DSDT. As such, on ARM64 these devices don't pick up coherence
    information and default to not hardware coherent.
    
    Approved by:    re (gjb)
    PR:             267654, 272666
    Reviewed by:    andrew, whu
    Tested by:      lwhsu
    Sponsored by:   Microsoft
    Differential Revision:  https://reviews.freebsd.org/D41728
    
    (cherry picked from commit e7a9817b8d328dda04069b65944ce2ed6f54c6f0)
    (cherry picked from commit 85bc81352e4b0d0a9da251bacec35eec130eee49)
---
 sys/dev/hyperv/vmbus/vmbus.c     | 33 +++++++++++++++++++++++++++++++++
 sys/dev/hyperv/vmbus/vmbus_var.h |  1 +
 2 files changed, 34 insertions(+)

diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index e0f7bbc99ca7..ee412e643b4f 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -137,6 +137,7 @@ static void			vmbus_intr_teardown(struct vmbus_softc *);
 static int			vmbus_doattach(struct vmbus_softc *);
 static void			vmbus_event_proc_dummy(struct vmbus_softc *,
 				    int);
+static bus_dma_tag_t	vmbus_get_dma_tag(device_t parent, device_t child);
 static struct vmbus_softc	*vmbus_sc;
 
 SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
@@ -183,6 +184,7 @@ static device_method_t vmbus_methods[] = {
 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
 	DEVMETHOD(bus_get_cpus,			bus_generic_get_cpus),
+	DEVMETHOD(bus_get_dma_tag,		vmbus_get_dma_tag),
 
 	/* pcib interface */
 	DEVMETHOD(pcib_alloc_msi,		vmbus_alloc_msi),
@@ -219,6 +221,13 @@ vmbus_get_softc(void)
 	return vmbus_sc;
 }
 
+static bus_dma_tag_t
+vmbus_get_dma_tag(device_t dev, device_t child)
+{
+	struct vmbus_softc *sc = vmbus_get_softc();
+	return (sc->dmat);
+}
+
 void
 vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
 {
@@ -1382,6 +1391,9 @@ vmbus_doattach(struct vmbus_softc *sc)
 	struct sysctl_oid_list *child;
 	struct sysctl_ctx_list *ctx;
 	int ret;
+	device_t dev_res;
+	ACPI_HANDLE handle;
+	unsigned int coherent;
 
 	if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
 		return (0);
@@ -1402,6 +1414,27 @@ vmbus_doattach(struct vmbus_softc *sc)
 	    sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF,
 	    M_WAITOK | M_ZERO);
 
+	/* Coherency attribute */
+	dev_res =  devclass_get_device(devclass_find("vmbus_res"), 0);
+	handle = acpi_get_handle(dev_res);
+
+	if (ACPI_FAILURE(acpi_GetInteger(handle, "_CCA", &coherent)))
+		coherent = 0;
+	if (bootverbose)
+		device_printf(sc->vmbus_dev, "Bus is%s cache-coherent\n",
+			coherent ? "" : " not");
+
+	bus_dma_tag_create(bus_get_dma_tag(sc->vmbus_dev),
+		1, 0,
+		BUS_SPACE_MAXADDR,
+		BUS_SPACE_MAXADDR,
+		NULL, NULL,
+		BUS_SPACE_MAXSIZE,
+		BUS_SPACE_UNRESTRICTED,
+		BUS_SPACE_MAXSIZE,
+		coherent ? BUS_DMA_COHERENT : 0,
+		NULL, NULL,
+		&sc->dmat);
 	/*
 	 * Create context for "post message" Hypercalls
 	 */
diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h
index f6fc875deb32..023d27c52cea 100644
--- a/sys/dev/hyperv/vmbus/vmbus_var.h
+++ b/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -129,6 +129,7 @@ struct vmbus_softc {
 	void *icookie;
 	int vector;
 #endif
+	bus_dma_tag_t   dmat;
 };
 
 #define VMBUS_FLAG_ATTACHED	0x0001	/* vmbus was attached */