PCI: endpoint: pci-ep-msi: Refactor doorbell allocation for new backends

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
This commit is contained in:
Koichiro Den 2026-04-14 23:15:11 +09:00 committed by Manivannan Sadhasivam
parent ec2075cfc6
commit a3a079e5c5
2 changed files with 60 additions and 17 deletions

View 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;

View 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;
};
/**