Re: [PATCH v8 1/4] fpga: add an initial KUnit suite for the FPGA Manager
From: Xu Yilun
Date: Mon Jul 10 2023 - 00:45:51 EST
On 2023-06-30 at 17:25:04 +0200, Marco Pagani wrote:
> The suite tests the basic behaviors of the FPGA Manager including
> programming using a single contiguous buffer and a scatter gather table.
>
> Signed-off-by: Marco Pagani <marpagan@xxxxxxxxxx>
> ---
> drivers/fpga/tests/fpga-mgr-test.c | 311 +++++++++++++++++++++++++++++
> 1 file changed, 311 insertions(+)
> create mode 100644 drivers/fpga/tests/fpga-mgr-test.c
>
> diff --git a/drivers/fpga/tests/fpga-mgr-test.c b/drivers/fpga/tests/fpga-mgr-test.c
> new file mode 100644
> index 000000000000..6fd2e235f195
> --- /dev/null
> +++ b/drivers/fpga/tests/fpga-mgr-test.c
> @@ -0,0 +1,311 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * KUnit test for the FPGA Manager
> + *
> + * Copyright (C) 2023 Red Hat, Inc.
> + *
> + * Author: Marco Pagani <marpagan@xxxxxxxxxx>
> + */
> +
> +#include <kunit/test.h>
> +#include <linux/device.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/module.h>
> +#include <linux/scatterlist.h>
> +#include <linux/types.h>
> +
> +#define HEADER_FILL 'H'
> +#define IMAGE_FILL 'P'
> +#define IMAGE_BLOCK 1024
> +
> +#define HEADER_SIZE IMAGE_BLOCK
> +#define IMAGE_SIZE (IMAGE_BLOCK * 4)
> +
> +struct mgr_stats {
> + bool header_match;
> + bool image_match;
> + u32 seq_num;
> + u32 op_parse_header_seq;
> + u32 op_write_init_seq;
> + u32 op_write_seq;
> + u32 op_write_sg_seq;
> + u32 op_write_complete_seq;
> + enum fpga_mgr_states op_parse_header_state;
> + enum fpga_mgr_states op_write_init_state;
> + enum fpga_mgr_states op_write_state;
> + enum fpga_mgr_states op_write_sg_state;
> + enum fpga_mgr_states op_write_complete_state;
> +};
> +
> +struct mgr_ctx {
> + struct fpga_image_info *img_info;
> + struct fpga_manager *mgr;
> + struct platform_device *pdev;
> + struct mgr_stats stats;
> +};
> +
> +/**
> + * init_test_buffer() - Allocate and initialize a test image in a buffer.
> + * @test: KUnit test context object.
> + * @count: image size in bytes.
> + *
> + * Return: pointer to the newly allocated image.
> + */
> +static char *init_test_buffer(struct kunit *test, size_t count)
> +{
> + char *buf;
> +
> + KUNIT_ASSERT_GE(test, count, HEADER_SIZE);
> +
> + buf = kunit_kzalloc(test, count, GFP_KERNEL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
> +
> + memset(buf, HEADER_FILL, HEADER_SIZE);
> + memset(buf + HEADER_SIZE, IMAGE_FILL, count - HEADER_SIZE);
> +
> + return buf;
> +}
> +
> +static int op_parse_header(struct fpga_manager *mgr, struct fpga_image_info *info,
> + const char *buf, size_t count)
> +{
> + struct mgr_stats *stats = mgr->priv;
> + size_t i;
> +
> + /* Set header_size and data_size for later */
> + info->header_size = HEADER_SIZE;
> + info->data_size = info->count - HEADER_SIZE;
> +
> + stats->header_match = true;
> +
> + /* Check header */
> + for (i = 0; i < info->header_size; i++)
> + if (buf[i] != HEADER_FILL)
> + stats->header_match = false;
> +
> + stats->op_parse_header_state = mgr->state;
> + stats->op_parse_header_seq = stats->seq_num++;
> +
> + return 0;
> +}
> +
> +static int op_write_init(struct fpga_manager *mgr, struct fpga_image_info *info,
> + const char *buf, size_t count)
> +{
> + struct mgr_stats *stats = mgr->priv;
> +
> + stats->op_write_init_state = mgr->state;
> + stats->op_write_init_seq = stats->seq_num++;
> +
> + return 0;
> +}
> +
> +static int op_write(struct fpga_manager *mgr, const char *buf, size_t count)
> +{
> + struct mgr_stats *stats = mgr->priv;
> + size_t i;
> +
> + /* Check the image */
> + stats->image_match = true;
> + for (i = 0; i < count; i++)
> + if (buf[i] != IMAGE_FILL)
> + stats->image_match = false;
> +
> + stats->op_write_state = mgr->state;
> + stats->op_write_seq = stats->seq_num++;
> +
> + return 0;
> +}
> +
> +static int op_write_sg(struct fpga_manager *mgr, struct sg_table *sgt)
> +{
> + struct mgr_stats *stats = mgr->priv;
> + struct sg_mapping_iter miter;
> + char *img;
> + size_t i;
> +
> + /*
> + * Check the image, but first skip the header since write_sg will get
> + * the whole image in sg_table.
> + */
> + stats->image_match = true;
> + sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
> +
> + if (!sg_miter_skip(&miter, HEADER_SIZE))
> + stats->image_match = false;
If this fails, should we continue?
> +
> + while (sg_miter_next(&miter)) {
> + img = miter.addr;
> + for (i = 0; i < miter.length; i++) {
> + if (img[i] != IMAGE_FILL)
> + stats->image_match = false;
> + }
> + }
> +
> + sg_miter_stop(&miter);
> +
> + stats->op_write_sg_state = mgr->state;
> + stats->op_write_sg_seq = stats->seq_num++;
> +
> + return 0;
> +}