* [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller
@ 2024-12-03 20:36 Frank Li
2024-12-03 20:36 ` [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all() Frank Li
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li, stable
┌────────────┐ ┌───────────────────────────────────┐ ┌────────────────┐
│ │ │ │ │ │
│ │ │ PCI Endpoint │ │ PCI Host │
│ │ │ │ │ │
│ │◄──┤ 1.platform_msi_domain_alloc_irqs()│ │ │
│ │ │ │ │ │
│ MSI ├──►│ 2.write_msi_msg() ├──►├─BAR<n> │
│ Controller │ │ update doorbell register address│ │ │
│ │ │ for BAR │ │ │
│ │ │ │ │ 3. Write BAR<n>│
│ │◄──┼───────────────────────────────────┼───┤ │
│ │ │ │ │ │
│ ├──►│ 4.Irq Handle │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
└────────────┘ └───────────────────────────────────┘ └────────────────┘
This patches based on old https://lore.kernel.org/imx/20221124055036.1630573-1-Frank.Li@nxp.com/
Original patch only target to vntb driver. But actually it is common
method.
This patches add new API to pci-epf-core, so any EP driver can use it.
Previous v2 discussion here.
https://lore.kernel.org/imx/20230911220920.1817033-1-Frank.Li@nxp.com/
Changes in v9
- Add patch platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
- Remove patch PCI: endpoint: Add pci_epc_get_fn() API for customizable filtering
- Remove API pci_epf_align_inbound_addr_lo_hi
- Move doorbell_alloc in to doorbell_enable function.
- Link to v8: https://lore.kernel.org/r/20241116-ep-msi-v8-0-6f1f68ffd1bb@nxp.com
Changes in v8:
- update helper function name to pci_epf_align_inbound_addr()
- Link to v7: https://lore.kernel.org/r/20241114-ep-msi-v7-0-d4ac7aafbd2c@nxp.com
Changes in v7:
- Add helper function pci_epf_align_addr();
- Link to v6: https://lore.kernel.org/r/20241112-ep-msi-v6-0-45f9722e3c2a@nxp.com
Changes in v6:
- change doorbell_addr to doorbell_offset
- use round_down()
- add Niklas's test by tag
- rebase to pci/endpoint
- Link to v5: https://lore.kernel.org/r/20241108-ep-msi-v5-0-a14951c0d007@nxp.com
Changes in v5:
- Move request_irq to epf test function driver for more flexiable user case
- Add fixed size bar handler
- Some minor improvememtn to see each patches's changelog.
- Link to v4: https://lore.kernel.org/r/20241031-ep-msi-v4-0-717da2d99b28@nxp.com
Changes in v4:
- Remove patch genirq/msi: Add cleanup guard define for msi_lock_descs()/msi_unlock_descs()
- Use new method to avoid compatible problem.
Add new command DOORBELL_ENABLE and DOORBELL_DISABLE.
pcitest -B send DOORBELL_ENABLE first, EP test function driver try to
remap one of BAR_N (except test register bar) to ITS MSI MMIO space. Old
driver don't support new command, so failure return, not side effect.
After test, DOORBELL_DISABLE command send out to recover original map, so
pcitest bar test can pass as normal.
- Other detail change see each patches's change log
- Link to v3: https://lore.kernel.org/r/20241015-ep-msi-v3-0-cedc89a16c1a@nxp.com
Change from v2 to v3
- Fixed manivannan's comments
- Move common part to pci-ep-msi.c and pci-ep-msi.h
- rebase to 6.12-rc1
- use RevID to distingiush old version
mkdir /sys/kernel/config/pci_ep/functions/pci_epf_test/func1
echo 16 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/msi_interrupts
echo 0x080c > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/deviceid
echo 0x1957 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/vendorid
echo 1 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/revid
^^^^^^ to enable platform msi support.
ln -s /sys/kernel/config/pci_ep/functions/pci_epf_test/func1 /sys/kernel/config/pci_ep/controllers/4c380000.pcie-ep
- use new device ID, which identify support doorbell to avoid broken
compatility.
Enable doorbell support only for PCI_DEVICE_ID_IMX8_DB, while other devices
keep the same behavior as before.
EP side RC with old driver RC with new driver
PCI_DEVICE_ID_IMX8_DB no probe doorbell enabled
Other device ID doorbell disabled* doorbell disabled*
* Behavior remains unchanged.
Change from v1 to v2
- Add missed patch for endpont/pci-epf-test.c
- Move alloc and free to epc driver from epf.
- Provide general help function for EPC driver to alloc platform msi irq.
- Fixed manivannan's comments.
To: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
To: Krzysztof Wilczyński <kw@linux.com>
To: Kishon Vijay Abraham I <kishon@kernel.org>
To: Bjorn Helgaas <bhelgaas@google.com>
To: Arnd Bergmann <arnd@arndb.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: imx@lists.linux.dev
Cc: Niklas Cassel <cassel@kernel.org>
Cc: cassel@kernel.org
Cc: dlemoal@kernel.org
Cc: maz@kernel.org
Cc: jdmason@kudzu.us
To: Rafael J. Wysocki <rafael@kernel.org>
To: Thomas Gleixner <tglx@linutronix.de>
To: Anup Patel <apatel@ventanamicro.com>
To: Kishon Vijay Abraham I <kishon@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Frank Li (6):
platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
PCI: endpoint: Add pci_epf_align_inbound_addr() helper for address alignment
PCI: endpoint: pci-epf-test: Add doorbell test support
misc: pci_endpoint_test: Add doorbell test case
tools: PCI: Add 'B' option for test doorbell
drivers/base/platform-msi.c | 1 +
drivers/misc/pci_endpoint_test.c | 80 ++++++++++++++++
drivers/pci/endpoint/Makefile | 2 +-
drivers/pci/endpoint/functions/pci-epf-test.c | 132 ++++++++++++++++++++++++++
drivers/pci/endpoint/pci-ep-msi.c | 106 +++++++++++++++++++++
drivers/pci/endpoint/pci-epf-core.c | 44 +++++++++
include/linux/pci-ep-msi.h | 15 +++
include/linux/pci-epf.h | 19 ++++
include/uapi/linux/pcitest.h | 1 +
tools/pci/pcitest.c | 16 +++-
10 files changed, 414 insertions(+), 2 deletions(-)
---
base-commit: 0b020199675f5fcb4df1120c33d01dc6e18ff8ae
change-id: 20241010-ep-msi-8b4cab33b1be
Best regards,
---
Frank Li <Frank.Li@nxp.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
@ 2024-12-03 20:36 ` Frank Li
2024-12-03 21:12 ` Thomas Gleixner
2024-12-03 20:36 ` [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller Frank Li
` (4 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li, stable
The follow steps trigger kernel dump warning and
platform_device_msi_init_and_alloc_irqs() return false.
1: platform_device_msi_init_and_alloc_irqs();
2: platform_device_msi_free_irqs_all();
3: platform_device_msi_init_and_alloc_irqs();
[ 76.713677] WARNING: CPU: 3 PID: 134 at kernel/irq/msi.c:1028 msi_create_device_irq_domain+0x1bc/0x22c
[ 76.723010] Modules linked in:
[ 76.726082] CPU: 3 UID: 0 PID: 134 Comm: kworker/3:1H Not tainted 6.13.0-rc1-00015-gd60b98003b43-dirty #57
[ 76.735741] Hardware name: NXP i.MX95 19X19 board (DT)
[ 76.740883] Workqueue: kpcitest pci_epf_test_cmd_handler
[ 76.746212] pstate: a0400009 (NzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 76.753172] pc : msi_create_device_irq_domain+0x1bc/0x22c
[ 76.758586] lr : msi_create_device_irq_domain+0x104/0x22c
[ 76.763988] sp : ffff800083f43be0
[ 76.767313] x29: ffff800083f43be0 x28: 0000000000000000 x27: ffff8000827a7000
[ 76.774466] x26: ffff00008085f400 x25: ffff00008000b180 x24: ffff000080fc6410
[ 76.781624] x23: ffff000085704cc0 x22: ffff8000811c8828 x21: ffff000085704cc0
[ 76.788774] x20: ffff000082814000 x19: 0000000000000000 x18: ffffffffffffffff
[ 76.795933] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
[ 76.803083] x14: 0000000000000000 x13: 0000000f00000000 x12: 0000000000000000
[ 76.810233] x11: 0000000000000000 x10: 000000000000002d x9 : ffff800083f43ba0
[ 76.817383] x8 : 00000000ffffffff x7 : 0000000000000019 x6 : ffff0000857e443a
[ 76.824533] x5 : 0000000000000000 x4 : ffffffffffffffff x3 : ffff000085704ce8
[ 76.831683] x2 : ffff000080835640 x1 : 0000000000000213 x0 : ffff0000877189c0
[ 76.838840] Call trace:
[ 76.841287] msi_create_device_irq_domain+0x1bc/0x22c (P)
[ 76.846701] msi_create_device_irq_domain+0x104/0x22c (L)
[ 76.852118] platform_device_msi_init_and_alloc_irqs+0x6c/0xb8
Do below two things in platform_device_msi_init_and_alloc_irqs().
- msi_create_device_irq_domain()
- msi_domain_alloc_irqs_range()
But only call msi_domain_free_irqs_all() in
platform_device_msi_free_irqs_all(), which missed call
msi_remove_device_irq_domain(). This cause above kernel dump when call
platform_device_msi_init_and_alloc_irqs() again.
Fixes: c88f9110bfbc ("platform-msi: Prepare for real per device domains")
Cc: stable@kernel.org
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/base/platform-msi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 4401cc31e4736..e7615daf5f539 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -98,5 +98,6 @@ EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
void platform_device_msi_free_irqs_all(struct device *dev)
{
msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
+ msi_remove_device_irq_domain(dev, MSI_DEFAULT_DOMAIN);
}
EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
2024-12-03 20:36 ` [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all() Frank Li
@ 2024-12-03 20:36 ` Frank Li
2024-12-03 22:15 ` Thomas Gleixner
2024-12-03 20:36 ` [PATCH v9 3/6] PCI: endpoint: Add pci_epf_align_inbound_addr() helper for address alignment Frank Li
` (3 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
Doorbell feature is implemented by mapping the EP's MSI interrupt
controller message address to a dedicated BAR in the EPC core. It is the
responsibility of the EPF driver to pass the actual message data to be
written by the host to the doorbell BAR region through its own logic.
Tested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Chagne from v8 to v9
- sort header file
- use pci_epc_get(dev_name(msi_desc_to_dev(desc)));
- check epf number at pci_epf_alloc_doorbell
- Add comments for miss msi-parent case
change from v5 to v8
-none
Change from v4 to v5
- Remove request_irq() in pci_epc_alloc_doorbell() and leave to EP function
driver, so ep function driver can register differece call back function for
difference doorbell events and set irq affinity to differece CPU core.
- Improve error message when MSI allocate failure.
Change from v3 to v4
- msi change to use msi_get_virq() avoid use msi_for_each_desc().
- add new struct for pci_epf_doorbell_msg to msi msg,virq and irq name.
- move mutex lock to epc function
- initialize variable at declear place.
- passdown epf to epc*() function to simplify code.
---
drivers/pci/endpoint/Makefile | 2 +-
drivers/pci/endpoint/pci-ep-msi.c | 106 ++++++++++++++++++++++++++++++++++++++
include/linux/pci-ep-msi.h | 15 ++++++
include/linux/pci-epf.h | 16 ++++++
4 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/endpoint/Makefile b/drivers/pci/endpoint/Makefile
index 95b2fe47e3b06..a1ccce440c2c5 100644
--- a/drivers/pci/endpoint/Makefile
+++ b/drivers/pci/endpoint/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS) += pci-ep-cfs.o
obj-$(CONFIG_PCI_ENDPOINT) += pci-epc-core.o pci-epf-core.o\
- pci-epc-mem.o functions/
+ pci-epc-mem.o pci-ep-msi.o functions/
diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c
new file mode 100644
index 0000000000000..8f92f447712d8
--- /dev/null
+++ b/drivers/pci/endpoint/pci-ep-msi.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCI Endpoint *Controller* (EPC) MSI library
+ *
+ * Copyright (C) 2024 NXP
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/pci-epc.h>
+#include <linux/pci-epf.h>
+#include <linux/pci-ep-cfs.h>
+#include <linux/pci-ep-msi.h>
+#include <linux/slab.h>
+
+static void pci_epc_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+ struct pci_epc *epc;
+ struct pci_epf *epf;
+
+ epc = pci_epc_get(dev_name(msi_desc_to_dev(desc)));
+ if (!epc)
+ return;
+
+ epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list);
+
+ if (epf && epf->db_msg && desc->msi_index < epf->num_db)
+ memcpy(&epf->db_msg[desc->msi_index].msg, msg, sizeof(*msg));
+
+ pci_epc_put(epc);
+}
+
+static void pci_epc_free_doorbell(struct pci_epc *epc, struct pci_epf *epf)
+{
+ guard(mutex)(&epc->lock);
+
+ platform_device_msi_free_irqs_all(epc->dev.parent);
+}
+
+static int pci_epc_alloc_doorbell(struct pci_epc *epc, struct pci_epf *epf)
+{
+ struct device *dev = epc->dev.parent;
+ u16 num_db = epf->num_db;
+ int i = 0;
+ int ret;
+
+ guard(mutex)(&epc->lock);
+
+ if (list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list) != epf) {
+ dev_err(dev, "MSI doorbell only support one endpoint function\n");
+ return -EINVAL;
+ }
+
+ ret = platform_device_msi_init_and_alloc_irqs(dev, num_db, pci_epc_write_msi_msg);
+ if (ret) {
+ /*
+ * The pcie_ep DT node has to specify 'msi-parent' for EP
+ * doorbell support to work. Right now only GIC ITS is
+ * supported. If you have GIC ITS and reached this print,
+ * perhaps you are missing 'msi-parent' in DT.
+ */
+ dev_err(dev, "Failed to allocate MSI\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_db; i++)
+ epf->db_msg[i].virq = msi_get_virq(dev, i);
+
+ return 0;
+};
+
+int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db)
+{
+ struct pci_epc *epc = epf->epc;
+ void *msg;
+ int ret;
+
+ msg = kcalloc(num_db, sizeof(struct pci_epf_doorbell_msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ epf->num_db = num_db;
+ epf->db_msg = msg;
+
+ ret = pci_epc_alloc_doorbell(epc, epf);
+ if (ret)
+ kfree(msg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epf_alloc_doorbell);
+
+void pci_epf_free_doorbell(struct pci_epf *epf)
+{
+ struct pci_epc *epc = epf->epc;
+
+ pci_epc_free_doorbell(epc, epf);
+
+ kfree(epf->db_msg);
+ epf->db_msg = NULL;
+ epf->num_db = 0;
+}
+EXPORT_SYMBOL_GPL(pci_epf_free_doorbell);
diff --git a/include/linux/pci-ep-msi.h b/include/linux/pci-ep-msi.h
new file mode 100644
index 0000000000000..f0cfecf491199
--- /dev/null
+++ b/include/linux/pci-ep-msi.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PCI Endpoint *Function* side MSI header file
+ *
+ * Copyright (C) 2024 NXP
+ * Author: Frank Li <Frank.Li@nxp.com>
+ */
+
+#ifndef __PCI_EP_MSI__
+#define __PCI_EP_MSI__
+
+int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 nums);
+void pci_epf_free_doorbell(struct pci_epf *epf);
+
+#endif /* __PCI_EP_MSI__ */
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 18a3aeb62ae4e..5374e6515ffa0 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -12,6 +12,7 @@
#include <linux/configfs.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
+#include <linux/msi.h>
#include <linux/pci.h>
struct pci_epf;
@@ -125,6 +126,17 @@ struct pci_epf_bar {
int flags;
};
+/**
+ * struct pci_epf_doorbell_msg - represents doorbell message
+ * @msi_msg: MSI message
+ * @virq: irq number of this doorbell MSI message
+ * @name: irq name for doorbell interrupt
+ */
+struct pci_epf_doorbell_msg {
+ struct msi_msg msg;
+ int virq;
+};
+
/**
* struct pci_epf - represents the PCI EPF device
* @dev: the PCI EPF device
@@ -152,6 +164,8 @@ struct pci_epf_bar {
* @vfunction_num_map: bitmap to manage virtual function number
* @pci_vepf: list of virtual endpoint functions associated with this function
* @event_ops: Callbacks for capturing the EPC events
+ * @db_msg: data for MSI from RC side
+ * @num_db: number of doorbells
*/
struct pci_epf {
struct device dev;
@@ -182,6 +196,8 @@ struct pci_epf {
unsigned long vfunction_num_map;
struct list_head pci_vepf;
const struct pci_epc_event_ops *event_ops;
+ struct pci_epf_doorbell_msg *db_msg;
+ u16 num_db;
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 3/6] PCI: endpoint: Add pci_epf_align_inbound_addr() helper for address alignment
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
2024-12-03 20:36 ` [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all() Frank Li
2024-12-03 20:36 ` [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller Frank Li
@ 2024-12-03 20:36 ` Frank Li
2024-12-03 20:36 ` [PATCH v9 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support Frank Li
` (2 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
Introduce the helper function pci_epf_align_inbound_addr() to adjust
addresses according to PCI BAR alignment requirements, converting addresses
into base and offset values.
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change from v8 to v9
- pci_epf_align_inbound_addr(), base and off must be not NULL
- rm pci_epf_align_inbound_addr_lo_hi()
change from v7 to v8
- change name to pci_epf_align_inbound_addr()
- update comment said only need for memory, which not allocated by
pci_epf_alloc_space().
change from v6 to v7
- new patch
---
drivers/pci/endpoint/pci-epf-core.c | 44 +++++++++++++++++++++++++++++++++++++
include/linux/pci-epf.h | 3 +++
2 files changed, 47 insertions(+)
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 8fa2797d4169a..d7a80f9c1e661 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -464,6 +464,50 @@ struct pci_epf *pci_epf_create(const char *name)
}
EXPORT_SYMBOL_GPL(pci_epf_create);
+/**
+ * pci_epf_align_inbound_addr() - Get base address and offset that match BAR's
+ * alignment requirement
+ * @epf: the EPF device
+ * @addr: the address of the memory
+ * @bar: the BAR number corresponding to map addr
+ * @base: return base address, which match BAR's alignment requirement.
+ * @off: return offset.
+ *
+ * Helper function to convert input 'addr' to base and offset, which match
+ * BAR's alignment requirement.
+ *
+ * The pci_epf_alloc_space() function already accounts for alignment. This is
+ * primarily intended for use with other memory regions not allocated by
+ * pci_epf_alloc_space(), such as peripheral register spaces or the trigger
+ * address for a platform MSI controller.
+ */
+int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
+ u64 addr, u64 *base, size_t *off)
+{
+ const struct pci_epc_features *epc_features;
+ u64 align;
+
+ if (!base || !off)
+ return -EINVAL;
+
+ epc_features = pci_epc_get_features(epf->epc, epf->func_no, epf->vfunc_no);
+ if (!epc_features) {
+ dev_err(&epf->dev, "epc_features not implemented\n");
+ return -EOPNOTSUPP;
+ }
+
+ align = epc_features->align;
+ align = align ? align : 128;
+ if (epc_features->bar[bar].type == BAR_FIXED)
+ align = max(epc_features->bar[bar].fixed_size, align);
+
+ *base = round_down(addr, align);
+ *off = addr & (align - 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_epf_align_inbound_addr);
+
static void pci_epf_dev_release(struct device *dev)
{
struct pci_epf *epf = to_pci_epf(dev);
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 5374e6515ffa0..2847d195433bf 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -238,6 +238,9 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
enum pci_epc_interface_type type);
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
+
+int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar,
+ u64 addr, u64 *base, size_t *off);
int pci_epf_bind(struct pci_epf *epf);
void pci_epf_unbind(struct pci_epf *epf);
int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
` (2 preceding siblings ...)
2024-12-03 20:36 ` [PATCH v9 3/6] PCI: endpoint: Add pci_epf_align_inbound_addr() helper for address alignment Frank Li
@ 2024-12-03 20:36 ` Frank Li
2024-12-03 20:36 ` [PATCH v9 5/6] misc: pci_endpoint_test: Add doorbell test case Frank Li
2024-12-03 20:36 ` [PATCH v9 6/6] tools: PCI: Add 'B' option for test doorbell Frank Li
5 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
Add three registers: doorbell_bar, doorbell_addr, and doorbell_data. Use
pci_epf_alloc_doorbell() to allocate a doorbell address space.
Enable the Root Complex (RC) side driver to trigger pci-epc-test's doorbell
callback handler by writing doorbell_data to the mapped doorbell_bar's
address space.
Set STATUS_DOORBELL_SUCCESS in the doorbell callback to indicate
completion.
Avoid breaking compatibility between host and endpoint, add new command
COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL. Host side need send
COMMAND_ENABLE_DOORBELL to map one bar's inbound address to MSI space.
the command COMMAND_DISABLE_DOORBELL to recovery original inbound address
mapping.
Host side new driver Host side old driver
EP: new driver S F
EP: old driver F F
S: If EP side support MSI, 'pcitest -B' return success.
If EP side doesn't support MSI, the same to 'F'.
F: 'pcitest -B' return failure, other case as usual.
Tested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v8 to v9
- move pci_epf_alloc_doorbell() into pci_epf_{enable/disable}_doorbell().
- remove doorbell_done in commit message.
- rename pci_epf_{enable/disable}_doorbell() to
pci_epf_test_{enable/disable}_doorbell() to align corrent code style.
Change from v7 to v8
- rename to pci_epf_align_inbound_addr_lo_hi()
Change from v6 to v7
- use help function pci_epf_align_addr_lo_hi()
Change from v5 to v6
- rename doorbell_addr to doorbell_offset
Chagne from v4 to v5
- Add doorbell free at unbind function.
- Move msi irq handler to here to more complex user case, such as differece
doorbell can use difference handler function.
- Add Niklas's code to handle fixed bar's case. If need add your signed-off
tag or co-developer tag, please let me know.
change from v3 to v4
- remove revid requirement
- Add command COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL.
- call pci_epc_set_bar() to map inbound address to MSI space only at
COMMAND_ENABLE_DOORBELL.
---
drivers/pci/endpoint/functions/pci-epf-test.c | 132 ++++++++++++++++++++++++++
1 file changed, 132 insertions(+)
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index ef6677f34116e..a0a0e86a081cb 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -11,12 +11,14 @@
#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/msi.h>
#include <linux/slab.h>
#include <linux/pci_ids.h>
#include <linux/random.h>
#include <linux/pci-epc.h>
#include <linux/pci-epf.h>
+#include <linux/pci-ep-msi.h>
#include <linux/pci_regs.h>
#define IRQ_TYPE_INTX 0
@@ -29,6 +31,8 @@
#define COMMAND_READ BIT(3)
#define COMMAND_WRITE BIT(4)
#define COMMAND_COPY BIT(5)
+#define COMMAND_ENABLE_DOORBELL BIT(6)
+#define COMMAND_DISABLE_DOORBELL BIT(7)
#define STATUS_READ_SUCCESS BIT(0)
#define STATUS_READ_FAIL BIT(1)
@@ -39,6 +43,11 @@
#define STATUS_IRQ_RAISED BIT(6)
#define STATUS_SRC_ADDR_INVALID BIT(7)
#define STATUS_DST_ADDR_INVALID BIT(8)
+#define STATUS_DOORBELL_SUCCESS BIT(9)
+#define STATUS_DOORBELL_ENABLE_SUCCESS BIT(10)
+#define STATUS_DOORBELL_ENABLE_FAIL BIT(11)
+#define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12)
+#define STATUS_DOORBELL_DISABLE_FAIL BIT(13)
#define FLAG_USE_DMA BIT(0)
@@ -74,6 +83,9 @@ struct pci_epf_test_reg {
u32 irq_type;
u32 irq_number;
u32 flags;
+ u32 doorbell_bar;
+ u32 doorbell_offset;
+ u32 doorbell_data;
} __packed;
static struct pci_epf_header test_header = {
@@ -642,6 +654,117 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
}
}
+static irqreturn_t pci_epf_test_doorbell_handler(int irq, void *data)
+{
+ struct pci_epf_test *epf_test = data;
+ enum pci_barno test_reg_bar = epf_test->test_reg_bar;
+ struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+
+ reg->status |= STATUS_DOORBELL_SUCCESS;
+ pci_epf_test_raise_irq(epf_test, reg);
+
+ return IRQ_HANDLED;
+}
+
+static void pci_epf_test_doorbell_cleanup(struct pci_epf_test *epf_test)
+{
+ struct pci_epf_test_reg *reg = epf_test->reg[epf_test->test_reg_bar];
+ struct pci_epf *epf = epf_test->epf;
+
+ if (reg->doorbell_bar > 0) {
+ free_irq(epf->db_msg[0].virq, epf_test);
+ reg->doorbell_bar = NO_BAR;
+ }
+
+ if (epf->db_msg)
+ pci_epf_free_doorbell(epf);
+}
+
+static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
+{
+ struct pci_epf *epf = epf_test->epf;
+ struct pci_epf_bar db_bar = {};
+ struct pci_epc *epc = epf->epc;
+ struct msi_msg *msg;
+ enum pci_barno bar;
+ size_t offset;
+ int ret;
+
+ ret = pci_epf_alloc_doorbell(epf, 1);
+ if (ret) {
+ reg->status |= STATUS_DOORBELL_ENABLE_FAIL;
+ return;
+ }
+
+ msg = &epf->db_msg[0].msg;
+ bar = pci_epc_get_next_free_bar(epf_test->epc_features, epf_test->test_reg_bar + 1);
+ if (bar < BAR_0 || bar == epf_test->test_reg_bar || !epf->db_msg) {
+ reg->status |= STATUS_DOORBELL_ENABLE_FAIL;
+ return;
+ }
+
+ ret = request_irq(epf->db_msg[0].virq, pci_epf_test_doorbell_handler, 0,
+ "pci-test-doorbell", epf_test);
+ if (ret) {
+ dev_err(&epf->dev,
+ "Failed to request irq %d, doorbell feature is not supported\n",
+ epf->db_msg[0].virq);
+ reg->status |= STATUS_DOORBELL_ENABLE_FAIL;
+ pci_epf_test_doorbell_cleanup(epf_test);
+ return;
+ }
+
+ reg->doorbell_data = msg->data;
+ reg->doorbell_bar = bar;
+
+ msg = &epf->db_msg[0].msg;
+ ret = pci_epf_align_inbound_addr(epf, bar, ((u64)msg->address_hi << 32) | msg->address_lo,
+ &db_bar.phys_addr, &offset);
+
+ if (ret) {
+ reg->status |= STATUS_DOORBELL_ENABLE_FAIL;
+ pci_epf_test_doorbell_cleanup(epf_test);
+ return;
+ }
+
+ reg->doorbell_offset = offset;
+
+ db_bar.barno = bar;
+ db_bar.size = epf->bar[bar].size;
+ db_bar.flags = epf->bar[bar].flags;
+
+ ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &db_bar);
+ if (ret) {
+ reg->status |= STATUS_DOORBELL_ENABLE_FAIL;
+ pci_epf_test_doorbell_cleanup(epf_test);
+ } else {
+ reg->status |= STATUS_DOORBELL_ENABLE_SUCCESS;
+ }
+}
+
+static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test,
+ struct pci_epf_test_reg *reg)
+{
+ enum pci_barno bar = reg->doorbell_bar;
+ struct pci_epf *epf = epf_test->epf;
+ struct pci_epc *epc = epf->epc;
+ int ret;
+
+ if (bar < BAR_0 || bar == epf_test->test_reg_bar || !epf->db_msg) {
+ reg->status |= STATUS_DOORBELL_DISABLE_FAIL;
+ return;
+ }
+
+ ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf->bar[bar]);
+ if (ret)
+ reg->status |= STATUS_DOORBELL_DISABLE_FAIL;
+ else
+ reg->status |= STATUS_DOORBELL_DISABLE_SUCCESS;
+
+ pci_epf_test_doorbell_cleanup(epf_test);
+}
+
static void pci_epf_test_cmd_handler(struct work_struct *work)
{
u32 command;
@@ -688,6 +811,14 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
pci_epf_test_copy(epf_test, reg);
pci_epf_test_raise_irq(epf_test, reg);
break;
+ case COMMAND_ENABLE_DOORBELL:
+ pci_epf_test_enable_doorbell(epf_test, reg);
+ pci_epf_test_raise_irq(epf_test, reg);
+ break;
+ case COMMAND_DISABLE_DOORBELL:
+ pci_epf_test_disable_doorbell(epf_test, reg);
+ pci_epf_test_raise_irq(epf_test, reg);
+ break;
default:
dev_err(dev, "Invalid command 0x%x\n", command);
break;
@@ -934,6 +1065,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
pci_epf_test_clean_dma_chan(epf_test);
pci_epf_test_clear_bar(epf);
}
+ pci_epf_test_doorbell_cleanup(epf_test);
pci_epf_test_free_space(epf);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 5/6] misc: pci_endpoint_test: Add doorbell test case
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
` (3 preceding siblings ...)
2024-12-03 20:36 ` [PATCH v9 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support Frank Li
@ 2024-12-03 20:36 ` Frank Li
2024-12-03 20:36 ` [PATCH v9 6/6] tools: PCI: Add 'B' option for test doorbell Frank Li
5 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
Add three registers: PCIE_ENDPOINT_TEST_DB_BAR, PCIE_ENDPOINT_TEST_DB_ADDR,
and PCIE_ENDPOINT_TEST_DB_DATA.
Trigger the doorbell by writing data from PCI_ENDPOINT_TEST_DB_DATA to the
address provided by PCI_ENDPOINT_TEST_DB_OFFSET and wait for endpoint
feedback.
Add two command to COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL
to enable EP side's doorbell support and avoid compatible problem, which
host side driver miss-match with endpoint side function driver. See below
table:
Host side new driver Host side old driver
EP: new driver S F
EP: old driver F F
S: If EP side support MSI, 'pcitest -B' return success.
If EP side doesn't support MSI, the same to 'F'.
F: 'pcitest -B' return failure, other case as usual.
Tested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v8 to v9
- change PCITEST_DOORBELL to 0xa
Change form v6 to v8
- none
Change from v5 to v6
- %s/PCI_ENDPOINT_TEST_DB_ADDR/PCI_ENDPOINT_TEST_DB_OFFSET/g
Change from v4 to v5
- remove unused varible
- add irq_type at pci_endpoint_test_doorbell();
change from v3 to v4
- Add COMMAND_ENABLE_DOORBELL and COMMAND_DISABLE_DOORBELL.
- Remove new DID requirement.
---
drivers/misc/pci_endpoint_test.c | 80 ++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/pcitest.h | 1 +
2 files changed, 81 insertions(+)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 3aaaf47fa4ee2..b3f36b6ba8ba2 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -42,6 +42,8 @@
#define COMMAND_READ BIT(3)
#define COMMAND_WRITE BIT(4)
#define COMMAND_COPY BIT(5)
+#define COMMAND_ENABLE_DOORBELL BIT(6)
+#define COMMAND_DISABLE_DOORBELL BIT(7)
#define PCI_ENDPOINT_TEST_STATUS 0x8
#define STATUS_READ_SUCCESS BIT(0)
@@ -53,6 +55,11 @@
#define STATUS_IRQ_RAISED BIT(6)
#define STATUS_SRC_ADDR_INVALID BIT(7)
#define STATUS_DST_ADDR_INVALID BIT(8)
+#define STATUS_DOORBELL_SUCCESS BIT(9)
+#define STATUS_DOORBELL_ENABLE_SUCCESS BIT(10)
+#define STATUS_DOORBELL_ENABLE_FAIL BIT(11)
+#define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12)
+#define STATUS_DOORBELL_DISABLE_FAIL BIT(13)
#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
@@ -67,6 +74,10 @@
#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
#define PCI_ENDPOINT_TEST_FLAGS 0x2c
+#define PCI_ENDPOINT_TEST_DB_BAR 0x30
+#define PCI_ENDPOINT_TEST_DB_OFFSET 0x34
+#define PCI_ENDPOINT_TEST_DB_DATA 0x38
+
#define FLAG_USE_DMA BIT(0)
#define PCI_DEVICE_ID_TI_AM654 0xb00c
@@ -108,6 +119,7 @@ enum pci_barno {
BAR_3,
BAR_4,
BAR_5,
+ NO_BAR = -1,
};
struct pci_endpoint_test {
@@ -746,6 +758,71 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
return false;
}
+static bool pci_endpoint_test_doorbell(struct pci_endpoint_test *test)
+{
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ int irq_type = test->irq_type;
+ enum pci_barno bar;
+ u32 data, status;
+ u32 addr;
+
+ if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
+ dev_err(dev, "Invalid IRQ type option\n");
+ return false;
+ }
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+ COMMAND_ENABLE_DOORBELL);
+
+ wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000));
+
+ status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+ if (status & STATUS_DOORBELL_ENABLE_FAIL) {
+ dev_err(dev, "Failed to enable doorbell\n");
+ return false;
+ }
+
+ data = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_DATA);
+ addr = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_OFFSET);
+ bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR);
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0);
+
+ bar = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_DB_BAR);
+
+ writel(data, test->bar[bar] + addr);
+
+ wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000));
+
+ status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+
+ if (!(status & STATUS_DOORBELL_SUCCESS))
+ dev_err(dev, "Endpoint have not received Doorbell\n");
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+ COMMAND_DISABLE_DOORBELL);
+
+ wait_for_completion_timeout(&test->irq_raised, msecs_to_jiffies(1000));
+
+ status |= pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+
+ if (status & STATUS_DOORBELL_DISABLE_FAIL) {
+ dev_err(dev, "Failed to disable doorbell\n");
+ return false;
+ }
+
+ if (!(status & STATUS_DOORBELL_SUCCESS))
+ return false;
+
+ return true;
+}
+
static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -793,6 +870,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
case PCITEST_CLEAR_IRQ:
ret = pci_endpoint_test_clear_irq(test);
break;
+ case PCITEST_DOORBELL:
+ ret = pci_endpoint_test_doorbell(test);
+ break;
}
ret:
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index 94b46b043b536..b82e7f2ed937d 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -20,6 +20,7 @@
#define PCITEST_MSIX _IOW('P', 0x7, int)
#define PCITEST_SET_IRQTYPE _IOW('P', 0x8, int)
#define PCITEST_GET_IRQTYPE _IO('P', 0x9)
+#define PCITEST_DOORBELL _IO('P', 0xa)
#define PCITEST_CLEAR_IRQ _IO('P', 0x10)
#define PCITEST_FLAGS_USE_DMA 0x00000001
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v9 6/6] tools: PCI: Add 'B' option for test doorbell
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
` (4 preceding siblings ...)
2024-12-03 20:36 ` [PATCH v9 5/6] misc: pci_endpoint_test: Add doorbell test case Frank Li
@ 2024-12-03 20:36 ` Frank Li
5 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2024-12-03 20:36 UTC (permalink / raw)
To: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Thomas Gleixner,
Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
Add doorbell test support.
Tested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from v3 to v8
- none
---
tools/pci/pcitest.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c
index 7b530d838d408..fcff0224a3381 100644
--- a/tools/pci/pcitest.c
+++ b/tools/pci/pcitest.c
@@ -34,6 +34,7 @@ struct pci_test {
bool copy;
unsigned long size;
bool use_dma;
+ bool doorbell;
};
static int run_test(struct pci_test *test)
@@ -147,6 +148,15 @@ static int run_test(struct pci_test *test)
fprintf(stdout, "%s\n", result[ret]);
}
+ if (test->doorbell) {
+ ret = ioctl(fd, PCITEST_DOORBELL, 0);
+ fprintf(stdout, "Ringing doorbell on the EP\t\t");
+ if (ret < 0)
+ fprintf(stdout, "TEST FAILED\n");
+ else
+ fprintf(stdout, "%s\n", result[ret]);
+ }
+
fflush(stdout);
close(fd);
return (ret < 0) ? ret : 1 - ret; /* return 0 if test succeeded */
@@ -172,7 +182,7 @@ int main(int argc, char **argv)
/* set default endpoint device */
test->device = "/dev/pci-endpoint-test.0";
- while ((c = getopt(argc, argv, "D:b:m:x:i:deIlhrwcs:")) != EOF)
+ while ((c = getopt(argc, argv, "D:b:m:x:i:BdeIlhrwcs:")) != EOF)
switch (c) {
case 'D':
test->device = optarg;
@@ -222,6 +232,9 @@ int main(int argc, char **argv)
case 'd':
test->use_dma = true;
continue;
+ case 'B':
+ test->doorbell = true;
+ continue;
case 'h':
default:
usage:
@@ -241,6 +254,7 @@ int main(int argc, char **argv)
"\t-w Write buffer test\n"
"\t-c Copy buffer test\n"
"\t-s <size> Size of buffer {default: 100KB}\n"
+ "\t-B Doorbell test\n"
"\t-h Print this help message\n",
argv[0]);
return -EINVAL;
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
2024-12-03 20:36 ` [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all() Frank Li
@ 2024-12-03 21:12 ` Thomas Gleixner
2024-12-03 21:40 ` Frank Li
0 siblings, 1 reply; 14+ messages in thread
From: Thomas Gleixner @ 2024-12-03 21:12 UTC (permalink / raw)
To: Frank Li, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li, stable
On Tue, Dec 03 2024 at 15:36, Frank Li wrote:
> The follow steps trigger kernel dump warning and
> platform_device_msi_init_and_alloc_irqs() return false.
>
> 1: platform_device_msi_init_and_alloc_irqs();
> 2: platform_device_msi_free_irqs_all();
> 3: platform_device_msi_init_and_alloc_irqs();
>
> Do below two things in platform_device_msi_init_and_alloc_irqs().
> - msi_create_device_irq_domain()
> - msi_domain_alloc_irqs_range()
>
> But only call msi_domain_free_irqs_all() in
> platform_device_msi_free_irqs_all(), which missed call
> msi_remove_device_irq_domain().
It's not a missed call. It's intentional as all existing users remove
the device afterwards.
> This cause above kernel dump when call
> platform_device_msi_init_and_alloc_irqs() again.
Sure, but that's not a fix and not required for stable because no
existing driver is affected by this unless I'm missing something.
What's the actual use case for this? You describe in great length what
fails, which is nice, but I'm missing the larger picture here.
Thanks,
tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
2024-12-03 21:12 ` Thomas Gleixner
@ 2024-12-03 21:40 ` Frank Li
2024-12-03 23:14 ` Thomas Gleixner
0 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2024-12-03 21:40 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel, linux-kernel,
linux-pci, imx, Niklas Cassel, dlemoal, maz, jdmason, stable
On Tue, Dec 03, 2024 at 10:12:36PM +0100, Thomas Gleixner wrote:
> On Tue, Dec 03 2024 at 15:36, Frank Li wrote:
> > The follow steps trigger kernel dump warning and
> > platform_device_msi_init_and_alloc_irqs() return false.
> >
> > 1: platform_device_msi_init_and_alloc_irqs();
> > 2: platform_device_msi_free_irqs_all();
> > 3: platform_device_msi_init_and_alloc_irqs();
> >
> > Do below two things in platform_device_msi_init_and_alloc_irqs().
> > - msi_create_device_irq_domain()
> > - msi_domain_alloc_irqs_range()
> >
> > But only call msi_domain_free_irqs_all() in
> > platform_device_msi_free_irqs_all(), which missed call
> > msi_remove_device_irq_domain().
>
> It's not a missed call. It's intentional as all existing users remove
> the device afterwards.
>
> > This cause above kernel dump when call
> > platform_device_msi_init_and_alloc_irqs() again.
>
> Sure, but that's not a fix and not required for stable because no
> existing driver is affected by this unless I'm missing something.
>
> What's the actual use case for this? You describe in great length what
> fails, which is nice, but I'm missing the larger picture here.
PCI host send a door bell to PCI endpoint, which use platform msi to
trigger a IRQ.
PCI Host side PCI endpoint side
Send "enable" command -> call platform_device_msi_init_and_alloc_irqs()
Get doorbell address <- send back MSI address by shared memory
Write data to doorbell -> MSI irq handler triggered.
Send "Disable" command -> call platform_device_msi_free_irqs_all()
At endpoint side, need dymatic response "enable/disable" commands. Of
course, I can call msi_remove_device_irq_domain() in my disable function.
But I think it should be symetic in alloc/free pair functions.
Previous version, alloc/free in bind/unbind function. I missed to do
unbind/bind test. the principle should be the same.
Frank
>
> Thanks,
>
> tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
2024-12-03 20:36 ` [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller Frank Li
@ 2024-12-03 22:15 ` Thomas Gleixner
2024-12-03 23:24 ` Frank Li
0 siblings, 1 reply; 14+ messages in thread
From: Thomas Gleixner @ 2024-12-03 22:15 UTC (permalink / raw)
To: Frank Li, Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel
Cc: linux-kernel, linux-pci, imx, Niklas Cassel, dlemoal, maz,
jdmason, Frank Li
On Tue, Dec 03 2024 at 15:36, Frank Li wrote:
> +static void pci_epc_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
> +{
> + struct pci_epc *epc;
> + struct pci_epf *epf;
> +
> + epc = pci_epc_get(dev_name(msi_desc_to_dev(desc)));
> + if (!epc)
This is wrong as pci_epc_get() never returns NULL on failure. It returns
an error pointer.
> + return;
> +
> + epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list);
How can the list be empty?
> + if (epf && epf->db_msg && desc->msi_index < epf->num_db)
> + memcpy(&epf->db_msg[desc->msi_index].msg, msg, sizeof(*msg));
So now the message is copied out into that db_msg array which is
somewhere in the memory which was allocated on the EP side.
How is the host side supposed to know about the change of the message?
This only works reliably if:
1) the message address/data pair is immutable once it is set up and
subsequent affinity changes are not affecting it
2) The ordering on the EP driver is:
request_irq()
publish_msg_to_host()
tell_host_that_message_is_ready()
#2 is a documentation problem, but #1 needs some thought.
It only works for MSI parent domains which use a translation table and
affinity changes only happen at the translation table level, which means
the address/data pair is unaffected.
Sure GIC-ITS, AMD/Intel remap domains work that way, but what happens if
the underlying MSI parent domain actually changes the message
(address/data pair) during an affinity change?
These domains expect that the message is known to the other side at the
time when irq_set_affinity() returns. In case of regular PCI/MSI this is
not a problem because the message is written to the device before the
function returns, but in this EP case nothing guarantees that the
modified message is host visible at that point.
The fact that a MSI parent domain supports DOMAIN_BUS_DEVICE_MSI does
not guarantee that the parent is translation table based.
As this is intended to be a generic library for all sorts of EP
implementations, there needs to be
- either a mechanism to prevent the initialization if the underlying
MSI parent domain does not provide immutable messages
- or support for endpoint specific msi_write_msg() implementations
Thanks,
tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
2024-12-03 21:40 ` Frank Li
@ 2024-12-03 23:14 ` Thomas Gleixner
2024-12-04 16:10 ` Frank Li
0 siblings, 1 reply; 14+ messages in thread
From: Thomas Gleixner @ 2024-12-03 23:14 UTC (permalink / raw)
To: Frank Li
Cc: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel, linux-kernel,
linux-pci, imx, Niklas Cassel, dlemoal, maz, jdmason, stable
On Tue, Dec 03 2024 at 16:40, Frank Li wrote:
> On Tue, Dec 03, 2024 at 10:12:36PM +0100, Thomas Gleixner wrote:
>> Sure, but that's not a fix and not required for stable because no
>> existing driver is affected by this unless I'm missing something.
>>
>> What's the actual use case for this? You describe in great length what
>> fails, which is nice, but I'm missing the larger picture here.
>
> PCI host send a door bell to PCI endpoint, which use platform msi to
> trigger a IRQ.
>
> PCI Host side PCI endpoint side
>
> Send "enable" command -> call platform_device_msi_init_and_alloc_irqs()
> Get doorbell address <- send back MSI address by shared memory
> Write data to doorbell -> MSI irq handler triggered.
> Send "Disable" command -> call platform_device_msi_free_irqs_all()
>
>
> At endpoint side, need dymatic response "enable/disable" commands. Of
> course, I can call msi_remove_device_irq_domain() in my disable function.
> But I think it should be symetic in alloc/free pair functions.
No objections, but that's not a justification for a stable backport as
nothing in tree has this problem right now. You add a new use case which
requires it, so only that new use case has this dependency, no?
Thanks,
tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
2024-12-03 22:15 ` Thomas Gleixner
@ 2024-12-03 23:24 ` Frank Li
2024-12-04 13:08 ` Thomas Gleixner
0 siblings, 1 reply; 14+ messages in thread
From: Frank Li @ 2024-12-03 23:24 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel, linux-kernel,
linux-pci, imx, Niklas Cassel, dlemoal, maz, jdmason
On Tue, Dec 03, 2024 at 11:15:27PM +0100, Thomas Gleixner wrote:
> On Tue, Dec 03 2024 at 15:36, Frank Li wrote:
> > +static void pci_epc_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
> > +{
> > + struct pci_epc *epc;
> > + struct pci_epf *epf;
> > +
> > + epc = pci_epc_get(dev_name(msi_desc_to_dev(desc)));
> > + if (!epc)
>
> This is wrong as pci_epc_get() never returns NULL on failure. It returns
> an error pointer.
>
> > + return;
> > +
> > + epf = list_first_entry_or_null(&epc->pci_epf, struct pci_epf, list);
>
> How can the list be empty?
It already checked at pci_epc_alloc_doorbell(), which should be never
empty when this function called.
>
> > + if (epf && epf->db_msg && desc->msi_index < epf->num_db)
> > + memcpy(&epf->db_msg[desc->msi_index].msg, msg, sizeof(*msg));
>
> So now the message is copied out into that db_msg array which is
> somewhere in the memory which was allocated on the EP side.
>
> How is the host side supposed to know about the change of the message?
>
> This only works reliably if:
>
> 1) the message address/data pair is immutable once it is set up and
> subsequent affinity changes are not affecting it
>
> 2) The ordering on the EP driver is:
>
> request_irq()
> publish_msg_to_host()
> tell_host_that_message_is_ready()
>
> #2 is a documentation problem, but #1 needs some thought.
>
> It only works for MSI parent domains which use a translation table and
> affinity changes only happen at the translation table level, which means
> the address/data pair is unaffected.
>
> Sure GIC-ITS, AMD/Intel remap domains work that way, but what happens if
> the underlying MSI parent domain actually changes the message
> (address/data pair) during an affinity change?
>
> These domains expect that the message is known to the other side at the
> time when irq_set_affinity() returns. In case of regular PCI/MSI this is
> not a problem because the message is written to the device before the
> function returns, but in this EP case nothing guarantees that the
> modified message is host visible at that point.
If irq_set_affinity() can change address/data pair, how to avoid below
raise condition:
1. device send out write data to address, but write command still
in bus fabric or some internal command FIFO, not reach MSI controller yet.
2. irq_set_affinity() change address/data pair.
1 and 2 is totally async. if 2 affect firstly, 1 maybe missed.
>
> The fact that a MSI parent domain supports DOMAIN_BUS_DEVICE_MSI does
> not guarantee that the parent is translation table based.
>
> As this is intended to be a generic library for all sorts of EP
> implementations, there needs to be
>
> - either a mechanism to prevent the initialization if the underlying
> MSI parent domain does not provide immutable messages
How to know such information?
>
> - or support for endpoint specific msi_write_msg() implementations
Even provide specific msi_write_msg(), write to address/data to shared
memory.
host driver:
1. read address/data from shared memory
2. write data to address.
1 and 2 is not atomic. So it can't avoid above raise conditon.
Frank
>
> Thanks,
>
> tglx
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
2024-12-03 23:24 ` Frank Li
@ 2024-12-04 13:08 ` Thomas Gleixner
0 siblings, 0 replies; 14+ messages in thread
From: Thomas Gleixner @ 2024-12-04 13:08 UTC (permalink / raw)
To: Frank Li
Cc: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel, linux-kernel,
linux-pci, imx, Niklas Cassel, dlemoal, maz, jdmason
On Tue, Dec 03 2024 at 18:24, Frank Li wrote:
> On Tue, Dec 03, 2024 at 11:15:27PM +0100, Thomas Gleixner wrote:
>> The fact that a MSI parent domain supports DOMAIN_BUS_DEVICE_MSI does
>> not guarantee that the parent is translation table based.
>>
>> As this is intended to be a generic library for all sorts of EP
>> implementations, there needs to be
>>
>> - either a mechanism to prevent the initialization if the underlying
>> MSI parent domain does not provide immutable messages
>
> How to know such information?
It obviously needs to be flagged somehow in the domain and the EP magic
needs to check that flag.
>>
>> - or support for endpoint specific msi_write_msg() implementations
>
> Even provide specific msi_write_msg(), write to address/data to shared
> memory.
>
> host driver:
> 1. read address/data from shared memory
> 2. write data to address.
>
> 1 and 2 is not atomic. So it can't avoid above raise conditon.
Correct. So you cannot support that case, which in turn requires to have
a mechanism to check for the immutable property.
Thanks,
tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all()
2024-12-03 23:14 ` Thomas Gleixner
@ 2024-12-04 16:10 ` Frank Li
0 siblings, 0 replies; 14+ messages in thread
From: Frank Li @ 2024-12-04 16:10 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Manivannan Sadhasivam, Krzysztof Wilczyński,
Kishon Vijay Abraham I, Bjorn Helgaas, Arnd Bergmann,
Greg Kroah-Hartman, Rafael J. Wysocki, Anup Patel, linux-kernel,
linux-pci, imx, Niklas Cassel, dlemoal, maz, jdmason, stable
On Wed, Dec 04, 2024 at 12:14:25AM +0100, Thomas Gleixner wrote:
> On Tue, Dec 03 2024 at 16:40, Frank Li wrote:
> > On Tue, Dec 03, 2024 at 10:12:36PM +0100, Thomas Gleixner wrote:
> >> Sure, but that's not a fix and not required for stable because no
> >> existing driver is affected by this unless I'm missing something.
> >>
> >> What's the actual use case for this? You describe in great length what
> >> fails, which is nice, but I'm missing the larger picture here.
> >
> > PCI host send a door bell to PCI endpoint, which use platform msi to
> > trigger a IRQ.
> >
> > PCI Host side PCI endpoint side
> >
> > Send "enable" command -> call platform_device_msi_init_and_alloc_irqs()
> > Get doorbell address <- send back MSI address by shared memory
> > Write data to doorbell -> MSI irq handler triggered.
> > Send "Disable" command -> call platform_device_msi_free_irqs_all()
> >
> >
> > At endpoint side, need dymatic response "enable/disable" commands. Of
> > course, I can call msi_remove_device_irq_domain() in my disable function.
> > But I think it should be symetic in alloc/free pair functions.
>
> No objections, but that's not a justification for a stable backport as
> nothing in tree has this problem right now. You add a new use case which
> requires it, so only that new use case has this dependency, no?
Okay, Let me drop fixes and stable tag in next version.
Frank
>
> Thanks,
>
> tglx
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-12-04 16:11 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-03 20:36 [PATCH v9 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
2024-12-03 20:36 ` [PATCH v9 1/6] platform-msi: Add msi_remove_device_irq_domain() in platform_device_msi_free_irqs_all() Frank Li
2024-12-03 21:12 ` Thomas Gleixner
2024-12-03 21:40 ` Frank Li
2024-12-03 23:14 ` Thomas Gleixner
2024-12-04 16:10 ` Frank Li
2024-12-03 20:36 ` [PATCH v9 2/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller Frank Li
2024-12-03 22:15 ` Thomas Gleixner
2024-12-03 23:24 ` Frank Li
2024-12-04 13:08 ` Thomas Gleixner
2024-12-03 20:36 ` [PATCH v9 3/6] PCI: endpoint: Add pci_epf_align_inbound_addr() helper for address alignment Frank Li
2024-12-03 20:36 ` [PATCH v9 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support Frank Li
2024-12-03 20:36 ` [PATCH v9 5/6] misc: pci_endpoint_test: Add doorbell test case Frank Li
2024-12-03 20:36 ` [PATCH v9 6/6] tools: PCI: Add 'B' option for test doorbell Frank Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox