brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 9cb37ae Raw
334 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * KUnit test for the FPGA Manager4 *5 * Copyright (C) 2023 Red Hat, Inc.6 *7 * Author: Marco Pagani <marpagan@redhat.com>8 */9 10#include <kunit/device.h>11#include <kunit/test.h>12#include <linux/fpga/fpga-mgr.h>13#include <linux/module.h>14#include <linux/scatterlist.h>15#include <linux/types.h>16 17#define HEADER_FILL		'H'18#define IMAGE_FILL		'P'19#define IMAGE_BLOCK		102420 21#define HEADER_SIZE		IMAGE_BLOCK22#define IMAGE_SIZE		(IMAGE_BLOCK * 4)23 24struct mgr_stats {25	bool header_match;26	bool image_match;27	u32 seq_num;28	u32 op_parse_header_seq;29	u32 op_write_init_seq;30	u32 op_write_seq;31	u32 op_write_sg_seq;32	u32 op_write_complete_seq;33	enum fpga_mgr_states op_parse_header_state;34	enum fpga_mgr_states op_write_init_state;35	enum fpga_mgr_states op_write_state;36	enum fpga_mgr_states op_write_sg_state;37	enum fpga_mgr_states op_write_complete_state;38};39 40struct mgr_ctx {41	struct fpga_image_info *img_info;42	struct fpga_manager *mgr;43	struct device *dev;44	struct mgr_stats stats;45};46 47/*48 * Wrappers to avoid cast warnings when passing action functions directly49 * to kunit_add_action().50 */51KUNIT_DEFINE_ACTION_WRAPPER(sg_free_table_wrapper, sg_free_table,52			    struct sg_table *);53 54KUNIT_DEFINE_ACTION_WRAPPER(fpga_image_info_free_wrapper, fpga_image_info_free,55			    struct fpga_image_info *);56 57/**58 * init_test_buffer() - Allocate and initialize a test image in a buffer.59 * @test: KUnit test context object.60 * @count: image size in bytes.61 *62 * Return: pointer to the newly allocated image.63 */64static char *init_test_buffer(struct kunit *test, size_t count)65{66	char *buf;67 68	KUNIT_ASSERT_GE(test, count, HEADER_SIZE);69 70	buf = kunit_kzalloc(test, count, GFP_KERNEL);71	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);72 73	memset(buf, HEADER_FILL, HEADER_SIZE);74	memset(buf + HEADER_SIZE, IMAGE_FILL, count - HEADER_SIZE);75 76	return buf;77}78 79/*80 * Check the image header. Do not return an error code if the image check fails81 * since, in this case, it is a failure of the FPGA manager itself, not this82 * op that tests it.83 */84static int op_parse_header(struct fpga_manager *mgr, struct fpga_image_info *info,85			   const char *buf, size_t count)86{87	struct mgr_stats *stats = mgr->priv;88	size_t i;89 90	stats->op_parse_header_state = mgr->state;91	stats->op_parse_header_seq = stats->seq_num++;92 93	/* Set header_size and data_size for later */94	info->header_size = HEADER_SIZE;95	info->data_size = info->count - HEADER_SIZE;96 97	stats->header_match = true;98	for (i = 0; i < info->header_size; i++) {99		if (buf[i] != HEADER_FILL) {100			stats->header_match = false;101			break;102		}103	}104 105	return 0;106}107 108static int op_write_init(struct fpga_manager *mgr, struct fpga_image_info *info,109			 const char *buf, size_t count)110{111	struct mgr_stats *stats = mgr->priv;112 113	stats->op_write_init_state = mgr->state;114	stats->op_write_init_seq = stats->seq_num++;115 116	return 0;117}118 119/*120 * Check the image data. As with op_parse_header, do not return an error code121 * if the image check fails.122 */123static int op_write(struct fpga_manager *mgr, const char *buf, size_t count)124{125	struct mgr_stats *stats = mgr->priv;126	size_t i;127 128	stats->op_write_state = mgr->state;129	stats->op_write_seq = stats->seq_num++;130 131	stats->image_match = true;132	for (i = 0; i < count; i++) {133		if (buf[i] != IMAGE_FILL) {134			stats->image_match = false;135			break;136		}137	}138 139	return 0;140}141 142/*143 * Check the image data, but first skip the header since write_sg will get144 * the whole image in sg_table. As with op_parse_header, do not return an145 * error code if the image check fails.146 */147static int op_write_sg(struct fpga_manager *mgr, struct sg_table *sgt)148{149	struct mgr_stats *stats = mgr->priv;150	struct sg_mapping_iter miter;151	char *img;152	size_t i;153 154	stats->op_write_sg_state = mgr->state;155	stats->op_write_sg_seq = stats->seq_num++;156 157	stats->image_match = true;158	sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);159 160	if (!sg_miter_skip(&miter, HEADER_SIZE)) {161		stats->image_match = false;162		goto out;163	}164 165	while (sg_miter_next(&miter)) {166		img = miter.addr;167		for (i = 0; i < miter.length; i++) {168			if (img[i] != IMAGE_FILL) {169				stats->image_match = false;170				goto out;171			}172		}173	}174out:175	sg_miter_stop(&miter);176	return 0;177}178 179static int op_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info)180{181	struct mgr_stats *stats = mgr->priv;182 183	stats->op_write_complete_state = mgr->state;184	stats->op_write_complete_seq = stats->seq_num++;185 186	return 0;187}188 189/*190 * Fake FPGA manager that implements all ops required to check the programming191 * sequence using a single contiguous buffer and a scatter gather table.192 */193static const struct fpga_manager_ops fake_mgr_ops = {194	.skip_header = true,195	.parse_header = op_parse_header,196	.write_init = op_write_init,197	.write = op_write,198	.write_sg = op_write_sg,199	.write_complete = op_write_complete,200};201 202static void fpga_mgr_test_get(struct kunit *test)203{204	struct mgr_ctx *ctx = test->priv;205	struct fpga_manager *mgr;206 207	mgr = fpga_mgr_get(ctx->dev);208	KUNIT_EXPECT_PTR_EQ(test, mgr, ctx->mgr);209 210	fpga_mgr_put(ctx->mgr);211}212 213static void fpga_mgr_test_lock(struct kunit *test)214{215	struct mgr_ctx *ctx = test->priv;216	int ret;217 218	ret = fpga_mgr_lock(ctx->mgr);219	KUNIT_EXPECT_EQ(test, ret, 0);220 221	ret = fpga_mgr_lock(ctx->mgr);222	KUNIT_EXPECT_EQ(test, ret, -EBUSY);223 224	fpga_mgr_unlock(ctx->mgr);225}226 227/* Check the programming sequence using an image in a buffer */228static void fpga_mgr_test_img_load_buf(struct kunit *test)229{230	struct mgr_ctx *ctx = test->priv;231	char *img_buf;232	int ret;233 234	img_buf = init_test_buffer(test, IMAGE_SIZE);235 236	ctx->img_info->count = IMAGE_SIZE;237	ctx->img_info->buf = img_buf;238 239	ret = fpga_mgr_load(ctx->mgr, ctx->img_info);240	KUNIT_EXPECT_EQ(test, ret, 0);241 242	KUNIT_EXPECT_TRUE(test, ctx->stats.header_match);243	KUNIT_EXPECT_TRUE(test, ctx->stats.image_match);244 245	KUNIT_EXPECT_EQ(test, ctx->stats.op_parse_header_state, FPGA_MGR_STATE_PARSE_HEADER);246	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_state, FPGA_MGR_STATE_WRITE_INIT);247	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_state, FPGA_MGR_STATE_WRITE);248	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_state, FPGA_MGR_STATE_WRITE_COMPLETE);249 250	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_seq, ctx->stats.op_parse_header_seq + 1);251	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_seq, ctx->stats.op_parse_header_seq + 2);252	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_seq, ctx->stats.op_parse_header_seq + 3);253}254 255/* Check the programming sequence using an image in a scatter gather table */256static void fpga_mgr_test_img_load_sgt(struct kunit *test)257{258	struct mgr_ctx *ctx = test->priv;259	struct sg_table *sgt;260	char *img_buf;261	int ret;262 263	img_buf = init_test_buffer(test, IMAGE_SIZE);264 265	sgt = kunit_kzalloc(test, sizeof(*sgt), GFP_KERNEL);266	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);267	KUNIT_ASSERT_EQ(test, ret, 0);268	sg_init_one(sgt->sgl, img_buf, IMAGE_SIZE);269 270	ret = kunit_add_action_or_reset(test, sg_free_table_wrapper, sgt);271	KUNIT_ASSERT_EQ(test, ret, 0);272 273	ctx->img_info->sgt = sgt;274 275	ret = fpga_mgr_load(ctx->mgr, ctx->img_info);276	KUNIT_EXPECT_EQ(test, ret, 0);277 278	KUNIT_EXPECT_TRUE(test, ctx->stats.header_match);279	KUNIT_EXPECT_TRUE(test, ctx->stats.image_match);280 281	KUNIT_EXPECT_EQ(test, ctx->stats.op_parse_header_state, FPGA_MGR_STATE_PARSE_HEADER);282	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_state, FPGA_MGR_STATE_WRITE_INIT);283	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_state, FPGA_MGR_STATE_WRITE);284	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_state, FPGA_MGR_STATE_WRITE_COMPLETE);285 286	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_seq, ctx->stats.op_parse_header_seq + 1);287	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_seq, ctx->stats.op_parse_header_seq + 2);288	KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_seq, ctx->stats.op_parse_header_seq + 3);289}290 291static int fpga_mgr_test_init(struct kunit *test)292{293	struct mgr_ctx *ctx;294	int ret;295 296	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);297	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);298 299	ctx->dev = kunit_device_register(test, "fpga-manager-test-dev");300	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev);301 302	ctx->mgr = devm_fpga_mgr_register(ctx->dev, "Fake FPGA Manager", &fake_mgr_ops,303					  &ctx->stats);304	KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr));305 306	ctx->img_info = fpga_image_info_alloc(ctx->dev);307	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->img_info);308 309	ret = kunit_add_action_or_reset(test, fpga_image_info_free_wrapper, ctx->img_info);310	KUNIT_ASSERT_EQ(test, ret, 0);311 312	test->priv = ctx;313 314	return 0;315}316 317static struct kunit_case fpga_mgr_test_cases[] = {318	KUNIT_CASE(fpga_mgr_test_get),319	KUNIT_CASE(fpga_mgr_test_lock),320	KUNIT_CASE(fpga_mgr_test_img_load_buf),321	KUNIT_CASE(fpga_mgr_test_img_load_sgt),322	{}323};324 325static struct kunit_suite fpga_mgr_suite = {326	.name = "fpga_mgr",327	.init = fpga_mgr_test_init,328	.test_cases = fpga_mgr_test_cases,329};330 331kunit_test_suite(fpga_mgr_suite);332 333MODULE_LICENSE("GPL");334