diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-09-19 17:49:25 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-09-19 17:49:25 +0100 |
commit | 081b3eefc48953795122c4b1a38430498e2bb2b6 (patch) | |
tree | 7547814c3c6def81170a5d896c933af9e51b12ec | |
parent | 3aa6b79c8d9dd0b4126c966aa83114dd0b9b4120 (diff) | |
download | ipxe-081b3eefc48953795122c4b1a38430498e2bb2b6.tar.gz |
[ena] Assign memory BAR if left empty by BIOS
Some BIOSes in AWS EC2 (observed with a c6i.metal instance in
eu-west-2) will fail to assign an MMIO address to the ENA device,
which causes ioremap() to fail.
Experiments show that the ENA device is the only device behind its
bridge, even when multiple ENA devices are present, and that the BIOS
does assign a memory window to the bridge.
We may therefore choose to assign the device an MMIO address at the
start of the bridge's memory window.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/drivers/net/ena.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 400ae44fa..22e7e1e30 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/iobuf.h> #include <ipxe/malloc.h> #include <ipxe/pci.h> +#include <ipxe/pcibridge.h> #include <ipxe/version.h> #include "ena.h" @@ -985,6 +986,45 @@ static struct net_device_operations ena_operations = { */ /** + * Assign memory BAR + * + * @v ena ENA device + * @v pci PCI device + * @ret rc Return status code + * + * Some BIOSes in AWS EC2 are observed to fail to assign a base + * address to the ENA device. The device is the only device behind + * its bridge, and the BIOS does assign a memory window to the bridge. + * We therefore place the device at the start of the memory window. + */ +static int ena_membase ( struct ena_nic *ena, struct pci_device *pci ) { + struct pci_bridge *bridge; + + /* Locate PCI bridge */ + bridge = pcibridge_find ( pci ); + if ( ! bridge ) { + DBGC ( ena, "ENA %p found no PCI bridge\n", ena ); + return -ENOTCONN; + } + + /* Sanity check */ + if ( PCI_SLOT ( pci->busdevfn ) || PCI_FUNC ( pci->busdevfn ) ) { + DBGC ( ena, "ENA %p at " PCI_FMT " may not be only device " + "on bus\n", ena, PCI_ARGS ( pci ) ); + return -ENOTSUP; + } + + /* Place device at start of memory window */ + pci_write_config_dword ( pci, PCI_BASE_ADDRESS_0, bridge->membase ); + pci->membase = bridge->membase; + DBGC ( ena, "ENA %p at " PCI_FMT " claiming bridge " PCI_FMT " mem " + "%08x\n", ena, PCI_ARGS ( pci ), PCI_ARGS ( bridge->pci ), + bridge->membase ); + + return 0; +} + +/** * Probe PCI device * * @v pci PCI device @@ -1020,6 +1060,10 @@ static int ena_probe ( struct pci_device *pci ) { /* Fix up PCI device */ adjust_pci_device ( pci ); + /* Fix up PCI BAR if left unassigned by BIOS */ + if ( ( ! pci->membase ) && ( ( rc = ena_membase ( ena, pci ) ) != 0 ) ) + goto err_membase; + /* Map registers */ ena->regs = pci_ioremap ( pci, pci->membase, ENA_BAR_SIZE ); if ( ! ena->regs ) { @@ -1085,6 +1129,7 @@ static int ena_probe ( struct pci_device *pci ) { err_info: iounmap ( ena->regs ); err_ioremap: + err_membase: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: |