@@ -2,6 +2,7 @@
include ../../../scripts/Makefile.include
INSTALL ?= install
+SUBDIRS := data
all:
@for SUBDIR in $(SUBDIRS); do \
@@ -15,6 +16,10 @@ install:
cp -rf cmds/ $(INSTALL_PATH)
cp -rf tests/ $(INSTALL_PATH)
+ @for SUBDIR in $(SUBDIRS); do \
+ $(MAKE) INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR -C $$SUBDIR install; \
+ done;
+
clean:
@for SUBDIR in $(SUBDIRS); do \
$(MAKE) -C $$SUBDIR clean; \
@@ -5,3 +5,9 @@
#
# Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
# Author: Wei Yongjun <weiyongjun1@huawei.com>
+
+__all__ = [
+ 'SPIDriverTest',
+]
+
+from .buses import SPIDriverTest
new file mode 100755
@@ -0,0 +1,13 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Kernel device driver verification
+#
+# Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+# Author: Wei Yongjun <weiyongjun1@huawei.com>
+
+__all__ = [
+ 'SPIDriverTest',
+]
+
+from .spi import SPIDriverTest
new file mode 100755
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Kernel device driver verification
+#
+# Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+# Author: Wei Yongjun <weiyongjun1@huawei.com>
+
+import logging
+
+from pathlib import Path
+
+from ..ddunit import DriverTest
+from ..device import Device
+from ..mockup import Mockup
+
+logger = logging.getLogger(__name__)
+
+class SPIDriverTest(DriverTest):
+ bus = 'spi'
+
+ @property
+ def bpf(self):
+ return f'spi-xfer-r{self.regbytes}v{self.valbytes}'
+
+class SPIDevice(Device):
+ bus = 'spi'
+
+ @property
+ def device_id(self):
+ return f"{self.bus}{self.busid}.{self.addr}"
+
+SPI_MASTER_PATH = '/sys/class/spi_master/spi0'
+
+class SPIMockup(Mockup):
+ bus = 'spi'
+ host = Path('/sys/kernel/config/spi-mockup/spi0')
+ live = Path('/sys/kernel/config/spi-mockup/spi0/live')
+
+ def setup(self):
+ logger.debug('setup')
+ if not self.host.exists():
+ self.host.mkdir()
+
+ self.live.write_text('true')
+
+ def teardown(self):
+ logger.debug('spi mockup teardown')
+ self.live.write_text('false')
+ self.host.rmdir()
+
+ @property
+ def device_id(self):
+ return f"{self.devid} {self.addr}"
+
+ def create_device(self):
+ logger.debug(f'new device {self.devid} to spi bus')
+ dev = Path(f'/sys/kernel/config/spi-mockup/spi0/targets/{self.devid}')
+ if not dev.exists():
+ dev.mkdir()
+ device_id = Path(f'/sys/kernel/config/spi-mockup/spi0/targets/{self.devid}/device_id')
+ device_id.write_text(self.devid)
+
+ device_live = Path(f'/sys/kernel/config/spi-mockup/spi0/targets/{self.devid}/live')
+ device_live.write_text('true')
+
+ def remove_device(self):
+ logger.debug(f'delete device {self.devid} from spi bus')
+ logger.debug(f'delete device {self.devid} to spi bus')
+ device_live = Path(f'/sys/kernel/config/spi-mockup/spi0/targets/{self.devid}/live')
+ device_live.write_text('false')
+ dev = Path(f'/sys/kernel/config/spi-mockup/spi0/targets/{self.devid}')
+ dev.rmdir()
+
@@ -101,7 +101,14 @@ class Mockup(object):
def remove_device(self):
pass
+ def setup(self):
+ pass
+
+ def teardown(self):
+ pass
+
def load(self):
+ self.setup()
self.load_bpf()
self.load_regmaps()
self.load_configs()
@@ -110,6 +117,7 @@ class Mockup(object):
def unload(self):
self.remove_device()
self.unload_bpf()
+ self.teardown()
def bpf_map_name(self):
bpf_name = re.sub("-", "_", self.bpf)
new file mode 100644
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0
+include ../../../../scripts/Makefile.include
+
+SUBDIRS := bpf
+
+all:
+ @for SUBDIR in $(SUBDIRS); do \
+ $(MAKE) -C $$SUBDIR;\
+ done;
+
+install:
+ @for SUBDIR in $(SUBDIRS); do \
+ $(MAKE) INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR -C $$SUBDIR install;\
+ done;
+
+clean:
+ @for SUBDIR in $(SUBDIRS); do \
+ $(MAKE) -C $$SUBDIR clean;\
+ done;
+
+.PHONY: all install clean
new file mode 100644
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+include ../../../../../scripts/Makefile.include
+
+CC = clang
+INSTALL ?= install
+
+bpf-objs-y := $(patsubst %.c,%.o,$(wildcard */*.c))
+
+CFLAGS += -I../../../../../bpf/bpftool/ -I../../../../../bpf/bpftool/libbpf/include
+CFLAGS += -Iinclude -Ispi
+
+all: $(bpf-objs-y)
+
+%.o: %.c
+ $(CC) -target bpf -Wall -O2 $(CFLAGS) -g -c $< -o $@
+
+install:
+ $(INSTALL) -m 0755 -d $(INSTALL_PATH)
+ $(INSTALL) $(bpf-objs-y) $(INSTALL_PATH)
+
+clean:
+ rm -rf $(bpf-objs-y)
new file mode 100644
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * The spi xfer helpers for bpf program
+ *
+ * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+ */
+
+#ifndef __SPI_XFER_BASE_
+#define __SPI_XFER_BASE_
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+int spi_xfer_read_u8(struct spi_msg_ctx *msg, unsigned int len,
+ void *map, unsigned int reg, int offset)
+{
+ unsigned int i, key = reg;
+ u8 *value;
+
+ for (i = offset; i < len && i < sizeof(msg->data); i++, key++) {
+ value = bpf_map_lookup_elem(map, &key);
+ if (!value) {
+ bpf_printk("key 0x%x not exists", key);
+ return -1;
+ }
+
+ msg->data[i] = *value;
+
+ bpf_printk("SPI R8 [0x%x]=0x%x", key, msg->data[i]);
+ }
+
+ return 0;
+}
+
+int spi_xfer_write_u8(struct spi_msg_ctx *msg, unsigned int len,
+ void *map, unsigned int reg, int offset)
+{
+ unsigned int i, key = reg;
+ u8 value;
+
+ for (i = offset; i < len && i < sizeof(msg->data); i++, key++) {
+ value = msg->data[i];
+
+ if (bpf_map_update_elem(map, &key, &value, BPF_EXIST)) {
+ bpf_printk("key 0x%x not exists", key);
+ return -1;
+ }
+
+ bpf_printk("SPI W8 [0x%x]=0x%x [%u/%u]", key, value, i, len);
+ }
+
+ return 0;
+}
+
+int spi_xfer_read_u16(struct spi_msg_ctx *msg, unsigned int len,
+ void *map, unsigned int reg, int offset)
+{
+ unsigned int i, key = reg;
+ u16 *value;
+
+ for (i = offset; i < len && i < sizeof(msg->data) - 1; i += 2, key++) {
+ value = bpf_map_lookup_elem(map, &key);
+ if (!value) {
+ bpf_printk("key 0x%x not exists", key);
+ return -1;
+ }
+
+ msg->data[i + 0] = *value >> 8;
+ msg->data[i + 1] = *value & 0xff;
+
+ bpf_printk("SPI R16 [0x%x]=0x%x [%u/%u]", key, *value, i, len);
+ }
+
+ return 0;
+}
+
+int spi_xfer_write_u16(struct spi_msg_ctx *msg, unsigned int len,
+ void *map, unsigned int reg, int offset)
+{
+ unsigned int i, key = reg;
+ u16 value;
+
+ for (i = offset; i < len && i < sizeof(msg->data) - 1; i += 2, key++) {
+ value = msg->data[i];
+ value = (value << 8) | msg->data[i + 1];
+
+ if (bpf_map_update_elem(map, &key, &value, BPF_EXIST)) {
+ bpf_printk("key 0x%x not exists", key);
+ return -1;
+ }
+
+ bpf_printk("SPI W16 [0x%x]=0x%x [%u/%u]", key, value, i, len);
+ }
+
+ return 0;
+}
+
+#endif
new file mode 100644
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x100
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u8);
+} regs_spi_xfer_r1v1 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ return spi_xfer_read_u8(msg, len, ®s_spi_xfer_r1v1, chip_reg, 0);
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ chip_reg = bpf_xfer_reg_u8(msg->data[0]);
+ return spi_xfer_write_u8(msg, len, ®s_spi_xfer_r1v1, chip_reg, 1);
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r1v1, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x100
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u16);
+} regs_spi_xfer_r1v2 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ return spi_xfer_read_u16(msg, len, ®s_spi_xfer_r1v2, chip_reg, 0);
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ chip_reg = bpf_xfer_reg_u8(msg->data[0]);
+ return spi_xfer_write_u16(msg, len, ®s_spi_xfer_r1v2, chip_reg, 1);
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r1v2, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x100
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u32);
+} regs_spi_xfer_r1v3 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ unsigned int i, key = chip_reg;
+ u32 *value;
+
+ for (i = 0; i < len && i < sizeof(msg->data) - 2; i += 3, key++) {
+ value = bpf_map_lookup_elem(®s_spi_xfer_r1v3, &key);
+ if (!value) {
+ bpf_printk("key 0x%x not exists", key);
+ return -EINVAL;
+ }
+
+ msg->data[i + 0] = (*value >> 16) & 0xff;
+ msg->data[i + 1] = (*value >> 8) & 0xff;
+ msg->data[i + 2] = *value & 0xff;
+
+ bpf_printk("SPI R24 [0x%x]=0x%x [%u/%u]", key, *value, i, len);
+ }
+
+ return 0;
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ unsigned int i, key;
+ u32 value;
+
+ chip_reg = bpf_xfer_reg_u8(msg->data[0]);
+ key = chip_reg;
+
+ for (i = 1; i < len && i < sizeof(msg->data) - 2; i += 3, key++) {
+ value = msg->data[i];
+ value = (value << 8) | msg->data[i + 1];
+ value = (value << 8) | msg->data[i + 2];
+
+ if (bpf_map_update_elem(®s_spi_xfer_r1v3, &key, &value, BPF_EXIST)) {
+ bpf_printk("key 0x%x not exists", key);
+ return -EINVAL;
+ }
+
+ bpf_printk("SPI W24 [0x%x]=0x%x", key, value);
+ }
+
+ return 0;
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r1v3, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x1000
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u8);
+} regs_spi_xfer_r2v1 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ return spi_xfer_read_u8(msg, len, ®s_spi_xfer_r2v1, chip_reg, 0);
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ chip_reg = bpf_xfer_reg_u16(msg->data[0] << 8 | msg->data[1]);
+ return spi_xfer_write_u8(msg, len, ®s_spi_xfer_r2v1, chip_reg, 2);
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r2v1, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x1000
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u16);
+} regs_spi_xfer_r2v2 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ return spi_xfer_read_u16(msg, len, ®s_spi_xfer_r2v2, chip_reg, 0);
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ chip_reg = bpf_xfer_reg_u16(msg->data[0] << 8 | msg->data[1]);
+ return spi_xfer_write_u16(msg, len, ®s_spi_xfer_r2v2, chip_reg, 2);
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r2v2, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x1000
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u8);
+} regs_spi_xfer_r3v1 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ return spi_xfer_read_u8(msg, len, ®s_spi_xfer_r3v1, chip_reg, 0);
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ chip_reg = bpf_xfer_reg_u24((msg->data[0] << 16) | (msg->data[1] << 8) |
+ msg->data[2]);
+ return spi_xfer_write_u8(msg, len, ®s_spi_xfer_r3v1, chip_reg, 3);
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r3v1, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
new file mode 100644
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2022-2023 Huawei Technologies Co., Ltd
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include <errno.h>
+
+#include "bpf-xfer-conf.h"
+#include "spi-xfer-base.h"
+
+#define CHIP_REGS_SIZE 0x8000
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, CHIP_REGS_SIZE);
+ __type(key, __u32);
+ __type(value, __u32);
+} regs_spi_xfer_r4v4 SEC(".maps");
+
+static unsigned int chip_reg;
+
+static int spi_xfer_read(struct spi_msg_ctx *msg, unsigned int len)
+{
+ unsigned int i, key = chip_reg;
+ u32 *value;
+
+ for (i = 0; i < len && i < sizeof(msg->data) - 3; i += 4, key++) {
+ value = bpf_map_lookup_elem(®s_spi_xfer_r4v4, &key);
+ if (!value) {
+ bpf_printk("key 0x%x not exists", key);
+ return -EINVAL;
+ }
+
+ msg->data[i + 0] = (*value >> 24) & 0xff;
+ msg->data[i + 1] = (*value >> 16) & 0xff;
+ msg->data[i + 2] = (*value >> 8) & 0xff;
+ msg->data[i + 3] = *value & 0xff;
+
+ bpf_printk("SPI R32 [0x%x]=0x%x [%u/%u]", key, *value, i, len);
+ }
+
+ return 0;
+}
+
+static int spi_xfer_write(struct spi_msg_ctx *msg, unsigned int len)
+{
+ unsigned int i, key;
+ u32 value;
+
+ key = bpf_xfer_reg_u32((msg->data[0] << 24) | (msg->data[1] << 16) |
+ (msg->data[2] << 8) | msg->data[3]);
+ chip_reg = key;
+
+ for (i = 4; i < len && i < sizeof(msg->data) - 3; i += 4, key++) {
+ value = msg->data[i];
+ value = (value << 8) | msg->data[i + 1];
+ value = (value << 8) | msg->data[i + 2];
+ value = (value << 8) | msg->data[i + 3];
+
+ if (bpf_map_update_elem(®s_spi_xfer_r4v4, &key, &value, 0)) {
+ bpf_printk("key 0x%x not exists", key);
+ return -EINVAL;
+ }
+
+ bpf_printk("SPI W32 [0x%x]=0x%x [%u/%u]", key, value, i, len);
+ }
+
+ return 0;
+}
+
+SEC("raw_tp.w/spi_transfer_writeable")
+int BPF_PROG(spi_xfer_r4v4, struct spi_msg_ctx *msg, u8 chip, unsigned int len)
+{
+ if (bpf_xfer_should_fault()) {
+ msg->ret = -EIO;
+ return 0;
+ }
+
+ if (msg->tx_nbits)
+ msg->ret = spi_xfer_write(msg, len);
+ else if (msg->rx_nbits)
+ msg->ret = spi_xfer_read(msg, len);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";