On 64K page systems, DPDK `pci_uio` driver aligns the physical
address to a 64K boundary before assigning a virtual address.
If the original physical BAR address is not 64K-aligned,
this adjustment leads to an incorrect mapping.

The fix ensures that the BAR virtual address received in the driver
accounts for both PAGE size and BAR physical offset to correctly map
each BAR. The fix is compatible for every PAGE size and applies to
every used BAR

Example:
- BAR0 physical address:
  0x80208000 (not 64K-aligned)
- DPDK aligned physical address:
  0x80208000 -> 0x80200000 (masking 0x8000 offset)
- DPDK mapped physical to virtual address:
  0x80200000 -> 0x1140000000
- Driver accessed BAR0 virtual address:
  0x1140000000 (causing init failure)
- Add correct offset to driver BAR0 address:
  0x1140000000 + 0x8000 (init success)

Fixes: 1173fca25af9 ("ena: add polling-mode driver")
Cc: sta...@dpdk.org
Signed-off-by: Amit Bernstein <amitb...@amazon.com>
Signed-off-by: Shai Brandes <shaib...@amazon.com>
Reviewed-by: Yosef Raisman <yrais...@amazon.com>
---
 doc/guides/rel_notes/release_25_07.rst |  1 +
 drivers/net/ena/ena_ethdev.c           | 14 ++++++++++++--
 drivers/net/ena/ena_ethdev.h           |  4 ++++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/doc/guides/rel_notes/release_25_07.rst 
b/doc/guides/rel_notes/release_25_07.rst
index 662b0db49e..ce42b81a24 100644
--- a/doc/guides/rel_notes/release_25_07.rst
+++ b/doc/guides/rel_notes/release_25_07.rst
@@ -63,6 +63,7 @@ New Features
     or enabling of interrupts when operating in control path interrupt mode.
   * Fixed an issue where the device might be incorrectly reported as 
unresponsive when using
     polling-based admin queue functionality with a poll interval of less than 
500 milliseconds.
+  * Fixed BAR mapping logic to handle 64K page alignment correctly, ensuring 
accurate offset adjustment.
 
 * **Added Mucse rnp net driver.**
 
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index 182e063bf4..bdb4938231 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -2285,6 +2285,16 @@ static int ena_init_once(void)
        return 0;
 }
 
+/*
+ * Retrieve the correct PCI BAR virtual address, accounting for physical
+ * address alignment to PAGE boundary.
+ */
+static void *pci_bar_addr(struct rte_pci_device *pci_dev, uint32_t bar)
+{
+       struct rte_mem_resource *resource = &pci_dev->mem_resource[bar];
+       return RTE_PTR_ADD(resource->addr, resource->phys_addr & PAGE_MASK);
+}
+
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 {
        struct ena_calc_queue_size_ctx calc_queue_ctx = { 0 };
@@ -2330,8 +2340,7 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 
        intr_handle = pci_dev->intr_handle;
 
-       adapter->regs = pci_dev->mem_resource[ENA_REGS_BAR].addr;
-       adapter->dev_mem_base = pci_dev->mem_resource[ENA_MEM_BAR].addr;
+       adapter->regs = pci_bar_addr(pci_dev, ENA_REGS_BAR);
 
        if (!adapter->regs) {
                PMD_INIT_LOG_LINE(CRIT, "Failed to access registers BAR(%d)",
@@ -2340,6 +2349,7 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
        }
 
        ena_dev->reg_bar = adapter->regs;
+       adapter->dev_mem_base = pci_bar_addr(pci_dev, ENA_MEM_BAR);
        /* Pass device data as a pointer which can be passed to the IO functions
         * by the ena_com (for example - the memory allocation).
         */
diff --git a/drivers/net/ena/ena_ethdev.h b/drivers/net/ena/ena_ethdev.h
index e5d23e2e27..1d5d4456dc 100644
--- a/drivers/net/ena/ena_ethdev.h
+++ b/drivers/net/ena/ena_ethdev.h
@@ -16,8 +16,12 @@
 #include <rte_timer.h>
 #include <rte_dev.h>
 #include <rte_net.h>
+#include <rte_eal_paging.h>
 
 #include "ena_com.h"
+#ifndef PAGE_MASK
+#define PAGE_MASK (rte_mem_page_size() - 1)
+#endif
 
 #define ENA_REGS_BAR   0
 #define ENA_MEM_BAR    2
-- 
2.17.1

Reply via email to