2022-08-26 14:29:23

by Wei Yongjun

[permalink] [raw]
Subject: [PATCH -next 0/4] spi: Introduce BPF based SPI mockup controller

This series Introduce a BPF based SPI mockup controller, which can be
used for testing SPI drivers without real device.

The testsuite for SPI drivers will be post in other series, with also
support for I2C and PCI bus device drivers.

patch 1-2 introduce BPF based SPI mockup controller
patch 3 interface for dynamically add devices from dts, may use
of-configfs insead
patch 4 add the document

Wei Yongjun (4):
spi: mockup: Add SPI controller testing driver
spi: mockup: Add writeable tracepoint for spi transfer
spi: mockup: Add runtime device tree overlay interface
spi: mockup: Add documentation

Documentation/spi/index.rst | 1 +
Documentation/spi/spi-mockup.rst | 201 +++++++++++++++++++
drivers/spi/Kconfig | 15 ++
drivers/spi/Makefile | 1 +
drivers/spi/spi-mockup.c | 315 ++++++++++++++++++++++++++++++
include/linux/spi/spi-mockup.h | 13 ++
include/trace/events/spi_mockup.h | 32 +++
7 files changed, 578 insertions(+)
create mode 100644 Documentation/spi/spi-mockup.rst
create mode 100644 drivers/spi/spi-mockup.c
create mode 100644 include/linux/spi/spi-mockup.h
create mode 100644 include/trace/events/spi_mockup.h

--
2.34.1



2022-08-26 14:29:30

by Wei Yongjun

[permalink] [raw]
Subject: [PATCH -next 2/4] spi: mockup: Add writeable tracepoint for spi transfer

Add writeable tracepoint for transfer_one_message(), then bpf program can
be used to control read and write data from spi master, as mockup chip's
expectation.

For example:

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

SEC("raw_tp.w/spi_transfer_writeable")
int BPF_PROG(spi_transfer_writeable_test, struct spi_msg_ctx *msg,
u8 chip, unsigned int len, u8 tx_nbits, u8 rx_nbits)
{
if (tx_nbits)
msg->data[0] = 0x20;

return 0;
}

char LICENSE[] SEC("license") = "GPL";

This will be useful for writing spi device mockup backend.

Signed-off-by: Wei Yongjun <[email protected]>
---
drivers/spi/Kconfig | 1 +
drivers/spi/spi-mockup.c | 50 +++++++++++++++++++++++++++++--
include/linux/spi/spi-mockup.h | 13 ++++++++
include/trace/events/spi_mockup.h | 32 ++++++++++++++++++++
4 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b58a1bd7999d..e0f0fa2746ad 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1161,6 +1161,7 @@ config SPI_TLE62X0
config SPI_MOCKUP
tristate "SPI controller Testing Driver"
depends on OF
+ select BPF_EVENTS
help
This enables SPI controller testing driver, which provides a way to
test SPI subsystem.
diff --git a/drivers/spi/spi-mockup.c b/drivers/spi/spi-mockup.c
index 06cf9d122d64..7a93b194ee53 100644
--- a/drivers/spi/spi-mockup.c
+++ b/drivers/spi/spi-mockup.c
@@ -13,6 +13,9 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>

+#define CREATE_TRACE_POINTS
+#include <trace/events/spi_mockup.h>
+
#define MOCKUP_CHIPSELECT_MAX 8

struct mockup_spi {
@@ -149,13 +152,56 @@ static struct attribute *spi_mockup_attrs[] = {
};
ATTRIBUTE_GROUPS(spi_mockup);

+static int spi_mockup_transfer_writeable(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_msg_ctx *ctx;
+ struct spi_transfer *t;
+ int ret = 0;
+
+ ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+ if (!ctx)
+ return -ENOMEM;
+
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ if (t->len > SPI_BUFSIZ_MAX)
+ return -E2BIG;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (t->tx_nbits)
+ memcpy(ctx->data, t->tx_buf, t->len);
+
+ trace_spi_transfer_writeable(ctx, msg->spi->chip_select, t->len,
+ t->tx_nbits, t->rx_nbits);
+
+ if (ctx->ret) {
+ ret = ctx->ret;
+ break;
+ }
+
+ if (t->rx_nbits)
+ memcpy(t->rx_buf, ctx->data, t->len);
+ msg->actual_length += t->len;
+ }
+
+ kfree(ctx);
+
+ return ret;
+}
+
static int spi_mockup_transfer(struct spi_master *master,
struct spi_message *msg)
{
- msg->status = 0;
+ int ret = 0;
+
+ if (trace_spi_transfer_writeable_enabled())
+ ret = spi_mockup_transfer_writeable(master, msg);
+
+ msg->status = ret;
spi_finalize_current_message(master);

- return 0;
+ return ret;
}

static int spi_mockup_probe(struct platform_device *pdev)
diff --git a/include/linux/spi/spi-mockup.h b/include/linux/spi/spi-mockup.h
new file mode 100644
index 000000000000..6a4fe88cb376
--- /dev/null
+++ b/include/linux/spi/spi-mockup.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_SPI_MOCKUP_H
+#define __LINUX_SPI_MOCKUP_H
+
+#define SPI_BUFSIZ_MAX 0x1000
+
+struct spi_msg_ctx {
+ int ret;
+ __u8 data[SPI_BUFSIZ_MAX];
+};
+
+#endif
diff --git a/include/trace/events/spi_mockup.h b/include/trace/events/spi_mockup.h
new file mode 100644
index 000000000000..193302f8627a
--- /dev/null
+++ b/include/trace/events/spi_mockup.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * SPI mockup controller transfer writeable tracepoint
+ *
+ * Copyright(c) 2022 Huawei Technologies Co., Ltd.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM spi_mockup
+
+#if !defined(_TRACE_SPI_MOCKUP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SPI_MOCKUP_H
+
+#include <linux/tracepoint.h>
+#include <linux/spi/spi-mockup.h>
+
+#ifndef DECLARE_TRACE_WRITABLE
+#define DECLARE_TRACE_WRITABLE(call, proto, args, size) \
+ DECLARE_TRACE(call, PARAMS(proto), PARAMS(args))
+#endif
+
+DECLARE_TRACE_WRITABLE(spi_transfer_writeable,
+ TP_PROTO(struct spi_msg_ctx *msg, u8 chip_select, unsigned int len,
+ u8 tx_nbits, u8 rx_nbits),
+ TP_ARGS(msg, chip_select, len, tx_nbits, rx_nbits),
+ sizeof(struct spi_msg_ctx)
+);
+
+#endif /* _TRACE_SPI_MOCKUP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.34.1

2022-08-26 14:29:35

by Wei Yongjun

[permalink] [raw]
Subject: [PATCH -next 1/4] spi: mockup: Add SPI controller testing driver

This enables SPI controller Testing driver, which provides a way
to test SPI drivers.

This is accomplished by executing the following command:

$ echo adcxx1s 0 > /sys/class/spi_master/spi0/new_device

The name of the target driver and its chip select were used to
instantiate the device.

$ ls /sys/bus/spi/devices/spi0.0/hwmon/hwmon0/ -l
total 0
lrwxrwxrwx 1 root root 0 Aug 10 08:58 device -> ../../../spi0.0
drwxr-xr-x 2 root root 0 Aug 10 08:58 power
lrwxrwxrwx 1 root root 0 Aug 10 08:58 subsystem -> ../../../../../../../../class/hwmon
-rw-r--r-- 1 root root 4096 Aug 10 08:58 uevent

Remove target device by executing the following command:
$ echo 0 > /sys/class/spi_master/spi0/delete_device

Signed-off-by: Wei Yongjun <[email protected]>
---
drivers/spi/Kconfig | 12 +++
drivers/spi/Makefile | 1 +
drivers/spi/spi-mockup.c | 221 +++++++++++++++++++++++++++++++++++++++
3 files changed, 234 insertions(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index d1bb62f7368b..b58a1bd7999d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1158,6 +1158,18 @@ config SPI_TLE62X0
sysfs interface, with each line presented as a kind of GPIO
exposing both switch control and diagnostic feedback.

+config SPI_MOCKUP
+ tristate "SPI controller Testing Driver"
+ depends on OF
+ help
+ This enables SPI controller testing driver, which provides a way to
+ test SPI subsystem.
+
+ If you do build this module, be sure to read the notes and warnings
+ in <file:Documentation/spi/spi-mockup.rst>.
+
+ If you don't know what to do here, definitely say N.
+
#
# Add new SPI protocol masters in alphabetical order above this line
#
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4b34e855c841..be87f49098b6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SPI_MEM) += spi-mem.o
obj-$(CONFIG_SPI_MUX) += spi-mux.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
+obj-$(CONFIG_SPI_MOCKUP) += spi-mockup.o

# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o
diff --git a/drivers/spi/spi-mockup.c b/drivers/spi/spi-mockup.c
new file mode 100644
index 000000000000..06cf9d122d64
--- /dev/null
+++ b/drivers/spi/spi-mockup.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SPI controller Testing Driver
+ *
+ * Copyright(c) 2022 Huawei Technologies Co., Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#define MOCKUP_CHIPSELECT_MAX 8
+
+struct mockup_spi {
+ struct mutex lock;
+ struct spi_device *devs[MOCKUP_CHIPSELECT_MAX];
+};
+
+static struct spi_master *to_spi_master(struct device *dev)
+{
+ return container_of(dev, struct spi_master, dev);
+}
+
+static ssize_t
+new_device_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_master *master = to_spi_master(dev);
+ struct spi_board_info info;
+ struct spi_device *slave;
+ struct mockup_spi *mock;
+ char *blank, end;
+ int status;
+
+ memset(&info, 0, sizeof(struct spi_board_info));
+
+ blank = strchr(buf, ' ');
+ if (!blank) {
+ dev_err(dev, "%s: Extra parameters\n", "new_device");
+ return -EINVAL;
+ }
+
+ if (blank - buf > SPI_NAME_SIZE - 1) {
+ dev_err(dev, "%s: Invalid device name\n", "new_device");
+ return -EINVAL;
+ }
+
+ memcpy(info.modalias, buf, blank - buf);
+
+ status = sscanf(++blank, "%hi%c", &info.chip_select, &end);
+ if (status < 1) {
+ dev_err(dev, "%s: Can't parse SPI chipselect\n", "new_device");
+ return -EINVAL;
+ }
+
+ if (status > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "new_device");
+ return -EINVAL;
+ }
+
+ if (info.chip_select >= master->num_chipselect) {
+ dev_err(dev, "%s: Invalid chip_select\n", "new_device");
+ return -EINVAL;
+ }
+
+ mock = spi_master_get_devdata(master);
+ mutex_lock(&mock->lock);
+
+ if (mock->devs[info.chip_select]) {
+ dev_err(dev, "%s: Chipselect %d already in use\n",
+ "new_device", info.chip_select);
+ mutex_unlock(&mock->lock);
+ return -EINVAL;
+ }
+
+ slave = spi_new_device(master, &info);
+ if (!slave) {
+ mutex_unlock(&mock->lock);
+ return -ENOMEM;
+ }
+ mock->devs[info.chip_select] = slave;
+
+ mutex_unlock(&mock->lock);
+
+ dev_info(dev, "%s: Instantiated device %s at 0x%02x\n", "new_device",
+ info.modalias, info.chip_select);
+
+ return count;
+}
+static DEVICE_ATTR_WO(new_device);
+
+static ssize_t
+delete_device_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_master *master = to_spi_master(dev);
+ struct spi_device *slave;
+ struct mockup_spi *mock;
+ unsigned short chip;
+ char end;
+ int res;
+
+ /* Parse parameters, reject extra parameters */
+ res = sscanf(buf, "%hi%c", &chip, &end);
+ if (res < 1) {
+ dev_err(dev, "%s: Can't parse SPI address\n", "delete_device");
+ return -EINVAL;
+ }
+ if (res > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "delete_device");
+ return -EINVAL;
+ }
+
+ if (chip >= master->num_chipselect) {
+ dev_err(dev, "%s: Invalid chip_select\n", "delete_device");
+ return -EINVAL;
+ }
+
+ mock = spi_master_get_devdata(master);
+ mutex_lock(&mock->lock);
+
+ slave = mock->devs[chip];
+ if (!slave) {
+ mutex_unlock(&mock->lock);
+ dev_err(dev, "%s: Invalid chip_select\n", "delete_device");
+ return -ENOENT;
+ }
+
+ dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", "delete_device",
+ dev_name(&slave->dev), chip);
+
+ spi_unregister_device(slave);
+ mock->devs[chip] = NULL;
+
+ mutex_unlock(&mock->lock);
+
+ return count;
+}
+static DEVICE_ATTR_WO(delete_device);
+
+static struct attribute *spi_mockup_attrs[] = {
+ &dev_attr_new_device.attr,
+ &dev_attr_delete_device.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(spi_mockup);
+
+static int spi_mockup_transfer(struct spi_master *master,
+ struct spi_message *msg)
+{
+ msg->status = 0;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int spi_mockup_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct mockup_spi *mock;
+ int ret;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct mockup_spi));
+ if (!master) {
+ pr_err("failed to alloc spi master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+
+ master->dev.of_node = pdev->dev.of_node;
+ master->dev.groups = spi_mockup_groups;
+ master->num_chipselect = MOCKUP_CHIPSELECT_MAX;
+ master->mode_bits = SPI_MODE_USER_MASK;
+ master->bus_num = 0;
+ master->transfer_one_message = spi_mockup_transfer;
+
+ mock = spi_master_get_devdata(master);
+ mutex_init(&mock->lock);
+
+ ret = spi_register_master(master);
+ if (ret) {
+ spi_master_put(master);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_mockup_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+static const struct of_device_id spi_mockup_match[] = {
+ { .compatible = "spi-mockup", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spi_mockup_match);
+
+static struct platform_driver spi_mockup_driver = {
+ .probe = spi_mockup_probe,
+ .remove = spi_mockup_remove,
+ .driver = {
+ .name = "spi-mockup",
+ .of_match_table = spi_mockup_match,
+ },
+};
+module_platform_driver(spi_mockup_driver);
+
+MODULE_AUTHOR("Wei Yongjun <[email protected]>");
+MODULE_DESCRIPTION("SPI controller Testing Driver");
+MODULE_LICENSE("GPL");
--
2.34.1

2022-08-26 14:30:05

by Wei Yongjun

[permalink] [raw]
Subject: [PATCH -next 4/4] spi: mockup: Add documentation

Add documentation for the SPI mockup controller driver.
This include the tutorial for how to mockup a api device.

Signed-off-by: Wei Yongjun <[email protected]>
---
Documentation/spi/index.rst | 1 +
Documentation/spi/spi-mockup.rst | 201 +++++++++++++++++++++++++++++++
2 files changed, 202 insertions(+)

diff --git a/Documentation/spi/index.rst b/Documentation/spi/index.rst
index 06c34ea11bcf..a8f4f5cd0f09 100644
--- a/Documentation/spi/index.rst
+++ b/Documentation/spi/index.rst
@@ -13,6 +13,7 @@ Serial Peripheral Interface (SPI)
pxa2xx
spi-lm70llp
spi-sc18is602
+ spi-mockup

.. only:: subproject and html

diff --git a/Documentation/spi/spi-mockup.rst b/Documentation/spi/spi-mockup.rst
new file mode 100644
index 000000000000..b38f44dca785
--- /dev/null
+++ b/Documentation/spi/spi-mockup.rst
@@ -0,0 +1,201 @@
+==========
+spi-mockup
+==========
+
+Description
+===========
+
+This module is a very simple fake SPI controller driver. It implements
+a BPF based interface to mockup SPI device.
+
+No hardware is needed nor associated with this module. It will respond
+spi message by BPF program attached to spi_transfer_writeable tracepoint
+by reading from or writing BPF maps.
+
+The typical use-case is like this:
+ 1. load this module
+ 2. use bpftool to load BPF program
+ 3. load the target chip driver module
+
+Example
+=======
+
+This example show how to mock a MTD device by using spi-mockup driver.
+
+Compile your copy of the kernel source. Make sure to configure the spi-mockup
+and the target chip driver as a module. Prepare a dts described the spi-mockup
+device.
+
+::
+
+ /dts-v1/;
+
+ / {
+ spi: spi {
+ compatible = "spi-mockup";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ }
+
+Write a BPF program as device's backup.
+
+::
+
+ #define MCHP23K256_CMD_WRITE_STATUS 0x01
+ #define MCHP23K256_CMD_WRITE 0x02
+ #define MCHP23K256_CMD_READ 0x03
+
+ #define CHIP_REGS_SIZE 0x20000
+
+ #define MAX_CMD_SIZE 4
+
+ struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u8);
+ } regs_mtd_mchp23k256 SEC(".maps");
+
+ static unsigned int chip_reg = 0;
+
+ static int spi_transfer_read(struct spi_msg_ctx *msg, unsigned int len)
+ {
+ int i, key;
+ u8 *reg;
+
+ for (i = 0; i < len && i < sizeof(msg->data); i++) {
+ key = i + chip_reg;
+
+ reg = bpf_map_lookup_elem(&regs_mtd_mchp23k256, &key);
+ if (!reg) {
+ bpf_printk("key %d not exists", key);
+ return -EINVAL;
+ }
+
+ msg->data[i] = *reg;
+ }
+
+ return 0;
+ }
+
+ static int spi_transfer_write(struct spi_msg_ctx *msg, unsigned int len)
+ {
+ u8 opcode = msg->data[0], value;
+ int i, key;
+
+ switch (opcode) {
+ case MCHP23K256_CMD_READ:
+ case MCHP23K256_CMD_WRITE:
+ if (len < 2)
+ return -EINVAL;
+
+ chip_reg = 0;
+ for (i = 0; i < MAX_CMD_SIZE && i < len - 1; i++)
+ chip_reg = (chip_reg << 8) + msg->data[1 + i];
+
+ return 0;
+ case MCHP23K256_CMD_WRITE_STATUS:
+ // ignore write status
+ return 0;
+ default:
+ break;
+ }
+
+ for (i = 0; i < len && i < sizeof(msg->data); i++) {
+ value = msg->data[i];
+ key = chip_reg + i;
+
+ if (bpf_map_update_elem(&regs_mtd_mchp23k256, &key, &value,
+ BPF_EXIST)) {
+ bpf_printk("key %d not exists", key);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+ }
+
+ SEC("raw_tp.w/spi_transfer_writeable")
+ int BPF_PROG(mtd_mchp23k256, struct spi_msg_ctx *msg, u8 chip,
+ unsigned int len, u8 tx_nbits, u8 rx_nbits)
+ {
+ int ret = 0;
+
+ if (tx_nbits)
+ ret = spi_transfer_write(msg, len);
+ else if (rx_nbits)
+ ret = spi_transfer_read(msg, len);
+
+ return ret;
+ }
+
+ char LICENSE[] SEC("license") = "GPL";
+
+
+Then boot a qemu instance by the following command:
+
+::
+
+ sudo qemu-system-x86_64 -m 4096 -smp 4 -display none -serial stdio -no-reboot \
+ -enable-kvm -cpu host,migratable=off -dtb mocktest.dtb -snapshot -hda linux.img \
+ -kernel arch/x86/boot/bzImage \
+ -append "earlyprintk=serial root=/dev/sda console=ttyS0"
+
+
+Use bpftool to load the BPF program.
+
+::
+
+ bpftool prog load mtd-mchp23k256.o /sys/fs/bpf/test_prog
+ bpftool perf attach name mtd_mchp23k256 spi_transfer_writeable /sys/fs/bpf/test_perf
+
+
+Load the target chip driver module. This is accomplished by executing the
+following command:
+
+::
+
+ $ echo mchp23k256 0 > /sys/class/spi_master/spi0/new_device
+
+
+The name of the target driver and its chip select were used to instantiate
+the device.
+
+Now, the mchp23k256 MTD device named /dev/mtd0 has been created successfully.
+
+::
+
+ $ ls /sys/bus/spi/devices/spi0.0/mtd/
+ mtd0 mtd0ro
+
+ $ cat /sys/class/mtd/mtd0/name
+ spi0.0
+
+ $ hexdump /dev/mtd0
+ 0000000 0000 0000 0000 0000 0000 0000 0000 0000
+ *
+ 0008000
+
+ $echo aaaa > /dev/mtd0
+
+ $ hexdump /dev/mtd0
+ 0000000 6161 6161 000a 0000 0000 0000 0000 0000
+ 0000010 0000 0000 0000 0000 0000 0000 0000 0000
+ *
+ 0008000
+
+ $ bpftool map update name mtd_mchp23k256_ key 0 0 0 0 value 0
+
+ $ hexdump /dev/mtd0
+ 0000000 6100 6161 000a 0000 0000 0000 0000 0000
+ 0000010 0000 0000 0000 0000 0000 0000 0000 0000
+ *
+ 0008000
+
+Remove the mockup device by executing the following command:
+
+::
+
+ $echo 0 > /sys/class/spi_master/spi0/delete_device
--
2.34.1

2022-08-26 14:48:14

by Wei Yongjun

[permalink] [raw]
Subject: [PATCH -next 3/4] spi: mockup: Add runtime device tree overlay interface

Add a runtime device tree overlay interface for device need dts file.
With it its possible to use device tree overlays without having to use
a per-platform overlay manager.

Add a new device by command:
$ cat test.dtbo > /sys/class/spi_master/spi0/overlay_fdto

Remove the device by command:
$ echo remove > /sys/class/spi_master/spi0/overlay_fdto

Signed-off-by: Wei Yongjun <[email protected]>
---
drivers/spi/Kconfig | 2 ++
drivers/spi/spi-mockup.c | 48 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e0f0fa2746ad..4b7c84ddb367 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1161,6 +1161,8 @@ config SPI_TLE62X0
config SPI_MOCKUP
tristate "SPI controller Testing Driver"
depends on OF
+ select OF_EARLY_FLATTREE
+ select OF_RESOLVE
select BPF_EVENTS
help
This enables SPI controller testing driver, which provides a way to
diff --git a/drivers/spi/spi-mockup.c b/drivers/spi/spi-mockup.c
index 7a93b194ee53..404ad821bf6a 100644
--- a/drivers/spi/spi-mockup.c
+++ b/drivers/spi/spi-mockup.c
@@ -21,6 +21,9 @@
struct mockup_spi {
struct mutex lock;
struct spi_device *devs[MOCKUP_CHIPSELECT_MAX];
+
+ void *fdto;
+ int ovcs_id;
};

static struct spi_master *to_spi_master(struct device *dev)
@@ -145,9 +148,53 @@ delete_device_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_WO(delete_device);

+static ssize_t
+overlay_fdto_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_master *master = to_spi_master(dev);
+ struct mockup_spi *mock = spi_master_get_devdata(master);
+ int ret;
+
+ mutex_lock(&mock->lock);
+
+ if (strncmp(buf, "remove\n", count) == 0) {
+ if (mock->ovcs_id < 0) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+ of_overlay_remove(&mock->ovcs_id);
+ kfree(mock->fdto);
+ mock->ovcs_id = -1;
+ mock->fdto = NULL;
+ } else {
+ if (mock->ovcs_id >= 0) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ mock->fdto = kmemdup(buf, count, GFP_KERNEL);
+ if (!mock->fdto) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+ ret = of_overlay_fdt_apply(mock->fdto, count, &mock->ovcs_id);
+ if (ret < 0)
+ goto out_unlock;
+ }
+
+ mutex_unlock(&mock->lock);
+ return count;
+
+out_unlock:
+ mutex_unlock(&mock->lock);
+ return ret;
+}
+static DEVICE_ATTR_WO(overlay_fdto);
+
static struct attribute *spi_mockup_attrs[] = {
&dev_attr_new_device.attr,
&dev_attr_delete_device.attr,
+ &dev_attr_overlay_fdto.attr,
NULL
};
ATTRIBUTE_GROUPS(spi_mockup);
@@ -227,6 +274,7 @@ static int spi_mockup_probe(struct platform_device *pdev)

mock = spi_master_get_devdata(master);
mutex_init(&mock->lock);
+ mock->ovcs_id = -1;

ret = spi_register_master(master);
if (ret) {
--
2.34.1

2022-08-29 21:47:19

by Frank Rowand

[permalink] [raw]
Subject: Re: [PATCH -next 3/4] spi: mockup: Add runtime device tree overlay interface

comment inline below, plus adding to cc: and to: list

On 8/26/22 09:43, Wei Yongjun wrote:
> Add a runtime device tree overlay interface for device need dts file.
> With it its possible to use device tree overlays without having to use
> a per-platform overlay manager.

Why is an overlay needed? The documentation in patch 4 shows providing
a dtb as an argument to the qemu-system-x86_64 command, which should be
sufficient to supply the appropriate dtb.

-Frank

>
> Add a new device by command:
> $ cat test.dtbo > /sys/class/spi_master/spi0/overlay_fdto
>
> Remove the device by command:
> $ echo remove > /sys/class/spi_master/spi0/overlay_fdto
>
> Signed-off-by: Wei Yongjun <[email protected]>
> ---
> drivers/spi/Kconfig | 2 ++
> drivers/spi/spi-mockup.c | 48 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 50 insertions(+)
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index e0f0fa2746ad..4b7c84ddb367 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -1161,6 +1161,8 @@ config SPI_TLE62X0
> config SPI_MOCKUP
> tristate "SPI controller Testing Driver"
> depends on OF
> + select OF_EARLY_FLATTREE
> + select OF_RESOLVE
> select BPF_EVENTS
> help
> This enables SPI controller testing driver, which provides a way to
> diff --git a/drivers/spi/spi-mockup.c b/drivers/spi/spi-mockup.c
> index 7a93b194ee53..404ad821bf6a 100644
> --- a/drivers/spi/spi-mockup.c
> +++ b/drivers/spi/spi-mockup.c
> @@ -21,6 +21,9 @@
> struct mockup_spi {
> struct mutex lock;
> struct spi_device *devs[MOCKUP_CHIPSELECT_MAX];
> +
> + void *fdto;
> + int ovcs_id;
> };
>
> static struct spi_master *to_spi_master(struct device *dev)
> @@ -145,9 +148,53 @@ delete_device_store(struct device *dev, struct device_attribute *attr,
> }
> static DEVICE_ATTR_WO(delete_device);
>
> +static ssize_t
> +overlay_fdto_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct spi_master *master = to_spi_master(dev);
> + struct mockup_spi *mock = spi_master_get_devdata(master);
> + int ret;
> +
> + mutex_lock(&mock->lock);
> +
> + if (strncmp(buf, "remove\n", count) == 0) {
> + if (mock->ovcs_id < 0) {
> + ret = -ENOENT;
> + goto out_unlock;
> + }
> + of_overlay_remove(&mock->ovcs_id);
> + kfree(mock->fdto);
> + mock->ovcs_id = -1;
> + mock->fdto = NULL;
> + } else {
> + if (mock->ovcs_id >= 0) {
> + ret = -EINVAL;
> + goto out_unlock;
> + }
> + mock->fdto = kmemdup(buf, count, GFP_KERNEL);
> + if (!mock->fdto) {
> + ret = -ENOMEM;
> + goto out_unlock;
> + }
> + ret = of_overlay_fdt_apply(mock->fdto, count, &mock->ovcs_id);
> + if (ret < 0)
> + goto out_unlock;
> + }
> +
> + mutex_unlock(&mock->lock);
> + return count;
> +
> +out_unlock:
> + mutex_unlock(&mock->lock);
> + return ret;
> +}
> +static DEVICE_ATTR_WO(overlay_fdto);
> +
> static struct attribute *spi_mockup_attrs[] = {
> &dev_attr_new_device.attr,
> &dev_attr_delete_device.attr,
> + &dev_attr_overlay_fdto.attr,
> NULL
> };
> ATTRIBUTE_GROUPS(spi_mockup);
> @@ -227,6 +274,7 @@ static int spi_mockup_probe(struct platform_device *pdev)
>
> mock = spi_master_get_devdata(master);
> mutex_init(&mock->lock);
> + mock->ovcs_id = -1;
>
> ret = spi_register_master(master);
> if (ret) {

2022-08-30 10:41:30

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 3/4] spi: mockup: Add runtime device tree overlay interface

On Fri, Aug 26, 2022 at 02:43:40PM +0000, Wei Yongjun wrote:

> Add a runtime device tree overlay interface for device need dts file.
> With it its possible to use device tree overlays without having to use
> a per-platform overlay manager.

Why would an entirely virtual device like this need to appear in
DT? DT is supposed to be a hardware description and this clearly
isn't hardware, nor is it something we're providing to a VM.


Attachments:
(No filename) (443.00 B)
signature.asc (499.00 B)
Download all attachments

2022-08-30 18:30:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 2/4] spi: mockup: Add writeable tracepoint for spi transfer

On Fri, Aug 26, 2022 at 02:43:39PM +0000, Wei Yongjun wrote:

> +#define SPI_BUFSIZ_MAX 0x1000
> +
> +struct spi_msg_ctx {
> + int ret;
> + __u8 data[SPI_BUFSIZ_MAX];
> +};

This has a hard limit on the size of messages of only 4k on the
size of messages, that seems a bit on the low side especially
considering that the example is for a flash device. There's also
things like firmware downloads which can easily exceed 4k. The
driver should at the very least report this limit via the SPI
API, and probably also complain loudly if the limit is exceeded
since it's unlikely that most drivers will actually be checking
for such a low limit given how rare they are.


Attachments:
(No filename) (685.00 B)
signature.asc (499.00 B)
Download all attachments

2022-08-30 18:35:57

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 4/4] spi: mockup: Add documentation

On Fri, Aug 26, 2022 at 02:43:41PM +0000, Wei Yongjun wrote:

> +The typical use-case is like this:
> + 1. load this module
> + 2. use bpftool to load BPF program
> + 3. load the target chip driver module

This needs to go into a bit more detail on how one is expected to
obtain a copy of bpftool I think (or point to some good
documentation, I can't seem to find any in tree right now),
things may have changed since the last time I looked into this
but in the past the userspace tooling for BPF had some extremely
ambitious build dependencies which would be a fairly substantial
barrier to entry.

> +Compile your copy of the kernel source. Make sure to configure the spi-mockup
> +and the target chip driver as a module. Prepare a dts described the spi-mockup
> +device.

As I said in another mail the DT part of this appears to be
inappropriate, the driver should just allow the creation of
virtual devices.


Attachments:
(No filename) (955.00 B)
signature.asc (499.00 B)
Download all attachments

2022-08-30 19:23:04

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 0/4] spi: Introduce BPF based SPI mockup controller

On Fri, Aug 26, 2022 at 02:43:37PM +0000, Wei Yongjun wrote:
> This series Introduce a BPF based SPI mockup controller, which can be
> used for testing SPI drivers without real device.
>
> The testsuite for SPI drivers will be post in other series, with also
> support for I2C and PCI bus device drivers.

I replied to some of the individual patches here with some more
detailed issues but I do have some big picture reservations with
this approach as well. One big one is that this seems like it's
only going to be able to handle emulation of devices that are
purely synchronous - I don't see any sensible direction here for
extending to devices that need an interrupt line as well. That
seems like a major limitation. It's fine not to immediately
implement everything but it should be fairly clear how that would
be done when someone needs it and some of the BPF design goals I
understood seem to conflict with that.

I'm also not clear what the BPF environment is like when it comes
to extensible frameworks, as soon as you start thinking about the
problem space there are some obvious extensions with things like
more detailed register map descriptions and validating that the
operations that the driver is doing to the device are actually in
spec for the device or trying to stimulate race conditions or
error paths in the driver.

There's also the issue with getting the BPF userspace tooling
that I mentioned in reply to one of the individual patches.

Basically while this does look very simple from a kernel point of
view I worry that BPF might not be the right tool for the job and
could be a bit of a blind alley, with people rapidly running into
issues trying to do anything non-trivial.

There was a series in the past year or so from someone
implementing a similarish idea but rather than using BPF they
provided a framework for writing device emulations in qemu with
a simplified Python framework. That seemed like a more obvious
direction here. They were initially focusing on I2C but it's a
similar space. Unfortunately I'm drawing a blank on who was
working on it or the name of the framework so I can't give a
useful reference here. Their direction was towards having
something that could also be used to validate what the driver was
doing to the device from the device's perspective. I do know it
was written up on LWN. Hopefully someone else will remember what
I'm talking about from this vauge description.


Attachments:
(No filename) (2.43 kB)
signature.asc (499.00 B)
Download all attachments

2022-08-30 19:33:23

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 1/4] spi: mockup: Add SPI controller testing driver

On Fri, Aug 26, 2022 at 02:43:38PM +0000, Wei Yongjun wrote:

> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * SPI controller Testing Driver
> + *
> + * Copyright(c) 2022 Huawei Technologies Co., Ltd.
> + */

Please make the entire comment a C++ one so things look more
intentional.

> + master = spi_alloc_master(&pdev->dev, sizeof(struct mockup_spi));
> + if (!master) {
> + pr_err("failed to alloc spi master\n");
> + return -ENOMEM;
> + }

Please use the new _controller() API, we're trying to remove the
use of outdated terminology.


Attachments:
(No filename) (592.00 B)
signature.asc (499.00 B)
Download all attachments

2022-08-30 19:43:42

by Frank Rowand

[permalink] [raw]
Subject: Re: [PATCH -next 3/4] spi: mockup: Add runtime device tree overlay interface

On 8/30/22 05:27, Mark Brown wrote:
> On Fri, Aug 26, 2022 at 02:43:40PM +0000, Wei Yongjun wrote:
>
>> Add a runtime device tree overlay interface for device need dts file.
>> With it its possible to use device tree overlays without having to use
>> a per-platform overlay manager.
>
> Why would an entirely virtual device like this need to appear in
> DT? DT is supposed to be a hardware description and this clearly
> isn't hardware, nor is it something we're providing to a VM.

Good point. Patch 3 seems to not be needed.

-Frank

2022-08-31 04:52:39

by Wei Yongjun

[permalink] [raw]
Subject: Re: [PATCH -next 1/4] spi: mockup: Add SPI controller testing driver



On 2022/8/31 3:11, Mark Brown wrote:
> On Fri, Aug 26, 2022 at 02:43:38PM +0000, Wei Yongjun wrote:
>
>> @@ -0,0 +1,221 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * SPI controller Testing Driver
>> + *
>> + * Copyright(c) 2022 Huawei Technologies Co., Ltd.
>> + */
>
> Please make the entire comment a C++ one so things look more
> intentional.
>
>> + master = spi_alloc_master(&pdev->dev, sizeof(struct mockup_spi));
>> + if (!master) {
>> + pr_err("failed to alloc spi master\n");
>> + return -ENOMEM;
>> + }
>
> Please use the new _controller() API, we're trying to remove the
> use of outdated terminology.
>


Will fix them in next version.

Thanks,
Wei Yongjun

2022-08-31 04:53:38

by Wei Yongjun

[permalink] [raw]
Subject: Re: [PATCH -next 2/4] spi: mockup: Add writeable tracepoint for spi transfer



On 2022/8/31 2:14, Mark Brown wrote:
> On Fri, Aug 26, 2022 at 02:43:39PM +0000, Wei Yongjun wrote:
>
>> +#define SPI_BUFSIZ_MAX 0x1000
>> +
>> +struct spi_msg_ctx {
>> + int ret;
>> + __u8 data[SPI_BUFSIZ_MAX];
>> +};
>
> This has a hard limit on the size of messages of only 4k on the
> size of messages, that seems a bit on the low side especially
> considering that the example is for a flash device. There's also
> things like firmware downloads which can easily exceed 4k. The
> driver should at the very least report this limit via the SPI
> API, and probably also complain loudly if the limit is exceeded
> since it's unlikely that most drivers will actually be checking
> for such a low limit given how rare they are.
>

We need a limit because of BPF writeble tracepoint only support const
size buffer write now. This limit can be fixed after make BPF support
dynptr write.


Regards,
Wei Yongjun

2022-09-01 11:53:33

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH -next 0/4] spi: Introduce BPF based SPI mockup controller

On Tue, Aug 30, 2022 at 08:09:16PM +0100, Mark Brown wrote:

> There was a series in the past year or so from someone
> implementing a similarish idea but rather than using BPF they
> provided a framework for writing device emulations in qemu with
> a simplified Python framework. That seemed like a more obvious
> direction here. They were initially focusing on I2C but it's a
> similar space. Unfortunately I'm drawing a blank on who was
> working on it or the name of the framework so I can't give a
> useful reference here. Their direction was towards having
> something that could also be used to validate what the driver was
> doing to the device from the device's perspective. I do know it
> was written up on LWN. Hopefully someone else will remember what
> I'm talking about from this vauge description.

The framework I was thinking of is called roadtest from Vincent
Whitchurch who I've copied in here.


Attachments:
(No filename) (937.00 B)
signature.asc (499.00 B)
Download all attachments

2022-09-01 12:49:22

by Wei Yongjun

[permalink] [raw]
Subject: Re: [PATCH -next 0/4] spi: Introduce BPF based SPI mockup controller



On 2022/8/31 3:08, Mark Brown wrote:
> On Fri, Aug 26, 2022 at 02:43:37PM +0000, Wei Yongjun wrote:
>> This series Introduce a BPF based SPI mockup controller, which can be
>> used for testing SPI drivers without real device.
>>
>> The testsuite for SPI drivers will be post in other series, with also
>> support for I2C and PCI bus device drivers.
>
> I replied to some of the individual patches here with some more
> detailed issues but I do have some big picture reservations with
> this approach as well. One big one is that this seems like it's
> only going to be able to handle emulation of devices that are
> purely synchronous - I don't see any sensible direction here for
> extending to devices that need an interrupt line as well. That
> seems like a major limitation. It's fine not to immediately


We can use gpio-sim as the interrupt controller which always exists
with some tiny fix, I had posted them and can be found from link:

https://www.spinics.net/lists/linux-gpio/msg74949.html


> implement everything but it should be fairly clear how that would
> be done when someone needs it and some of the BPF design goals I
> understood seem to conflict with that.
>
> I'm also not clear what the BPF environment is like when it comes
> to extensible frameworks, as soon as you start thinking about the
> problem space there are some obvious extensions with things like
> more detailed register map descriptions and validating that the
> operations that the driver is doing to the device are actually in
> spec for the device or trying to stimulate race conditions or
> error paths in the driver.


The bpftool in kernel still need some works, I am still working on
fix comments from maintainers, which can be found at:

https://lore.kernel.org/bpf/[email protected]/

>
> There's also the issue with getting the BPF userspace tooling
> that I mentioned in reply to one of the individual patches.
>
> Basically while this does look very simple from a kernel point of
> view I worry that BPF might not be the right tool for the job and
> could be a bit of a blind alley, with people rapidly running into
> issues trying to do anything non-trivial.
>

Base on BPF's map, we can using wrap for read/write registers as
the device's requirement. And it is possible to control each register
and runtime.

For example, simple write data to MTD device, and check whether
the data is write to registers:

def test_write_data(self):
with self.device() as dev:
self.device_write_bytes(dev, [1, 2, 3, 4]) <- write to /dev/mtd
data = self.read_regs(0x00, 4)
self.assertEqual(data, [1, 2, 3, 4])

I am working on a light weight framework which just 400 loc's python
code, and can do similar tests to roadtest.

Once I finished the bpftool, I will post a proposal.

> There was a series in the past year or so from someone
> implementing a similarish idea but rather than using BPF they
> provided a framework for writing device emulations in qemu with
> a simplified Python framework. That seemed like a more obvious
> direction here. They were initially focusing on I2C but it's a
> similar space. Unfortunately I'm drawing a blank on who was
> working on it or the name of the framework so I can't give a
> useful reference here. Their direction was towards having
> something that could also be used to validate what the driver was
> doing to the device from the device's perspective. I do know it
> was written up on LWN. Hopefully someone else will remember what
> I'm talking about from this vauge description.
>

I saw your other mail, and know you mean roatest, which is based on
virtio as the backend.

The bpf backend can be easily integrate to roadtest.


Regards,
Wei Yongjun