svn commit: r333174 - head/sys/amd64/vmm/io

Peter Grehan grehan at FreeBSD.org
Wed May 2 17:41:01 UTC 2018


Author: grehan
Date: Wed May  2 17:41:00 2018
New Revision: 333174
URL: https://svnweb.freebsd.org/changeset/base/333174

Log:
  Use PCI power-mgmt to reset a device if FLR fails.
  
  A large number of devices don't support PCIe FLR, in particular
  graphics adapters. Use PCI power management to perform the
  reset if FLR fails or isn't available, by cycling the device
  through the D3 state.
  
  This has been tested by a number of users with Nvidia and AMD GPUs.
  
  Submitted and tested by: Matt Macy
  Reviewed by:	jhb, imp, rgrimes
  MFC after:	3 weeks
  Differential Revision:	https://reviews.freebsd.org/D15268

Modified:
  head/sys/amd64/vmm/io/ppt.c

Modified: head/sys/amd64/vmm/io/ppt.c
==============================================================================
--- head/sys/amd64/vmm/io/ppt.c	Wed May  2 15:59:15 2018	(r333173)
+++ head/sys/amd64/vmm/io/ppt.c	Wed May  2 17:41:00 2018	(r333174)
@@ -353,6 +353,30 @@ ppt_is_mmio(struct vm *vm, vm_paddr_t gpa)
 	return (FALSE);
 }
 
+static void
+ppt_pci_reset(device_t dev)
+{
+	int ps;
+
+	if (pcie_flr(dev,
+		     max(pcie_get_max_completion_timeout(dev) / 1000, 10),
+		     true))
+		return;
+
+	/*
+	 * If FLR fails, attempt a power-management reset by cycling
+	 * the device in/out of D3 state.
+	 * PCI spec says we can only go into D3 state from D0 state.
+	 * Transition from D[12] into D0 before going to D3 state.
+	 */
+	ps = pci_get_powerstate(dev);
+	if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3)
+		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3)
+		pci_set_powerstate(dev, PCI_POWERSTATE_D3);
+	pci_set_powerstate(dev, ps);
+}
+
 int
 ppt_assign_device(struct vm *vm, int bus, int slot, int func)
 {
@@ -368,9 +392,7 @@ ppt_assign_device(struct vm *vm, int bus, int slot, in
 			return (EBUSY);
 
 		pci_save_state(ppt->dev);
-		pcie_flr(ppt->dev,
-		    max(pcie_get_max_completion_timeout(ppt->dev) / 1000, 10),
-		    true);
+		ppt_pci_reset(ppt->dev);
 		pci_restore_state(ppt->dev);
 		ppt->vm = vm;
 		iommu_add_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
@@ -393,9 +415,7 @@ ppt_unassign_device(struct vm *vm, int bus, int slot, 
 			return (EBUSY);
 
 		pci_save_state(ppt->dev);
-		pcie_flr(ppt->dev,
-		    max(pcie_get_max_completion_timeout(ppt->dev) / 1000, 10),
-		    true);
+		ppt_pci_reset(ppt->dev);
 		pci_restore_state(ppt->dev);
 		ppt_unmap_mmio(vm, ppt);
 		ppt_teardown_msi(ppt);


More information about the svn-src-all mailing list