@@ -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.
@@ -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)
new file mode 100644
@@ -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
new file mode 100644
@@ -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>
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 <weiyongjun1@huawei.com> --- 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(-)