[PATCH v7 6/9] PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends
Koichiro Den
den at valinux.co.jp
Sun Feb 15 08:38:44 PST 2026
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 at valinux.co.jp>
---
drivers/pci/endpoint/pci-ep-msi.c | 55 ++++++++++++++++++++++---------
include/linux/pci-epf.h | 23 +++++++++++--
2 files changed, 61 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
index ad8a81d6ad77..a42f69ad24ad 100644
--- a/drivers/pci/endpoint/pci-ep-msi.c
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -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,13 @@ 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].irq_flags = 0;
+ msg[i].type = PCI_EPF_DOORBELL_MSI;
+ msg[i].bar = NO_BAR;
+ msg[i].offset = 0;
+ }
+
epf->num_db = num_db;
epf->db_msg = msg;
@@ -90,13 +88,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;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 7737a7c03260..cd747447a1ea 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -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;
};
/**
--
2.51.0
More information about the Linux-rockchip
mailing list