git: d5f4d9d52458 - releng/12.3 - Hyper-V: vPCI: Prepopulate device bars

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Tue, 11 Jan 2022 18:18:11 UTC
The branch releng/12.3 has been updated by emaste:

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

commit d5f4d9d5245813f89a64ec6f84eebc025f3e9df9
Author:     Wei Hu <whu@FreeBSD.org>
AuthorDate: 2021-11-27 06:42:34 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2022-01-10 00:42:55 +0000

    Hyper-V: vPCI: Prepopulate device bars
    
    In recent Hyper-V releases on Windows Server 2022, vPCI code does not
    initialize the last 4 bit of device bar registers. This behavior change
    could result weird problems cuasing PCI code failure when configuring
    bars.
    
    Just write all 1's to those bars whose probed values are not the same
    as current read ones. This seems to make Hyper-V vPCI and
    pci_write_bar() to cooperate correctly on these releases.
    
    Reported by:    khng@freebsd.org
    Tested by:      khng@freebsd.org
    MFC after:      2 weeks
    Sponsored by:   Microsoft
    
    (cherry picked from commit 75412a521f60d4b0393c730ffb284e7c6ff9d2de)
    (cherry picked from commit eabea1c700ad8eacb8dc780d8620b59ce72b2cf2)
    
    Approved by:    so
    Errata:         FreeBSD-EN-22:03.hyperv
---
 sys/dev/hyperv/pcib/vmbus_pcib.c | 43 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/sys/dev/hyperv/pcib/vmbus_pcib.c b/sys/dev/hyperv/pcib/vmbus_pcib.c
index 72e430c946db..c7df32044678 100644
--- a/sys/dev/hyperv/pcib/vmbus_pcib.c
+++ b/sys/dev/hyperv/pcib/vmbus_pcib.c
@@ -1356,6 +1356,47 @@ _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size,
 	}
 }
 
+/*
+ * The vPCI in some Hyper-V releases do not initialize the last 4
+ * bit of BAR registers. This could result weird problems causing PCI
+ * code fail to configure BAR correctly.
+ *
+ * Just write all 1's to those BARs whose probed values are not zero.
+ * This seems to make the Hyper-V vPCI and pci_write_bar() to cooperate
+ * correctly.
+ */
+
+static void
+vmbus_pcib_prepopulate_bars(struct hv_pcibus *hbus)
+{
+	struct hv_pci_dev *hpdev;
+	int i;
+
+	mtx_lock(&hbus->device_list_lock);
+	TAILQ_FOREACH(hpdev, &hbus->children, link) {
+		for (i = 0; i < 6; i++) {
+			/* Ignore empty bar */
+			if (hpdev->probed_bar[i] == 0)
+				continue;
+
+			uint32_t bar_val = 0;
+
+			_hv_pcifront_read_config(hpdev, PCIR_BAR(i),
+			    4, &bar_val);
+
+			if (hpdev->probed_bar[i] != bar_val) {
+				if (bootverbose)
+					printf("vmbus_pcib: initialize bar %d "
+					    "by writing all 1s\n", i);
+
+				_hv_pcifront_write_config(hpdev, PCIR_BAR(i),
+				    4, 0xffffffff);
+			}
+		}
+	}
+	mtx_unlock(&hbus->device_list_lock);
+}
+
 static void
 vmbus_pcib_set_detaching(void *arg, int pending __unused)
 {
@@ -1479,6 +1520,8 @@ vmbus_pcib_attach(device_t dev)
 	if (ret)
 		goto vmbus_close;
 
+	vmbus_pcib_prepopulate_bars(hbus);
+
 	hbus->pci_bus = device_add_child(dev, "pci", -1);
 	if (!hbus->pci_bus) {
 		device_printf(dev, "failed to create pci bus\n");