1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test for the FPGA Bridge
*
* Copyright (C) 2023 Red Hat, Inc.
*
* Author: Marco Pagani <marpagan@redhat.com>
*/
#include <kunit/device.h>
#include <kunit/test.h>
#include <linux/fpga/fpga-bridge.h>
#include <linux/module.h>
#include <linux/types.h>
struct bridge_stats {
bool enable;
};
struct bridge_ctx {
struct fpga_bridge *bridge;
struct device *dev;
struct bridge_stats stats;
};
/*
* Wrapper to avoid a cast warning when passing the action function directly
* to kunit_add_action().
*/
KUNIT_DEFINE_ACTION_WRAPPER(fpga_bridge_unregister_wrapper, fpga_bridge_unregister,
struct fpga_bridge *);
static int op_enable_set(struct fpga_bridge *bridge, bool enable)
{
struct bridge_stats *stats = bridge->priv;
stats->enable = enable;
return 0;
}
/*
* Fake FPGA bridge that implements only the enable_set op to track
* the state.
*/
static const struct fpga_bridge_ops fake_bridge_ops = {
.enable_set = op_enable_set,
};
/**
* register_test_bridge() - Register a fake FPGA bridge for testing.
* @test: KUnit test context object.
* @dev_name: name of the kunit device to be registered
*
* Return: Context of the newly registered FPGA bridge.
*/
static struct bridge_ctx *register_test_bridge(struct kunit *test, const char *dev_name)
{
struct bridge_ctx *ctx;
int ret;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
ctx->dev = kunit_device_register(test, dev_name);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev);
ctx->bridge = fpga_bridge_register(ctx->dev, "Fake FPGA bridge", &fake_bridge_ops,
&ctx->stats);
KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->bridge));
ret = kunit_add_action_or_reset(test, fpga_bridge_unregister_wrapper, ctx->bridge);
KUNIT_ASSERT_EQ(test, ret, 0);
return ctx;
}
static void fpga_bridge_test_get(struct kunit *test)
{
struct bridge_ctx *ctx = test->priv;
struct fpga_bridge *bridge;
bridge = fpga_bridge_get(ctx->dev, NULL);
KUNIT_EXPECT_PTR_EQ(test, bridge, ctx->bridge);
bridge = fpga_bridge_get(ctx->dev, NULL);
KUNIT_EXPECT_EQ(test, PTR_ERR(bridge), -EBUSY);
fpga_bridge_put(ctx->bridge);
}
static void fpga_bridge_test_toggle(struct kunit *test)
{
struct bridge_ctx *ctx = test->priv;
int ret;
ret = fpga_bridge_disable(ctx->bridge);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_FALSE(test, ctx->stats.enable);
ret = fpga_bridge_enable(ctx->bridge);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_TRUE(test, ctx->stats.enable);
}
/* Test the functions for getting and controlling a list of bridges */
static void fpga_bridge_test_get_put_list(struct kunit *test)
{
struct list_head bridge_list;
struct bridge_ctx *ctx_0, *ctx_1;
int ret;
ctx_0 = test->priv;
ctx_1 = register_test_bridge(test, "fpga-bridge-test-dev-1");
INIT_LIST_HEAD(&bridge_list);
/* Get bridge 0 and add it to the list */
ret = fpga_bridge_get_to_list(ctx_0->dev, NULL, &bridge_list);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_PTR_EQ(test, ctx_0->bridge,
list_first_entry_or_null(&bridge_list, struct fpga_bridge, node));
/* Get bridge 1 and add it to the list */
ret = fpga_bridge_get_to_list(ctx_1->dev, NULL, &bridge_list);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_PTR_EQ(test, ctx_1->bridge,
list_first_entry_or_null(&bridge_list, struct fpga_bridge, node));
/* Disable an then enable both bridges from the list */
ret = fpga_bridges_disable(&bridge_list);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_FALSE(test, ctx_0->stats.enable);
KUNIT_EXPECT_FALSE(test, ctx_1->stats.enable);
ret = fpga_bridges_enable(&bridge_list);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_TRUE(test, ctx_0->stats.enable);
KUNIT_EXPECT_TRUE(test, ctx_1->stats.enable);
/* Put and remove both bridges from the list */
fpga_bridges_put(&bridge_list);
KUNIT_EXPECT_TRUE(test, list_empty(&bridge_list));
}
static int fpga_bridge_test_init(struct kunit *test)
{
test->priv = register_test_bridge(test, "fpga-bridge-test-dev-0");
return 0;
}
static struct kunit_case fpga_bridge_test_cases[] = {
KUNIT_CASE(fpga_bridge_test_get),
KUNIT_CASE(fpga_bridge_test_toggle),
KUNIT_CASE(fpga_bridge_test_get_put_list),
{}
};
static struct kunit_suite fpga_bridge_suite = {
.name = "fpga_bridge",
.init = fpga_bridge_test_init,
.test_cases = fpga_bridge_test_cases,
};
kunit_test_suite(fpga_bridge_suite);
MODULE_LICENSE("GPL");
|