kunit: fake: added library to make faking devices easier
Adds infrastructure to allow hardware fakes to be easily inserted behind
iomemory access routines.
Change-Id: I2491a1eccb83a3e93317a67731f61c6b45c73ded
Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
diff --git a/include/test/fake.h b/include/test/fake.h
new file mode 100644
index 0000000..d92e47c
--- /dev/null
+++ b/include/test/fake.h
@@ -0,0 +1,51 @@
+#ifndef _TEST_FAKE_H
+#define _TEST_FAKE_H
+
+#include <test/mock.h>
+
+struct fake_device;
+
+struct fake_register_map_entry {
+ phys_addr_t offset;
+ bool valid_entry;
+ u8 (*readb)(struct fake_device *fd);
+ u16 (*readw)(struct fake_device *fd);
+ u32 (*readl)(struct fake_device *fd);
+ u64 (*readq)(struct fake_device *fd);
+ void (*writeb)(struct fake_device *fd, u8 value);
+ void (*writew)(struct fake_device *fd, u16 value);
+ void (*writel)(struct fake_device *fd, u32 value);
+ void (*writeq)(struct fake_device *fd, u64 value);
+};
+
+#define FAKE_32_RW(offset_, read, write) { .offset = offset_, .valid_entry = true, .readl = read, .writel = write, }
+#define FAKE_32_RO(offset, read) FAKE_32_RW(offset, read, NULL)
+#define FAKE_32_WO(offset, write) FAKE_32_RW(offset, NULL, write)
+#define FAKE_32_NOP(offset) FAKE_32_RW(offset, NULL, NULL)
+
+struct fake_device_description {
+ struct fake_register_map_entry *register_map;
+};
+
+struct fake_device {
+ /* private */
+ struct mock_action readl_action;
+ struct mock_action writel_action;
+ const struct fake_device_description *description;
+ struct test *test;
+ void *priv;
+};
+
+static inline struct test *fake_get_test(struct fake_device *fd)
+{
+ return fd->test;
+}
+
+static inline void *fake_get_data(struct fake_device *fd)
+{
+ return fd->priv;
+}
+
+void fake_device_init(struct test *test, const struct fake_device_description *descr, void *priv);
+
+#endif /* _TEST_FAKE_H */
diff --git a/test/Makefile b/test/Makefile
index 4d69804..606c081 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -2,6 +2,6 @@
test-stream.o
obj-$(CONFIG_TEST_TEST) += \
test-mock.o mock-macro-test.o mock-test.o string-stream-test.o \
- test-stream-test.o
+ test-stream-test.o fake.o
obj-$(CONFIG_TEST_DEATH_TEST) += test-death-test.o
obj-$(CONFIG_EXAMPLE_TEST) += example-test.o
diff --git a/test/fake.c b/test/fake.c
new file mode 100644
index 0000000..4d2ce57
--- /dev/null
+++ b/test/fake.c
@@ -0,0 +1,94 @@
+#include <test/fake.h>
+#include <linux/io.h>
+
+static struct fake_register_map_entry *fake_find_reg_action(struct fake_device *fd, phys_addr_t offset)
+{
+ struct fake_register_map_entry *reg_entry;
+ struct test *test = fake_get_test(fd);
+
+ for (reg_entry = fd->description->register_map; reg_entry->valid_entry; reg_entry++) {
+ if (reg_entry->offset == offset)
+ break;
+ }
+
+ ASSERT_NOT_ERR_OR_NULL(test, reg_entry);
+
+ return reg_entry;
+}
+
+static u32 fake_readl(struct fake_device *fd, phys_addr_t offset)
+{
+ struct fake_register_map_entry *reg_entry;
+
+ reg_entry = fake_find_reg_action(fd, offset);
+
+ if (reg_entry->readl)
+ return reg_entry->readl(fd);
+ else
+ return 0;
+}
+
+static void *fake_readl_action(struct mock_action *this, const void **params, int len)
+{
+ struct fake_device *fd = container_of(this, struct fake_device, readl_action);
+ struct test *test = fake_get_test(fd);
+ phys_addr_t offset;
+ u32 *ret;
+
+ ASSERT_EQ(test, len, 1);
+ offset = CONVERT_TO_ACTUAL_TYPE(phys_addr_t, params[0]);
+ ret = test_kzalloc(test, sizeof(*ret), GFP_KERNEL);
+ *ret = fake_readl(fd, offset);
+
+ return ret;
+}
+
+static void fake_writel(struct fake_device *fd, phys_addr_t offset, u32 value)
+{
+ struct fake_register_map_entry *reg_entry;
+
+ reg_entry = fake_find_reg_action(fd, offset);
+
+ if (reg_entry->writel)
+ reg_entry->writel(fd, value);
+}
+
+static void *fake_writel_action(struct mock_action *this, const void **params, int len)
+{
+ struct fake_device *fd = container_of(this, struct fake_device, writel_action);
+ struct test *test = fake_get_test(fd);
+ phys_addr_t offset;
+ u32 *ret, value;
+
+ ASSERT_EQ(test, len, 2);
+ value = CONVERT_TO_ACTUAL_TYPE(u32, params[0]);
+ offset = CONVERT_TO_ACTUAL_TYPE(phys_addr_t, params[1]);
+ ret = test_kzalloc(test, sizeof(*ret), GFP_KERNEL);
+ *ret = 0;
+ fake_writel(fd, offset, value);
+
+ return ret;
+}
+
+void fake_device_init(struct test *test, const struct fake_device_description *descr, void *priv)
+{
+ struct fake_device *fd;
+
+ fd = test_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+
+ fd->description = descr;
+ fd->test = test;
+ fd->priv = priv;
+ fd->readl_action.do_action = fake_readl_action;
+ fd->writel_action.do_action = fake_writel_action;
+
+ mock_set_default_action(mock_get_global_mock(),
+ "readl",
+ readl,
+ &fd->readl_action);
+ mock_set_default_action(mock_get_global_mock(),
+ "writel",
+ writel,
+ &fd->writel_action);
+}
+