[PATCH 3/3] PCI: endpoint: pci-ep-msi: Let non-first EPFs use embedded doorbells

Koichiro Den <[email protected]> Wed, 29 Jul 2026 02:23:06 +0900
Newsgroups dev.linux.lists.ntb,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <[email protected]>
pci_epf_alloc_doorbell() rejects every EPF that is not the first one
attached to the EPC because the MSI-backed path can populate doorbell
messages only for that EPF. This also prevents non-first EPFs from using
the embedded doorbell backend.

Keep the MSI-backed path limited to the first attached EPF. Let
non-first EPFs skip it and try the embedded doorbell directly. The
embedded IRQ is exclusive, so a second embedded user fails to request
the IRQ instead of receiving another EPF's notifications.

Signed-off-by: Koichiro Den <[email protected]>
---
 drivers/pci/endpoint/pci-ep-msi.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index a123a189b4e6..5ea7eef9794f 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -199,28 +199,31 @@ static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
 int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
 {
 	struct pci_epc *epc = epf->epc;
+	struct pci_epf *first_epf;
 	struct device *dev = &epf->dev;
 	int ret;
 
-	/* TODO: Multi-EPF support */
-	if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
-		dev_err(dev, "Doorbell doesn't support multiple EPF\n");
-		return -EINVAL;
-	}
-
 	if (epf->db_msg)
 		return -EBUSY;
 
-	ret = pci_epf_alloc_doorbell_msi(epf, num_db);
-	if (!ret)
-		return 0;
-
 	/*
-	 * Fall back to embedded doorbell only when platform MSI is unavailable
-	 * for this EPC.
+	 * The MSI-backed doorbell path currently targets the first EPF attached
+	 * to the EPC. Let non-first EPFs try the embedded doorbell instead.
 	 */
-	if (ret != -ENODEV)
-		return ret;
+	first_epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf,
+					     list);
+	if (first_epf == epf) {
+		ret = pci_epf_alloc_doorbell_msi(epf, num_db);
+		if (!ret)
+			return 0;
+
+		/*
+		 * Fall back to embedded doorbell only when platform MSI is
+		 * unavailable for this EPC.
+		 */
+		if (ret != -ENODEV)
+			return ret;
+	}
 
 	ret = pci_epf_alloc_doorbell_embedded(epf, num_db);
 	if (ret) {
-- 
2.51.0