Linux kernel and device drivers for NXP i.MX platforms
 help / color / mirror / Atom feed
From: Niklas Cassel <cassel@kernel.org>
To: Frank Li <Frank.Li@nxp.com>
Cc: "Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>,
	"Krzysztof Wilczyński" <kw@linux.com>,
	"Kishon Vijay Abraham I" <kishon@kernel.org>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	imx@lists.linux.dev, dlemoal@kernel.org, maz@kernel.org,
	tglx@linutronix.de, jdmason@kudzu.us
Subject: Re: [PATCH v3 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support
Date: Fri, 18 Oct 2024 16:01:05 +0200	[thread overview]
Message-ID: <ZxJqITunljv0PGxn@ryzen.lan> (raw)
In-Reply-To: <20241015-ep-msi-v3-4-cedc89a16c1a@nxp.com>

Hello Frank,

On Tue, Oct 15, 2024 at 06:07:17PM -0400, Frank Li wrote:
> Add three registers: doorbell_bar, doorbell_addr, and doorbell_data,
> along with doorbell_done. 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 doorbell_done in the doorbell callback to indicate completion.
> 
> To avoid broken compatibility, use new PID/VID and set RevID bigger than 0.
> So only new pcitest program can distinguish with/without doorbell support
> and avoid wrongly write test data to doorbell bar.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  drivers/pci/endpoint/functions/pci-epf-test.c | 58 ++++++++++++++++++++++++++-
>  1 file changed, 56 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 7c2ed6eae53ad..c054d621353a6 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
> @@ -39,6 +41,7 @@
>  #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 FLAG_USE_DMA			BIT(0)
>  
> @@ -50,6 +53,7 @@ struct pci_epf_test {
>  	void			*reg[PCI_STD_NUM_BARS];
>  	struct pci_epf		*epf;
>  	enum pci_barno		test_reg_bar;
> +	enum pci_barno		doorbell_bar;
>  	size_t			msix_table_offset;
>  	struct delayed_work	cmd_handler;
>  	struct dma_chan		*dma_chan_tx;
> @@ -74,6 +78,9 @@ struct pci_epf_test_reg {
>  	u32	irq_type;
>  	u32	irq_number;
>  	u32	flags;
> +	u32	doorbell_bar;
> +	u32	doorbell_addr;
> +	u32	doorbell_data;
>  } __packed;
>  
>  static struct pci_epf_header test_header = {
> @@ -695,7 +702,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
>  	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
>  
>  	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
> -		if (!epf_test->reg[bar])
> +		if (!epf_test->reg[bar] && bar != epf_test->doorbell_bar)
>  			continue;
>  
>  		ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no,
> @@ -810,11 +817,24 @@ static int pci_epf_test_link_down(struct pci_epf *epf)
>  	return 0;
>  }
>  
> +static int pci_epf_test_doorbell(struct pci_epf *epf, int index)
> +{
> +	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
> +	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 0;
> +}
> +
>  static const struct pci_epc_event_ops pci_epf_test_event_ops = {
>  	.epc_init = pci_epf_test_epc_init,
>  	.epc_deinit = pci_epf_test_epc_deinit,
>  	.link_up = pci_epf_test_link_up,
>  	.link_down = pci_epf_test_link_down,
> +	.doorbell = pci_epf_test_doorbell,
>  };
>  
>  static int pci_epf_test_alloc_space(struct pci_epf *epf)
> @@ -853,7 +873,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
>  		if (bar == NO_BAR)
>  			break;
>  
> -		if (bar == test_reg_bar)
> +		if (bar == test_reg_bar || bar == epf_test->doorbell_bar)
>  			continue;
>  
>  		base = pci_epf_alloc_space(epf, bar_size[bar], bar,
> @@ -887,7 +907,11 @@ static int pci_epf_test_bind(struct pci_epf *epf)
>  	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
>  	const struct pci_epc_features *epc_features;
>  	enum pci_barno test_reg_bar = BAR_0;
> +	enum pci_barno doorbell_bar = NO_BAR;
>  	struct pci_epc *epc = epf->epc;
> +	struct msi_msg *msg;
> +	u64 doorbell_addr;
> +	u32 align;
>  
>  	if (WARN_ON_ONCE(!epc))
>  		return -EINVAL;
> @@ -905,10 +929,40 @@ static int pci_epf_test_bind(struct pci_epf *epf)
>  	epf_test->test_reg_bar = test_reg_bar;
>  	epf_test->epc_features = epc_features;
>  
> +	align = epc_features->align;
> +	align = align ? align : 128;
> +
> +	/* Only revid >=1 support RC-to-EP Door bell */
> +	ret = epf->header->revid > 0 ?  pci_epf_alloc_doorbell(epf, 1) : -EINVAL;

I really, really don't like this idea.

This means that you would need to write a revid > 1 in configfs to test this.
I also don't think that it is right that pci-epf-test takes ownership of "rev".

How about something like this instead:

My thinking is that you add a doorbell_capable struct member to epc_features,
and then populate CAPS_DOORBELL_SUPPORT based on epc_features in
pci_epf_test_init_caps() (similar to how my proposal sets CAPS_MSI_SUPPORT).


From 0f6bb535c6d56e03e9b3550194deec04a1c1d370 Mon Sep 17 00:00:00 2001
From: Niklas Cassel <cassel@kernel.org>
Date: Fri, 18 Oct 2024 10:32:39 +0200
Subject: [PATCH] PCI: endpoint: pci-epf-test: Add support for exposing EPC
 capabilities

Currently, there is no way for the pci-endpoint-test driver (RC side),
to know which features the EPC supports.

Expose some of the EPC:s capabilities in the test_reg_bar, such that
the pci-endpoint-test driver can know if a feature (e.g. MSI-X or DMA)
is supported before attempting to test it.

Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
 drivers/misc/pci_endpoint_test.c              | 34 +++++++++++++++
 drivers/pci/endpoint/functions/pci-epf-test.c | 43 +++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 3aaaf47fa4ee..7eb045dc81b6 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -69,6 +69,20 @@
 #define PCI_ENDPOINT_TEST_FLAGS			0x2c
 #define FLAG_USE_DMA				BIT(0)
 
+#define CAPS_MAGIC				0x25ccf687
+#define PCI_ENDPOINT_TEST_CAPS_MAGIC		0x30
+#define PCI_ENDPOINT_TEST_CAPS_VERSION		0x34
+#define PCI_ENDPOINT_TEST_CAPS			0x38
+
+#define CAPS_MSI_SUPPORT		BIT(0)
+#define CAPS_MSIX_SUPPORT		BIT(1)
+#define CAPS_DMA_SUPPORT		BIT(2)
+#define CAPS_DMA_IS_PRIVATE		BIT(3) /* only valid if DMA_SUPPORT */
+#define CAPS_DOORBELL_SUPPORT		BIT(4)
+#define CAPS_DOORBELL_BAR_MASK		GENMASK(7, 5) /* only valid if DOORBELL_SUPPORT */
+#define CAPS_DOORBELL_BAR_SHIFT		5
+#define CAPS_DOORBELL_BAR(x)		(((x) & CAPS_DOORBELL_BAR_MASK) >> CAPS_DOORBELL_BAR_SHIFT)
+
 #define PCI_DEVICE_ID_TI_AM654			0xb00c
 #define PCI_DEVICE_ID_TI_J7200			0xb00f
 #define PCI_DEVICE_ID_TI_AM64			0xb010
@@ -805,6 +819,24 @@ static const struct file_operations pci_endpoint_test_fops = {
 	.unlocked_ioctl = pci_endpoint_test_ioctl,
 };
 
+static void pci_endpoint_get_caps(struct pci_endpoint_test *test)
+{
+	u32 caps_magic, caps;
+
+	/* check if endpoint has CAPS support */
+	caps_magic = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS_MAGIC);
+	if (caps_magic != CAPS_MAGIC)
+		return;
+
+	caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS);
+	pr_info("CAPS: MSI support: %u\n", (caps & CAPS_MSI_SUPPORT) ? 1 : 0);
+	pr_info("CAPS: MSI-X support: %u\n", (caps & CAPS_MSIX_SUPPORT) ? 1 : 0);
+	pr_info("CAPS: DMA support: %u\n", (caps & CAPS_DMA_SUPPORT) ? 1 : 0);
+	pr_info("CAPS: DMA is private: %u\n", (caps & CAPS_DMA_IS_PRIVATE) ? 1 : 0);
+	pr_info("CAPS: DOORBELL support: %u\n", (caps & CAPS_DOORBELL_SUPPORT) ? 1 : 0);
+	pr_info("CAPS: DOORBELL BAR: %lu\n", CAPS_DOORBELL_BAR(caps));
+}
+
 static int pci_endpoint_test_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *ent)
 {
@@ -906,6 +938,8 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 		goto err_kfree_test_name;
 	}
 
+	pci_endpoint_get_caps(test);
+
 	misc_device = &test->miscdev;
 	misc_device->minor = MISC_DYNAMIC_MINOR;
 	misc_device->name = kstrdup(name, GFP_KERNEL);
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index a73bc0771d35..2dd90e2e8565 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -44,6 +44,18 @@
 
 #define TIMER_RESOLUTION		1
 
+#define CAPS_MAGIC			0x25ccf687
+#define CAPS_VERSION			0x1
+
+#define CAPS_MSI_SUPPORT		BIT(0)
+#define CAPS_MSIX_SUPPORT		BIT(1)
+#define CAPS_DMA_SUPPORT		BIT(2)
+#define CAPS_DMA_IS_PRIVATE		BIT(3) /* only valid if DMA_SUPPORT */
+#define CAPS_DOORBELL_SUPPORT		BIT(4)
+#define CAPS_DOORBELL_BAR_MASK		GENMASK(7, 5) /* only valid if DOORBELL_SUPPORT */
+#define CAPS_DOORBELL_BAR_SHIFT		5
+#define CAPS_DOORBELL_BAR(x)		(((x) & CAPS_DOORBELL_BAR_MASK) >> CAPS_DOORBELL_BAR_SHIFT)
+
 static struct workqueue_struct *kpcitest_workqueue;
 
 struct pci_epf_test {
@@ -74,6 +86,9 @@ struct pci_epf_test_reg {
 	u32	irq_type;
 	u32	irq_number;
 	u32	flags;
+	u32	caps_magic;
+	u32	caps_version;
+	u32	caps;
 } __packed;
 
 static struct pci_epf_header test_header = {
@@ -741,6 +756,32 @@ static void pci_epf_test_clear_bar(struct pci_epf *epf)
 	}
 }
 
+static void pci_epf_test_init_caps(struct pci_epf *epf)
+{
+	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
+	const struct pci_epc_features *epc_features = epf_test->epc_features;
+	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
+	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+	u32 caps = 0;
+
+	reg->caps_magic = cpu_to_le32(CAPS_MAGIC);
+	reg->caps_version = cpu_to_le32(CAPS_VERSION);
+
+	if (epc_features->msi_capable)
+		caps |= CAPS_MSI_SUPPORT;
+
+	if (epc_features->msix_capable)
+		caps |= CAPS_MSIX_SUPPORT;
+
+	if (epf_test->dma_supported)
+		caps |= CAPS_DMA_SUPPORT;
+
+	if (epf_test->dma_private)
+		caps |= CAPS_DMA_IS_PRIVATE;
+
+	reg->caps = cpu_to_le64(caps);
+}
+
 static int pci_epf_test_epc_init(struct pci_epf *epf)
 {
 	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@@ -765,6 +806,8 @@ static int pci_epf_test_epc_init(struct pci_epf *epf)
 		}
 	}
 
+	pci_epf_test_init_caps(epf);
+
 	ret = pci_epf_test_set_bar(epf);
 	if (ret)
 		return ret;
-- 
2.47.0


  reply	other threads:[~2024-10-18 14:01 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-15 22:07 [PATCH v3 0/6] PCI: EP: Add RC-to-EP doorbell with platform MSI controller Frank Li
2024-10-15 22:07 ` [PATCH v3 1/6] genirq/msi: Add cleanup guard define for msi_lock_descs()/msi_unlock_descs() Frank Li
2024-10-16  1:12   ` Damien Le Moal
2024-10-16 16:21   ` Thomas Gleixner
2024-10-16 16:33     ` Frank Li
2024-10-15 22:07 ` [PATCH v3 2/6] PCI: endpoint: Add pci_epc_get_fn() API for customizable filtering Frank Li
2024-10-15 22:07 ` [PATCH v3 3/6] PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller Frank Li
2024-10-16  1:36   ` Damien Le Moal
2024-10-16 15:03     ` Frank Li
2024-10-16 16:30   ` Thomas Gleixner
2024-10-16 16:54     ` Frank Li
2024-10-16 17:35       ` Thomas Gleixner
2024-10-15 22:07 ` [PATCH v3 4/6] PCI: endpoint: pci-epf-test: Add doorbell test support Frank Li
2024-10-18 14:01   ` Niklas Cassel [this message]
2024-10-18 14:05     ` Niklas Cassel
2024-10-18 15:13     ` Frank Li
2024-10-20 14:41       ` Niklas Cassel
2024-10-21  6:55         ` Niklas Cassel
2024-10-21 16:17           ` Frank Li
2024-10-15 22:07 ` [PATCH v3 5/6] misc: pci_endpoint_test: Add doorbell test case Frank Li
2024-10-15 22:07 ` [PATCH v3 6/6] tools: PCI: Add 'B' option for test doorbell Frank Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZxJqITunljv0PGxn@ryzen.lan \
    --to=cassel@kernel.org \
    --cc=Frank.Li@nxp.com \
    --cc=arnd@arndb.de \
    --cc=bhelgaas@google.com \
    --cc=dlemoal@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=imx@lists.linux.dev \
    --cc=jdmason@kudzu.us \
    --cc=kishon@kernel.org \
    --cc=kw@linux.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=manivannan.sadhasivam@linaro.org \
    --cc=maz@kernel.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox