[PATCH v7 7/9] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags

Koichiro Den den at valinux.co.jp
Sun Feb 15 08:38:45 PST 2026


Support doorbell backends where the doorbell target is already exposed
via a platform-owned fixed BAR mapping and/or where the doorbell IRQ
must be requested with specific flags.

When pci_epf_alloc_doorbell() provides db_msg[].bar/offset, reuse the
pre-exposed BAR window and skip programming a new inbound mapping. Also
honor db_msg[].irq_flags when requesting the doorbell IRQ.

For embedded doorbells (e.g. interrupt-emulation), multiple doorbells
may share a single address/data pair and a single Linux IRQ. Avoid
requesting duplicate handlers by requesting only one IRQ in that case.

Signed-off-by: Koichiro Den <den at valinux.co.jp>
---
 drivers/pci/endpoint/functions/pci-epf-vntb.c | 57 +++++++++++++++++--
 1 file changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 20efa27325f1..39ba4d6b7d8d 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -134,6 +134,11 @@ struct epf_ntb {
 	u16 vntb_vid;
 
 	bool linkup;
+
+	/*
+	 * True when doorbells are interrupt-driven (MSI or embedded), false
+	 * when polled.
+	 */
 	bool msi_doorbell;
 	u32 spad_size;
 
@@ -523,7 +528,7 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 					    enum pci_barno barno)
 {
 	struct pci_epf *epf = ntb->epf;
-	unsigned int req;
+	unsigned int req, cnt;
 	dma_addr_t low, high;
 	struct msi_msg *msg;
 	size_t sz;
@@ -534,9 +539,29 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 	if (ret)
 		return ret;
 
-	for (req = 0; req < ntb->db_count; req++) {
+	/*
+	 * The doorbell target may already be exposed by a platform-owned fixed
+	 * BAR. In that case, we must reuse it and the requested db_bar must
+	 * match.
+	 */
+	if (epf->db_msg[0].bar != NO_BAR && epf->db_msg[0].bar != barno) {
+		ret = -EINVAL;
+		goto err_free_doorbell;
+	}
+
+	/*
+	 * For PCI_EPF_DOORBELL_EMBEDDED, the backend may provide a single MMIO
+	 * address/data pair and a single Linux IRQ even if multiple doorbells
+	 * were requested. Avoid requesting duplicate handlers in that case.
+	 */
+	cnt = ntb->db_count;
+	if (epf->db_msg[0].type == PCI_EPF_DOORBELL_EMBEDDED)
+		cnt = 1;
+
+	for (req = 0; req < cnt; req++) {
 		ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler,
-				  0, "pci_epf_vntb_db", ntb);
+				  epf->db_msg[req].irq_flags, "pci_epf_vntb_db",
+				  ntb);
 
 		if (ret) {
 			dev_err(&epf->dev,
@@ -546,6 +571,22 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 		}
 	}
 
+	if (epf->db_msg[0].bar != NO_BAR) {
+		for (i = 0; i < ntb->db_count; i++) {
+			msg = &epf->db_msg[i].msg;
+
+			if (epf->db_msg[i].bar != barno) {
+				ret = -EINVAL;
+				goto err_free_irq;
+			}
+
+			ntb->reg->db_data[i] = msg->data;
+			ntb->reg->db_offset[i] = epf->db_msg[i].offset;
+		}
+		goto out;
+	}
+
+	/* Program inbound mapping for the doorbell */
 	msg = &epf->db_msg[0].msg;
 
 	high = 0;
@@ -592,6 +633,7 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 		ntb->reg->db_offset[i] = offset;
 	}
 
+out:
 	ntb->reg->db_entry_size = 0;
 
 	ntb->msi_doorbell = true;
@@ -602,6 +644,7 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
 	while (req)
 		free_irq(epf->db_msg[--req].virq, ntb);
 
+err_free_doorbell:
 	pci_epf_free_doorbell(ntb->epf);
 	return ret;
 }
@@ -665,9 +708,13 @@ static void epf_ntb_db_bar_clear(struct epf_ntb *ntb)
 	enum pci_barno barno;
 
 	if (ntb->msi_doorbell) {
-		int i;
+		unsigned int cnt = ntb->db_count;
+		unsigned int i;
 
-		for (i = 0; i < ntb->db_count; i++)
+		if (ntb->epf->db_msg[0].type == PCI_EPF_DOORBELL_EMBEDDED)
+			cnt = 1;
+
+		for (i = 0; i < cnt; i++)
 			free_irq(ntb->epf->db_msg[i].virq, ntb);
 	}
 
-- 
2.51.0




More information about the Linux-rockchip mailing list