From: Michael Brown Date: Wed, 15 Oct 2025 14:27:03 +0000 (+0100) Subject: [ena] Map the on-device memory, if present X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dcc5d36ce59e9aaf662f6d827d1966a3e1fb87d5;p=thirdparty%2Fipxe.git [ena] Map the on-device memory, if present Newer generations of the ENA hardware require the use of low latency transmit queues, where the submission queues and the initial portion of the transmitted packet are written to on-device memory via BAR2 instead of being read from host memory. Prepare for this by mapping the on-device memory BAR. As with the register BAR, we may need to steal a base address from the upstream PCI bridge since the BIOS on some instance types (observed with an m8i.metal-48xl instance in eu-south-2) will fail to assign an address to the device. Signed-off-by: Michael Brown --- diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 7f6e8164f..51375e47f 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -1095,10 +1095,12 @@ static struct net_device_operations ena_operations = { */ /** - * Assign memory BAR + * Assign memory BARs * * @v ena ENA device * @v pci PCI device + * @v prefmembase On-device memory base address to fill in + * @v prefmemsize On-device memory size to fill in * @ret rc Return status code * * Some BIOSes in AWS EC2 are observed to fail to assign a base @@ -1106,15 +1108,27 @@ static struct net_device_operations ena_operations = { * 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 ) { +static int ena_membases ( struct ena_nic *ena, struct pci_device *pci, + unsigned long *prefmembase, + unsigned long *prefmemsize ) { struct pci_bridge *bridge; + /* Get on-device memory base address and size */ + *prefmembase = pci_bar_start ( pci, ENA_MEM_BAR ); + *prefmemsize = pci_bar_size ( pci, ENA_MEM_BAR ); + + /* Do nothing if addresses are already assigned */ + if ( pci->membase && ( *prefmembase || ( ! *prefmemsize ) ) ) + return 0; + /* Locate PCI bridge */ bridge = pcibridge_find ( pci ); if ( ! bridge ) { DBGC ( ena, "ENA %p found no PCI bridge\n", ena ); return -ENOTCONN; } + DBGC ( ena, "ENA %p at " PCI_FMT " claiming bridge " PCI_FMT "\n", + ena, PCI_ARGS ( pci ), PCI_ARGS ( bridge->pci ) ); /* Sanity check */ if ( PCI_SLOT ( pci->busdevfn ) || PCI_FUNC ( pci->busdevfn ) ) { @@ -1123,12 +1137,21 @@ static int ena_membase ( struct ena_nic *ena, struct pci_device *pci ) { return -ENOTSUP; } - /* Place device at start of memory window */ - pci_bar_set ( 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 ); + /* Place register BAR at start of memory window, if applicable */ + if ( ! pci->membase ) { + pci_bar_set ( pci, ENA_REGS_BAR, bridge->membase ); + pci->membase = bridge->membase; + DBGC ( ena, "ENA %p at " PCI_FMT " claiming mem %08lx\n", + ena, PCI_ARGS ( pci ), pci->membase ); + } + + /* Place memory BAR at start of prefetchable window, if applicable */ + if ( *prefmemsize && ( ! *prefmembase ) ) { + pci_bar_set ( pci, ENA_MEM_BAR, bridge->prefmembase ); + *prefmembase = bridge->prefmembase; + DBGC ( ena, "ENA %p at " PCI_FMT " claiming prefmem %08lx\n", + ena, PCI_ARGS ( pci ), *prefmembase ); + } return 0; } @@ -1143,6 +1166,8 @@ static int ena_probe ( struct pci_device *pci ) { struct net_device *netdev; struct ena_nic *ena; struct ena_host_info *info; + unsigned long prefmembase; + unsigned long prefmemsize; int rc; /* Allocate and initialise net device */ @@ -1170,14 +1195,27 @@ static int ena_probe ( struct pci_device *pci ) { 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; + if ( ( rc = ena_membases ( ena, pci, &prefmembase, + &prefmemsize ) ) != 0 ) { + goto err_membases; + } /* Map registers */ - ena->regs = pci_ioremap ( pci, pci->membase, ENA_BAR_SIZE ); + ena->regs = pci_ioremap ( pci, pci->membase, ENA_REGS_SIZE ); if ( ! ena->regs ) { rc = -ENODEV; - goto err_ioremap; + goto err_regs; + } + + /* Map device memory */ + if ( prefmemsize ) { + ena->mem = pci_ioremap ( pci, prefmembase, prefmemsize ); + if ( ! ena->mem ) { + rc = -ENODEV; + goto err_mem; + } + DBGC ( ena, "ENA %p has %ldkB of on-device memory\n", + ena, ( prefmemsize >> 10 ) ); } /* Allocate and initialise host info */ @@ -1242,9 +1280,12 @@ static int ena_probe ( struct pci_device *pci ) { err_reset: free_phys ( ena->info, PAGE_SIZE ); err_info: + if ( ena->mem ) + iounmap ( ena->mem ); + err_mem: iounmap ( ena->regs ); - err_ioremap: - err_membase: + err_regs: + err_membases: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: @@ -1275,8 +1316,12 @@ static void ena_remove ( struct pci_device *pci ) { /* Free host info */ free_phys ( ena->info, PAGE_SIZE ); - /* Free network device */ + /* Unmap registers and on-device memory */ + if ( ena->mem ) + iounmap ( ena->mem ); iounmap ( ena->regs ); + + /* Free network device */ netdev_nullify ( netdev ); netdev_put ( netdev ); } diff --git a/src/drivers/net/ena.h b/src/drivers/net/ena.h index 9fda9979f..b5ec6d0bf 100644 --- a/src/drivers/net/ena.h +++ b/src/drivers/net/ena.h @@ -12,8 +12,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** BAR size */ -#define ENA_BAR_SIZE 16384 +/** Register BAR */ +#define ENA_REGS_BAR PCI_BASE_ADDRESS_0 + +/** Register BAR size */ +#define ENA_REGS_SIZE 16384 + +/** On-device memory BAR */ +#define ENA_MEM_BAR PCI_BASE_ADDRESS_2 /** Queue alignment */ #define ENA_ALIGN 4096 @@ -743,6 +749,8 @@ struct ena_qp { struct ena_nic { /** Registers */ void *regs; + /** On-device memory */ + void *mem; /** Host info */ struct ena_host_info *info; /** Admin queue */