git: 776cd02b891c - main - vmm ppt: Enable busmastering and BAR decoding while a device is assigned

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 22 Aug 2024 18:41:18 UTC
The branch main has been updated by jhb:

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

commit 776cd02b891ccd984963c9ec26f9748d213f0b9b
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-08-22 18:40:48 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-08-22 18:40:48 +0000

    vmm ppt: Enable busmastering and BAR decoding while a device is assigned
    
    Reviewed by:    corvink, markj
    Fixes:          f44ff2aba2d6 bhyve: Treat the COMMAND register for PCI passthru devices as emulated
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D46245
---
 sys/amd64/vmm/io/ppt.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/sys/amd64/vmm/io/ppt.c b/sys/amd64/vmm/io/ppt.c
index 3451e91d9de1..9fcfdc7cb441 100644
--- a/sys/amd64/vmm/io/ppt.c
+++ b/sys/amd64/vmm/io/ppt.c
@@ -151,9 +151,13 @@ static int
 ppt_attach(device_t dev)
 {
 	struct pptdev *ppt;
+	uint16_t cmd;
 
 	ppt = device_get_softc(dev);
 
+	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+	cmd &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
+	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
 	iommu_remove_device(iommu_host_domain(), pci_get_rid(dev));
 	num_pptdevs++;
 	TAILQ_INSERT_TAIL(&pptdev_list, ppt, next);
@@ -176,7 +180,6 @@ ppt_detach(device_t dev)
 		return (EBUSY);
 	num_pptdevs--;
 	TAILQ_REMOVE(&pptdev_list, ppt, next);
-	pci_disable_busmaster(dev);
 
 	if (iommu_host_domain() != NULL)
 		iommu_add_device(iommu_host_domain(), pci_get_rid(dev));
@@ -376,11 +379,28 @@ ppt_pci_reset(device_t dev)
 	pci_power_reset(dev);
 }
 
+static uint16_t
+ppt_bar_enables(struct pptdev *ppt)
+{
+	struct pci_map *pm;
+	uint16_t cmd;
+
+	cmd = 0;
+	for (pm = pci_first_bar(ppt->dev); pm != NULL; pm = pci_next_bar(pm)) {
+		if (PCI_BAR_IO(pm->pm_value))
+			cmd |= PCIM_CMD_PORTEN;
+		if (PCI_BAR_MEM(pm->pm_value))
+			cmd |= PCIM_CMD_MEMEN;
+	}
+	return (cmd);
+}
+
 int
 ppt_assign_device(struct vm *vm, int bus, int slot, int func)
 {
 	struct pptdev *ppt;
 	int error;
+	uint16_t cmd;
 
 	/* Passing NULL requires the device to be unowned. */
 	error = ppt_find(NULL, bus, slot, func, &ppt);
@@ -392,6 +412,9 @@ ppt_assign_device(struct vm *vm, int bus, int slot, int func)
 	pci_restore_state(ppt->dev);
 	ppt->vm = vm;
 	iommu_add_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
+	cmd = pci_read_config(ppt->dev, PCIR_COMMAND, 2);
+	cmd |= PCIM_CMD_BUSMASTEREN | ppt_bar_enables(ppt);
+	pci_write_config(ppt->dev, PCIR_COMMAND, cmd, 2);
 	return (0);
 }
 
@@ -400,11 +423,15 @@ ppt_unassign_device(struct vm *vm, int bus, int slot, int func)
 {
 	struct pptdev *ppt;
 	int error;
+	uint16_t cmd;
 
 	error = ppt_find(vm, bus, slot, func, &ppt);
 	if (error)
 		return (error);
 
+	cmd = pci_read_config(ppt->dev, PCIR_COMMAND, 2);
+	cmd &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
+	pci_write_config(ppt->dev, PCIR_COMMAND, cmd, 2);
 	pci_save_state(ppt->dev);
 	ppt_pci_reset(ppt->dev);
 	pci_restore_state(ppt->dev);