Author: avg
Date: Fri May 29 07:50:55 2020
New Revision: 361621
URL: https://svnweb.freebsd.org/changeset/base/361621

Log:
  do not enable pci bridge decoding on resume until I/O windows are restored
  
  PCI bus driver restores most but not all of a child PCI-PCI bridge
  configuration.  The bridge's I/O windows are restored by pcib driver and
  that happens later in time.  This can be problematic because the Command
  register is restored before the windows are restored.  If the firmware
  programs the windows incorrectly or even does not program them at all,
  then the bridge can start claiming I/O cycles that are not intended for
  it.  This will continue until the correct windows are restored.
  
  I have observed this problem with a buggy BIOS where after resuming from
  S3 an I/O port window of a PCI-PCI bridge was configured with zero base
  and limit causing the bridge to claim 0x0 - 0xFFF port range.  That
  interfered with ACPI port access including ACPI PM Timer at port 0x808,
  thus wreaking havoc in the time keeping.
  
  The solution is to restore the Command register of PCI-PCI bridges after
  the windows are restored in pcib driver.  While here, I decided that for
  other PCI device types (normal and cardbus) it's better to restore the
  Command register after their BARs are restored.
  
  To do: per jhb's suggestion, move the window handling to pci driver.
  
  Reviewed by:  imp, jhb, kib
  MFC after:    2 weeks
  Differential Revision: https://reviews.freebsd.org/D25028

Modified:
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pci_pci.c

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c      Fri May 29 07:44:02 2020        (r361620)
+++ head/sys/dev/pci/pci.c      Fri May 29 07:50:55 2020        (r361621)
@@ -5932,7 +5932,6 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinf
         */
        if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
                pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-       pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
        pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
        pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
        pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1);
@@ -5970,6 +5969,9 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinf
                break;
        }
        pci_restore_bars(dev);
+
+       if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_BRIDGE)
+               pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
 
        /*
         * Restore extended capabilities for PCI-Express and PCI-X

Modified: head/sys/dev/pci/pci_pci.c
==============================================================================
--- head/sys/dev/pci/pci_pci.c  Fri May 29 07:44:02 2020        (r361620)
+++ head/sys/dev/pci/pci_pci.c  Fri May 29 07:50:55 2020        (r361621)
@@ -1792,6 +1792,12 @@ pcib_resume(device_t dev)
 {
 
        pcib_cfg_restore(device_get_softc(dev));
+
+       /*
+        * Restore the Command register only after restoring the windows.
+        * The bridge should not be claiming random windows.
+        */
+       pci_write_config(dev, PCIR_COMMAND, pci_get_cmdreg(dev), 2);
        return (bus_generic_resume(dev));
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to