]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends
authorKoichiro Den <den@valinux.co.jp>
Tue, 14 Apr 2026 14:15:11 +0000 (23:15 +0900)
committerManivannan Sadhasivam <mani@kernel.org>
Thu, 30 Apr 2026 16:18:48 +0000 (21:48 +0530)
Prepare pci-ep-msi for non-MSI doorbell backends.

Factor MSI doorbell allocation into a helper and extend struct
pci_epf_doorbell_msg with:

  - irq_flags: required IRQ request flags (e.g. IRQF_SHARED for some
    backends)
  - type: doorbell backend type
  - bar/offset: pre-exposed doorbell target location, if any

Initialize these fields for the existing MSI-backed doorbell
implementation.

Also add PCI_EPF_DOORBELL_EMBEDDED type, which is to be implemented in a
follow-up patch.

No functional changes.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260414141514.1341429-5-den@valinux.co.jp
drivers/pci/endpoint/pci-ep-msi.c
include/linux/pci-epf.h

index 1395919571f83f0ad24648ff43897b932a5c589a..85fe46103220f9d1b5015d3d308f8b79375dfd27 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/device.h>
 #include <linux/export.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/msi.h>
@@ -35,23 +36,13 @@ static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
        pci_epc_put(epc);
 }
 
-int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
+static int pci_epf_alloc_doorbell_msi(struct pci_epf *epf, u16 num_db)
 {
-       struct pci_epc *epc = epf->epc;
+       struct pci_epf_doorbell_msg *msg;
        struct device *dev = &epf->dev;
+       struct pci_epc *epc = epf->epc;
        struct irq_domain *domain;
-       void *msg;
-       int ret;
-       int i;
-
-       /* TODO: Multi-EPF support */
-       if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
-               dev_err(dev, "MSI doorbell doesn't support multiple EPF\n");
-               return -EINVAL;
-       }
-
-       if (epf->db_msg)
-               return -EBUSY;
+       int ret, i;
 
        domain = of_msi_map_get_device_domain(epc->dev.parent, 0,
                                              DOMAIN_BUS_PLATFORM_MSI);
@@ -74,6 +65,12 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
        if (!msg)
                return -ENOMEM;
 
+       for (i = 0; i < num_db; i++)
+               msg[i] = (struct pci_epf_doorbell_msg) {
+                       .type = PCI_EPF_DOORBELL_MSI,
+                       .bar = NO_BAR,
+               };
+
        epf->num_db = num_db;
        epf->db_msg = msg;
 
@@ -90,13 +87,40 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
        for (i = 0; i < num_db; i++)
                epf->db_msg[i].virq = msi_get_virq(epc->dev.parent, i);
 
+       return 0;
+}
+
+int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
+{
+       struct pci_epc *epc = epf->epc;
+       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;
+
+       dev_err(dev, "Failed to allocate doorbell: %d\n", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
 
 void pci_epf_free_doorbell(struct pci_epf *epf)
 {
-       platform_device_msi_free_irqs_all(epf->epc->dev.parent);
+       if (!epf->db_msg)
+               return;
+
+       if (epf->db_msg[0].type == PCI_EPF_DOORBELL_MSI)
+               platform_device_msi_free_irqs_all(epf->epc->dev.parent);
 
        kfree(epf->db_msg);
        epf->db_msg = NULL;
index 7737a7c03260d9a7e17ba333cbbd3945d3536dce..cd747447a1eafe0cc1a2507555416ab9b3987553 100644 (file)
@@ -152,14 +152,33 @@ struct pci_epf_bar {
        struct pci_epf_bar_submap       *submap;
 };
 
+enum pci_epf_doorbell_type {
+       PCI_EPF_DOORBELL_MSI = 0,
+       PCI_EPF_DOORBELL_EMBEDDED,
+};
+
 /**
  * struct pci_epf_doorbell_msg - represents doorbell message
- * @msg: MSI message
- * @virq: IRQ number of this doorbell MSI message
+ * @msg: Doorbell address/data pair to be mapped into BAR space.
+ *       For MSI-backed doorbells this is the MSI message, while for
+ *       "embedded" doorbells this represents an MMIO write that asserts
+ *       an interrupt on the EP side.
+ * @virq: IRQ number of this doorbell message
+ * @irq_flags: Required flags for request_irq()/request_threaded_irq().
+ *             Callers may OR-in additional flags (e.g. IRQF_ONESHOT).
+ * @type: Doorbell type.
+ * @bar: BAR number where the doorbell target is already exposed to the RC
+ *       (NO_BAR if not)
+ * @offset: offset within @bar for the doorbell target (valid iff
+ *          @bar != NO_BAR)
  */
 struct pci_epf_doorbell_msg {
        struct msi_msg msg;
        int virq;
+       unsigned long irq_flags;
+       enum pci_epf_doorbell_type type;
+       enum pci_barno bar;
+       resource_size_t offset;
 };
 
 /**