Skip to content

Commit 1c3b002

Browse files
nxpfranklibjorn-helgaas
authored andcommitted
PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
Implement the doorbell feature by mapping the EP's MSI interrupt controller message address to a dedicated BAR. The EPF driver should pass the actual message data to be written to the message address by the host through implementation-specific logic. Signed-off-by: Frank Li <Frank.Li@nxp.com> [mani: minor code cleanups and reworded commit message] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> [bhelgaas: fix kernel-doc] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Niklas Cassel <cassel@kernel.org> Link: https://patch.msgid.link/20250710-ep-msi-v21-3-57683fc7fb25@nxp.com
1 parent 19272b3 commit 1c3b002

5 files changed

Lines changed: 144 additions & 0 deletions

File tree

drivers/pci/endpoint/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ config PCI_ENDPOINT_CONFIGFS
2828
configure the endpoint function and used to bind the
2929
function with an endpoint controller.
3030

31+
config PCI_ENDPOINT_MSI_DOORBELL
32+
bool "PCI Endpoint MSI Doorbell Support"
33+
depends on PCI_ENDPOINT && GENERIC_MSI_IRQ
34+
help
35+
This enables the EP's MSI interrupt controller to function as a
36+
doorbell. The RC can trigger doorbell in EP by writing data to a
37+
dedicated BAR, which the EP maps to the controller's message address.
38+
3139
source "drivers/pci/endpoint/functions/Kconfig"
3240

3341
endmenu

drivers/pci/endpoint/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS) += pci-ep-cfs.o
77
obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\
88
pci-epc-mem.o functions/
9+
obj-$(CONFIG_PCI_ENDPOINT_MSI_DOORBELL) += pci-ep-msi.o

drivers/pci/endpoint/pci-ep-msi.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* PCI Endpoint *Controller* (EPC) MSI library
4+
*
5+
* Copyright (C) 2025 NXP
6+
* Author: Frank Li <Frank.Li@nxp.com>
7+
*/
8+
9+
#include <linux/device.h>
10+
#include <linux/export.h>
11+
#include <linux/irqdomain.h>
12+
#include <linux/module.h>
13+
#include <linux/msi.h>
14+
#include <linux/of_irq.h>
15+
#include <linux/pci-epc.h>
16+
#include <linux/pci-epf.h>
17+
#include <linux/pci-ep-cfs.h>
18+
#include <linux/pci-ep-msi.h>
19+
#include <linux/slab.h>
20+
21+
static void pci_epf_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
22+
{
23+
struct pci_epc *epc;
24+
struct pci_epf *epf;
25+
26+
epc = pci_epc_get(dev_name(msi_desc_to_dev(desc)));
27+
if (!epc)
28+
return;
29+
30+
epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list);
31+
32+
if (epf && epf->db_msg && desc->msi_index < epf->num_db)
33+
memcpy(&epf->db_msg[desc->msi_index].msg, msg, sizeof(*msg));
34+
35+
pci_epc_put(epc);
36+
}
37+
38+
int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
39+
{
40+
struct pci_epc *epc = epf->epc;
41+
struct device *dev = &epf->dev;
42+
struct irq_domain *domain;
43+
void *msg;
44+
int ret;
45+
int i;
46+
47+
/* TODO: Multi-EPF support */
48+
if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
49+
dev_err(dev, "MSI doorbell doesn't support multiple EPF\n");
50+
return -EINVAL;
51+
}
52+
53+
domain = of_msi_map_get_device_domain(epc->dev.parent, 0,
54+
DOMAIN_BUS_PLATFORM_MSI);
55+
if (!domain) {
56+
dev_err(dev, "Can't find MSI domain for EPC\n");
57+
return -ENODEV;
58+
}
59+
60+
dev_set_msi_domain(epc->dev.parent, domain);
61+
62+
msg = kcalloc(num_db, sizeof(struct pci_epf_doorbell_msg), GFP_KERNEL);
63+
if (!msg)
64+
return -ENOMEM;
65+
66+
epf->num_db = num_db;
67+
epf->db_msg = msg;
68+
69+
ret = platform_device_msi_init_and_alloc_irqs(epc->dev.parent, num_db,
70+
pci_epf_write_msi_msg);
71+
if (ret) {
72+
dev_err(dev, "Failed to allocate MSI\n");
73+
kfree(msg);
74+
return ret;
75+
}
76+
77+
for (i = 0; i < num_db; i++)
78+
epf->db_msg[i].virq = msi_get_virq(epc->dev.parent, i);
79+
80+
return ret;
81+
}
82+
EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
83+
84+
void pci_epf_free_doorbell(struct pci_epf *epf)
85+
{
86+
platform_device_msi_free_irqs_all(epf->epc->dev.parent);
87+
88+
kfree(epf->db_msg);
89+
epf->db_msg = NULL;
90+
epf->num_db = 0;
91+
}
92+
EXPORT_SYMBOL_GPL(pci_epf_free_doorbell);

include/linux/pci-ep-msi.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* PCI Endpoint *Function* side MSI header file
4+
*
5+
* Copyright (C) 2024 NXP
6+
* Author: Frank Li <Frank.Li@nxp.com>
7+
*/
8+
9+
#ifndef __PCI_EP_MSI__
10+
#define __PCI_EP_MSI__
11+
12+
struct pci_epf;
13+
14+
#ifdef CONFIG_PCI_ENDPOINT_MSI_DOORBELL
15+
int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 nums);
16+
void pci_epf_free_doorbell(struct pci_epf *epf);
17+
#else
18+
static inline int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 nums)
19+
{
20+
return -ENODATA;
21+
}
22+
23+
static inline void pci_epf_free_doorbell(struct pci_epf *epf)
24+
{
25+
}
26+
#endif /* CONFIG_GENERIC_MSI_IRQ */
27+
28+
#endif /* __PCI_EP_MSI__ */

include/linux/pci-epf.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/configfs.h>
1313
#include <linux/device.h>
1414
#include <linux/mod_devicetable.h>
15+
#include <linux/msi.h>
1516
#include <linux/pci.h>
1617

1718
struct pci_epf;
@@ -128,6 +129,16 @@ struct pci_epf_bar {
128129
int flags;
129130
};
130131

132+
/**
133+
* struct pci_epf_doorbell_msg - represents doorbell message
134+
* @msg: MSI message
135+
* @virq: IRQ number of this doorbell MSI message
136+
*/
137+
struct pci_epf_doorbell_msg {
138+
struct msi_msg msg;
139+
int virq;
140+
};
141+
131142
/**
132143
* struct pci_epf - represents the PCI EPF device
133144
* @dev: the PCI EPF device
@@ -155,6 +166,8 @@ struct pci_epf_bar {
155166
* @vfunction_num_map: bitmap to manage virtual function number
156167
* @pci_vepf: list of virtual endpoint functions associated with this function
157168
* @event_ops: callbacks for capturing the EPC events
169+
* @db_msg: data for MSI from RC side
170+
* @num_db: number of doorbells
158171
*/
159172
struct pci_epf {
160173
struct device dev;
@@ -185,6 +198,8 @@ struct pci_epf {
185198
unsigned long vfunction_num_map;
186199
struct list_head pci_vepf;
187200
const struct pci_epc_event_ops *event_ops;
201+
struct pci_epf_doorbell_msg *db_msg;
202+
u16 num_db;
188203
};
189204

190205
/**

0 commit comments

Comments
 (0)