From: Koichiro Den <den@valinux.co.jp>
To: jingoohan1@gmail.com, mani@kernel.org, lpieralisi@kernel.org,
kwilczynski@kernel.org, robh@kernel.org, bhelgaas@google.com,
cassel@kernel.org, Frank.Li@nxp.com
Cc: vigneshr@ti.com, s-vadapalli@ti.com, hongxing.zhu@nxp.com,
l.stach@pengutronix.de, shawnguo@kernel.org,
s.hauer@pengutronix.de, kernel@pengutronix.de,
festevam@gmail.com, minghuan.Lian@nxp.com, mingkai.hu@nxp.com,
roy.zang@nxp.com, jesper.nilsson@axis.com, heiko@sntech.de,
srikanth.thokala@intel.com, marek.vasut+renesas@gmail.com,
yoshihiro.shimoda.uh@renesas.com, geert+renesas@glider.be,
magnus.damm@gmail.com, christian.bruel@foss.st.com,
mcoquelin.stm32@gmail.com, alexandre.torgue@foss.st.com,
thierry.reding@gmail.com, jonathanh@nvidia.com,
hayashi.kunihiko@socionext.com, mhiramat@kernel.org,
kishon@kernel.org, jirislaby@kernel.org, rongqianfeng@vivo.com,
18255117159@163.com, shawn.lin@rock-chips.com,
nicolas.frattaroli@collabora.com, linux.amoon@gmail.com,
vidyas@nvidia.com, shuah@kernel.org, linux-omap@vger.kernel.org,
linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, imx@lists.linux.dev,
linuxppc-dev@lists.ozlabs.org, linux-arm-kernel@axis.com,
linux-rockchip@lists.infradead.org,
linux-arm-msm@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-tegra@vger.kernel.org, linux-kselftest@vger.kernel.org
Subject: [PATCH v10 7/8] misc: pci_endpoint_test: Add BAR subrange mapping test case
Date: Sat, 24 Jan 2026 23:50:11 +0900 [thread overview]
Message-ID: <20260124145012.2794108-8-den@valinux.co.jp> (raw)
In-Reply-To: <20260124145012.2794108-1-den@valinux.co.jp>
Add a new PCITEST_BAR_SUBRANGE ioctl to exercise EPC BAR subrange
mapping end-to-end.
The test programs a simple 2-subrange layout on the endpoint (via
pci-epf-test) and verifies that:
- the endpoint-provided per-subrange signature bytes are observed at
the expected PCIe BAR offsets, and
- writes to each subrange are routed to the correct backing region
(i.e. the submap order is applied rather than accidentally working
due to an identity mapping).
Return -EOPNOTSUPP when the endpoint does not advertise subrange
mapping, -ENODATA when the BAR is disabled, and -EBUSY when the BAR is
reserved for the test register space.
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
drivers/misc/pci_endpoint_test.c | 203 ++++++++++++++++++++++++++++++-
include/uapi/linux/pcitest.h | 1 +
2 files changed, 203 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 1c0fd185114f..74ab5b5b9011 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -39,6 +39,8 @@
#define COMMAND_COPY BIT(5)
#define COMMAND_ENABLE_DOORBELL BIT(6)
#define COMMAND_DISABLE_DOORBELL BIT(7)
+#define COMMAND_BAR_SUBRANGE_SETUP BIT(8)
+#define COMMAND_BAR_SUBRANGE_CLEAR BIT(9)
#define PCI_ENDPOINT_TEST_STATUS 0x8
#define STATUS_READ_SUCCESS BIT(0)
@@ -55,6 +57,10 @@
#define STATUS_DOORBELL_ENABLE_FAIL BIT(11)
#define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12)
#define STATUS_DOORBELL_DISABLE_FAIL BIT(13)
+#define STATUS_BAR_SUBRANGE_SETUP_SUCCESS BIT(14)
+#define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
+#define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
+#define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
#define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c
#define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10
@@ -77,6 +83,7 @@
#define CAP_MSI BIT(1)
#define CAP_MSIX BIT(2)
#define CAP_INTX BIT(3)
+#define CAP_SUBRANGE_MAPPING BIT(4)
#define PCI_ENDPOINT_TEST_DB_BAR 0x34
#define PCI_ENDPOINT_TEST_DB_OFFSET 0x38
@@ -100,6 +107,8 @@
#define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588
+#define PCI_ENDPOINT_TEST_BAR_SUBRANGE_NSUB 2
+
static DEFINE_IDA(pci_endpoint_test_ida);
#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
@@ -414,6 +423,193 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test)
return 0;
}
+static u8 pci_endpoint_test_subrange_sig_byte(enum pci_barno barno,
+ unsigned int subno)
+{
+ return 0x50 + (barno * 8) + subno;
+}
+
+static u8 pci_endpoint_test_subrange_test_byte(enum pci_barno barno,
+ unsigned int subno)
+{
+ return 0xa0 + (barno * 8) + subno;
+}
+
+static int pci_endpoint_test_bar_subrange_cmd(struct pci_endpoint_test *test,
+ enum pci_barno barno, u32 command,
+ u32 ok_bit, u32 fail_bit)
+{
+ struct pci_dev *pdev = test->pdev;
+ struct device *dev = &pdev->dev;
+ int irq_type = test->irq_type;
+ u32 status;
+
+ if (irq_type < PCITEST_IRQ_TYPE_INTX ||
+ irq_type > PCITEST_IRQ_TYPE_MSIX) {
+ dev_err(dev, "Invalid IRQ type\n");
+ return -EINVAL;
+ }
+
+ reinit_completion(&test->irq_raised);
+
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+ /* Reuse SIZE as a command parameter: bar number. */
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, barno);
+ pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, command);
+
+ if (!wait_for_completion_timeout(&test->irq_raised,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+ if (status & fail_bit)
+ return -EIO;
+
+ if (!(status & ok_bit))
+ return -EIO;
+
+ return 0;
+}
+
+static int pci_endpoint_test_bar_subrange_setup(struct pci_endpoint_test *test,
+ enum pci_barno barno)
+{
+ return pci_endpoint_test_bar_subrange_cmd(test, barno,
+ COMMAND_BAR_SUBRANGE_SETUP,
+ STATUS_BAR_SUBRANGE_SETUP_SUCCESS,
+ STATUS_BAR_SUBRANGE_SETUP_FAIL);
+}
+
+static int pci_endpoint_test_bar_subrange_clear(struct pci_endpoint_test *test,
+ enum pci_barno barno)
+{
+ return pci_endpoint_test_bar_subrange_cmd(test, barno,
+ COMMAND_BAR_SUBRANGE_CLEAR,
+ STATUS_BAR_SUBRANGE_CLEAR_SUCCESS,
+ STATUS_BAR_SUBRANGE_CLEAR_FAIL);
+}
+
+static int pci_endpoint_test_bar_subrange(struct pci_endpoint_test *test,
+ enum pci_barno barno)
+{
+ u32 nsub = PCI_ENDPOINT_TEST_BAR_SUBRANGE_NSUB;
+ struct device *dev = &test->pdev->dev;
+ size_t sub_size, buf_size;
+ resource_size_t bar_size;
+ void __iomem *bar_addr;
+ void *read_buf = NULL;
+ int ret, clear_ret;
+ size_t off, chunk;
+ u32 i, exp, val;
+ u8 pattern;
+
+ if (!(test->ep_caps & CAP_SUBRANGE_MAPPING))
+ return -EOPNOTSUPP;
+
+ /*
+ * The test register BAR is not safe to reprogram and write/read
+ * over its full size. BAR_TEST already special-cases it to a tiny
+ * range. For subrange mapping tests, let's simply skip it.
+ */
+ if (barno == test->test_reg_bar)
+ return -EBUSY;
+
+ bar_size = pci_resource_len(test->pdev, barno);
+ if (!bar_size)
+ return -ENODATA;
+
+ bar_addr = test->bar[barno];
+ if (!bar_addr)
+ return -ENOMEM;
+
+ ret = pci_endpoint_test_bar_subrange_setup(test, barno);
+ if (ret)
+ return ret;
+
+ if (bar_size % nsub || bar_size / nsub > SIZE_MAX) {
+ ret = -EINVAL;
+ goto out_clear;
+ }
+
+ sub_size = bar_size / nsub;
+ if (sub_size < sizeof(u32)) {
+ ret = -ENOSPC;
+ goto out_clear;
+ }
+
+ /* Limit the temporary buffer size */
+ buf_size = min_t(size_t, sub_size, SZ_1M);
+
+ read_buf = kmalloc(buf_size, GFP_KERNEL);
+ if (!read_buf) {
+ ret = -ENOMEM;
+ goto out_clear;
+ }
+
+ /*
+ * Step 1: verify EP-provided signature per subrange. This detects
+ * whether the EP actually applied the submap order.
+ */
+ for (i = 0; i < nsub; i++) {
+ exp = (u32)pci_endpoint_test_subrange_sig_byte(barno, i) *
+ 0x01010101U;
+ val = ioread32(bar_addr + (i * sub_size));
+ if (val != exp) {
+ dev_err(dev,
+ "BAR%d subrange%u signature mismatch @%#zx: exp %#08x got %#08x\n",
+ barno, i, (size_t)i * sub_size, exp, val);
+ ret = -EIO;
+ goto out_clear;
+ }
+ val = ioread32(bar_addr + (i * sub_size) + sub_size - sizeof(u32));
+ if (val != exp) {
+ dev_err(dev,
+ "BAR%d subrange%u signature mismatch @%#zx: exp %#08x got %#08x\n",
+ barno, i,
+ ((size_t)i * sub_size) + sub_size - sizeof(u32),
+ exp, val);
+ ret = -EIO;
+ goto out_clear;
+ }
+ }
+
+ /* Step 2: write unique pattern per subrange (write all first). */
+ for (i = 0; i < nsub; i++) {
+ pattern = pci_endpoint_test_subrange_test_byte(barno, i);
+ memset_io(bar_addr + (i * sub_size), pattern, sub_size);
+ }
+
+ /* Step 3: read back and verify (read all after all writes). */
+ for (i = 0; i < nsub; i++) {
+ pattern = pci_endpoint_test_subrange_test_byte(barno, i);
+ for (off = 0; off < sub_size; off += chunk) {
+ void *bad;
+
+ chunk = min_t(size_t, buf_size, sub_size - off);
+ memcpy_fromio(read_buf, bar_addr + (i * sub_size) + off,
+ chunk);
+ bad = memchr_inv(read_buf, pattern, chunk);
+ if (bad) {
+ size_t bad_off = (u8 *)bad - (u8 *)read_buf;
+
+ dev_err(dev,
+ "BAR%d subrange%u data mismatch @%#zx (pattern %#02x)\n",
+ barno, i, (size_t)i * sub_size + off + bad_off,
+ pattern);
+ ret = -EIO;
+ goto out_clear;
+ }
+ }
+ }
+
+out_clear:
+ kfree(read_buf);
+ clear_ret = pci_endpoint_test_bar_subrange_clear(test, barno);
+ return ret ?: clear_ret;
+}
+
static int pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)
{
u32 val;
@@ -936,12 +1132,17 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case PCITEST_BAR:
+ case PCITEST_BAR_SUBRANGE:
bar = arg;
if (bar <= NO_BAR || bar > BAR_5)
goto ret;
if (is_am654_pci_dev(pdev) && bar == BAR_0)
goto ret;
- ret = pci_endpoint_test_bar(test, bar);
+
+ if (cmd == PCITEST_BAR)
+ ret = pci_endpoint_test_bar(test, bar);
+ else
+ ret = pci_endpoint_test_bar_subrange(test, bar);
break;
case PCITEST_BARS:
ret = pci_endpoint_test_bars(test);
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index d6023a45a9d0..710f8842223f 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -22,6 +22,7 @@
#define PCITEST_GET_IRQTYPE _IO('P', 0x9)
#define PCITEST_BARS _IO('P', 0xa)
#define PCITEST_DOORBELL _IO('P', 0xb)
+#define PCITEST_BAR_SUBRANGE _IO('P', 0xc)
#define PCITEST_CLEAR_IRQ _IO('P', 0x10)
#define PCITEST_IRQ_TYPE_UNDEFINED -1
--
2.51.0
next prev parent reply other threads:[~2026-01-24 14:51 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-24 14:50 [PATCH v10 0/8] PCI: endpoint: BAR subrange mapping support Koichiro Den
2026-01-24 14:50 ` [PATCH v10 1/8] PCI: endpoint: Add dynamic_inbound_mapping EPC feature Koichiro Den
2026-01-24 14:50 ` [PATCH v10 2/8] PCI: endpoint: Add BAR subrange mapping support Koichiro Den
2026-01-24 14:50 ` [PATCH v10 3/8] PCI: dwc: Advertise dynamic inbound " Koichiro Den
2026-03-13 15:59 ` Christian Bruel
2026-03-13 18:18 ` Bjorn Helgaas
2026-03-16 12:26 ` Christian Bruel
2026-03-14 4:33 ` Koichiro Den
2026-03-16 12:41 ` Christian Bruel
2026-03-16 12:57 ` Niklas Cassel
2026-03-16 13:29 ` Christian Bruel
2026-03-16 13:50 ` Koichiro Den
2026-01-24 14:50 ` [PATCH v10 4/8] PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU Koichiro Den
2026-01-26 10:25 ` Niklas Cassel
2026-01-24 14:50 ` [PATCH v10 5/8] Documentation: PCI: endpoint: Clarify pci_epc_set_bar() usage Koichiro Den
2026-01-24 14:50 ` [PATCH v10 6/8] PCI: endpoint: pci-epf-test: Add BAR subrange mapping test support Koichiro Den
2026-01-24 14:50 ` Koichiro Den [this message]
2026-01-24 14:50 ` [PATCH v10 8/8] selftests: pci_endpoint: Add BAR subrange mapping test case Koichiro Den
2026-01-28 13:47 ` [PATCH v10 0/8] PCI: endpoint: BAR subrange mapping support Manivannan Sadhasivam
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=20260124145012.2794108-8-den@valinux.co.jp \
--to=den@valinux.co.jp \
--cc=18255117159@163.com \
--cc=Frank.Li@nxp.com \
--cc=alexandre.torgue@foss.st.com \
--cc=bhelgaas@google.com \
--cc=cassel@kernel.org \
--cc=christian.bruel@foss.st.com \
--cc=festevam@gmail.com \
--cc=geert+renesas@glider.be \
--cc=hayashi.kunihiko@socionext.com \
--cc=heiko@sntech.de \
--cc=hongxing.zhu@nxp.com \
--cc=imx@lists.linux.dev \
--cc=jesper.nilsson@axis.com \
--cc=jingoohan1@gmail.com \
--cc=jirislaby@kernel.org \
--cc=jonathanh@nvidia.com \
--cc=kernel@pengutronix.de \
--cc=kishon@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=l.stach@pengutronix.de \
--cc=linux-arm-kernel@axis.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=linux-stm32@st-md-mailman.stormreply.com \
--cc=linux-tegra@vger.kernel.org \
--cc=linux.amoon@gmail.com \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lpieralisi@kernel.org \
--cc=magnus.damm@gmail.com \
--cc=mani@kernel.org \
--cc=marek.vasut+renesas@gmail.com \
--cc=mcoquelin.stm32@gmail.com \
--cc=mhiramat@kernel.org \
--cc=minghuan.Lian@nxp.com \
--cc=mingkai.hu@nxp.com \
--cc=nicolas.frattaroli@collabora.com \
--cc=robh@kernel.org \
--cc=rongqianfeng@vivo.com \
--cc=roy.zang@nxp.com \
--cc=s-vadapalli@ti.com \
--cc=s.hauer@pengutronix.de \
--cc=shawn.lin@rock-chips.com \
--cc=shawnguo@kernel.org \
--cc=shuah@kernel.org \
--cc=srikanth.thokala@intel.com \
--cc=thierry.reding@gmail.com \
--cc=vidyas@nvidia.com \
--cc=vigneshr@ti.com \
--cc=yoshihiro.shimoda.uh@renesas.com \
/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