diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-11-13 20:45:38 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-11-13 21:38:41 +0000 |
commit | 2ae535532188b7772c2aba80247dfdce23d8f275 (patch) | |
tree | 20e4364923e725d91ac259040d403a0d420c4905 | |
parent | ca2be7e094c900542e36f70f3abc3c8ff7c3055d (diff) | |
download | ipxe-2ae535532188b7772c2aba80247dfdce23d8f275.zip ipxe-2ae535532188b7772c2aba80247dfdce23d8f275.tar.gz ipxe-2ae535532188b7772c2aba80247dfdce23d8f275.tar.bz2 |
[pci] Backup and restore standard config space across PCIe FLR
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>
-rw-r--r-- | src/drivers/bus/pciextra.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/src/drivers/bus/pciextra.c b/src/drivers/bus/pciextra.c index 23617bc..1eeb9b2 100644 --- a/src/drivers/bus/pciextra.c +++ b/src/drivers/bus/pciextra.c @@ -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 ); } |