Thread (21 messages) 21 messages, 3 authors, 2026-02-17

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

From: Koichiro Den <hidden>
Date: 2026-02-17 01:39:10
Also in: linux-pci, linux-rockchip, lkml

On Mon, Feb 16, 2026 at 11:14:58AM -0500, Frank Li wrote:
On Mon, Feb 16, 2026 at 01:38:45AM +0900, Koichiro Den wrote:
quoted
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 <redacted>
---
 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;
Most SoC combine all DMA channel to one irqs. But it should be not
neccessary for SoC design. It is possible each DMA channel have dedicate
irq number. I suggest check irq, instead of type.
Sounds reasonable. I was trying to keep the code minimal, but your suggestion
makes it more future-proof and avoids exposing PCI_EPF_DOORBELL_EMBEDDED details
to this consumer layer. I'll adjust this part accordingly.

THanks for the review,
Koichiro
Frank
quoted
+
+	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
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help