aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2022-11-13 20:45:38 +0000
committerMichael Brown <mcb30@ipxe.org>2022-11-13 21:38:41 +0000
commit2ae535532188b7772c2aba80247dfdce23d8f275 (patch)
tree20e4364923e725d91ac259040d403a0d420c4905
parentca2be7e094c900542e36f70f3abc3c8ff7c3055d (diff)
downloadipxe-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.c9
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 );
}