]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
PCI: endpoint: pci-epf-vntb: Reuse pre-exposed doorbells and IRQ flags
authorKoichiro Den <den@valinux.co.jp>
Tue, 14 Apr 2026 14:15:12 +0000 (23:15 +0900)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 4 May 2026 23:01:28 +0000 (18:01 -0500)
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.

Multiple doorbells may share the same Linux IRQ. Avoid duplicate
request_irq() calls by requesting each unique virq once.

Make pci-epf-vntb work with platform-defined or embedded doorbell
backends without exposing backend-specific details to the consumer
layer.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260414141514.1341429-6-den@valinux.co.jp
drivers/pci/endpoint/functions/pci-epf-vntb.c

index 2256c3062b1ae01be754e5afe9d93d2421a60018..b493a300da4dcadcb8991c53392cfa3d8ba0753d 100644 (file)
@@ -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;
 
@@ -517,6 +522,17 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)
        return 0;
 }
 
+static bool epf_ntb_db_irq_is_duplicated(const struct pci_epf *epf, unsigned int idx)
+{
+       unsigned int i;
+
+       for (i = 0; i < idx; i++)
+               if (epf->db_msg[i].virq == epf->db_msg[idx].virq)
+                       return true;
+
+       return false;
+}
+
 static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
                                            struct pci_epf_bar *db_bar,
                                            const struct pci_epc_features *epc_features,
@@ -533,9 +549,24 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
        if (ret)
                return ret;
 
+       /*
+        * 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 (req = 0; req < ntb->db_count; req++) {
+               /* Avoid requesting duplicate handlers */
+               if (epf_ntb_db_irq_is_duplicated(epf, req))
+                       continue;
+
                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,
@@ -545,6 +576,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;
@@ -591,6 +638,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;
@@ -598,9 +646,13 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
        return 0;
 
 err_free_irq:
-       for (req--; req >= 0; req--)
+       for (req--; req >= 0; req--) {
+               if (epf_ntb_db_irq_is_duplicated(epf, req))
+                       continue;
                free_irq(epf->db_msg[req].virq, ntb);
+       }
 
+err_free_doorbell:
        pci_epf_free_doorbell(ntb->epf);
        return ret;
 }
@@ -666,8 +718,11 @@ static void epf_ntb_db_bar_clear(struct epf_ntb *ntb)
        if (ntb->msi_doorbell) {
                int i;
 
-               for (i = 0; i < ntb->db_count; i++)
+               for (i = 0; i < ntb->db_count; i++) {
+                       if (epf_ntb_db_irq_is_duplicated(ntb->epf, i))
+                               continue;
                        free_irq(ntb->epf->db_msg[i].virq, ntb);
+               }
        }
 
        if (ntb->epf->db_msg)