Message ID | 20230203170653.414990-2-marpagan@redhat.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp961953wrn; Fri, 3 Feb 2023 09:21:11 -0800 (PST) X-Google-Smtp-Source: AK7set+hGStbzmjRR5+Xgwi3sIjjwjpq3zxGVvCu85TsPT4LEwZeLyK7i4rSWKHtT41P7NnjmEEc X-Received: by 2002:a05:6a20:d2c9:b0:bf:7ae0:5faf with SMTP id ir9-20020a056a20d2c900b000bf7ae05fafmr8047731pzb.46.1675444871458; Fri, 03 Feb 2023 09:21:11 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675444871; cv=none; d=google.com; s=arc-20160816; b=bgGKkcoXgn1LCRQ+7lZvOkIyQ2Q2nuDUrkL0QlC1O4avlUIwlxmKq4ofx1LV+dk1gS 8qZ5Et8ZCz1385SCoy6bo2KlfI7IUvRdcucD0NpD+sQimthAplk++0AtPYlefEz9eq7y kNdnGEUPvTlcBhh7j/ZrzqI1V78vyf5r9TJ65EtvEWbxTfDzJsduPbvz0OkUFO5m+peL sbV4nG78d/Qdv67Hw/vDoJOO6Kr29+ggtAtFpFPXBMIBB7NU0t9c8Gd5xv8VJsxc+Kco r/I66eawZsMwvxhrkxmqenojZL49FTrmQI6ox6LnngsKx2Imlkr+zV6vNI2bUi0dS+oK N2YA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=QQmhmkEzd3xkaSu4HvpTV2rx3eqChwz0npZXZDCowYk=; b=khQXTU0Yzl9mxTZoyud9CDQ52YWzKglOuRAYiftB2xmvqWGE2q7aGIA1ywBGeiHOEt JuOzs4eFdPnBYM2u5AwEUAVgPA4gOUuqDYMURumYxdr9GpDTAXAOmqdxXzlwPQOvEItv oEOkMQR9xHmu4zCo6EGkxiaazRWqQuThOiXsLGBy2OdI/HnSc4ZxwCnGltwS6c+paF5m wUe1B1kyURzfbpekrU7BLBAqWDr/Z1hB/TFjXMMsgJRQKCSK0UvGkJF4h64EN857av0a yZitgHHN4ekIQAjkt8mc+eM5huK4o2egKz/ZbWWDYW3zQDOPH3JINA/153ZPdvlh9Nj1 vlyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=S9i4U2qQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 12-20020a630d4c000000b004efd1529e26si3353078pgn.330.2023.02.03.09.20.58; Fri, 03 Feb 2023 09:21:11 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=S9i4U2qQ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233705AbjBCRIX (ORCPT <rfc822;il.mystafa@gmail.com> + 99 others); Fri, 3 Feb 2023 12:08:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233039AbjBCRIL (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 3 Feb 2023 12:08:11 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 338C6A9104 for <linux-kernel@vger.kernel.org>; Fri, 3 Feb 2023 09:07:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675444038; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QQmhmkEzd3xkaSu4HvpTV2rx3eqChwz0npZXZDCowYk=; b=S9i4U2qQ5Ir1g6CBxz5LWKY11qvlu8k1V7XZRpMSpmHop/GAM8rnaSg250xeI5B2115qug pLWAFQ7teKXJzvKPJVppCHqk0G8aycJvbFaOqgOVw2mUnXlsQ58xKCYgvT5NtPZ2MLYabn tRVJ2woXBJAs6lOgUiQ1L04h7mgGKvs= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-251-17xKA9r0P8KR3vxGXWiI7A-1; Fri, 03 Feb 2023 12:07:17 -0500 X-MC-Unique: 17xKA9r0P8KR3vxGXWiI7A-1 Received: by mail-qk1-f199.google.com with SMTP id ay10-20020a05620a178a00b0072db6346c39so2332004qkb.16 for <linux-kernel@vger.kernel.org>; Fri, 03 Feb 2023 09:07:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QQmhmkEzd3xkaSu4HvpTV2rx3eqChwz0npZXZDCowYk=; b=lPRNpwrSS8qk4M1XJT1UJVYGacIOpUkjgP/Wbczl4uwpTmVa7U8UbqjV6vNa+GLWrD MUp8z5fCpdSH8ThQ9qyeCgStUqr+wAx4E/qhBARCDZMyLym0KvUyr4FhAqF3JOYhBDkN skdJrHoqlodRdgj9W2IVHjI5rVwTGelYO+NjyYpEn0W+QTjcL5aS43gQFdnqL0RyeRFD 1Uwi6eTvJnaCKaAVbV2bttwTttNOUnrjVQ4lt2e6FznHh6ugiyU9/2e5M4qux7TMCFYB 2dGZtHCh3RJ5f1eYDNCRskHQqmjrTmk8DlNaucfHJaMYHVOaZLTU3XcYPGMJOKIxehyV 4sCA== X-Gm-Message-State: AO0yUKXT9GIIByaH/JMfC9gdUwcKxZBxdPZ8CQFvD3XkV9Qlj2I/FJLO UfGgD0pMH3ktTJ8Idf3f7uRegT+ZF9V9XfuQqkP34mA4Bnt7CzCQ+Q5FO16rn4bK2Wq3Ob3+277 zm54PQN7hLCuSlmIdxBBjOOs= X-Received: by 2002:a05:622a:14ca:b0:3b8:58d0:b4e4 with SMTP id u10-20020a05622a14ca00b003b858d0b4e4mr19562218qtx.33.1675444036417; Fri, 03 Feb 2023 09:07:16 -0800 (PST) X-Received: by 2002:a05:622a:14ca:b0:3b8:58d0:b4e4 with SMTP id u10-20020a05622a14ca00b003b858d0b4e4mr19562176qtx.33.1675444036095; Fri, 03 Feb 2023 09:07:16 -0800 (PST) Received: from klayman.redhat.com (net-2-34-30-183.cust.vodafonedsl.it. [2.34.30.183]) by smtp.gmail.com with ESMTPSA id b13-20020ac801cd000000b003a6a19ee4f0sm1884287qtg.33.2023.02.03.09.07.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Feb 2023 09:07:15 -0800 (PST) From: Marco Pagani <marpagan@redhat.com> To: Moritz Fischer <mdf@kernel.org>, Wu Hao <hao.wu@intel.com>, Xu Yilun <yilun.xu@intel.com>, Tom Rix <trix@redhat.com> Cc: Marco Pagani <marpagan@redhat.com>, linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [RFC PATCH 1/4] fpga: add initial KUnit test suite Date: Fri, 3 Feb 2023 18:06:50 +0100 Message-Id: <20230203170653.414990-2-marpagan@redhat.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230203170653.414990-1-marpagan@redhat.com> References: <20230203170653.414990-1-marpagan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756831281678052070?= X-GMAIL-MSGID: =?utf-8?q?1756831281678052070?= |
Series |
fpga: add initial KUnit test suite for the subsystem
|
|
Commit Message
Marco Pagani
Feb. 3, 2023, 5:06 p.m. UTC
Introduce an initial KUnit suite to test the core components of the
FPGA subsystem.
The test suite consists of two test cases. The first test case checks
the programming of a static image on a fake FPGA with a single hardware
bridge. The FPGA is first programmed using a test image stored in a
buffer, and then with the same image linked to a single-entry
scatter-gather list.
The second test case models dynamic partial reconfiguration. The FPGA
is first configured with a static image that implements a
reconfigurable design containing a sub-region controlled by two soft
bridges. Then, the reconfigurable sub-region is reconfigured using
a fake partial bitstream image. After the reconfiguration, the test
checks that the soft bridges have been correctly activated.
Signed-off-by: Marco Pagani <marpagan@redhat.com>
---
drivers/fpga/Kconfig | 2 +
drivers/fpga/Makefile | 3 +
drivers/fpga/tests/.kunitconfig | 5 +
drivers/fpga/tests/Kconfig | 15 ++
drivers/fpga/tests/Makefile | 6 +
drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++
6 files changed, 295 insertions(+)
create mode 100644 drivers/fpga/tests/.kunitconfig
create mode 100644 drivers/fpga/tests/Kconfig
create mode 100644 drivers/fpga/tests/Makefile
create mode 100644 drivers/fpga/tests/fpga-tests.c
Comments
Hi Marco, I've just started looking at this, but I have a couple of early comments below On 2/3/23 09:06, Marco Pagani wrote: > Introduce an initial KUnit suite to test the core components of the > FPGA subsystem. > > The test suite consists of two test cases. The first test case checks > the programming of a static image on a fake FPGA with a single hardware > bridge. The FPGA is first programmed using a test image stored in a > buffer, and then with the same image linked to a single-entry > scatter-gather list. > > The second test case models dynamic partial reconfiguration. The FPGA > is first configured with a static image that implements a > reconfigurable design containing a sub-region controlled by two soft > bridges. Then, the reconfigurable sub-region is reconfigured using > a fake partial bitstream image. After the reconfiguration, the test > checks that the soft bridges have been correctly activated. > > Signed-off-by: Marco Pagani <marpagan@redhat.com> > --- > drivers/fpga/Kconfig | 2 + > drivers/fpga/Makefile | 3 + > drivers/fpga/tests/.kunitconfig | 5 + > drivers/fpga/tests/Kconfig | 15 ++ > drivers/fpga/tests/Makefile | 6 + > drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ > 6 files changed, 295 insertions(+) > create mode 100644 drivers/fpga/tests/.kunitconfig > create mode 100644 drivers/fpga/tests/Kconfig > create mode 100644 drivers/fpga/tests/Makefile > create mode 100644 drivers/fpga/tests/fpga-tests.c > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig > index 0a00763b9f28..2f689ac4ba3a 100644 > --- a/drivers/fpga/Kconfig > +++ b/drivers/fpga/Kconfig > @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI > FPGA manager driver support for Lattice FPGAs programming over slave > SPI sysCONFIG interface. > > +source "drivers/fpga/tests/Kconfig" > + > endif # FPGA > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile > index 72e554b4d2f7..352a2612623e 100644 > --- a/drivers/fpga/Makefile > +++ b/drivers/fpga/Makefile > @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o > > # Drivers for FPGAs which implement DFL > obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o > + > +# KUnit tests > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ > diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig > new file mode 100644 > index 000000000000..a1c2a2974c39 > --- /dev/null > +++ b/drivers/fpga/tests/.kunitconfig > @@ -0,0 +1,5 @@ > +CONFIG_KUNIT=y > +CONFIG_FPGA=y > +CONFIG_FPGA_REGION=y > +CONFIG_FPGA_BRIDGE=y > +CONFIG_FPGA_KUNIT_TESTS=y > diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig > new file mode 100644 > index 000000000000..5198e605b38d > --- /dev/null > +++ b/drivers/fpga/tests/Kconfig > @@ -0,0 +1,15 @@ > +config FPGA_KUNIT_TESTS > + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS > + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT > + default KUNIT_ALL_TESTS > + help > + Builds unit tests for the FPGA subsystem. This option > + is not useful for distributions or general kernels, > + but only for kernel developers working on the FPGA > + subsystem and its associated drivers. These lines seem shorter than necessary. You can use up to 75 characters per line. > + > + For more information on KUnit and unit tests in general, > + please refer to the KUnit documentation in > + Documentation/dev-tools/kunit/. > + > + If in doubt, say "N". > diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile > new file mode 100644 > index 000000000000..74346ae62457 > --- /dev/null > +++ b/drivers/fpga/tests/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o > diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c > new file mode 100644 > index 000000000000..33f04079b32f > --- /dev/null > +++ b/drivers/fpga/tests/fpga-tests.c > @@ -0,0 +1,264 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Test suite for the FPGA subsystem > + * > + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. > + * > + * Author: Marco Pagani <marpagan@redhat.com> > + */ > + > +#include <kunit/test.h> > +#include <linux/platform_device.h> > +#include <linux/scatterlist.h> > + > +#include <linux/fpga/fpga-mgr.h> > +#include <linux/fpga/fpga-region.h> > +#include <linux/fpga/fpga-bridge.h> > + > +#include "fake-fpga-region.h" > +#include "fake-fpga-bridge.h" > +#include "fake-fpga-mgr.h" > + > +#define FAKE_BIT_BLOCKS 16 > +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) > + > +static u8 fake_bit[FAKE_BIT_SIZE]; > + > +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) > +{ > + int ret; > + > + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > + if (ret) > + return ret; > + > + sg_init_one(sgt->sgl, bit, len); > + > + return ret; > +} > + > +static void free_sgt_bit(struct sg_table *sgt) > +{ > + if (sgt) > + sg_free_table(sgt); > +} > + > +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + int ret; > + > + ret = fake_fpga_mgr_register(mgr_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(bridge_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > +} > + > +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + if (region_ctx) > + fake_fpga_region_unregister(region_ctx); > + > + if (bridge_ctx) > + fake_fpga_bridge_unregister(bridge_ctx); > + > + if (region_ctx) > + fake_fpga_mgr_unregister(mgr_ctx); > +} > + > +static int fpga_suite_init(struct kunit_suite *suite) > +{ > + fake_fpga_mgr_fill_header(fake_bit); > + > + return 0; > +} > + > +static void fpga_base_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fpga_image_info *test_img_info; > + > + struct sg_table sgt_bit; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > + > + /* Allocate a fake test image using a buffer */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + test_img_info->buf = fake_bit; > + test_img_info->count = sizeof(fake_bit); > + > + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_img_info); > + > + /* Allocate another fake test image using a scatter list */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + test_img_info->sgt = &sgt_bit; > + > + /* Re-program the fake FPGA using the image scatter list */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_sg(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + free_sgt_bit(&sgt_bit); > + fpga_image_info_free(test_img_info); > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > +} > + > +static void fpga_pr_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fake_fpga_bridge pr_bridge_0_ctx; > + struct fake_fpga_bridge pr_bridge_1_ctx; > + struct fake_fpga_region pr_region_ctx; > + > + struct fpga_image_info *test_static_img_info; > + struct fpga_image_info *test_pr_img_info; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > + > + /* Allocate a fake test image using a buffer */ > + test_static_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_static_img_info); > + > + test_static_img_info->buf = fake_bit; > + test_static_img_info->count = sizeof(fake_bit); > + > + kunit_info(test, "fake bitstream size: %zu\n", test_static_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_static_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* The static image contains a reconfigurable sub-region with two soft bridges */ > + ret = fake_fpga_bridge_register(&pr_bridge_0_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(&pr_bridge_1_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(&pr_region_ctx, mgr_ctx.mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_0_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_1_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + /* Allocate a fake partial test image using a buffer */ > + test_pr_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_pr_img_info); > + > + test_pr_img_info->buf = fake_bit; > + test_pr_img_info->count = sizeof(fake_bit) / 2; > + test_pr_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; > + > + kunit_info(test, "fake partial bitstream size: %zu\n", test_pr_img_info->count); > + > + /* Program the reconfigurable sub-region */ > + pr_region_ctx.region->info = test_pr_img_info; > + ret = fpga_region_program_fpga(pr_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_0_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_0_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_1_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_1_ctx)); > + > + /* Check that the base bridge has not been disabled */ > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_pr_img_info); > + fpga_image_info_free(test_static_img_info); > + > + fake_fpga_region_unregister(&pr_region_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_0_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_1_ctx); > + > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > +} > + > +static struct kunit_case fpga_test_cases[] = { > + KUNIT_CASE(fpga_base_test), > + KUNIT_CASE(fpga_pr_test), > + {}, > +}; > + > +static struct kunit_suite fpga_test_suite = { > + .name = "fpga-tests", > + .suite_init = fpga_suite_init, > + .test_cases = fpga_test_cases, > +}; > + > +kunit_test_suite(fpga_test_suite); When I try to build with these patches, I get this error: > > ERROR: modpost: missing MODULE_LICENSE() in drivers/fpga/tests/fpga-tests.o I was able to fix it by adding this line at the bottom of the file: > MODULE_LICENSE("GPL"); - Russ
On 2023-02-07 02:05, Russ Weight wrote: > Hi Marco, > > I've just started looking at this, but I have a couple of early comments below > Thanks for looking into this. [...] >> --- /dev/null >> +++ b/drivers/fpga/tests/Kconfig >> @@ -0,0 +1,15 @@ >> +config FPGA_KUNIT_TESTS >> + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS >> + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT >> + default KUNIT_ALL_TESTS >> + help >> + Builds unit tests for the FPGA subsystem. This option >> + is not useful for distributions or general kernels, >> + but only for kernel developers working on the FPGA >> + subsystem and its associated drivers. > These lines seem shorter than necessary. You can use up to 75 > characters per line. > I'll reflow the text in the next revision. [...] >> +static struct kunit_case fpga_test_cases[] = { >> + KUNIT_CASE(fpga_base_test), >> + KUNIT_CASE(fpga_pr_test), >> + {}, >> +}; >> + >> +static struct kunit_suite fpga_test_suite = { >> + .name = "fpga-tests", >> + .suite_init = fpga_suite_init, >> + .test_cases = fpga_test_cases, >> +}; >> + >> +kunit_test_suite(fpga_test_suite); > > When I try to build with these patches, I get this error: >> >> ERROR: modpost: missing MODULE_LICENSE() in drivers/fpga/tests/fpga-tests.o > > I was able to fix it by adding this line at the bottom of the file: > >> MODULE_LICENSE("GPL"); > > - Russ > Right, I forgot to add module info macros to the test suite module. I'll add MODULE_LICENSE() in the next revision. Thanks for the feedback, Marco
On 2/3/23 09:06, Marco Pagani wrote: > Introduce an initial KUnit suite to test the core components of the > FPGA subsystem. > > The test suite consists of two test cases. The first test case checks > the programming of a static image on a fake FPGA with a single hardware > bridge. The FPGA is first programmed using a test image stored in a > buffer, and then with the same image linked to a single-entry > scatter-gather list. > > The second test case models dynamic partial reconfiguration. The FPGA > is first configured with a static image that implements a > reconfigurable design containing a sub-region controlled by two soft > bridges. Then, the reconfigurable sub-region is reconfigured using > a fake partial bitstream image. After the reconfiguration, the test > checks that the soft bridges have been correctly activated. > > Signed-off-by: Marco Pagani <marpagan@redhat.com> > --- > drivers/fpga/Kconfig | 2 + > drivers/fpga/Makefile | 3 + > drivers/fpga/tests/.kunitconfig | 5 + > drivers/fpga/tests/Kconfig | 15 ++ > drivers/fpga/tests/Makefile | 6 + > drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ > 6 files changed, 295 insertions(+) > create mode 100644 drivers/fpga/tests/.kunitconfig > create mode 100644 drivers/fpga/tests/Kconfig > create mode 100644 drivers/fpga/tests/Makefile > create mode 100644 drivers/fpga/tests/fpga-tests.c > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig > index 0a00763b9f28..2f689ac4ba3a 100644 > --- a/drivers/fpga/Kconfig > +++ b/drivers/fpga/Kconfig > @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI > FPGA manager driver support for Lattice FPGAs programming over slave > SPI sysCONFIG interface. > > +source "drivers/fpga/tests/Kconfig" > + > endif # FPGA > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile > index 72e554b4d2f7..352a2612623e 100644 > --- a/drivers/fpga/Makefile > +++ b/drivers/fpga/Makefile > @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o > > # Drivers for FPGAs which implement DFL > obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o > + > +# KUnit tests > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ > diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig > new file mode 100644 > index 000000000000..a1c2a2974c39 > --- /dev/null > +++ b/drivers/fpga/tests/.kunitconfig > @@ -0,0 +1,5 @@ > +CONFIG_KUNIT=y > +CONFIG_FPGA=y > +CONFIG_FPGA_REGION=y > +CONFIG_FPGA_BRIDGE=y > +CONFIG_FPGA_KUNIT_TESTS=y > diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig > new file mode 100644 > index 000000000000..5198e605b38d > --- /dev/null > +++ b/drivers/fpga/tests/Kconfig > @@ -0,0 +1,15 @@ > +config FPGA_KUNIT_TESTS > + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS > + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT > + default KUNIT_ALL_TESTS > + help > + Builds unit tests for the FPGA subsystem. This option > + is not useful for distributions or general kernels, > + but only for kernel developers working on the FPGA > + subsystem and its associated drivers. > + > + For more information on KUnit and unit tests in general, > + please refer to the KUnit documentation in > + Documentation/dev-tools/kunit/. > + > + If in doubt, say "N". > diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile > new file mode 100644 > index 000000000000..74346ae62457 > --- /dev/null > +++ b/drivers/fpga/tests/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o > diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c > new file mode 100644 > index 000000000000..33f04079b32f > --- /dev/null > +++ b/drivers/fpga/tests/fpga-tests.c > @@ -0,0 +1,264 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Test suite for the FPGA subsystem > + * > + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. > + * > + * Author: Marco Pagani <marpagan@redhat.com> > + */ > + > +#include <kunit/test.h> > +#include <linux/platform_device.h> > +#include <linux/scatterlist.h> > + > +#include <linux/fpga/fpga-mgr.h> > +#include <linux/fpga/fpga-region.h> > +#include <linux/fpga/fpga-bridge.h> > + > +#include "fake-fpga-region.h" > +#include "fake-fpga-bridge.h" > +#include "fake-fpga-mgr.h" > + > +#define FAKE_BIT_BLOCKS 16 > +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) > + > +static u8 fake_bit[FAKE_BIT_SIZE]; I take it "bit" in fake_bit and sgt_bit is short for "bitstream". Initially, I found this confusing as I tend to think of a bit as a single bit. It might be better to expand that something like "fake_bitstream" or "fake_image". - Russ > + > +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) > +{ > + int ret; > + > + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > + if (ret) > + return ret; > + > + sg_init_one(sgt->sgl, bit, len); > + > + return ret; > +} > + > +static void free_sgt_bit(struct sg_table *sgt) > +{ > + if (sgt) > + sg_free_table(sgt); > +} > + > +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + int ret; > + > + ret = fake_fpga_mgr_register(mgr_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(bridge_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > +} > + > +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + if (region_ctx) > + fake_fpga_region_unregister(region_ctx); > + > + if (bridge_ctx) > + fake_fpga_bridge_unregister(bridge_ctx); > + > + if (region_ctx) > + fake_fpga_mgr_unregister(mgr_ctx); > +} > + > +static int fpga_suite_init(struct kunit_suite *suite) > +{ > + fake_fpga_mgr_fill_header(fake_bit); > + > + return 0; > +} > + > +static void fpga_base_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fpga_image_info *test_img_info; > + > + struct sg_table sgt_bit; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > + > + /* Allocate a fake test image using a buffer */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + test_img_info->buf = fake_bit; > + test_img_info->count = sizeof(fake_bit); > + > + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_img_info); > + > + /* Allocate another fake test image using a scatter list */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + test_img_info->sgt = &sgt_bit; > + > + /* Re-program the fake FPGA using the image scatter list */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_sg(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + free_sgt_bit(&sgt_bit); > + fpga_image_info_free(test_img_info); > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > +} > + > +static void fpga_pr_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fake_fpga_bridge pr_bridge_0_ctx; > + struct fake_fpga_bridge pr_bridge_1_ctx; > + struct fake_fpga_region pr_region_ctx; > + > + struct fpga_image_info *test_static_img_info; > + struct fpga_image_info *test_pr_img_info; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > + > + /* Allocate a fake test image using a buffer */ > + test_static_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_static_img_info); > + > + test_static_img_info->buf = fake_bit; > + test_static_img_info->count = sizeof(fake_bit); > + > + kunit_info(test, "fake bitstream size: %zu\n", test_static_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_static_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* The static image contains a reconfigurable sub-region with two soft bridges */ > + ret = fake_fpga_bridge_register(&pr_bridge_0_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(&pr_bridge_1_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(&pr_region_ctx, mgr_ctx.mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_0_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_1_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + /* Allocate a fake partial test image using a buffer */ > + test_pr_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_pr_img_info); > + > + test_pr_img_info->buf = fake_bit; > + test_pr_img_info->count = sizeof(fake_bit) / 2; > + test_pr_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; > + > + kunit_info(test, "fake partial bitstream size: %zu\n", test_pr_img_info->count); > + > + /* Program the reconfigurable sub-region */ > + pr_region_ctx.region->info = test_pr_img_info; > + ret = fpga_region_program_fpga(pr_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_0_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_0_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_1_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_1_ctx)); > + > + /* Check that the base bridge has not been disabled */ > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_pr_img_info); > + fpga_image_info_free(test_static_img_info); > + > + fake_fpga_region_unregister(&pr_region_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_0_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_1_ctx); > + > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > +} > + > +static struct kunit_case fpga_test_cases[] = { > + KUNIT_CASE(fpga_base_test), > + KUNIT_CASE(fpga_pr_test), > + {}, > +}; > + > +static struct kunit_suite fpga_test_suite = { > + .name = "fpga-tests", > + .suite_init = fpga_suite_init, > + .test_cases = fpga_test_cases, > +}; > + > +kunit_test_suite(fpga_test_suite);
On 2023-02-14 00:37, Russ Weight wrote: > > > On 2/3/23 09:06, Marco Pagani wrote: >> Introduce an initial KUnit suite to test the core components of the >> FPGA subsystem. >> >> The test suite consists of two test cases. The first test case checks >> the programming of a static image on a fake FPGA with a single hardware >> bridge. The FPGA is first programmed using a test image stored in a >> buffer, and then with the same image linked to a single-entry >> scatter-gather list. >> >> The second test case models dynamic partial reconfiguration. The FPGA >> is first configured with a static image that implements a >> reconfigurable design containing a sub-region controlled by two soft >> bridges. Then, the reconfigurable sub-region is reconfigured using >> a fake partial bitstream image. After the reconfiguration, the test >> checks that the soft bridges have been correctly activated. >> >> Signed-off-by: Marco Pagani <marpagan@redhat.com> >> --- >> drivers/fpga/Kconfig | 2 + >> drivers/fpga/Makefile | 3 + >> drivers/fpga/tests/.kunitconfig | 5 + >> drivers/fpga/tests/Kconfig | 15 ++ >> drivers/fpga/tests/Makefile | 6 + >> drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ >> 6 files changed, 295 insertions(+) >> create mode 100644 drivers/fpga/tests/.kunitconfig >> create mode 100644 drivers/fpga/tests/Kconfig >> create mode 100644 drivers/fpga/tests/Makefile >> create mode 100644 drivers/fpga/tests/fpga-tests.c >> >> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig >> index 0a00763b9f28..2f689ac4ba3a 100644 >> --- a/drivers/fpga/Kconfig >> +++ b/drivers/fpga/Kconfig >> @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI >> FPGA manager driver support for Lattice FPGAs programming over slave >> SPI sysCONFIG interface. >> >> +source "drivers/fpga/tests/Kconfig" >> + >> endif # FPGA >> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile >> index 72e554b4d2f7..352a2612623e 100644 >> --- a/drivers/fpga/Makefile >> +++ b/drivers/fpga/Makefile >> @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o >> >> # Drivers for FPGAs which implement DFL >> obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o >> + >> +# KUnit tests >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ >> diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig >> new file mode 100644 >> index 000000000000..a1c2a2974c39 >> --- /dev/null >> +++ b/drivers/fpga/tests/.kunitconfig >> @@ -0,0 +1,5 @@ >> +CONFIG_KUNIT=y >> +CONFIG_FPGA=y >> +CONFIG_FPGA_REGION=y >> +CONFIG_FPGA_BRIDGE=y >> +CONFIG_FPGA_KUNIT_TESTS=y >> diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig >> new file mode 100644 >> index 000000000000..5198e605b38d >> --- /dev/null >> +++ b/drivers/fpga/tests/Kconfig >> @@ -0,0 +1,15 @@ >> +config FPGA_KUNIT_TESTS >> + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS >> + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT >> + default KUNIT_ALL_TESTS >> + help >> + Builds unit tests for the FPGA subsystem. This option >> + is not useful for distributions or general kernels, >> + but only for kernel developers working on the FPGA >> + subsystem and its associated drivers. >> + >> + For more information on KUnit and unit tests in general, >> + please refer to the KUnit documentation in >> + Documentation/dev-tools/kunit/. >> + >> + If in doubt, say "N". >> diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile >> new file mode 100644 >> index 000000000000..74346ae62457 >> --- /dev/null >> +++ b/drivers/fpga/tests/Makefile >> @@ -0,0 +1,6 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> + >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o >> diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c >> new file mode 100644 >> index 000000000000..33f04079b32f >> --- /dev/null >> +++ b/drivers/fpga/tests/fpga-tests.c >> @@ -0,0 +1,264 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Test suite for the FPGA subsystem >> + * >> + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. >> + * >> + * Author: Marco Pagani <marpagan@redhat.com> >> + */ >> + >> +#include <kunit/test.h> >> +#include <linux/platform_device.h> >> +#include <linux/scatterlist.h> >> + >> +#include <linux/fpga/fpga-mgr.h> >> +#include <linux/fpga/fpga-region.h> >> +#include <linux/fpga/fpga-bridge.h> >> + >> +#include "fake-fpga-region.h" >> +#include "fake-fpga-bridge.h" >> +#include "fake-fpga-mgr.h" >> + >> +#define FAKE_BIT_BLOCKS 16 >> +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) >> + >> +static u8 fake_bit[FAKE_BIT_SIZE]; > > I take it "bit" in fake_bit and sgt_bit is short for "bitstream". Initially, > I found this confusing as I tend to think of a bit as a single bit. It might > be better to expand that something like "fake_bitstream" or "fake_image". > > - Russ You're right. Using "bit" in the name can be confusing. I'll change it to "fake_image" or maybe "fake_image_buf" to be consistent with the naming convention used in the subsystem. I'll also change "test_img_info" to "fake_img_info" to improve naming consistency. Thanks, Marco
On 2023-02-03 at 18:06:50 +0100, Marco Pagani wrote: > Introduce an initial KUnit suite to test the core components of the > FPGA subsystem. I'm not familiar with kunit, and I spend some time to read the Documentation/dev-tools/kunit/, sorry for late response. > > The test suite consists of two test cases. The first test case checks > the programming of a static image on a fake FPGA with a single hardware > bridge. The FPGA is first programmed using a test image stored in a > buffer, and then with the same image linked to a single-entry > scatter-gather list. > > The second test case models dynamic partial reconfiguration. The FPGA > is first configured with a static image that implements a > reconfigurable design containing a sub-region controlled by two soft > bridges. Then, the reconfigurable sub-region is reconfigured using > a fake partial bitstream image. After the reconfiguration, the test > checks that the soft bridges have been correctly activated. > > Signed-off-by: Marco Pagani <marpagan@redhat.com> > --- > drivers/fpga/Kconfig | 2 + > drivers/fpga/Makefile | 3 + > drivers/fpga/tests/.kunitconfig | 5 + > drivers/fpga/tests/Kconfig | 15 ++ > drivers/fpga/tests/Makefile | 6 + > drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ > 6 files changed, 295 insertions(+) > create mode 100644 drivers/fpga/tests/.kunitconfig > create mode 100644 drivers/fpga/tests/Kconfig > create mode 100644 drivers/fpga/tests/Makefile > create mode 100644 drivers/fpga/tests/fpga-tests.c > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig > index 0a00763b9f28..2f689ac4ba3a 100644 > --- a/drivers/fpga/Kconfig > +++ b/drivers/fpga/Kconfig > @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI > FPGA manager driver support for Lattice FPGAs programming over slave > SPI sysCONFIG interface. > > +source "drivers/fpga/tests/Kconfig" > + > endif # FPGA > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile > index 72e554b4d2f7..352a2612623e 100644 > --- a/drivers/fpga/Makefile > +++ b/drivers/fpga/Makefile > @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o > > # Drivers for FPGAs which implement DFL > obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o > + > +# KUnit tests > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ > diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig > new file mode 100644 > index 000000000000..a1c2a2974c39 > --- /dev/null > +++ b/drivers/fpga/tests/.kunitconfig > @@ -0,0 +1,5 @@ > +CONFIG_KUNIT=y > +CONFIG_FPGA=y > +CONFIG_FPGA_REGION=y > +CONFIG_FPGA_BRIDGE=y > +CONFIG_FPGA_KUNIT_TESTS=y > diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig > new file mode 100644 > index 000000000000..5198e605b38d > --- /dev/null > +++ b/drivers/fpga/tests/Kconfig > @@ -0,0 +1,15 @@ > +config FPGA_KUNIT_TESTS > + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS > + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT > + default KUNIT_ALL_TESTS > + help > + Builds unit tests for the FPGA subsystem. This option > + is not useful for distributions or general kernels, > + but only for kernel developers working on the FPGA > + subsystem and its associated drivers. > + > + For more information on KUnit and unit tests in general, > + please refer to the KUnit documentation in > + Documentation/dev-tools/kunit/. > + > + If in doubt, say "N". > diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile > new file mode 100644 > index 000000000000..74346ae62457 > --- /dev/null > +++ b/drivers/fpga/tests/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o It is better the patches for fake components come first, otherwise may break the compilation. Also not friendly for review. > +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o Maybe fpga-test.o? And could they be built in a single module? I haven't find a reason these fake components been used alone. > diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c > new file mode 100644 > index 000000000000..33f04079b32f > --- /dev/null > +++ b/drivers/fpga/tests/fpga-tests.c > @@ -0,0 +1,264 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Test suite for the FPGA subsystem > + * > + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. > + * > + * Author: Marco Pagani <marpagan@redhat.com> > + */ > + > +#include <kunit/test.h> > +#include <linux/platform_device.h> > +#include <linux/scatterlist.h> > + > +#include <linux/fpga/fpga-mgr.h> > +#include <linux/fpga/fpga-region.h> > +#include <linux/fpga/fpga-bridge.h> > + > +#include "fake-fpga-region.h" > +#include "fake-fpga-bridge.h" > +#include "fake-fpga-mgr.h" > + > +#define FAKE_BIT_BLOCKS 16 > +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) > + > +static u8 fake_bit[FAKE_BIT_SIZE]; > + > +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) > +{ > + int ret; > + > + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > + if (ret) > + return ret; > + > + sg_init_one(sgt->sgl, bit, len); > + > + return ret; > +} > + > +static void free_sgt_bit(struct sg_table *sgt) > +{ > + if (sgt) > + sg_free_table(sgt); > +} > + > +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + int ret; > + > + ret = fake_fpga_mgr_register(mgr_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(bridge_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > +} > + > +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, > + struct fake_fpga_bridge *bridge_ctx, > + struct fake_fpga_region *region_ctx) > +{ > + if (region_ctx) > + fake_fpga_region_unregister(region_ctx); > + > + if (bridge_ctx) > + fake_fpga_bridge_unregister(bridge_ctx); > + > + if (region_ctx) > + fake_fpga_mgr_unregister(mgr_ctx); > +} > + > +static int fpga_suite_init(struct kunit_suite *suite) > +{ > + fake_fpga_mgr_fill_header(fake_bit); Do we need to run it before every case? Or just run once for all cases? > + > + return 0; > +} > + > +static void fpga_base_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fpga_image_info *test_img_info; > + > + struct sg_table sgt_bit; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > + > + /* Allocate a fake test image using a buffer */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + test_img_info->buf = fake_bit; > + test_img_info->count = sizeof(fake_bit); > + > + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_img_info); > + > + /* Allocate another fake test image using a scatter list */ > + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > + > + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); > + KUNIT_ASSERT_EQ(test, ret, 0); This is not fpga function, do we need the ASSERT? > + > + test_img_info->sgt = &sgt_bit; > + > + /* Re-program the fake FPGA using the image scatter list */ > + base_region_ctx.region->info = test_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_sg(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + free_sgt_bit(&sgt_bit); > + fpga_image_info_free(test_img_info); > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > +} > + > +static void fpga_pr_test(struct kunit *test) > +{ > + int ret; > + > + struct fake_fpga_mgr mgr_ctx; > + struct fake_fpga_bridge base_bridge_ctx; > + struct fake_fpga_region base_region_ctx; > + > + struct fake_fpga_bridge pr_bridge_0_ctx; > + struct fake_fpga_bridge pr_bridge_1_ctx; > + struct fake_fpga_region pr_region_ctx; > + > + struct fpga_image_info *test_static_img_info; > + struct fpga_image_info *test_pr_img_info; > + > + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); If we need the base region/bridge/mgr for each case, could we create global ones in .init(), or .suite_init()? > + > + /* Allocate a fake test image using a buffer */ > + test_static_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_static_img_info); > + > + test_static_img_info->buf = fake_bit; > + test_static_img_info->count = sizeof(fake_bit); Same concern, may remove the test image info initialization from each test case code. > + > + kunit_info(test, "fake bitstream size: %zu\n", test_static_img_info->count); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* Program the fake FPGA using the image buffer */ > + base_region_ctx.region->info = test_static_img_info; > + ret = fpga_region_program_fpga(base_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + /* The static image contains a reconfigurable sub-region with two soft bridges */ Till now I didn't find any difference with fpga_base_test. And I can't figure out how the "static parent region - sub pr region" topology is created? > + ret = fake_fpga_bridge_register(&pr_bridge_0_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_bridge_register(&pr_bridge_1_ctx, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_register(&pr_region_ctx, mgr_ctx.mgr, test); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_0_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_1_ctx.bridge); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + /* Allocate a fake partial test image using a buffer */ > + test_pr_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_pr_img_info); > + > + test_pr_img_info->buf = fake_bit; > + test_pr_img_info->count = sizeof(fake_bit) / 2; > + test_pr_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; > + > + kunit_info(test, "fake partial bitstream size: %zu\n", test_pr_img_info->count); > + > + /* Program the reconfigurable sub-region */ > + pr_region_ctx.region->info = test_pr_img_info; > + ret = fpga_region_program_fpga(pr_region_ctx.region); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + fake_fpga_mgr_check_write_buf(&mgr_ctx); > + > + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_0_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_0_ctx)); > + > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_1_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_1_ctx)); > + > + /* Check that the base bridge has not been disabled */ > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > + > + fpga_image_info_free(test_pr_img_info); > + fpga_image_info_free(test_static_img_info); > + > + fake_fpga_region_unregister(&pr_region_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_0_ctx); > + fake_fpga_bridge_unregister(&pr_bridge_1_ctx); > + > + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); Same concern, may put them in .exit() or suite_exit()? > +} > + > +static struct kunit_case fpga_test_cases[] = { > + KUNIT_CASE(fpga_base_test), > + KUNIT_CASE(fpga_pr_test), I feel there are too many tasks for each test case, and some duplicated routines. Could we have a suite for the common routine test in each case, like region/bridge/mgr (un)register, fpga image alloc ... And another suite which have these common routines in .init() or .suite_init(). > + {}, > +}; > + > +static struct kunit_suite fpga_test_suite = { > + .name = "fpga-tests", I see from style.rst that: "Names should use underscores, not dashes, to separate words" and "*Do not* include "test" or "kunit" directly in the subsystem name unless we are actually testing other tests or the kunit framework itself" So IIUC I assume the name should be "fpga"? BTW: I do see some existing test cases that are not conform to the style, even the examples in doc itself. Thanks, Yilun > + .suite_init = fpga_suite_init, > + .test_cases = fpga_test_cases, > +}; > + > +kunit_test_suite(fpga_test_suite); > -- > 2.39.1 >
On 2023-02-18 10:59, Xu Yilun wrote: > On 2023-02-03 at 18:06:50 +0100, Marco Pagani wrote: >> Introduce an initial KUnit suite to test the core components of the >> FPGA subsystem. > > I'm not familiar with kunit, and I spend some time to read the > Documentation/dev-tools/kunit/, sorry for late response. Thank you for reviewing. > >> >> The test suite consists of two test cases. The first test case checks >> the programming of a static image on a fake FPGA with a single hardware >> bridge. The FPGA is first programmed using a test image stored in a >> buffer, and then with the same image linked to a single-entry >> scatter-gather list. >> >> The second test case models dynamic partial reconfiguration. The FPGA >> is first configured with a static image that implements a >> reconfigurable design containing a sub-region controlled by two soft >> bridges. Then, the reconfigurable sub-region is reconfigured using >> a fake partial bitstream image. After the reconfiguration, the test >> checks that the soft bridges have been correctly activated. >> >> Signed-off-by: Marco Pagani <marpagan@redhat.com> >> --- >> drivers/fpga/Kconfig | 2 + >> drivers/fpga/Makefile | 3 + >> drivers/fpga/tests/.kunitconfig | 5 + >> drivers/fpga/tests/Kconfig | 15 ++ >> drivers/fpga/tests/Makefile | 6 + >> drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ >> 6 files changed, 295 insertions(+) >> create mode 100644 drivers/fpga/tests/.kunitconfig >> create mode 100644 drivers/fpga/tests/Kconfig >> create mode 100644 drivers/fpga/tests/Makefile >> create mode 100644 drivers/fpga/tests/fpga-tests.c >> >> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig >> index 0a00763b9f28..2f689ac4ba3a 100644 >> --- a/drivers/fpga/Kconfig >> +++ b/drivers/fpga/Kconfig >> @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI >> FPGA manager driver support for Lattice FPGAs programming over slave >> SPI sysCONFIG interface. >> >> +source "drivers/fpga/tests/Kconfig" >> + >> endif # FPGA >> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile >> index 72e554b4d2f7..352a2612623e 100644 >> --- a/drivers/fpga/Makefile >> +++ b/drivers/fpga/Makefile >> @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o >> >> # Drivers for FPGAs which implement DFL >> obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o >> + >> +# KUnit tests >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ >> diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig >> new file mode 100644 >> index 000000000000..a1c2a2974c39 >> --- /dev/null >> +++ b/drivers/fpga/tests/.kunitconfig >> @@ -0,0 +1,5 @@ >> +CONFIG_KUNIT=y >> +CONFIG_FPGA=y >> +CONFIG_FPGA_REGION=y >> +CONFIG_FPGA_BRIDGE=y >> +CONFIG_FPGA_KUNIT_TESTS=y >> diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig >> new file mode 100644 >> index 000000000000..5198e605b38d >> --- /dev/null >> +++ b/drivers/fpga/tests/Kconfig >> @@ -0,0 +1,15 @@ >> +config FPGA_KUNIT_TESTS >> + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS >> + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT >> + default KUNIT_ALL_TESTS >> + help >> + Builds unit tests for the FPGA subsystem. This option >> + is not useful for distributions or general kernels, >> + but only for kernel developers working on the FPGA >> + subsystem and its associated drivers. >> + >> + For more information on KUnit and unit tests in general, >> + please refer to the KUnit documentation in >> + Documentation/dev-tools/kunit/. >> + >> + If in doubt, say "N". >> diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile >> new file mode 100644 >> index 000000000000..74346ae62457 >> --- /dev/null >> +++ b/drivers/fpga/tests/Makefile >> @@ -0,0 +1,6 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> + >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o > > It is better the patches for fake components come first, otherwise may > break the compilation. Also not friendly for review. Sorry. I'll change the order in the next version. > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o > > Maybe fpga-test.o? I'll change the name in the next version. > > And could they be built in a single module? I haven't find a reason > these fake components been used alone. > My feeling is that they could also come in handy to do some general development or testing on the subsystem. For instance, I used the fake FPGA manager in isolation to experiment with the OF region. Initially, the fake manager also had an of_device_id device matching struct. However, I later removed it because it was not used for the test setup, and I was not sure if adding an OF device matching struct was acceptable for a test driver. >> diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c >> new file mode 100644 >> index 000000000000..33f04079b32f >> --- /dev/null >> +++ b/drivers/fpga/tests/fpga-tests.c >> @@ -0,0 +1,264 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Test suite for the FPGA subsystem >> + * >> + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. >> + * >> + * Author: Marco Pagani <marpagan@redhat.com> >> + */ >> + >> +#include <kunit/test.h> >> +#include <linux/platform_device.h> >> +#include <linux/scatterlist.h> >> + >> +#include <linux/fpga/fpga-mgr.h> >> +#include <linux/fpga/fpga-region.h> >> +#include <linux/fpga/fpga-bridge.h> >> + >> +#include "fake-fpga-region.h" >> +#include "fake-fpga-bridge.h" >> +#include "fake-fpga-mgr.h" >> + >> +#define FAKE_BIT_BLOCKS 16 >> +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) >> + >> +static u8 fake_bit[FAKE_BIT_SIZE]; >> + >> +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) >> +{ >> + int ret; >> + >> + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); >> + if (ret) >> + return ret; >> + >> + sg_init_one(sgt->sgl, bit, len); >> + >> + return ret; >> +} >> + >> +static void free_sgt_bit(struct sg_table *sgt) >> +{ >> + if (sgt) >> + sg_free_table(sgt); >> +} >> + >> +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, >> + struct fake_fpga_bridge *bridge_ctx, >> + struct fake_fpga_region *region_ctx) >> +{ >> + int ret; >> + >> + ret = fake_fpga_mgr_register(mgr_ctx, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_bridge_register(bridge_ctx, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> +} >> + >> +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, >> + struct fake_fpga_bridge *bridge_ctx, >> + struct fake_fpga_region *region_ctx) >> +{ >> + if (region_ctx) >> + fake_fpga_region_unregister(region_ctx); >> + >> + if (bridge_ctx) >> + fake_fpga_bridge_unregister(bridge_ctx); >> + >> + if (region_ctx) >> + fake_fpga_mgr_unregister(mgr_ctx); >> +} >> + >> +static int fpga_suite_init(struct kunit_suite *suite) >> +{ >> + fake_fpga_mgr_fill_header(fake_bit); > > Do we need to run it before every case? Or just run once for all cases? > Just once for all cases. So I'm calling it from the suite_init function. For the next version, I'm thinking of allocating the image buffer using kunit_kzalloc() instead of using a global static array. >> + >> + return 0; >> +} >> + >> +static void fpga_base_test(struct kunit *test) >> +{ >> + int ret; >> + >> + struct fake_fpga_mgr mgr_ctx; >> + struct fake_fpga_bridge base_bridge_ctx; >> + struct fake_fpga_region base_region_ctx; >> + >> + struct fpga_image_info *test_img_info; >> + >> + struct sg_table sgt_bit; >> + >> + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); >> + >> + /* Allocate a fake test image using a buffer */ >> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); >> + >> + test_img_info->buf = fake_bit; >> + test_img_info->count = sizeof(fake_bit); >> + >> + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); >> + >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + /* Program the fake FPGA using the image buffer */ >> + base_region_ctx.region->info = test_img_info; >> + ret = fpga_region_program_fpga(base_region_ctx.region); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + fake_fpga_mgr_check_write_buf(&mgr_ctx); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + fpga_image_info_free(test_img_info); >> + >> + /* Allocate another fake test image using a scatter list */ >> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); >> + >> + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); >> + KUNIT_ASSERT_EQ(test, ret, 0); > > This is not fpga function, do we need the ASSERT? > You're right. I'll change it to EXPECT. >> + >> + test_img_info->sgt = &sgt_bit; >> + >> + /* Re-program the fake FPGA using the image scatter list */ >> + base_region_ctx.region->info = test_img_info; >> + ret = fpga_region_program_fpga(base_region_ctx.region); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + fake_fpga_mgr_check_write_sg(&mgr_ctx); >> + >> + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + free_sgt_bit(&sgt_bit); >> + fpga_image_info_free(test_img_info); >> + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); >> +} >> + >> +static void fpga_pr_test(struct kunit *test) >> +{ >> + int ret; >> + >> + struct fake_fpga_mgr mgr_ctx; >> + struct fake_fpga_bridge base_bridge_ctx; >> + struct fake_fpga_region base_region_ctx; >> + >> + struct fake_fpga_bridge pr_bridge_0_ctx; >> + struct fake_fpga_bridge pr_bridge_1_ctx; >> + struct fake_fpga_region pr_region_ctx; >> + >> + struct fpga_image_info *test_static_img_info; >> + struct fpga_image_info *test_pr_img_info; >> + >> + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > > If we need the base region/bridge/mgr for each case, could we create > global ones in .init(), or .suite_init()? > Ok, I'll reduce code duplication in the next version. My only concern is that I would not want to complicate the test code. In my intentions, this is just an initial set of tests intended to lay the foundation for other test suites. At this stage, I'm not sure if other tests will need or use this kind of setup. So I would like to keep the test code as simple as possible. >> + >> + /* Allocate a fake test image using a buffer */ >> + test_static_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_static_img_info); >> + >> + test_static_img_info->buf = fake_bit; >> + test_static_img_info->count = sizeof(fake_bit); > > Same concern, may remove the test image info initialization from each > test case code. > Same as above, I'll reduce code duplication in the next version. >> + >> + kunit_info(test, "fake bitstream size: %zu\n", test_static_img_info->count); >> + >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + /* Program the fake FPGA using the image buffer */ >> + base_region_ctx.region->info = test_static_img_info; >> + ret = fpga_region_program_fpga(base_region_ctx.region); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + fake_fpga_mgr_check_write_buf(&mgr_ctx); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + /* The static image contains a reconfigurable sub-region with two soft bridges */ > > Till now I didn't find any difference with fpga_base_test. > And I can't figure out how the "static parent region - sub pr region" > topology is created? > You're right, the topology is missing. I'm preparing a new version where regions are hierarchically organized according to the FPGA Region DT binding documentation. I.e., the static region is the parent device of the reconfigurable region. >> + ret = fake_fpga_bridge_register(&pr_bridge_0_ctx, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_bridge_register(&pr_bridge_1_ctx, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_region_register(&pr_region_ctx, mgr_ctx.mgr, test); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_0_ctx.bridge); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_1_ctx.bridge); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + /* Allocate a fake partial test image using a buffer */ >> + test_pr_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_pr_img_info); >> + >> + test_pr_img_info->buf = fake_bit; >> + test_pr_img_info->count = sizeof(fake_bit) / 2; >> + test_pr_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; >> + >> + kunit_info(test, "fake partial bitstream size: %zu\n", test_pr_img_info->count); >> + >> + /* Program the reconfigurable sub-region */ >> + pr_region_ctx.region->info = test_pr_img_info; >> + ret = fpga_region_program_fpga(pr_region_ctx.region); >> + KUNIT_ASSERT_EQ(test, ret, 0); >> + >> + fake_fpga_mgr_check_write_buf(&mgr_ctx); >> + >> + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_0_ctx)); >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_0_ctx)); >> + >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_1_ctx)); >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_1_ctx)); >> + >> + /* Check that the base bridge has not been disabled */ >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >> + >> + fpga_image_info_free(test_pr_img_info); >> + fpga_image_info_free(test_static_img_info); >> + >> + fake_fpga_region_unregister(&pr_region_ctx); >> + fake_fpga_bridge_unregister(&pr_bridge_0_ctx); >> + fake_fpga_bridge_unregister(&pr_bridge_1_ctx); >> + >> + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); > > Same concern, may put them in .exit() or suite_exit()? Same as above, I'll reduce code duplication. > >> +} >> + >> +static struct kunit_case fpga_test_cases[] = { >> + KUNIT_CASE(fpga_base_test), >> + KUNIT_CASE(fpga_pr_test), > > I feel there are too many tasks for each test case, and some duplicated > routines. > > Could we have a suite for the common routine test in each case, like > region/bridge/mgr (un)register, fpga image alloc ... And another suite > which have these common routines in .init() or .suite_init(). > Right, I'll reduce code duplication in the next version. >> + {}, >> +}; >> + >> +static struct kunit_suite fpga_test_suite = { >> + .name = "fpga-tests", > > I see from style.rst that: > > "Names should use underscores, not dashes, to separate words" > > and > > "*Do not* include "test" or "kunit" directly in the subsystem name > unless we are actually testing other tests or the kunit framework > itself" > > So IIUC I assume the name should be "fpga"? > > BTW: I do see some existing test cases that are not conform to the style, > even the examples in doc itself. Thanks for noticing this. I'll change the name in the next version. > > Thanks, > Yilun > >> + .suite_init = fpga_suite_init, >> + .test_cases = fpga_test_cases, >> +}; >> + >> +kunit_test_suite(fpga_test_suite); >> -- >> 2.39.1 >> > Thanks, Marco
On 2023-02-21 at 12:10:48 +0100, Marco Pagani wrote: > > > On 2023-02-18 10:59, Xu Yilun wrote: > > On 2023-02-03 at 18:06:50 +0100, Marco Pagani wrote: > >> Introduce an initial KUnit suite to test the core components of the > >> FPGA subsystem. > > > > I'm not familiar with kunit, and I spend some time to read the > > Documentation/dev-tools/kunit/, sorry for late response. > > Thank you for reviewing. > > > > >> > >> The test suite consists of two test cases. The first test case checks > >> the programming of a static image on a fake FPGA with a single hardware > >> bridge. The FPGA is first programmed using a test image stored in a > >> buffer, and then with the same image linked to a single-entry > >> scatter-gather list. > >> > >> The second test case models dynamic partial reconfiguration. The FPGA > >> is first configured with a static image that implements a > >> reconfigurable design containing a sub-region controlled by two soft > >> bridges. Then, the reconfigurable sub-region is reconfigured using > >> a fake partial bitstream image. After the reconfiguration, the test > >> checks that the soft bridges have been correctly activated. > >> > >> Signed-off-by: Marco Pagani <marpagan@redhat.com> > >> --- > >> drivers/fpga/Kconfig | 2 + > >> drivers/fpga/Makefile | 3 + > >> drivers/fpga/tests/.kunitconfig | 5 + > >> drivers/fpga/tests/Kconfig | 15 ++ > >> drivers/fpga/tests/Makefile | 6 + > >> drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ > >> 6 files changed, 295 insertions(+) > >> create mode 100644 drivers/fpga/tests/.kunitconfig > >> create mode 100644 drivers/fpga/tests/Kconfig > >> create mode 100644 drivers/fpga/tests/Makefile > >> create mode 100644 drivers/fpga/tests/fpga-tests.c > >> > >> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig > >> index 0a00763b9f28..2f689ac4ba3a 100644 > >> --- a/drivers/fpga/Kconfig > >> +++ b/drivers/fpga/Kconfig > >> @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI > >> FPGA manager driver support for Lattice FPGAs programming over slave > >> SPI sysCONFIG interface. > >> > >> +source "drivers/fpga/tests/Kconfig" > >> + > >> endif # FPGA > >> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile > >> index 72e554b4d2f7..352a2612623e 100644 > >> --- a/drivers/fpga/Makefile > >> +++ b/drivers/fpga/Makefile > >> @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o > >> > >> # Drivers for FPGAs which implement DFL > >> obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o > >> + > >> +# KUnit tests > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ > >> diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig > >> new file mode 100644 > >> index 000000000000..a1c2a2974c39 > >> --- /dev/null > >> +++ b/drivers/fpga/tests/.kunitconfig > >> @@ -0,0 +1,5 @@ > >> +CONFIG_KUNIT=y > >> +CONFIG_FPGA=y > >> +CONFIG_FPGA_REGION=y > >> +CONFIG_FPGA_BRIDGE=y > >> +CONFIG_FPGA_KUNIT_TESTS=y > >> diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig > >> new file mode 100644 > >> index 000000000000..5198e605b38d > >> --- /dev/null > >> +++ b/drivers/fpga/tests/Kconfig > >> @@ -0,0 +1,15 @@ > >> +config FPGA_KUNIT_TESTS > >> + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS > >> + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT > >> + default KUNIT_ALL_TESTS > >> + help > >> + Builds unit tests for the FPGA subsystem. This option > >> + is not useful for distributions or general kernels, > >> + but only for kernel developers working on the FPGA > >> + subsystem and its associated drivers. > >> + > >> + For more information on KUnit and unit tests in general, > >> + please refer to the KUnit documentation in > >> + Documentation/dev-tools/kunit/. > >> + > >> + If in doubt, say "N". > >> diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile > >> new file mode 100644 > >> index 000000000000..74346ae62457 > >> --- /dev/null > >> +++ b/drivers/fpga/tests/Makefile > >> @@ -0,0 +1,6 @@ > >> +# SPDX-License-Identifier: GPL-2.0 > >> + > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o > > > > It is better the patches for fake components come first, otherwise may > > break the compilation. Also not friendly for review. > > Sorry. I'll change the order in the next version. > > > > >> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o > > > > Maybe fpga-test.o? > > I'll change the name in the next version. > > > > > And could they be built in a single module? I haven't find a reason > > these fake components been used alone. > > > > My feeling is that they could also come in handy to do some general > development or testing on the subsystem. For instance, I used the fake > FPGA manager in isolation to experiment with the OF region. That's fine. > > Initially, the fake manager also had an of_device_id device matching > struct. However, I later removed it because it was not used for the > test setup, and I was not sure if adding an OF device matching struct > was acceptable for a test driver. > > >> diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c > >> new file mode 100644 > >> index 000000000000..33f04079b32f > >> --- /dev/null > >> +++ b/drivers/fpga/tests/fpga-tests.c > >> @@ -0,0 +1,264 @@ > >> +// SPDX-License-Identifier: GPL-2.0 > >> +/* > >> + * Test suite for the FPGA subsystem > >> + * > >> + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. > >> + * > >> + * Author: Marco Pagani <marpagan@redhat.com> > >> + */ > >> + > >> +#include <kunit/test.h> > >> +#include <linux/platform_device.h> > >> +#include <linux/scatterlist.h> > >> + > >> +#include <linux/fpga/fpga-mgr.h> > >> +#include <linux/fpga/fpga-region.h> > >> +#include <linux/fpga/fpga-bridge.h> > >> + > >> +#include "fake-fpga-region.h" > >> +#include "fake-fpga-bridge.h" > >> +#include "fake-fpga-mgr.h" > >> + > >> +#define FAKE_BIT_BLOCKS 16 > >> +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) > >> + > >> +static u8 fake_bit[FAKE_BIT_SIZE]; > >> + > >> +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) > >> +{ > >> + int ret; > >> + > >> + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > >> + if (ret) > >> + return ret; > >> + > >> + sg_init_one(sgt->sgl, bit, len); > >> + > >> + return ret; > >> +} > >> + > >> +static void free_sgt_bit(struct sg_table *sgt) > >> +{ > >> + if (sgt) > >> + sg_free_table(sgt); > >> +} > >> + > >> +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, > >> + struct fake_fpga_bridge *bridge_ctx, > >> + struct fake_fpga_region *region_ctx) > >> +{ > >> + int ret; > >> + > >> + ret = fake_fpga_mgr_register(mgr_ctx, test); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > >> + > >> + ret = fake_fpga_bridge_register(bridge_ctx, test); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > >> + > >> + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > >> + > >> + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > >> +} > >> + > >> +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, > >> + struct fake_fpga_bridge *bridge_ctx, > >> + struct fake_fpga_region *region_ctx) > >> +{ > >> + if (region_ctx) > >> + fake_fpga_region_unregister(region_ctx); > >> + > >> + if (bridge_ctx) > >> + fake_fpga_bridge_unregister(bridge_ctx); > >> + > >> + if (region_ctx) > >> + fake_fpga_mgr_unregister(mgr_ctx); > >> +} > >> + > >> +static int fpga_suite_init(struct kunit_suite *suite) > >> +{ > >> + fake_fpga_mgr_fill_header(fake_bit); > > > > Do we need to run it before every case? Or just run once for all cases? > > > > Just once for all cases. So I'm calling it from the suite_init function. > > For the next version, I'm thinking of allocating the image buffer using > kunit_kzalloc() instead of using a global static array. > > >> + > >> + return 0; > >> +} > >> + > >> +static void fpga_base_test(struct kunit *test) > >> +{ > >> + int ret; > >> + > >> + struct fake_fpga_mgr mgr_ctx; > >> + struct fake_fpga_bridge base_bridge_ctx; > >> + struct fake_fpga_region base_region_ctx; > >> + > >> + struct fpga_image_info *test_img_info; > >> + > >> + struct sg_table sgt_bit; > >> + > >> + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); > >> + > >> + /* Allocate a fake test image using a buffer */ > >> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > >> + > >> + test_img_info->buf = fake_bit; > >> + test_img_info->count = sizeof(fake_bit); > >> + > >> + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); > >> + > >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > >> + > >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); > >> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > >> + > >> + /* Program the fake FPGA using the image buffer */ > >> + base_region_ctx.region->info = test_img_info; > >> + ret = fpga_region_program_fpga(base_region_ctx.region); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > >> + > >> + fake_fpga_mgr_check_write_buf(&mgr_ctx); > >> + > >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); > >> + > >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); > >> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); > >> + > >> + fpga_image_info_free(test_img_info); > >> + > >> + /* Allocate another fake test image using a scatter list */ > >> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); > >> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); > >> + > >> + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); > >> + KUNIT_ASSERT_EQ(test, ret, 0); > > > > This is not fpga function, do we need the ASSERT? > > > > You're right. I'll change it to EXPECT. Mm.. I think we may move the sgt initialization in .suite_init, and just return ERROR for failure. Does it help to quickly find out this is an ENV error, not a test case failure? Thanks, Yilun
On 2023-02-24 07:14, Xu Yilun wrote: > On 2023-02-21 at 12:10:48 +0100, Marco Pagani wrote: >> >> >> On 2023-02-18 10:59, Xu Yilun wrote: >>> On 2023-02-03 at 18:06:50 +0100, Marco Pagani wrote: >>>> Introduce an initial KUnit suite to test the core components of the >>>> FPGA subsystem. >>> >>> I'm not familiar with kunit, and I spend some time to read the >>> Documentation/dev-tools/kunit/, sorry for late response. >> >> Thank you for reviewing. >> >>> >>>> >>>> The test suite consists of two test cases. The first test case checks >>>> the programming of a static image on a fake FPGA with a single hardware >>>> bridge. The FPGA is first programmed using a test image stored in a >>>> buffer, and then with the same image linked to a single-entry >>>> scatter-gather list. >>>> >>>> The second test case models dynamic partial reconfiguration. The FPGA >>>> is first configured with a static image that implements a >>>> reconfigurable design containing a sub-region controlled by two soft >>>> bridges. Then, the reconfigurable sub-region is reconfigured using >>>> a fake partial bitstream image. After the reconfiguration, the test >>>> checks that the soft bridges have been correctly activated. >>>> >>>> Signed-off-by: Marco Pagani <marpagan@redhat.com> >>>> --- >>>> drivers/fpga/Kconfig | 2 + >>>> drivers/fpga/Makefile | 3 + >>>> drivers/fpga/tests/.kunitconfig | 5 + >>>> drivers/fpga/tests/Kconfig | 15 ++ >>>> drivers/fpga/tests/Makefile | 6 + >>>> drivers/fpga/tests/fpga-tests.c | 264 ++++++++++++++++++++++++++++++++ >>>> 6 files changed, 295 insertions(+) >>>> create mode 100644 drivers/fpga/tests/.kunitconfig >>>> create mode 100644 drivers/fpga/tests/Kconfig >>>> create mode 100644 drivers/fpga/tests/Makefile >>>> create mode 100644 drivers/fpga/tests/fpga-tests.c >>>> >>>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig >>>> index 0a00763b9f28..2f689ac4ba3a 100644 >>>> --- a/drivers/fpga/Kconfig >>>> +++ b/drivers/fpga/Kconfig >>>> @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI >>>> FPGA manager driver support for Lattice FPGAs programming over slave >>>> SPI sysCONFIG interface. >>>> >>>> +source "drivers/fpga/tests/Kconfig" >>>> + >>>> endif # FPGA >>>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile >>>> index 72e554b4d2f7..352a2612623e 100644 >>>> --- a/drivers/fpga/Makefile >>>> +++ b/drivers/fpga/Makefile >>>> @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o >>>> >>>> # Drivers for FPGAs which implement DFL >>>> obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o >>>> + >>>> +# KUnit tests >>>> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ >>>> diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig >>>> new file mode 100644 >>>> index 000000000000..a1c2a2974c39 >>>> --- /dev/null >>>> +++ b/drivers/fpga/tests/.kunitconfig >>>> @@ -0,0 +1,5 @@ >>>> +CONFIG_KUNIT=y >>>> +CONFIG_FPGA=y >>>> +CONFIG_FPGA_REGION=y >>>> +CONFIG_FPGA_BRIDGE=y >>>> +CONFIG_FPGA_KUNIT_TESTS=y >>>> diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig >>>> new file mode 100644 >>>> index 000000000000..5198e605b38d >>>> --- /dev/null >>>> +++ b/drivers/fpga/tests/Kconfig >>>> @@ -0,0 +1,15 @@ >>>> +config FPGA_KUNIT_TESTS >>>> + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS >>>> + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT >>>> + default KUNIT_ALL_TESTS >>>> + help >>>> + Builds unit tests for the FPGA subsystem. This option >>>> + is not useful for distributions or general kernels, >>>> + but only for kernel developers working on the FPGA >>>> + subsystem and its associated drivers. >>>> + >>>> + For more information on KUnit and unit tests in general, >>>> + please refer to the KUnit documentation in >>>> + Documentation/dev-tools/kunit/. >>>> + >>>> + If in doubt, say "N". >>>> diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile >>>> new file mode 100644 >>>> index 000000000000..74346ae62457 >>>> --- /dev/null >>>> +++ b/drivers/fpga/tests/Makefile >>>> @@ -0,0 +1,6 @@ >>>> +# SPDX-License-Identifier: GPL-2.0 >>>> + >>>> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o >>>> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o >>>> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o >>> >>> It is better the patches for fake components come first, otherwise may >>> break the compilation. Also not friendly for review. >> >> Sorry. I'll change the order in the next version. >> >>> >>>> +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o >>> >>> Maybe fpga-test.o? >> >> I'll change the name in the next version. >> >>> >>> And could they be built in a single module? I haven't find a reason >>> these fake components been used alone. >>> >> >> My feeling is that they could also come in handy to do some general >> development or testing on the subsystem. For instance, I used the fake >> FPGA manager in isolation to experiment with the OF region. > > That's fine. > >> >> Initially, the fake manager also had an of_device_id device matching >> struct. However, I later removed it because it was not used for the >> test setup, and I was not sure if adding an OF device matching struct >> was acceptable for a test driver. >> >>>> diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c >>>> new file mode 100644 >>>> index 000000000000..33f04079b32f >>>> --- /dev/null >>>> +++ b/drivers/fpga/tests/fpga-tests.c >>>> @@ -0,0 +1,264 @@ >>>> +// SPDX-License-Identifier: GPL-2.0 >>>> +/* >>>> + * Test suite for the FPGA subsystem >>>> + * >>>> + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. >>>> + * >>>> + * Author: Marco Pagani <marpagan@redhat.com> >>>> + */ >>>> + >>>> +#include <kunit/test.h> >>>> +#include <linux/platform_device.h> >>>> +#include <linux/scatterlist.h> >>>> + >>>> +#include <linux/fpga/fpga-mgr.h> >>>> +#include <linux/fpga/fpga-region.h> >>>> +#include <linux/fpga/fpga-bridge.h> >>>> + >>>> +#include "fake-fpga-region.h" >>>> +#include "fake-fpga-bridge.h" >>>> +#include "fake-fpga-mgr.h" >>>> + >>>> +#define FAKE_BIT_BLOCKS 16 >>>> +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) >>>> + >>>> +static u8 fake_bit[FAKE_BIT_SIZE]; >>>> + >>>> +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) >>>> +{ >>>> + int ret; >>>> + >>>> + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); >>>> + if (ret) >>>> + return ret; >>>> + >>>> + sg_init_one(sgt->sgl, bit, len); >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +static void free_sgt_bit(struct sg_table *sgt) >>>> +{ >>>> + if (sgt) >>>> + sg_free_table(sgt); >>>> +} >>>> + >>>> +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, >>>> + struct fake_fpga_bridge *bridge_ctx, >>>> + struct fake_fpga_region *region_ctx) >>>> +{ >>>> + int ret; >>>> + >>>> + ret = fake_fpga_mgr_register(mgr_ctx, test); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>>> + >>>> + ret = fake_fpga_bridge_register(bridge_ctx, test); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>>> + >>>> + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>>> + >>>> + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>>> +} >>>> + >>>> +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, >>>> + struct fake_fpga_bridge *bridge_ctx, >>>> + struct fake_fpga_region *region_ctx) >>>> +{ >>>> + if (region_ctx) >>>> + fake_fpga_region_unregister(region_ctx); >>>> + >>>> + if (bridge_ctx) >>>> + fake_fpga_bridge_unregister(bridge_ctx); >>>> + >>>> + if (region_ctx) >>>> + fake_fpga_mgr_unregister(mgr_ctx); >>>> +} >>>> + >>>> +static int fpga_suite_init(struct kunit_suite *suite) >>>> +{ >>>> + fake_fpga_mgr_fill_header(fake_bit); >>> >>> Do we need to run it before every case? Or just run once for all cases? >>> >> >> Just once for all cases. So I'm calling it from the suite_init function. >> >> For the next version, I'm thinking of allocating the image buffer using >> kunit_kzalloc() instead of using a global static array. >> >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static void fpga_base_test(struct kunit *test) >>>> +{ >>>> + int ret; >>>> + >>>> + struct fake_fpga_mgr mgr_ctx; >>>> + struct fake_fpga_bridge base_bridge_ctx; >>>> + struct fake_fpga_region base_region_ctx; >>>> + >>>> + struct fpga_image_info *test_img_info; >>>> + >>>> + struct sg_table sgt_bit; >>>> + >>>> + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); >>>> + >>>> + /* Allocate a fake test image using a buffer */ >>>> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >>>> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); >>>> + >>>> + test_img_info->buf = fake_bit; >>>> + test_img_info->count = sizeof(fake_bit); >>>> + >>>> + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); >>>> + >>>> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >>>> + >>>> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); >>>> + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >>>> + >>>> + /* Program the fake FPGA using the image buffer */ >>>> + base_region_ctx.region->info = test_img_info; >>>> + ret = fpga_region_program_fpga(base_region_ctx.region); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>>> + >>>> + fake_fpga_mgr_check_write_buf(&mgr_ctx); >>>> + >>>> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); >>>> + >>>> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); >>>> + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); >>>> + >>>> + fpga_image_info_free(test_img_info); >>>> + >>>> + /* Allocate another fake test image using a scatter list */ >>>> + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); >>>> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); >>>> + >>>> + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); >>>> + KUNIT_ASSERT_EQ(test, ret, 0); >>> >>> This is not fpga function, do we need the ASSERT? >>> >> >> You're right. I'll change it to EXPECT. > > Mm.. I think we may move the sgt initialization in .suite_init, and just > return ERROR for failure. Does it help to quickly find out this is an > ENV error, not a test case failure? I looked through the documentation for guidelines on how to handle initialization errors, but found only the eeprom example where KUNIT_ASSERT is used to handle errors in eeprom_buffer_test_init(). Existing test suites seem to use different approaches to handle initialization errors. Some return an error code, while others use KUnit assertions. I'm more inclined to follow the example in the documentation and use KUnit assertions. Does this approach work for you? After some thought, I'm restructuring the code to test single components in isolation before testing them together. In this way, I think the test suite will be more in line with the unit testing methodology. Thanks, Marco
> >>>> + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); > >>>> + KUNIT_ASSERT_EQ(test, ret, 0); > >>> > >>> This is not fpga function, do we need the ASSERT? > >>> > >> > >> You're right. I'll change it to EXPECT. > > > > Mm.. I think we may move the sgt initialization in .suite_init, and just > > return ERROR for failure. Does it help to quickly find out this is an > > ENV error, not a test case failure? > > I looked through the documentation for guidelines on how to handle > initialization errors, but found only the eeprom example where KUNIT_ASSERT > is used to handle errors in eeprom_buffer_test_init(). Existing test suites > seem to use different approaches to handle initialization errors. Some > return an error code, while others use KUnit assertions. > > I'm more inclined to follow the example in the documentation and use > KUnit assertions. Does this approach work for you? It's good to me. > > > After some thought, I'm restructuring the code to test single components > in isolation before testing them together. In this way, I think the test > suite will be more in line with the unit testing methodology. > > > Thanks, > Marco >
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 0a00763b9f28..2f689ac4ba3a 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -276,4 +276,6 @@ config FPGA_MGR_LATTICE_SYSCONFIG_SPI FPGA manager driver support for Lattice FPGAs programming over slave SPI sysCONFIG interface. +source "drivers/fpga/tests/Kconfig" + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 72e554b4d2f7..352a2612623e 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -55,3 +55,6 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o + +# KUnit tests +obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ diff --git a/drivers/fpga/tests/.kunitconfig b/drivers/fpga/tests/.kunitconfig new file mode 100644 index 000000000000..a1c2a2974c39 --- /dev/null +++ b/drivers/fpga/tests/.kunitconfig @@ -0,0 +1,5 @@ +CONFIG_KUNIT=y +CONFIG_FPGA=y +CONFIG_FPGA_REGION=y +CONFIG_FPGA_BRIDGE=y +CONFIG_FPGA_KUNIT_TESTS=y diff --git a/drivers/fpga/tests/Kconfig b/drivers/fpga/tests/Kconfig new file mode 100644 index 000000000000..5198e605b38d --- /dev/null +++ b/drivers/fpga/tests/Kconfig @@ -0,0 +1,15 @@ +config FPGA_KUNIT_TESTS + tristate "FPGA KUnit tests" if !KUNIT_ALL_TESTS + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT + default KUNIT_ALL_TESTS + help + Builds unit tests for the FPGA subsystem. This option + is not useful for distributions or general kernels, + but only for kernel developers working on the FPGA + subsystem and its associated drivers. + + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + + If in doubt, say "N". diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile new file mode 100644 index 000000000000..74346ae62457 --- /dev/null +++ b/drivers/fpga/tests/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-mgr.o +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-region.o +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fake-fpga-bridge.o +obj-$(CONFIG_FPGA_KUNIT_TESTS) += fpga-tests.o diff --git a/drivers/fpga/tests/fpga-tests.c b/drivers/fpga/tests/fpga-tests.c new file mode 100644 index 000000000000..33f04079b32f --- /dev/null +++ b/drivers/fpga/tests/fpga-tests.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test suite for the FPGA subsystem + * + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. + * + * Author: Marco Pagani <marpagan@redhat.com> + */ + +#include <kunit/test.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> + +#include <linux/fpga/fpga-mgr.h> +#include <linux/fpga/fpga-region.h> +#include <linux/fpga/fpga-bridge.h> + +#include "fake-fpga-region.h" +#include "fake-fpga-bridge.h" +#include "fake-fpga-mgr.h" + +#define FAKE_BIT_BLOCKS 16 +#define FAKE_BIT_SIZE (FPGA_TEST_BIT_BLOCK * FAKE_BIT_BLOCKS) + +static u8 fake_bit[FAKE_BIT_SIZE]; + +static int init_sgt_bit(struct sg_table *sgt, void *bit, size_t len) +{ + int ret; + + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + if (ret) + return ret; + + sg_init_one(sgt->sgl, bit, len); + + return ret; +} + +static void free_sgt_bit(struct sg_table *sgt) +{ + if (sgt) + sg_free_table(sgt); +} + +static void fpga_build_base_sys(struct kunit *test, struct fake_fpga_mgr *mgr_ctx, + struct fake_fpga_bridge *bridge_ctx, + struct fake_fpga_region *region_ctx) +{ + int ret; + + ret = fake_fpga_mgr_register(mgr_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_bridge_register(bridge_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_region_register(region_ctx, mgr_ctx->mgr, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_region_add_bridge(region_ctx, bridge_ctx->bridge); + KUNIT_ASSERT_EQ(test, ret, 0); +} + +static void fpga_free_base_sys(struct fake_fpga_mgr *mgr_ctx, + struct fake_fpga_bridge *bridge_ctx, + struct fake_fpga_region *region_ctx) +{ + if (region_ctx) + fake_fpga_region_unregister(region_ctx); + + if (bridge_ctx) + fake_fpga_bridge_unregister(bridge_ctx); + + if (region_ctx) + fake_fpga_mgr_unregister(mgr_ctx); +} + +static int fpga_suite_init(struct kunit_suite *suite) +{ + fake_fpga_mgr_fill_header(fake_bit); + + return 0; +} + +static void fpga_base_test(struct kunit *test) +{ + int ret; + + struct fake_fpga_mgr mgr_ctx; + struct fake_fpga_bridge base_bridge_ctx; + struct fake_fpga_region base_region_ctx; + + struct fpga_image_info *test_img_info; + + struct sg_table sgt_bit; + + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); + + /* Allocate a fake test image using a buffer */ + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); + + test_img_info->buf = fake_bit; + test_img_info->count = sizeof(fake_bit); + + kunit_info(test, "fake bitstream size: %zu\n", test_img_info->count); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + /* Program the fake FPGA using the image buffer */ + base_region_ctx.region->info = test_img_info; + ret = fpga_region_program_fpga(base_region_ctx.region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(&mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + fpga_image_info_free(test_img_info); + + /* Allocate another fake test image using a scatter list */ + test_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_img_info); + + ret = init_sgt_bit(&sgt_bit, fake_bit, FAKE_BIT_SIZE); + KUNIT_ASSERT_EQ(test, ret, 0); + + test_img_info->sgt = &sgt_bit; + + /* Re-program the fake FPGA using the image scatter list */ + base_region_ctx.region->info = test_img_info; + ret = fpga_region_program_fpga(base_region_ctx.region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_sg(&mgr_ctx); + + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + free_sgt_bit(&sgt_bit); + fpga_image_info_free(test_img_info); + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); +} + +static void fpga_pr_test(struct kunit *test) +{ + int ret; + + struct fake_fpga_mgr mgr_ctx; + struct fake_fpga_bridge base_bridge_ctx; + struct fake_fpga_region base_region_ctx; + + struct fake_fpga_bridge pr_bridge_0_ctx; + struct fake_fpga_bridge pr_bridge_1_ctx; + struct fake_fpga_region pr_region_ctx; + + struct fpga_image_info *test_static_img_info; + struct fpga_image_info *test_pr_img_info; + + fpga_build_base_sys(test, &mgr_ctx, &base_bridge_ctx, &base_region_ctx); + + /* Allocate a fake test image using a buffer */ + test_static_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_static_img_info); + + test_static_img_info->buf = fake_bit; + test_static_img_info->count = sizeof(fake_bit); + + kunit_info(test, "fake bitstream size: %zu\n", test_static_img_info->count); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + /* Program the fake FPGA using the image buffer */ + base_region_ctx.region->info = test_static_img_info; + ret = fpga_region_program_fpga(base_region_ctx.region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(&mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + /* The static image contains a reconfigurable sub-region with two soft bridges */ + ret = fake_fpga_bridge_register(&pr_bridge_0_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_bridge_register(&pr_bridge_1_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_region_register(&pr_region_ctx, mgr_ctx.mgr, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_0_ctx.bridge); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret = fake_fpga_region_add_bridge(&pr_region_ctx, pr_bridge_1_ctx.bridge); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* Allocate a fake partial test image using a buffer */ + test_pr_img_info = fpga_image_info_alloc(&mgr_ctx.pdev->dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_pr_img_info); + + test_pr_img_info->buf = fake_bit; + test_pr_img_info->count = sizeof(fake_bit) / 2; + test_pr_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; + + kunit_info(test, "fake partial bitstream size: %zu\n", test_pr_img_info->count); + + /* Program the reconfigurable sub-region */ + pr_region_ctx.region->info = test_pr_img_info; + ret = fpga_region_program_fpga(pr_region_ctx.region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(&mgr_ctx); + + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(&mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_0_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_0_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&pr_bridge_1_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&pr_bridge_1_ctx)); + + /* Check that the base bridge has not been disabled */ + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(&base_bridge_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(&base_bridge_ctx)); + + fpga_image_info_free(test_pr_img_info); + fpga_image_info_free(test_static_img_info); + + fake_fpga_region_unregister(&pr_region_ctx); + fake_fpga_bridge_unregister(&pr_bridge_0_ctx); + fake_fpga_bridge_unregister(&pr_bridge_1_ctx); + + fpga_free_base_sys(&mgr_ctx, &base_bridge_ctx, &base_region_ctx); +} + +static struct kunit_case fpga_test_cases[] = { + KUNIT_CASE(fpga_base_test), + KUNIT_CASE(fpga_pr_test), + {}, +}; + +static struct kunit_suite fpga_test_suite = { + .name = "fpga-tests", + .suite_init = fpga_suite_init, + .test_cases = fpga_test_cases, +}; + +kunit_test_suite(fpga_test_suite);