git: d0cb4674df97 - main - Hyper-V: move memory alloc call for tlb hypercall out of smp_rendezvous

From: Wei Hu <whu_at_FreeBSD.org>
Date: Sat, 15 Jun 2024 14:24:53 UTC
The branch main has been updated by whu:

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

commit d0cb4674df97aa638d5d17861c364b1625f79401
Author:     Wei Hu <whu@FreeBSD.org>
AuthorDate: 2024-06-15 14:07:58 +0000
Commit:     Wei Hu <whu@FreeBSD.org>
CommitDate: 2024-06-15 14:07:58 +0000

    Hyper-V: move memory alloc call for tlb hypercall out of smp_rendezvous
    
    The allocation call could result in sleep lock violation if it is in
    smp_rendezvous. Move it out. Also move the pcpu memory pointer to
    vmbus_pcpu_data since it is only used on Hyper-V.
    
    PR:             279738
    Reported by:    gbe
    Fixes:          2b887687edc25bb4553f0d8a1183f454a85d413d
    MFC after:      2 weeks
    Sponsored by:   Microsoft
---
 sys/dev/hyperv/vmbus/hyperv_mmu.c |  6 +--
 sys/dev/hyperv/vmbus/vmbus.c      | 88 +++++++++++++++++++++++++++++----------
 sys/dev/hyperv/vmbus/vmbus_var.h  |  5 ++-
 3 files changed, 71 insertions(+), 28 deletions(-)

diff --git a/sys/dev/hyperv/vmbus/hyperv_mmu.c b/sys/dev/hyperv/vmbus/hyperv_mmu.c
index 13b1f52fa1f6..7c29fe294093 100644
--- a/sys/dev/hyperv/vmbus/hyperv_mmu.c
+++ b/sys/dev/hyperv/vmbus/hyperv_mmu.c
@@ -144,7 +144,7 @@ hv_vm_tlb_flush(pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2,
 		return smp_targeted_tlb_shootdown_native(pmap, addr1, addr2,
 		    curcpu_cb, op);
 
-	flush = *DPCPU_PTR(hv_pcpu_mem);
+	flush = *VMBUS_PCPU_PTR(sc, cpu_mem, curcpu);
 	if (flush == NULL)
 		return smp_targeted_tlb_shootdown_native(pmap, addr1, addr2,
 		    curcpu_cb, op);
@@ -253,9 +253,9 @@ hv_flush_tlb_others_ex(pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2,
 {
 	int nr_bank = 0, max_gvas, gva_n;
 	struct hv_tlb_flush_ex *flush;
-	if(*DPCPU_PTR(hv_pcpu_mem) == NULL)
+	if(*VMBUS_PCPU_PTR(sc, cpu_mem, curcpu) == NULL)
 		return EINVAL;
-	flush = *DPCPU_PTR(hv_pcpu_mem);
+	flush = *VMBUS_PCPU_PTR(sc, cpu_mem, curcpu);
 	uint64_t status = 0;
 	uint64_t cr3;
 
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index f55f0329b017..dee738f6e373 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -139,7 +139,10 @@ 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;
-static void free_pcpu_ptr(void);
+#if defined(__x86_64__)
+static int vmbus_alloc_cpu_mem(struct vmbus_softc *sc);
+static void vmbus_free_cpu_mem(struct vmbus_softc *sc);
+#endif
 
 SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
     "Hyper-V vmbus");
@@ -217,7 +220,6 @@ static driver_t vmbus_driver = {
 };
 
 uint32_t hv_max_vp_index;
-DPCPU_DEFINE(void *, hv_pcpu_mem);
 
 DRIVER_MODULE(vmbus, pcib, vmbus_driver, NULL, NULL);
 DRIVER_MODULE(vmbus, acpi_syscontainer, vmbus_driver, NULL, NULL);
@@ -750,7 +752,6 @@ vmbus_synic_setup(void *xsc)
 	int cpu = curcpu;
 	uint64_t val, orig;
 	uint32_t sint;
-	void **hv_cpu_mem;
 
 	if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
 		/* Save virtual processor id. */
@@ -762,19 +763,6 @@ vmbus_synic_setup(void *xsc)
 
 	if (VMBUS_PCPU_GET(sc, vcpuid, cpu) > hv_max_vp_index)
 		hv_max_vp_index = VMBUS_PCPU_GET(sc, vcpuid, cpu);
-	hv_cpu_mem = DPCPU_ID_PTR(cpu, hv_pcpu_mem);
-	*hv_cpu_mem = contigmalloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO,
-	    0ul, ~0ul, PAGE_SIZE, 0);
-
-#if defined(__x86_64__)
-	if (*hv_cpu_mem == NULL && hv_tlb_hcall) {
-		hv_tlb_hcall = 0;
-		if (bootverbose && sc)
-			device_printf(sc->vmbus_dev,
-			    "cannot alloc contig memory for hv_pcpu_mem, "
-			    "use system provided tlb flush call.\n");
-	}
-#endif
 
 	/*
 	 * Setup the SynIC message.
@@ -858,7 +846,6 @@ vmbus_synic_teardown(void *arg)
 	 */
 	orig = RDMSR(MSR_HV_SIEFP);
 	WRMSR(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
-	free_pcpu_ptr();
 }
 
 static int
@@ -1412,15 +1399,41 @@ vmbus_probe(device_t dev)
 	return (BUS_PROBE_DEFAULT);
 }
 
+#if defined(__x86_64__)
+static int
+vmbus_alloc_cpu_mem(struct vmbus_softc *sc)
+{
+	int cpu;
 
-static void free_pcpu_ptr(void)
+	CPU_FOREACH(cpu) {
+		void **hv_cpu_mem;
+
+		hv_cpu_mem = VMBUS_PCPU_PTR(sc, cpu_mem, cpu);
+		*hv_cpu_mem = contigmalloc(PAGE_SIZE, M_DEVBUF,
+		    M_NOWAIT | M_ZERO, 0ul, ~0ul, PAGE_SIZE, 0);
+
+		if (*hv_cpu_mem == NULL)
+			return ENOMEM;
+	}
+
+	return 0;
+}
+
+static void
+vmbus_free_cpu_mem(struct vmbus_softc *sc)
 {
-	int cpu = curcpu;
-	void **hv_cpu_mem;
-	hv_cpu_mem = DPCPU_ID_PTR(cpu, hv_pcpu_mem);
-	if(*hv_cpu_mem)
-		contigfree(*hv_cpu_mem, PAGE_SIZE, M_DEVBUF);
+	int cpu;
+
+	CPU_FOREACH(cpu) {
+		void **hv_cpu_mem;
+		hv_cpu_mem = VMBUS_PCPU_PTR(sc, cpu_mem, cpu);
+		if(*hv_cpu_mem != NULL) {
+			contigfree(*hv_cpu_mem, PAGE_SIZE, M_DEVBUF);
+			*hv_cpu_mem = NULL;
+		}
+	}
 }
+#endif
 
 /**
  * @brief Main vmbus driver initialization routine.
@@ -1511,6 +1524,25 @@ vmbus_doattach(struct vmbus_softc *sc)
 	if (ret != 0)
 		goto cleanup;
 
+#if defined(__x86_64__)
+	/*
+	 * Alloc per cpu memory for tlb flush hypercall
+	 */
+	if (hv_tlb_hcall) {
+		ret = vmbus_alloc_cpu_mem(sc);
+		if (ret != 0) {
+			hv_tlb_hcall = 0;
+			if (bootverbose)
+				device_printf(sc->vmbus_dev,
+				    "cannot alloc contig memory for "
+				    "cpu_mem, use system provided "
+				    "tlb flush call.\n");
+
+			vmbus_free_cpu_mem(sc);
+		}
+	}
+#endif
+
 	/*
 	 * Setup SynIC.
 	 */
@@ -1627,6 +1659,16 @@ vmbus_detach(device_t dev)
 		smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
 	}
 
+#if defined(__x86_64__)
+	/*
+	 * Restore the tlb flush to native call
+	 */
+	if (hv_tlb_hcall) {
+		smp_targeted_tlb_shootdown = &smp_targeted_tlb_shootdown_native;
+		vmbus_free_cpu_mem(sc);
+	}
+#endif
+
 	vmbus_intr_teardown(sc);
 	vmbus_dma_free(sc);
 
diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h
index 4f0668476716..4e0a769402d5 100644
--- a/sys/dev/hyperv/vmbus/vmbus_var.h
+++ b/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -74,6 +74,9 @@ struct vmbus_pcpu_data {
 	uint32_t		vcpuid;		/* virtual cpuid */
 	int			event_flags_cnt;/* # of event flags */
 	struct vmbus_evtflags	*event_flags;	/* event flags from host */
+#if defined(__x86_64__)
+	void			*cpu_mem;	/* For Hyper-V tlb hypercall */
+#endif
 
 	/* Rarely used fields */
 	struct taskqueue	*event_tq;	/* event taskq */
@@ -216,8 +219,6 @@ void    vmbus_synic_teardown1(void);
 int     vmbus_setup_intr1(struct vmbus_softc *sc);
 void    vmbus_intr_teardown1(struct vmbus_softc *sc);
 
-DPCPU_DECLARE(void *, hv_pcpu_mem);
-
 extern uint32_t hv_max_vp_index;