]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[pci] Backup and restore standard config space across PCIe FLR 801/head
authorMichael Brown <mcb30@ipxe.org>
Sun, 13 Nov 2022 20:45:38 +0000 (20:45 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 13 Nov 2022 21:38:41 +0000 (21:38 +0000)
The behaviour of PCI devices across a function-level reset seems to be
inconsistent in practice: some devices will preserve PCI BARs, some
will not.

Fix the behaviour of FLR on devices that do not preserve PCI BARs by
backing up and restoring PCI configuration space across the reset.
Preserve only the standard portion of the configuration space, since
there may be registers with unexpected side effects in the remaining
non-standardised space.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/bus/pciextra.c

index 23617bc9a6f16b48e31a4a6a3ff9eac5f88587c4..1eeb9b2a0f0a3fc26c83399d9ef8475cb3167242 100644 (file)
@@ -3,6 +3,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <stdint.h>
 #include <ipxe/timer.h>
 #include <ipxe/pci.h>
+#include <ipxe/pcibackup.h>
 
 static int pci_find_capability_common ( struct pci_device *pci,
                                        uint8_t pos, int cap ) {
@@ -121,8 +122,12 @@ unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
  * @v exp              PCI Express Capability address
  */
 void pci_reset ( struct pci_device *pci, unsigned int exp ) {
+       struct pci_config_backup backup;
        uint16_t control;
 
+       /* Back up configuration space */
+       pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL );
+
        /* Perform a PCIe function-level reset */
        pci_read_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), &control );
        control |= PCI_EXP_DEVCTL_FLR;
@@ -131,6 +136,6 @@ void pci_reset ( struct pci_device *pci, unsigned int exp ) {
        /* Allow time for reset to complete */
        mdelay ( PCI_EXP_FLR_DELAY_MS );
 
-       /* Re-enable device */
-       adjust_pci_device ( pci );
+       /* Restore configuration */
+       pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL );
 }