[PATCH v7 7/9] PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
Koichiro Den
den at valinux.co.jp
Mon Feb 16 17:39:05 PST 2026
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:
> > 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;
>
> 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
> > +
> > + 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