svn commit: r361621 - head/sys/dev/pci
Andriy Gapon
avg at FreeBSD.org
Fri May 29 07:50:56 UTC 2020
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));
}
More information about the svn-src-head
mailing list