[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