[WIP PATCH v3 4/7] PCI: endpoint: pci-epf-vntb: Use hardware-owned MSI-X layout

From: Koichiro Den

Date: Tue Sep 01 2026 - 03:06:56 EST


pci-epf-vntb allocates an MSI-X Table and PBA in its config BAR when the
EPC supports MSI-X. Some endpoint controllers instead provide fixed,
hardware-owned regions for them.

Use the hardware-owned layout when it can hold the configured MSI-X
entries. Keep allocating an EPF-owned Table and PBA when no suitable
hardware-owned layout is available.

Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes in v3:
- Split hardware-owned layout selection from the vNTB MSI-X fix. (Niklas)
- Fall back to an EPF-owned layout if the fixed regions are too small.
---
drivers/pci/endpoint/functions/pci-epf-vntb.c | 43 ++++++++++++-------
1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index e019d6e1ba69..53ccbbb0ba4b 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -443,8 +443,8 @@ static void epf_ntb_config_spad_bar_free(struct epf_ntb *ntb)
* @ntb: NTB device that facilitates communication between HOST and VHOST
*
* Allocate the control and scratchpad regions described in the above diagram.
- * If the EPC supports MSI-X, allocate space for its Table and PBA between the
- * control and scratchpad regions.
+ * If the EPC does not provide a hardware-owned MSI-X Table and PBA, allocate
+ * space for them between the control and scratchpad regions.
*
* Returns: Zero for success, or an error code in case of failure
*/
@@ -457,7 +457,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
struct device *dev = &epf->dev;
u32 spad_count;
void *base;
- int i;
+ int i, ret;
const struct pci_epc_features *epc_features = pci_epc_get_features(epf->epc,
epf->func_no,
epf->vfunc_no);
@@ -466,18 +466,31 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)

ctrl_size = ALIGN(sizeof(struct epf_ntb_ctrl), sizeof(u32));
if (epc_features->msix_capable) {
- ntb->msix_layout.table_bar = barno;
- ntb->msix_layout.table_offset = ALIGN(ctrl_size, 8);
- ntb->msix_layout.table_size =
- ntb->db_count * PCI_MSIX_ENTRY_SIZE;
- ntb->msix_layout.pba_bar = barno;
- ntb->msix_layout.pba_offset =
- ntb->msix_layout.table_offset +
- ntb->msix_layout.table_size;
- ntb->msix_layout.pba_size =
- BITS_TO_U64(ntb->db_count) * sizeof(u64);
- ctrl_size = ntb->msix_layout.pba_offset +
- ntb->msix_layout.pba_size;
+ ret = pci_epc_get_hw_msix_layout(epc_features,
+ &ntb->msix_layout);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "Invalid hardware-owned MSI-X layout\n");
+ return ret;
+ }
+
+ if (ret == -ENOENT ||
+ ntb->msix_layout.table_size <
+ ntb->db_count * PCI_MSIX_ENTRY_SIZE ||
+ ntb->msix_layout.pba_size <
+ BITS_TO_U64(ntb->db_count) * sizeof(u64)) {
+ ntb->msix_layout.table_bar = barno;
+ ntb->msix_layout.table_offset = ALIGN(ctrl_size, 8);
+ ntb->msix_layout.table_size =
+ ntb->db_count * PCI_MSIX_ENTRY_SIZE;
+ ntb->msix_layout.pba_bar = barno;
+ ntb->msix_layout.pba_offset =
+ ntb->msix_layout.table_offset +
+ ntb->msix_layout.table_size;
+ ntb->msix_layout.pba_size =
+ BITS_TO_U64(ntb->db_count) * sizeof(u64);
+ ctrl_size = ntb->msix_layout.pba_offset +
+ ntb->msix_layout.pba_size;
+ }
}
spad_size = 2 * spad_count * sizeof(u32);

--
2.51.0