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
Frankquoted
+ + 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