* [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support
@ 2025-10-15 15:27 Frank Li
2025-10-15 15:27 ` [PATCH v6 1/4] PCI: endpoint: Rename aligned_size to mem_size Frank Li
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Frank Li @ 2025-10-15 15:27 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Jon Mason, Dave Jiang,
Allen Hubbe
Cc: linux-pci, linux-kernel, ntb, imx, Frank Li, Niklas Cassel
Since commit 1c3b002c6bf68 PCI: endpoint: Add RC-to-EP doorbell support
using platform MSI controller, PCI EP can get notification from Host.
VNTB use this feature to reduce ping latency.
The first patch impove epf core API to allow set any MMIO address to specfic
bar.
The second patch add MSI doorbell support.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Changes in v6:
- update commit message by bar_size
- collect Niklas Cassel's review by tags
- rebased to v6.18-rc1
- Link to v5: https://lore.kernel.org/r/20251009-vntb_msi_doorbell-v5-0-4cfb7b6c4be1@nxp.com
Changes in v5:
- update atu field aligned_size to mem_size.
- Link to v4: https://lore.kernel.org/r/20250930-vntb_msi_doorbell-v4-0-ea2c94c6ff2e@nxp.com
Changes in v4:
- use 'bar_size' instead of aligned_bar_size
- Link to v3: https://lore.kernel.org/r/20250925-vntb_msi_doorbell-v3-0-ae0b0c93caae@nxp.com
Changes in v3:
- update function name to pci_epf_assign_bar_space()
- detail check each patch's change log
- Link to v2: https://lore.kernel.org/r/20250915-vntb_msi_doorbell-v2-0-ca71605e3444@nxp.com
Changes in v2:
- add help funciton to get bar's inbounce size
- fix miss x8 when caculate bits
- Link to v1: https://lore.kernel.org/r/20250815-vntb_msi_doorbell-v1-0-32df6c4bf96c@nxp.com
---
Frank Li (4):
PCI: endpoint: Rename aligned_size to mem_size
PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
PCI: endpoint: Add API pci_epf_assign_bar_space()
PCI: endpoint: pci-epf-vntb: Add MSI doorbell support
drivers/pci/endpoint/functions/pci-epf-vntb.c | 152 +++++++++++++++++++++---
drivers/pci/endpoint/pci-epf-core.c | 163 +++++++++++++++++++++-----
include/linux/pci-epf.h | 12 +-
3 files changed, 275 insertions(+), 52 deletions(-)
---
base-commit: 48a881fd8adc6ef7d29b4cf2395b04cdc271e636
change-id: 20250812-vntb_msi_doorbell-bf0fbac6d6d7
Best regards,
--
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 1/4] PCI: endpoint: Rename aligned_size to mem_size
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
@ 2025-10-15 15:27 ` Frank Li
2025-10-15 15:27 ` [PATCH v6 2/4] PCI: endpoint: Add helper function pci_epf_get_bar_required_size() Frank Li
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Frank Li @ 2025-10-15 15:27 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Jon Mason, Dave Jiang,
Allen Hubbe
Cc: linux-pci, linux-kernel, ntb, imx, Frank Li, Niklas Cassel
Rename the variable aligned_size to mem_size to better reflect its purpose.
'aligned_size' was misleading, as it actually represents the backing memory
size allocated for the BAR rather than an alignment value.
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v5
- new patch
---
drivers/pci/endpoint/pci-epf-core.c | 12 ++++++------
include/linux/pci-epf.h | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index d54e18872aefc07c655c94c104a347328ff7a432..214e3f6e6d0d5a216c3469b8ff47908414cd1286 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -236,13 +236,13 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
}
dev = epc->dev.parent;
- dma_free_coherent(dev, epf_bar[bar].aligned_size, addr,
+ dma_free_coherent(dev, epf_bar[bar].mem_size, addr,
epf_bar[bar].phys_addr);
epf_bar[bar].phys_addr = 0;
epf_bar[bar].addr = NULL;
epf_bar[bar].size = 0;
- epf_bar[bar].aligned_size = 0;
+ epf_bar[bar].mem_size = 0;
epf_bar[bar].barno = 0;
epf_bar[bar].flags = 0;
}
@@ -265,7 +265,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
enum pci_epc_interface_type type)
{
u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
- size_t aligned_size, align = epc_features->align;
+ size_t mem_size, align = epc_features->align;
struct pci_epf_bar *epf_bar;
dma_addr_t phys_addr;
struct pci_epc *epc;
@@ -297,7 +297,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
* it might be different if, for example, the fixed size of a BAR
* is smaller than align.
*/
- aligned_size = align ? ALIGN(size, align) : size;
+ mem_size = align ? ALIGN(size, align) : size;
if (type == PRIMARY_INTERFACE) {
epc = epf->epc;
@@ -308,7 +308,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
}
dev = epc->dev.parent;
- space = dma_alloc_coherent(dev, aligned_size, &phys_addr, GFP_KERNEL);
+ space = dma_alloc_coherent(dev, mem_size, &phys_addr, GFP_KERNEL);
if (!space) {
dev_err(dev, "failed to allocate mem space\n");
return NULL;
@@ -317,7 +317,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
epf_bar[bar].phys_addr = phys_addr;
epf_bar[bar].addr = space;
epf_bar[bar].size = size;
- epf_bar[bar].aligned_size = aligned_size;
+ epf_bar[bar].mem_size = mem_size;
epf_bar[bar].barno = bar;
if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 2e85504ba2baf93827224884ca19ae2bd0e6906b..4022dd080e20f2959f3a5faf4cfe054ddb5856a7 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -115,8 +115,8 @@ struct pci_epf_driver {
* @phys_addr: physical address that should be mapped to the BAR
* @addr: virtual address corresponding to the @phys_addr
* @size: the size of the address space present in BAR
- * @aligned_size: the size actually allocated to accommodate the iATU alignment
- * requirement
+ * @mem_size: the size actually allocated to accommodate the iATU alignment
+ * requirement
* @barno: BAR number
* @flags: flags that are set for the BAR
*/
@@ -124,7 +124,7 @@ struct pci_epf_bar {
dma_addr_t phys_addr;
void *addr;
size_t size;
- size_t aligned_size;
+ size_t mem_size;
enum pci_barno barno;
int flags;
};
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v6 2/4] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
2025-10-15 15:27 ` [PATCH v6 1/4] PCI: endpoint: Rename aligned_size to mem_size Frank Li
@ 2025-10-15 15:27 ` Frank Li
2025-10-15 15:27 ` [PATCH v6 3/4] PCI: endpoint: Add API pci_epf_assign_bar_space() Frank Li
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Frank Li @ 2025-10-15 15:27 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Jon Mason, Dave Jiang,
Allen Hubbe
Cc: linux-pci, linux-kernel, ntb, imx, Frank Li, Niklas Cassel
Introduce pci_epf_get_bar_required_size() to retrieve the required BAR
size and memory size. Prepare for adding support to set an MMIO address to
a specific BAR.
Use two variables 'bar_size' and 'aligned_mem_size' to avoid confuse.
No functional changes.
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v6
- update commit message by using bar_size
- collect Niklas Cassel reviewed-by tag
change in v5
- update commit message.
change in v4
- use size_t *bar_size as in/out arugment.
change in v3
- change return value to int.
- use two pointers return bar size aligned and memory start address aligned
- update comments about why need memory align size. Actually iATU require
start address match aligned requirement. Since kernel return align to
size's address.
- use two varible aligned_bar_size and aligned_mem_size to avoid confuse
use 'size'.
change in v2
- new patch
---
drivers/pci/endpoint/pci-epf-core.c | 75 +++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 28 deletions(-)
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 214e3f6e6d0d5a216c3469b8ff47908414cd1286..38c4fd06e9693ceaa0c86f67090faa6e390425e1 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -208,6 +208,49 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
}
EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
+static int
+pci_epf_get_bar_required_size(struct pci_epf *epf, size_t *bar_size,
+ size_t *aligned_mem_size,
+ enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type)
+{
+ u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
+ size_t align = epc_features->align;
+ size_t size = *bar_size;
+
+ if (size < 128)
+ size = 128;
+
+ /* According to PCIe base spec, min size for a resizable BAR is 1 MB. */
+ if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
+ size = SZ_1M;
+
+ if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
+ if (size > bar_fixed_size) {
+ dev_err(&epf->dev,
+ "requested BAR size is larger than fixed size\n");
+ return -ENOMEM;
+ }
+ size = bar_fixed_size;
+ } else {
+ /* BAR size must be power of two */
+ size = roundup_pow_of_two(size);
+ }
+
+ *bar_size = size;
+
+ /*
+ * The EPC's BAR start address must meet alignment requirements. In most
+ * cases, the alignment will match the BAR size. However, differences
+ * can occur—for example, when the fixed BAR size (e.g., 128 bytes) is
+ * smaller than the required alignment (e.g., 4 KB).
+ */
+ *aligned_mem_size = align ? ALIGN(size, align) : size;
+
+ return 0;
+}
+
/**
* pci_epf_free_space() - free the allocated PCI EPF register space
* @epf: the EPF device from whom to free the memory
@@ -264,40 +307,16 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
const struct pci_epc_features *epc_features,
enum pci_epc_interface_type type)
{
- u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
- size_t mem_size, align = epc_features->align;
struct pci_epf_bar *epf_bar;
dma_addr_t phys_addr;
struct pci_epc *epc;
struct device *dev;
+ size_t mem_size;
void *space;
- if (size < 128)
- size = 128;
-
- /* According to PCIe base spec, min size for a resizable BAR is 1 MB. */
- if (epc_features->bar[bar].type == BAR_RESIZABLE && size < SZ_1M)
- size = SZ_1M;
-
- if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
- if (size > bar_fixed_size) {
- dev_err(&epf->dev,
- "requested BAR size is larger than fixed size\n");
- return NULL;
- }
- size = bar_fixed_size;
- } else {
- /* BAR size must be power of two */
- size = roundup_pow_of_two(size);
- }
-
- /*
- * Allocate enough memory to accommodate the iATU alignment
- * requirement. In most cases, this will be the same as .size but
- * it might be different if, for example, the fixed size of a BAR
- * is smaller than align.
- */
- mem_size = align ? ALIGN(size, align) : size;
+ if (pci_epf_get_bar_required_size(epf, &size, &mem_size, bar,
+ epc_features, type))
+ return NULL;
if (type == PRIMARY_INTERFACE) {
epc = epf->epc;
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v6 3/4] PCI: endpoint: Add API pci_epf_assign_bar_space()
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
2025-10-15 15:27 ` [PATCH v6 1/4] PCI: endpoint: Rename aligned_size to mem_size Frank Li
2025-10-15 15:27 ` [PATCH v6 2/4] PCI: endpoint: Add helper function pci_epf_get_bar_required_size() Frank Li
@ 2025-10-15 15:27 ` Frank Li
2025-10-15 15:27 ` [PATCH v6 4/4] PCI: endpoint: pci-epf-vntb: Add MSI doorbell support Frank Li
2025-10-27 15:20 ` [PATCH v6 0/4] pci: endpoint: vntb: add " Manivannan Sadhasivam
4 siblings, 0 replies; 6+ messages in thread
From: Frank Li @ 2025-10-15 15:27 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Jon Mason, Dave Jiang,
Allen Hubbe
Cc: linux-pci, linux-kernel, ntb, imx, Frank Li
Add pci_epf_assign_bar_space() to allow setting any physical address as
inbound memory space, such as an MSI message base address.
Since PCI BAR size must be a power of two, the input MMIO range
[inbound_addr, inbound_addr + size) is mapped by finding n such that
[base, base + 2^n) covers the range. The base address is also required
to be aligned to 2^n.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v5
- use bar_addr in head file to align function define
change in v4
- use size for bar size.
chagne in v3.
- update function name to pci_epf_assign_bar_space()
- s/allocated/assigned/
- add check when align down input address to memory align require, may not
bar's size can't cover required ragion.
change in v2
- add new API pci_epf_set_inbound_space()
- fix bits 8 * size_of(dma_addr_t);
---
drivers/pci/endpoint/pci-epf-core.c | 80 +++++++++++++++++++++++++++++++++++++
include/linux/pci-epf.h | 6 +++
2 files changed, 86 insertions(+)
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 38c4fd06e9693ceaa0c86f67090faa6e390425e1..1c64d69556e6c7c4841ef8a60866515a1f68333b 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -347,6 +347,86 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
}
EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
+/**
+ * pci_epf_assign_bar_space() - Assign PCI EPF BAR space
+ * @epf: the EPF device to whom allocate the memory
+ * @size: the size of the memory that has to be assigned
+ * @bar: the BAR number corresponding to the assigned register space
+ * @epc_features: the features provided by the EPC specific to this EPF
+ * @type: Identifies if the assignment is for primary EPC or secondary EPC
+ * @bar_addr: Address to be assigned for the @bar
+ *
+ * Invoke to assigned memory for the PCI EPF register space.
+ * Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR
+ * can only be a 64-bit BAR, or if the requested size is larger than 2 GB.
+ */
+int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size,
+ enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type,
+ dma_addr_t bar_addr)
+{
+ size_t bar_size, aligned_mem_size;
+ struct pci_epf_bar *epf_bar;
+ struct pci_epc *epc;
+ dma_addr_t limit;
+ int pos;
+
+ if (!size)
+ return -EINVAL;
+
+ limit = bar_addr + size - 1;
+
+ /*
+ * Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ * bar_addr: U U U U U U 0 X X X X X X X X X
+ * limit: U U U U U U 1 X X X X X X X X X
+ *
+ * U means address bits have not change in Range [bar_addr, limit]
+ * X means bit 0 or 1.
+ *
+ * bar_addr^limit 0 0 0 0 0 0 1 X X X X X X X X X
+ * Find first bit 1 pos from MSB, 2 ^ pos windows will cover
+ * [bar_Addr, limit] range.
+ */
+ for (pos = 8 * sizeof(dma_addr_t) - 1; pos > 0; pos--)
+ if ((limit ^ bar_addr) & BIT_ULL(pos))
+ break;
+
+ if (pos == 8 * sizeof(dma_addr_t) - 1)
+ return -EINVAL;
+
+ bar_size = BIT_ULL(pos + 1);
+ if (pci_epf_get_bar_required_size(epf, &bar_size, &aligned_mem_size,
+ bar, epc_features, type))
+ return -ENOMEM;
+
+ if (type == PRIMARY_INTERFACE) {
+ epc = epf->epc;
+ epf_bar = epf->bar;
+ } else {
+ epc = epf->sec_epc;
+ epf_bar = epf->sec_epc_bar;
+ }
+
+ epf_bar[bar].phys_addr = ALIGN_DOWN(bar_addr, aligned_mem_size);
+
+ if (epf_bar[bar].phys_addr + bar_size < limit)
+ return -ENOMEM;
+
+ epf_bar[bar].addr = NULL;
+ epf_bar[bar].size = bar_size;
+ epf_bar[bar].mem_size = aligned_mem_size;
+ epf_bar[bar].barno = bar;
+ if (upper_32_bits(size) || epc_features->bar[bar].only_64bit)
+ epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+ else
+ epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_epf_assign_bar_space);
+
static void pci_epf_remove_cfs(struct pci_epf_driver *driver)
{
struct config_group *group, *tmp;
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 4022dd080e20f2959f3a5faf4cfe054ddb5856a7..48f68c4dcfa5e2e3bb97963c6b0f47effe87f53b 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -242,6 +242,12 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
+int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size,
+ enum pci_barno bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_epc_interface_type type,
+ dma_addr_t bar_addr);
+
int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
u64 addr, dma_addr_t *base, size_t *off);
int pci_epf_bind(struct pci_epf *epf);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v6 4/4] PCI: endpoint: pci-epf-vntb: Add MSI doorbell support
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
` (2 preceding siblings ...)
2025-10-15 15:27 ` [PATCH v6 3/4] PCI: endpoint: Add API pci_epf_assign_bar_space() Frank Li
@ 2025-10-15 15:27 ` Frank Li
2025-10-27 15:20 ` [PATCH v6 0/4] pci: endpoint: vntb: add " Manivannan Sadhasivam
4 siblings, 0 replies; 6+ messages in thread
From: Frank Li @ 2025-10-15 15:27 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Jon Mason, Dave Jiang,
Allen Hubbe
Cc: linux-pci, linux-kernel, ntb, imx, Frank Li
Add MSI doorbell support to reduce latency between PCI host and EP.
Before this change:
ping 169.254.172.137
64 bytes from 169.254.172.137: icmp_seq=1 ttl=64 time=0.575 ms
64 bytes from 169.254.172.137: icmp_seq=2 ttl=64 time=1.80 ms
64 bytes from 169.254.172.137: icmp_seq=3 ttl=64 time=8.19 ms
64 bytes from 169.254.172.137: icmp_seq=4 ttl=64 time=2.00 ms
After this change:
ping 169.254.144.71
64 bytes from 169.254.144.71: icmp_seq=1 ttl=64 time=0.215 ms
64 bytes from 169.254.144.71: icmp_seq=2 ttl=64 time=0.456 ms
64 bytes from 169.254.144.71: icmp_seq=3 ttl=64 time=0.448 ms
Change u64 db to atomic_64 because difference doorbell may happen at the
same time.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v5
- none
change in v4
- add check of return value pci_epf_assign_bar_space()
change in v3
- update api pci_epf_assign_bar_space
- remove dead code for db 0.
change in v2
- update api pci_epf_set_inbound_space
- atomic_64 should be enough, which just record doorbell events, which is
similar with W1C irq status register.
---
drivers/pci/endpoint/functions/pci-epf-vntb.c | 152 +++++++++++++++++++++++---
1 file changed, 135 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 83e9ab10f9c4fc2b485d5463faa2172500f12999..6e48a1efe1eb267c4c80c7c09fe1c6f73c7ccf44 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -36,11 +36,13 @@
* PCIe Root Port PCI EP
*/
+#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/pci-ep-msi.h>
#include <linux/pci-epc.h>
#include <linux/pci-epf.h>
#include <linux/ntb.h>
@@ -126,12 +128,13 @@ struct epf_ntb {
u32 db_count;
u32 spad_count;
u64 mws_size[MAX_MW];
- u64 db;
+ atomic64_t db;
u32 vbus_number;
u16 vntb_pid;
u16 vntb_vid;
bool linkup;
+ bool msi_doorbell;
u32 spad_size;
enum pci_barno epf_ntb_bar[VNTB_BAR_NUM];
@@ -258,9 +261,9 @@ static void epf_ntb_cmd_handler(struct work_struct *work)
ntb = container_of(work, struct epf_ntb, cmd_handler.work);
- for (i = 1; i < ntb->db_count; i++) {
+ for (i = 1; i < ntb->db_count && !ntb->msi_doorbell; i++) {
if (ntb->epf_db[i]) {
- ntb->db |= 1 << (i - 1);
+ atomic64_or(1 << (i - 1), &ntb->db);
ntb_db_event(&ntb->ntb, i);
ntb->epf_db[i] = 0;
}
@@ -319,7 +322,21 @@ static void epf_ntb_cmd_handler(struct work_struct *work)
reset_handler:
queue_delayed_work(kpcintb_workqueue, &ntb->cmd_handler,
- msecs_to_jiffies(5));
+ ntb->msi_doorbell ? msecs_to_jiffies(500) : msecs_to_jiffies(5));
+}
+
+static irqreturn_t epf_ntb_doorbell_handler(int irq, void *data)
+{
+ struct epf_ntb *ntb = data;
+ int i = 0;
+
+ for (i = 1; i < ntb->db_count; i++)
+ if (irq == ntb->epf->db_msg[i].virq) {
+ atomic64_or(1 << (i - 1), &ntb->db);
+ ntb_db_event(&ntb->ntb, i);
+ }
+
+ return IRQ_HANDLED;
}
/**
@@ -500,6 +517,93 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)
return 0;
}
+static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb,
+ struct pci_epf_bar *db_bar,
+ const struct pci_epc_features *epc_features,
+ enum pci_barno barno)
+{
+ struct pci_epf *epf = ntb->epf;
+ dma_addr_t low, high;
+ struct msi_msg *msg;
+ size_t sz;
+ int ret;
+ int i;
+
+ ret = pci_epf_alloc_doorbell(epf, ntb->db_count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ntb->db_count; i++) {
+ ret = request_irq(epf->db_msg[i].virq, epf_ntb_doorbell_handler,
+ 0, "vntb_db", ntb);
+
+ if (ret) {
+ dev_err(&epf->dev,
+ "Failed to request doorbell IRQ: %d\n",
+ epf->db_msg[i].virq);
+ goto err_request_irq;
+ }
+ }
+
+ msg = &epf->db_msg[0].msg;
+
+ high = 0;
+ low = (u64)msg->address_hi << 32 | msg->address_lo;
+
+ for (i = 0; i < ntb->db_count; i++) {
+ struct msi_msg *msg = &epf->db_msg[i].msg;
+ dma_addr_t addr = (u64)msg->address_hi << 32 | msg->address_lo;
+
+ low = min(low, addr);
+ high = max(high, addr);
+ }
+
+ sz = high - low + sizeof(u32);
+
+ ret = pci_epf_assign_bar_space(epf, sz, barno, epc_features, 0, low);
+ if (ret) {
+ dev_err(&epf->dev, "Doorbell BAR assign space failed\n");
+ goto err_request_irq;
+ }
+
+ ret = pci_epc_set_bar(ntb->epf->epc, ntb->epf->func_no, ntb->epf->vfunc_no, db_bar);
+ if (ret) {
+ dev_err(&epf->dev, "Doorbell BAR set failed\n");
+ goto err_request_irq;
+ }
+
+ for (i = 0; i < ntb->db_count; i++) {
+ struct msi_msg *msg = &epf->db_msg[i].msg;
+ dma_addr_t addr;
+ size_t offset;
+
+ ret = pci_epf_align_inbound_addr(epf, db_bar->barno,
+ ((u64)msg->address_hi << 32) | msg->address_lo,
+ &addr, &offset);
+
+ if (ret) {
+ ntb->msi_doorbell = false;
+ goto err_request_irq;
+ }
+
+ ntb->reg->db_data[i] = msg->data;
+ ntb->reg->db_offset[i] = offset;
+ }
+
+ ntb->reg->db_entry_size = 0;
+
+ ntb->msi_doorbell = true;
+
+ return 0;
+
+err_request_irq:
+ for (i--; i >= 0; i--)
+ free_irq(epf->db_msg[i].virq, ntb);
+
+ pci_epf_free_doorbell(ntb->epf);
+ return ret;
+}
+
/**
* epf_ntb_db_bar_init() - Configure Doorbell window BARs
* @ntb: NTB device that facilitates communication between HOST and VHOST
@@ -520,21 +624,25 @@ static int epf_ntb_db_bar_init(struct epf_ntb *ntb)
ntb->epf->func_no,
ntb->epf->vfunc_no);
barno = ntb->epf_ntb_bar[BAR_DB];
-
- mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, epc_features, 0);
- if (!mw_addr) {
- dev_err(dev, "Failed to allocate OB address\n");
- return -ENOMEM;
- }
-
- ntb->epf_db = mw_addr;
-
epf_bar = &ntb->epf->bar[barno];
- ret = pci_epc_set_bar(ntb->epf->epc, ntb->epf->func_no, ntb->epf->vfunc_no, epf_bar);
+ ret = epf_ntb_db_bar_init_msi_doorbell(ntb, epf_bar, epc_features, barno);
if (ret) {
- dev_err(dev, "Doorbell BAR set failed\n");
+ /* fall back to polling mode */
+ mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, epc_features, 0);
+ if (!mw_addr) {
+ dev_err(dev, "Failed to allocate OB address\n");
+ return -ENOMEM;
+ }
+
+ ntb->epf_db = mw_addr;
+
+ ret = pci_epc_set_bar(ntb->epf->epc, ntb->epf->func_no,
+ ntb->epf->vfunc_no, epf_bar);
+ if (ret) {
+ dev_err(dev, "Doorbell BAR set failed\n");
goto err_alloc_peer_mem;
+ }
}
return ret;
@@ -554,6 +662,16 @@ static void epf_ntb_db_bar_clear(struct epf_ntb *ntb)
{
enum pci_barno barno;
+ if (ntb->msi_doorbell) {
+ int i;
+
+ for (i = 0; i < ntb->db_count; i++)
+ free_irq(ntb->epf->db_msg[i].virq, ntb);
+ }
+
+ if (ntb->epf->db_msg)
+ pci_epf_free_doorbell(ntb->epf);
+
barno = ntb->epf_ntb_bar[BAR_DB];
pci_epf_free_space(ntb->epf, ntb->epf_db, barno, 0);
pci_epc_clear_bar(ntb->epf->epc,
@@ -1268,7 +1386,7 @@ static u64 vntb_epf_db_read(struct ntb_dev *ndev)
{
struct epf_ntb *ntb = ntb_ndev(ndev);
- return ntb->db;
+ return atomic64_read(&ntb->db);
}
static int vntb_epf_mw_get_align(struct ntb_dev *ndev, int pidx, int idx,
@@ -1308,7 +1426,7 @@ static int vntb_epf_db_clear(struct ntb_dev *ndev, u64 db_bits)
{
struct epf_ntb *ntb = ntb_ndev(ndev);
- ntb->db &= ~db_bits;
+ atomic64_and(~db_bits, &ntb->db);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
` (3 preceding siblings ...)
2025-10-15 15:27 ` [PATCH v6 4/4] PCI: endpoint: pci-epf-vntb: Add MSI doorbell support Frank Li
@ 2025-10-27 15:20 ` Manivannan Sadhasivam
4 siblings, 0 replies; 6+ messages in thread
From: Manivannan Sadhasivam @ 2025-10-27 15:20 UTC (permalink / raw)
To: Krzysztof Wilczyński, Kishon Vijay Abraham I, Bjorn Helgaas,
Jon Mason, Dave Jiang, Allen Hubbe, Frank Li
Cc: Manivannan Sadhasivam, linux-pci, linux-kernel, ntb, imx,
Niklas Cassel
On Wed, 15 Oct 2025 11:27:27 -0400, Frank Li wrote:
> Since commit 1c3b002c6bf68 PCI: endpoint: Add RC-to-EP doorbell support
> using platform MSI controller, PCI EP can get notification from Host.
>
> VNTB use this feature to reduce ping latency.
>
> The first patch impove epf core API to allow set any MMIO address to specfic
> bar.
>
> [...]
I've done some minor code cleanups and applied the series to pci/endpoint.
Please check the commits to make sure I didn't mess up like last time. Thanks!
[1/4] PCI: endpoint: Rename aligned_size to mem_size
commit: 483768846d66c04354898f00bcdaad58a3763be2
[2/4] PCI: endpoint: Add helper function pci_epf_get_bar_required_size()
commit: f71e2b67b51dcb2fd8c6d566230f17a735770bee
[3/4] PCI: endpoint: Add API pci_epf_assign_bar_space()
commit: 0bfc6758f213a701bd662982de86f0032b51f18c
[4/4] PCI: endpoint: pci-epf-vntb: Add MSI doorbell support
commit: dc693d60664470ec47188c328055d80e8ce7ea44
Best regards,
--
Manivannan Sadhasivam <mani@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-10-27 15:21 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-15 15:27 [PATCH v6 0/4] pci: endpoint: vntb: add MSI doorbell support Frank Li
2025-10-15 15:27 ` [PATCH v6 1/4] PCI: endpoint: Rename aligned_size to mem_size Frank Li
2025-10-15 15:27 ` [PATCH v6 2/4] PCI: endpoint: Add helper function pci_epf_get_bar_required_size() Frank Li
2025-10-15 15:27 ` [PATCH v6 3/4] PCI: endpoint: Add API pci_epf_assign_bar_space() Frank Li
2025-10-15 15:27 ` [PATCH v6 4/4] PCI: endpoint: pci-epf-vntb: Add MSI doorbell support Frank Li
2025-10-27 15:20 ` [PATCH v6 0/4] pci: endpoint: vntb: add " Manivannan Sadhasivam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).