From patchwork Fri Mar 10 17:04:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 67598 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp998407wrd; Fri, 10 Mar 2023 09:24:13 -0800 (PST) X-Google-Smtp-Source: AK7set9TzR4slaHMGb1roZ+To/bVggzCtsCytVDsh/cbeOHPjLo0LNkgyp0e6IsBboHwsK0KwVxO X-Received: by 2002:a17:902:ab4f:b0:19a:9897:461 with SMTP id ij15-20020a170902ab4f00b0019a98970461mr20648114plb.52.1678469053607; Fri, 10 Mar 2023 09:24:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678469053; cv=none; d=google.com; s=arc-20160816; b=bWZG2UAt/iE8auHK1+DCLqty2H2gq/bX/99JHQS9ql748JEsyDE6Gq+0duJ7buviII KK7MGC5lpfzsY1w0F/aQe2FpQ8ubUN3wLLRZsjSRtSWFooz33mfG5pqAxRE+Z3Ic6rqa jrBYzGHmyNHejGkjh1TQ/SGSAM7E/8/mROVtu19AH4P6Zgg9fVI2My5YhPvpT9TyKuWC qp5x2GLgS50iOnXXFrBLbsWEryDe32ckGlsDYOZddqUkoM1Kt1BipIJibxyj8axrAfKf DFTpiRK5z+Zg/bhui0s3M5y/nZALwKE/qmYa/QLtfEugx/qk00AcGmFnGEjj5/jVyk4m PQpA== 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=ar/llKR8abJ7wDatTJh3Vi/fK/K7kyCaNJ9z2TjsCKo=; b=zlTrd7GjB/TksHwViW6/kWx6LkgQsZ4k4OHMHg0MrOAqYMzio7oPRH79h//5SuDsPN VYUvjbrBP4qqzybLrc0iNdln/FkKFDL6Z3esJksVJOnsCeE10lTmegwCnxF+uhlzuOif 5Wox7qL6VHRokUezPxKXIJGfMT2ENpBvfthKCmQcFc7HpWI9Cn7vX8odwzeQ6LFTmyeX 85TSjmx/DMq60w7qgjTd0WxqTUY72/+Cpkxxkb1IMep3PU0Fzj8nP5TVNPlHt2mNvH/Y s46xrQnn8oUMCyyi5nQVOrBt349pxUs7qz5RzAVzRfiylThvUYNWQVfjY14/GvYldgx+ RkfQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=SK6zOqpA; 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 e32-20020a630f20000000b00502e27a4e6esi238371pgl.617.2023.03.10.09.23.59; Fri, 10 Mar 2023 09:24:13 -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=SK6zOqpA; 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 S231690AbjCJRHB (ORCPT + 99 others); Fri, 10 Mar 2023 12:07:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231479AbjCJRGi (ORCPT ); Fri, 10 Mar 2023 12:06:38 -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 2CF5A12970C for ; Fri, 10 Mar 2023 09:04:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1678467861; 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=ar/llKR8abJ7wDatTJh3Vi/fK/K7kyCaNJ9z2TjsCKo=; b=SK6zOqpASh+ApF9xOhBjL02n+B/pj0522LsYPFHM7MvFsbMUaHro8mHok/YrZKGHzLSKFS 4NrNRsm+y1uZNmHmKMPc+tUW85+qu6YoywHUzzXR9xbsi+JkimvbcAmg05ct2ua39IxrXw 9pDrkOuU2Yo+cB8KppSG5PoBKxCEEfo= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-463-fSGIhcbKOVm3TjUy1JIU-A-1; Fri, 10 Mar 2023 12:04:20 -0500 X-MC-Unique: fSGIhcbKOVm3TjUy1JIU-A-1 Received: by mail-wr1-f69.google.com with SMTP id d14-20020adfa34e000000b002bfc062eaa8so1185737wrb.20 for ; Fri, 10 Mar 2023 09:04:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678467859; 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=ar/llKR8abJ7wDatTJh3Vi/fK/K7kyCaNJ9z2TjsCKo=; b=LM5TtZ5x85Yau62vqqaaBtE2psJFu7/QrCyVJuoXw7fl7D/gg4mkddDJVUVpgCfO/A log1SAqsMDjjGmoiB4PA4CkfmHlMidUa7jEe1ThGObyV/tHQlxsELEh5o4WgTkPqKKkr W2hI9YWxldUL2fCuw8h0pf5sc3ovZMz01vT9W6eqmPkvMu+qEjGEzpnC5UPcpxrHXhAY rmdY8A331F81VuYvrrn/S6NK7v2fZuiXVkswH5kHjyYLGnIQNlZbEcrJsIivQlKIcBhY QnbqBYJQtXsF2OcOrnWcEpMbYs29A61YHWviMV8R5bRfwVZ8XhQMYFkrRr3schjIsOow 3jDg== X-Gm-Message-State: AO0yUKV1SC0VR+TMgAnectAskJ4QRiWAKaHksBsScKt4j/C06aZk2ZU+ SUVqx5WbgEYBVBkWW83LuIi4lT/yBBLSylB/t3yK68d6r6xPM629gIobzrli5jfZV9PoepARqrB 2t8sd8iemmoRBG46RtHnsNaQ= X-Received: by 2002:a05:600c:314c:b0:3eb:2f06:c989 with SMTP id h12-20020a05600c314c00b003eb2f06c989mr3429934wmo.22.1678467858997; Fri, 10 Mar 2023 09:04:18 -0800 (PST) X-Received: by 2002:a05:600c:314c:b0:3eb:2f06:c989 with SMTP id h12-20020a05600c314c00b003eb2f06c989mr3429901wmo.22.1678467858683; Fri, 10 Mar 2023 09:04:18 -0800 (PST) Received: from klayman.redhat.com (net-2-34-29-20.cust.vodafonedsl.it. [2.34.29.20]) by smtp.gmail.com with ESMTPSA id u10-20020a05600c00ca00b003eb192787bfsm417294wmm.25.2023.03.10.09.04.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Mar 2023 09:04:18 -0800 (PST) From: Marco Pagani To: Moritz Fischer , Wu Hao , Xu Yilun , Tom Rix Cc: Marco Pagani , linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [RFC PATCH v2 1/4] fpga: add fake FPGA manager Date: Fri, 10 Mar 2023 18:04:09 +0100 Message-Id: <20230310170412.708363-2-marpagan@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230310170412.708363-1-marpagan@redhat.com> References: <20230310170412.708363-1-marpagan@redhat.com> MIME-Version: 1.0 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: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760002366186389531?= X-GMAIL-MSGID: =?utf-8?q?1760002366186389531?= Add fake FPGA manager platform driver with support functions. The driver checks the programming sequence using KUnit expectations. This module is part of the KUnit tests for the FPGA subsystem. Signed-off-by: Marco Pagani --- drivers/fpga/tests/fake-fpga-mgr.c | 369 +++++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-mgr.h | 42 ++++ 2 files changed, 411 insertions(+) create mode 100644 drivers/fpga/tests/fake-fpga-mgr.c create mode 100644 drivers/fpga/tests/fake-fpga-mgr.h diff --git a/drivers/fpga/tests/fake-fpga-mgr.c b/drivers/fpga/tests/fake-fpga-mgr.c new file mode 100644 index 000000000000..1bca6baeb0e5 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-mgr.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the fake FPGA manager + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#include +#include +#include +#include +#include + +#include "fake-fpga-mgr.h" + +#define FAKE_FPGA_MGR_DEV_NAME "fake_fpga_mgr" + +#define FAKE_HEADER_BYTE 0x3f +#define FAKE_HEADER_SIZE FPGA_IMG_BLOCK + +struct fake_mgr_priv { + int rcfg_count; + bool op_parse_header; + bool op_write_init; + bool op_write; + bool op_write_sg; + bool op_write_complete; + struct kunit *test; +}; + +struct fake_mgr_data { + struct kunit *test; +}; + +static void check_header(struct kunit *test, const u8 *buf); + +static enum fpga_mgr_states op_state(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA manager: state\n"); + + return FPGA_MGR_STATE_UNKNOWN; +} + +static u64 op_status(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA manager: status\n"); + + return 0; +} + +static int op_parse_header(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) { + kunit_info(priv->test, "Fake FPGA manager: parse_header\n"); + + KUNIT_EXPECT_EQ(priv->test, mgr->state, + FPGA_MGR_STATE_PARSE_HEADER); + + check_header(priv->test, buf); + } + + priv->op_parse_header = true; + + return 0; +} + +static int op_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) { + kunit_info(priv->test, "Fake FPGA manager: write_init\n"); + + KUNIT_EXPECT_EQ(priv->test, mgr->state, + FPGA_MGR_STATE_WRITE_INIT); + } + + priv->op_write_init = true; + + return 0; +} + +static int op_write(struct fpga_manager *mgr, const char *buf, size_t count) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) { + kunit_info(priv->test, "Fake FPGA manager: write\n"); + + KUNIT_EXPECT_EQ(priv->test, mgr->state, + FPGA_MGR_STATE_WRITE); + } + + priv->op_write = true; + + return 0; +} + +static int op_write_sg(struct fpga_manager *mgr, struct sg_table *sgt) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) { + kunit_info(priv->test, "Fake FPGA manager: write_sg\n"); + + KUNIT_EXPECT_EQ(priv->test, mgr->state, + FPGA_MGR_STATE_WRITE); + } + + priv->op_write_sg = true; + + return 0; +} + +static int op_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) { + kunit_info(priv->test, "Fake FPGA manager: write_complete\n"); + + KUNIT_EXPECT_EQ(priv->test, mgr->state, + FPGA_MGR_STATE_WRITE_COMPLETE); + } + + priv->op_write_complete = true; + priv->rcfg_count++; + + return 0; +} + +static void op_fpga_remove(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA manager: remove\n"); +} + +static const struct fpga_manager_ops fake_fpga_mgr_ops = { + .initial_header_size = FAKE_HEADER_SIZE, + .skip_header = false, + .state = op_state, + .status = op_status, + .parse_header = op_parse_header, + .write_init = op_write_init, + .write = op_write, + .write_sg = op_write_sg, + .write_complete = op_write_complete, + .fpga_remove = op_fpga_remove, +}; + +/** + * fake_fpga_mgr_register() - register a fake FPGA manager. + * @mgr_ctx: fake FPGA manager context data structure. + * @test: KUnit test context object. + * + * Return: 0 if registration succeeded, an error code otherwise. + */ +int fake_fpga_mgr_register(struct fake_fpga_mgr *mgr_ctx, struct kunit *test) +{ + struct fake_mgr_data pdata; + int ret; + + pdata.test = test; + + mgr_ctx->pdev = platform_device_alloc(FAKE_FPGA_MGR_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (IS_ERR_OR_NULL(mgr_ctx->pdev)) { + pr_err("Fake FPGA manager device allocation failed\n"); + return -ENOMEM; + } + + platform_device_add_data(mgr_ctx->pdev, &pdata, sizeof(pdata)); + + ret = platform_device_add(mgr_ctx->pdev); + if (ret) { + pr_err("Fake FPGA manager device add failed\n"); + platform_device_put(mgr_ctx->pdev); + return ret; + } + + mgr_ctx->mgr = platform_get_drvdata(mgr_ctx->pdev); + + if (test) + kunit_info(test, "Fake FPGA manager registered\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_register); + +/** + * fake_fpga_mgr_unregister() - unregister a fake FPGA manager. + * @mgr_ctx: fake FPGA manager context data structure. + */ +void fake_fpga_mgr_unregister(struct fake_fpga_mgr *mgr_ctx) +{ + struct fake_mgr_priv *priv; + struct kunit *test; + + if (!mgr_ctx) + return; + + priv = mgr_ctx->mgr->priv; + test = priv->test; + + if (mgr_ctx->pdev) { + platform_device_unregister(mgr_ctx->pdev); + if (test) + kunit_info(test, "Fake FPGA manager unregistered\n"); + } +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_unregister); + +/** + * fake_fpga_mgr_get_rcfg_count() - get the number of reconfigurations. + * @mgr_ctx: fake FPGA manager context data structure. + * + * Return: number of reconfigurations. + */ +int fake_fpga_mgr_get_rcfg_count(const struct fake_fpga_mgr *mgr_ctx) +{ + struct fake_mgr_priv *priv; + + priv = mgr_ctx->mgr->priv; + + return priv->rcfg_count; +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_get_rcfg_count); + +/** + * fake_fpga_mgr_fill_header() - fill an image buffer with the test header. + * @buf: image buffer. + */ +void fake_fpga_mgr_fill_header(u8 *buf) +{ + int i; + + for (i = 0; i < FAKE_HEADER_SIZE; i++) + buf[i] = FAKE_HEADER_BYTE; +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_fill_header); + +static void check_header(struct kunit *test, const u8 *buf) +{ + int i; + + for (i = 0; i < FAKE_HEADER_SIZE; i++) + KUNIT_EXPECT_EQ(test, buf[i], FAKE_HEADER_BYTE); +} + +static void clear_op_flags(struct fake_mgr_priv *priv) +{ + priv->op_parse_header = false; + priv->op_write_init = false; + priv->op_write = false; + priv->op_write_sg = false; + priv->op_write_complete = false; +} + +/** + * fake_fpga_mgr_check_write_buf() - check if programming using a buffer succeeded. + * @mgr_ctx: fake FPGA manager context data structure. + */ +void fake_fpga_mgr_check_write_buf(struct fake_fpga_mgr *mgr_ctx) +{ + struct fake_mgr_priv *priv; + + priv = mgr_ctx->mgr->priv; + + if (priv->test) { + KUNIT_EXPECT_EQ(priv->test, priv->op_parse_header, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write_init, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write_complete, true); + } + + clear_op_flags(priv); +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_check_write_buf); + +/** + * fake_fpga_mgr_check_write_sgt() - check if programming using a s.g. table succeeded. + * @mgr_ctx: fake FPGA manager context data structure. + */ +void fake_fpga_mgr_check_write_sgt(struct fake_fpga_mgr *mgr_ctx) +{ + struct fake_mgr_priv *priv; + + priv = mgr_ctx->mgr->priv; + + if (priv->test) { + KUNIT_EXPECT_EQ(priv->test, priv->op_parse_header, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write_init, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write_sg, true); + KUNIT_EXPECT_EQ(priv->test, priv->op_write_complete, true); + } + + clear_op_flags(priv); +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_check_write_sgt); + +static int fake_fpga_mgr_probe(struct platform_device *pdev) +{ + struct device *dev; + struct fake_mgr_priv *priv; + struct fake_mgr_data *pdata; + struct fpga_manager *mgr; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (pdata) + priv->test = pdata->test; + + mgr = devm_fpga_mgr_register(dev, "Fake FPGA Manager", + &fake_fpga_mgr_ops, priv); + if (IS_ERR(mgr)) + return PTR_ERR(mgr); + + platform_set_drvdata(pdev, mgr); + + return 0; +} + +static struct platform_driver fake_fpga_mgr_drv = { + .driver = { + .name = FAKE_FPGA_MGR_DEV_NAME + }, + .probe = fake_fpga_mgr_probe, +}; + +module_platform_driver(fake_fpga_mgr_drv); + +MODULE_AUTHOR("Marco Pagani "); +MODULE_DESCRIPTION("Fake FPGA Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/tests/fake-fpga-mgr.h b/drivers/fpga/tests/fake-fpga-mgr.h new file mode 100644 index 000000000000..3778cbf594bc --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-mgr.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for the fake FPGA manager + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#ifndef __FPGA_FAKE_MGR_H +#define __FPGA_FAKE_MGR_H + +#include +#include +#include + +#define FPGA_IMG_BLOCK 1024 + +/** + * struct fake_fpga_mgr - fake FPGA manager context data structure + * + * @mgr: FPGA manager. + * @pdev: platform device of the FPGA manager. + */ +struct fake_fpga_mgr { + struct fpga_manager *mgr; + struct platform_device *pdev; +}; + +int fake_fpga_mgr_register(struct fake_fpga_mgr *mgr_ctx, struct kunit *test); + +void fake_fpga_mgr_unregister(struct fake_fpga_mgr *mgr_ctx); + +int fake_fpga_mgr_get_rcfg_count(const struct fake_fpga_mgr *mgr_ctx); + +void fake_fpga_mgr_fill_header(u8 *buf); + +void fake_fpga_mgr_check_write_buf(struct fake_fpga_mgr *mgr_ctx); + +void fake_fpga_mgr_check_write_sgt(struct fake_fpga_mgr *mgr_ctx); + +#endif /* __FPGA_FAKE_MGR_H */ From patchwork Fri Mar 10 17:04:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 67597 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp998315wrd; Fri, 10 Mar 2023 09:24:02 -0800 (PST) X-Google-Smtp-Source: AK7set/6eYr4Sy2aOV/PJO4ZJiCcFWqhyxFnlj3bJ0AzPHq1wp+7nNo0g8VflG8qbEKuRP0K0Z0g X-Received: by 2002:a17:902:8f83:b0:19c:c9d0:5bf8 with SMTP id z3-20020a1709028f8300b0019cc9d05bf8mr21177443plo.35.1678469042071; Fri, 10 Mar 2023 09:24:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678469042; cv=none; d=google.com; s=arc-20160816; b=PSvh71deWk9PSL00EtXMT8d4jlaHDUDmUgkIMdO9HCsqJ/8Hfkfgc7MsrzenLmN3V+ TBxUg21Az9rBpaCGDFkSwFCL3PDIkiDQ9axQKQKktwg+zlElpe64TTbGHCvnM+S9tmCg /v9b4yzHzye5MKB0mh2gcgk4zmiDkuqxnSFmWtEKjGrey8LRGrZDKY3hREHUwSFD0Fxf 3MoKc7DRcGQIn4EQtRxp7UXKa4AO7t1FuUtwSls43kJVEIy1fFZe6Sqiy3oBImtH3nEG s0Mn8VJGDQ7ZRB1YbvSJq0mHmMNIobGowq/eHMiJZYvspBais/tP4MfD8q9aOqD9VIRh sCEA== 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=TLMUZ4rcRrVbv/xw3bzEUDacK1AkWuGTxKePE+7Ll2Q=; b=PR/dvDDRu7q0D9UhoAIzpD4BwKzvkiV4pa0YshtDBiv56WjC1LG1jXBiRmIYFpi2Ib ogivZiljD7dKAv+w1m37vgcyiAr9MA2bXeASdrKmCwHA85zNox7ijov4vP0uAfgobdm3 /eXO1gexEPbKSePI3OOdDLQPNySsIlLYQ43kLV2BNJeEA0AVb/3ZYk2+rx6uGHBy+LYZ gE8SBgcrRF6KsYrDsJ7Yh0FBCooXt1CW5T1DnlPNcbPOggrAFZLFDsZEi1yUcLWym9u3 wSZop3Td0Q0TrnoY/k7K0j8jG7vHZGqNYksG1f/8/Owu6YRwuAJ/cLwvp4cEd57vAQsw oI0Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=cy00tXgX; 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 ll5-20020a170903090500b00198b022d9d0si407967plb.12.2023.03.10.09.23.47; Fri, 10 Mar 2023 09:24:02 -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=cy00tXgX; 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 S231806AbjCJRHP (ORCPT + 99 others); Fri, 10 Mar 2023 12:07:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43036 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231364AbjCJRGn (ORCPT ); Fri, 10 Mar 2023 12:06:43 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 58D3312C0E2 for ; Fri, 10 Mar 2023 09:04:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1678467862; 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=TLMUZ4rcRrVbv/xw3bzEUDacK1AkWuGTxKePE+7Ll2Q=; b=cy00tXgX+53RqlbwuGg8p4jLHaMh59OvO9rzA6niOK37B7Hntf5UdLmQhezKlppLRsudAg BCr42RbKDqZnZHYKHe415EBsQUxpFTSkgRxzNEcl/PMN+Aq5z6kBvq48aeyoHqvE67Yn6X SIhmoy35A6p9/BzUnW2ls+AmEMTUVGw= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-534-CzBooUDiM4KKHiU76ulJeg-1; Fri, 10 Mar 2023 12:04:20 -0500 X-MC-Unique: CzBooUDiM4KKHiU76ulJeg-1 Received: by mail-wm1-f72.google.com with SMTP id bi21-20020a05600c3d9500b003e836e354e0so2219075wmb.5 for ; Fri, 10 Mar 2023 09:04:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678467859; 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=TLMUZ4rcRrVbv/xw3bzEUDacK1AkWuGTxKePE+7Ll2Q=; b=dEsU9jKXzlJibcK7bEjHOpHBnhltnX/61ftABC//QzyNdJUvUDmTY8yMSR/9XLwOdv qQfBzgHxQh2+ZXH0FTL0cGP0aZmfZZdqoVZWQM+cTk6OfCB0gE6jUcRH6UxK/jmC+IiU Mo8JO/8/sAKUx9Rf2ukEfgkGSRU4nRP5LQutJhVNDsygLJOnTV+C8S4n+9rOqDHfqqVX O4ajJLJsLFtPSwC9e0vrtU0LrjfhBUGnFf3+PTVOuf/eKjlqFXYeigjiJIC2m3S9nhm+ OWiT0mgckDZRDrZMva48VO0DVQF7fTc3mIFPXI7FXxOu/jXZPQ2FuRjulSyHIm+uxZEc Zl1g== X-Gm-Message-State: AO0yUKUsmAnyaytZh5/rnL3RAW9LbPZrr0ln23FiUIcjVZZosAmXPHld Q4lJIyzHCMt4GRhXXO1S3SsFaJ3932a+/I0Xu0IX6CCOnGcGWiC8+P8rlDHJFi/p50V767+C6Lf RfxWZmD6dlGaFykov99fRl3w= X-Received: by 2002:a05:600c:35c4:b0:3df:9858:c039 with SMTP id r4-20020a05600c35c400b003df9858c039mr1902547wmq.14.1678467859781; Fri, 10 Mar 2023 09:04:19 -0800 (PST) X-Received: by 2002:a05:600c:35c4:b0:3df:9858:c039 with SMTP id r4-20020a05600c35c400b003df9858c039mr1902526wmq.14.1678467859516; Fri, 10 Mar 2023 09:04:19 -0800 (PST) Received: from klayman.redhat.com (net-2-34-29-20.cust.vodafonedsl.it. [2.34.29.20]) by smtp.gmail.com with ESMTPSA id u10-20020a05600c00ca00b003eb192787bfsm417294wmm.25.2023.03.10.09.04.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Mar 2023 09:04:19 -0800 (PST) From: Marco Pagani To: Moritz Fischer , Wu Hao , Xu Yilun , Tom Rix Cc: Marco Pagani , linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [RFC PATCH v2 2/4] fpga: add fake FPGA bridge Date: Fri, 10 Mar 2023 18:04:10 +0100 Message-Id: <20230310170412.708363-3-marpagan@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230310170412.708363-1-marpagan@redhat.com> References: <20230310170412.708363-1-marpagan@redhat.com> MIME-Version: 1.0 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: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760002354174180994?= X-GMAIL-MSGID: =?utf-8?q?1760002354174180994?= Add fake FPGA bridge driver with support functions. The driver includes a counter for the number of switching cycles. This module is part of the KUnit tests for the FPGA subsystem. Signed-off-by: Marco Pagani --- drivers/fpga/tests/fake-fpga-bridge.c | 228 ++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-bridge.h | 36 ++++ 2 files changed, 264 insertions(+) create mode 100644 drivers/fpga/tests/fake-fpga-bridge.c create mode 100644 drivers/fpga/tests/fake-fpga-bridge.h diff --git a/drivers/fpga/tests/fake-fpga-bridge.c b/drivers/fpga/tests/fake-fpga-bridge.c new file mode 100644 index 000000000000..8a2f64fc1bbb --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-bridge.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the fake FPGA bridge + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#include +#include +#include +#include +#include + +#include "fake-fpga-bridge.h" + +#define FAKE_FPGA_BRIDGE_DEV_NAME "fake_fpga_bridge" + +struct fake_bridge_priv { + int id; + bool enable; + int cycles_count; + struct kunit *test; +}; + +struct fake_bridge_data { + struct kunit *test; +}; + +static int op_enable_show(struct fpga_bridge *bridge) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA bridge %d: enable_show\n", + priv->id); + + return priv->enable; +} + +static int op_enable_set(struct fpga_bridge *bridge, bool enable) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + if (enable && !priv->enable) + priv->cycles_count++; + + priv->enable = enable; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA bridge %d: enable_set: %d\n", + priv->id, enable); + + return 0; +} + +static void op_remove(struct fpga_bridge *bridge) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + if (priv->test) + kunit_info(priv->test, "Fake FPGA bridge: remove\n"); +} + +static const struct fpga_bridge_ops fake_fpga_bridge_ops = { + .enable_show = op_enable_show, + .enable_set = op_enable_set, + .fpga_bridge_remove = op_remove, +}; + +/** + * fake_fpga_bridge_register() - register a fake FPGA bridge. + * @bridge_ctx: fake FPGA bridge context data structure. + * @parent: parent device. + * @test: KUnit test context object. + * + * Return: 0 if registration succeeded, an error code otherwise. + */ +int fake_fpga_bridge_register(struct fake_fpga_bridge *bridge_ctx, + struct device *parent, struct kunit *test) +{ + struct fake_bridge_data pdata; + struct fake_bridge_priv *priv; + int ret; + + pdata.test = test; + + bridge_ctx->pdev = platform_device_alloc(FAKE_FPGA_BRIDGE_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (IS_ERR(bridge_ctx->pdev)) { + pr_err("Fake FPGA bridge device allocation failed\n"); + return -ENOMEM; + } + + bridge_ctx->pdev->dev.parent = parent; + platform_device_add_data(bridge_ctx->pdev, &pdata, sizeof(pdata)); + + ret = platform_device_add(bridge_ctx->pdev); + if (ret) { + pr_err("Fake FPGA bridge device add failed\n"); + platform_device_put(bridge_ctx->pdev); + return ret; + } + + bridge_ctx->bridge = platform_get_drvdata(bridge_ctx->pdev); + + if (test) { + priv = bridge_ctx->bridge->priv; + kunit_info(test, "Fake FPGA bridge %d registered\n", priv->id); + } + + return 0; +} +EXPORT_SYMBOL_GPL(fake_fpga_bridge_register); + +/** + * fake_fpga_bridge_unregister() - unregister a fake FPGA bridge. + * @bridge_ctx: fake FPGA bridge context data structure. + */ +void fake_fpga_bridge_unregister(struct fake_fpga_bridge *bridge_ctx) +{ + struct fake_bridge_priv *priv; + struct kunit *test; + int id; + + if (!bridge_ctx) + return; + + priv = bridge_ctx->bridge->priv; + test = priv->test; + id = priv->id; + + if (bridge_ctx->pdev) { + platform_device_unregister(bridge_ctx->pdev); + if (test) + kunit_info(test, "Fake FPGA bridge %d unregistered\n", id); + } +} +EXPORT_SYMBOL_GPL(fake_fpga_bridge_unregister); + +/** + * fake_fpga_bridge_get_state() - get state of a fake FPGA bridge. + * @bridge_ctx: fake FPGA bridge context data structure. + * + * Return: 1 if the bridge is enabled, 0 if disabled. + */ +int fake_fpga_bridge_get_state(const struct fake_fpga_bridge *bridge_ctx) +{ + return bridge_ctx->bridge->br_ops->enable_show(bridge_ctx->bridge); +} +EXPORT_SYMBOL_GPL(fake_fpga_bridge_get_state); + +/** + * fake_fpga_bridge_get_cycles_count() - get the number of switching cycles. + * @bridge_ctx: fake FPGA bridge context data structure. + * + * Return: number of switching cycles. + */ +int fake_fpga_bridge_get_cycles_count(const struct fake_fpga_bridge *bridge_ctx) +{ + struct fake_bridge_priv *priv; + + priv = bridge_ctx->bridge->priv; + + return priv->cycles_count; +} +EXPORT_SYMBOL_GPL(fake_fpga_bridge_get_cycles_count); + +static int fake_fpga_bridge_probe(struct platform_device *pdev) +{ + struct device *dev; + struct fpga_bridge *bridge; + struct fake_bridge_data *pdata; + struct fake_bridge_priv *priv; + static int id_count; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->id = id_count++; + priv->enable = true; + + if (pdata) + priv->test = pdata->test; + + bridge = fpga_bridge_register(dev, "Fake FPGA Bridge", + &fake_fpga_bridge_ops, priv); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + + platform_set_drvdata(pdev, bridge); + + return 0; +} + +static int fake_fpga_bridge_remove(struct platform_device *pdev) +{ + struct fpga_bridge *bridge = platform_get_drvdata(pdev); + + fpga_bridge_unregister(bridge); + + return 0; +} + +static struct platform_driver fake_fpga_bridge_drv = { + .driver = { + .name = FAKE_FPGA_BRIDGE_DEV_NAME + }, + .probe = fake_fpga_bridge_probe, + .remove = fake_fpga_bridge_remove, +}; + +module_platform_driver(fake_fpga_bridge_drv); + +MODULE_AUTHOR("Marco Pagani "); +MODULE_DESCRIPTION("Fake FPGA Bridge"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/tests/fake-fpga-bridge.h b/drivers/fpga/tests/fake-fpga-bridge.h new file mode 100644 index 000000000000..ae224b13f284 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-bridge.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for the fake FPGA bridge + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#ifndef __FPGA_FAKE_BRIDGE_H +#define __FPGA_FAKE_BRIDGE_H + +#include +#include + +/** + * struct fake_fpga_bridge - fake FPGA bridge context data structure + * + * @bridge: FPGA bridge. + * @pdev: platform device of the FPGA bridge. + */ +struct fake_fpga_bridge { + struct fpga_bridge *bridge; + struct platform_device *pdev; +}; + +int fake_fpga_bridge_register(struct fake_fpga_bridge *bridge_ctx, + struct device *parent, struct kunit *test); + +void fake_fpga_bridge_unregister(struct fake_fpga_bridge *bridge_ctx); + +int fake_fpga_bridge_get_state(const struct fake_fpga_bridge *bridge_ctx); + +int fake_fpga_bridge_get_cycles_count(const struct fake_fpga_bridge *bridge_ctx); + +#endif /* __FPGA_FAKE_BRIDGE_H */ From patchwork Fri Mar 10 17:04:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 67600 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp998719wrd; Fri, 10 Mar 2023 09:24:57 -0800 (PST) X-Google-Smtp-Source: AK7set+qtB5i6QJhChWr3V6sybdlvJWjt470aB/LsAOzStHF3A8bHj3B4EP6uGdSaG+NyD0NEYbo X-Received: by 2002:a17:902:c40b:b0:19e:8bfe:7d68 with SMTP id k11-20020a170902c40b00b0019e8bfe7d68mr34330511plk.11.1678469097450; Fri, 10 Mar 2023 09:24:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678469097; cv=none; d=google.com; s=arc-20160816; b=fYRT/wDgBHwS95L8LCLqhp52lwEr5CJUsclaVI9lC0FlM3lxpMOH6cjo1J9ACwWQWm pevSLoxGroP8xWOQOr8dkcVx6iApIfUxRYQgOeQ3xpyBXETcboO2WP3DS9/AIlWPtNIr RzriSyCrXU4fj6QcTF43hv/yBA15vNhBDOCbFZr9OFWxaxm+aqGgYNIsOG0hH/hQ4Q69 tH6fN0wcglQ3+Q+q7Rj2x6WkCq8dK5ChYGvfWtSC8zWbdlZ7+ohXuu8dRPQaESaoSeB+ dvKnObOF020G0a6gMfqQ1cFtqQUW8pUMrf2Y1DYuZZe3mgPZrT2nY7ChhSvbeF6l5tKY uQCQ== 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=JO3sx9KQ7oN1zllI/65sQBKcfWX+lgrDYeSnCW02Np8=; b=eAIWNArx7J6iZlznzYs5JaT7tkGiWzsLQ251joY1dkdmkcx3EHiEr1+D22VAjfCuWJ 4aqm1369cCi1O/QXYkYauttK+T8h3gigqTIUvEr8IU3LNAc5Fc3kPHymqvWkkHCBtoNz K61uRzqrGkKkm6iIgOrSx5wrVk7UMeIvQqyGXbZb38NmBaXyo3ACPnc4bURrZVd+0wTZ WE7OZl0AcbvY+ZcsGSxEGPuTva4eIDUvPe9Tr+6NZhdbhGXj6PQ5wWfwBc4StHODFbBG vj4qnvfJycXUlhFFoy5TqGhv1NklMAcPz7wbNcQJTKskXvmMtBtxmyN0dLOGLCl72nA6 vJAQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=QV6ylzYH; 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 y21-20020a1709027c9500b0019e8c3cd415si397227pll.260.2023.03.10.09.24.42; Fri, 10 Mar 2023 09:24:57 -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=QV6ylzYH; 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 S231364AbjCJRHT (ORCPT + 99 others); Fri, 10 Mar 2023 12:07:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43038 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231785AbjCJRGn (ORCPT ); Fri, 10 Mar 2023 12:06:43 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD6EB12DC20 for ; Fri, 10 Mar 2023 09:04:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1678467863; 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=JO3sx9KQ7oN1zllI/65sQBKcfWX+lgrDYeSnCW02Np8=; b=QV6ylzYHdt/dN5tfq4rxkOApZOvWArtIt9EhjtXgYfj3gBf4AHTImUN+PNJXythUWhqVcn qMn48BpqM5xViQhYwVIWCIwQqr5K7lKNePHDHZNsVNpfVFcOWrM6CcDqKEgPa5/v9cXkE/ D/1MogTR4sJLWMBhPG9G18EHUOlXnSM= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-582-TveBDDJaPTOFE1ddtCPEFQ-1; Fri, 10 Mar 2023 12:04:22 -0500 X-MC-Unique: TveBDDJaPTOFE1ddtCPEFQ-1 Received: by mail-wm1-f71.google.com with SMTP id j6-20020a05600c1c0600b003eaf882cb85so2212118wms.9 for ; Fri, 10 Mar 2023 09:04:22 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678467861; 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=JO3sx9KQ7oN1zllI/65sQBKcfWX+lgrDYeSnCW02Np8=; b=DKU9eFt5FGfWKtHpGbzDGDAxnCpDxz6X2f9ArvrxqiRUtbd2mvovdYNDxaaCTghTG5 wmJwl2JVlKhQUjyS2fDDTi0+V2dwuDEdolq3iJiWNsfjlVS4ogG01DKtzqkFIzVRtDAn prWWCcWKf2z0EwmfEc3p/yKhdm9UcA9D/S1l/34ELHWNWzKRtgvcwNo//YyE4EIfsgb0 NGFqJ/8/kGV8a3QRad4kFuzVtM6D0OpCxKktO3XsOlEAw0F20Sp0LqESXpdSeMrAp9TD CmtUvEuHO4T7ERHGr8Jg+LYdm+zgxwLjCL7lzp60Q6FLtsVKw83/coKUB9qSwBNqlEWR am/w== X-Gm-Message-State: AO0yUKXkLE304qOSadHFhfn+VQ7EwKVou3zPhpnIFdRv8xZZNcvDvFjm 3ZbYcOnRMuSNR4t+nQRh2jkJ39fICUmOSGYRgZklNt9p1zRAJ/4xpOhCsEZtIqUpCHoAl5j4kT/ KhouCuHVJ9VoqeL7Ux+zf3aUJNztde7A= X-Received: by 2002:a05:600c:4ed0:b0:3e2:20c7:6553 with SMTP id g16-20020a05600c4ed000b003e220c76553mr3538245wmq.13.1678467860799; Fri, 10 Mar 2023 09:04:20 -0800 (PST) X-Received: by 2002:a05:600c:4ed0:b0:3e2:20c7:6553 with SMTP id g16-20020a05600c4ed000b003e220c76553mr3538218wmq.13.1678467860569; Fri, 10 Mar 2023 09:04:20 -0800 (PST) Received: from klayman.redhat.com (net-2-34-29-20.cust.vodafonedsl.it. [2.34.29.20]) by smtp.gmail.com with ESMTPSA id u10-20020a05600c00ca00b003eb192787bfsm417294wmm.25.2023.03.10.09.04.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Mar 2023 09:04:20 -0800 (PST) From: Marco Pagani To: Moritz Fischer , Wu Hao , Xu Yilun , Tom Rix Cc: Marco Pagani , linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [RFC PATCH v2 3/4] fpga: add fake FPGA region Date: Fri, 10 Mar 2023 18:04:11 +0100 Message-Id: <20230310170412.708363-4-marpagan@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230310170412.708363-1-marpagan@redhat.com> References: <20230310170412.708363-1-marpagan@redhat.com> MIME-Version: 1.0 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=unavailable 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: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760002411951573374?= X-GMAIL-MSGID: =?utf-8?q?1760002411951573374?= Add fake FPGA region platform driver with support functions. This module is part of the KUnit tests for the FPGA subsystem. Signed-off-by: Marco Pagani --- drivers/fpga/tests/fake-fpga-region.c | 219 ++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-region.h | 38 +++++ 2 files changed, 257 insertions(+) create mode 100644 drivers/fpga/tests/fake-fpga-region.c create mode 100644 drivers/fpga/tests/fake-fpga-region.h diff --git a/drivers/fpga/tests/fake-fpga-region.c b/drivers/fpga/tests/fake-fpga-region.c new file mode 100644 index 000000000000..54d0e564728b --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-region.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the fake FPGA region + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "fake-fpga-region.h" + +#define FAKE_FPGA_REGION_DEV_NAME "fake_fpga_region" + +struct fake_region_priv { + int id; + struct kunit *test; + struct list_head bridge_list; +}; + +struct fake_region_data { + struct fpga_manager *mgr; + struct kunit *test; +}; + +/** + * fake_fpga_region_register() - register a fake FPGA region. + * @region_ctx: fake FPGA region context data structure. + * @mgr: associated FPGA manager. + * @parent: parent device. + * @test: KUnit test context object. + * + * Return: 0 if registration succeeded, an error code otherwise. + */ +int fake_fpga_region_register(struct fake_fpga_region *region_ctx, + struct fpga_manager *mgr, struct device *parent, + struct kunit *test) +{ + struct fake_region_data pdata; + struct fake_region_priv *priv; + int ret; + + pdata.mgr = mgr; + pdata.test = test; + + region_ctx->pdev = platform_device_alloc(FAKE_FPGA_REGION_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (IS_ERR(region_ctx->pdev)) { + pr_err("Fake FPGA region device allocation failed\n"); + return -ENOMEM; + } + + region_ctx->pdev->dev.parent = parent; + platform_device_add_data(region_ctx->pdev, &pdata, sizeof(pdata)); + + ret = platform_device_add(region_ctx->pdev); + if (ret) { + pr_err("Fake FPGA region device add failed\n"); + platform_device_put(region_ctx->pdev); + return ret; + } + + region_ctx->region = platform_get_drvdata(region_ctx->pdev); + + if (test) { + priv = region_ctx->region->priv; + kunit_info(test, "Fake FPGA region %d registered\n", priv->id); + } + + return 0; +} +EXPORT_SYMBOL_GPL(fake_fpga_region_register); + +/** + * fake_fpga_region_unregister() - unregister a fake FPGA region. + * @region_ctx: fake FPGA region context data structure. + */ +void fake_fpga_region_unregister(struct fake_fpga_region *region_ctx) +{ + struct fake_region_priv *priv; + struct kunit *test; + int id; + + if (!region_ctx) + return; + + priv = region_ctx->region->priv; + test = priv->test; + id = priv->id; + + if (region_ctx->pdev) { + platform_device_unregister(region_ctx->pdev); + if (test) + kunit_info(test, "Fake FPGA region %d unregistered\n", id); + } +} +EXPORT_SYMBOL_GPL(fake_fpga_region_unregister); + +/** + * fake_fpga_region_add_bridge() - add a bridge to a fake FPGA region. + * @region_ctx: fake FPGA region context data structure. + * @bridge: FPGA bridge. + * + * Return: 0 if registration succeeded, an error code otherwise. + */ +void fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, + struct fpga_bridge *bridge) +{ + struct fake_region_priv *priv; + + priv = region_ctx->region->priv; + + /* Add bridge to the list of bridges in the private context */ + list_add(&bridge->node, &priv->bridge_list); + + if (priv->test) + kunit_info(priv->test, "Bridge added to fake FPGA region %d\n", + priv->id); +} +EXPORT_SYMBOL_GPL(fake_fpga_region_add_bridge); + +static int fake_region_get_bridges(struct fpga_region *region) +{ + struct fake_region_priv *priv; + struct fpga_bridge *bridge, *tmp; + int ret; + + priv = region->priv; + + list_for_each_entry_safe(bridge, tmp, &priv->bridge_list, node) { + list_del(&bridge->node); + ret = fpga_bridge_get_to_list(bridge->dev.parent, + region->info, + ®ion->bridge_list); + if (ret) + break; + } + + return ret; +} + +static int fake_fpga_region_probe(struct platform_device *pdev) +{ + struct device *dev; + struct fpga_region *region; + struct fpga_manager *mgr; + struct fake_region_data *pdata; + struct fake_region_priv *priv; + struct fpga_region_info info; + static int id_count; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mgr = fpga_mgr_get(pdata->mgr->dev.parent); + if (IS_ERR(mgr)) + return PTR_ERR(mgr); + + INIT_LIST_HEAD(&priv->bridge_list); + priv->id = id_count++; + priv->test = pdata->test; + + memset(&info, 0, sizeof(info)); + info.priv = priv; + info.mgr = mgr; + info.get_bridges = fake_region_get_bridges; + + region = fpga_region_register_full(dev, &info); + if (IS_ERR(region)) { + fpga_mgr_put(mgr); + return PTR_ERR(region); + } + + platform_set_drvdata(pdev, region); + + return 0; +} + +static int fake_fpga_region_remove(struct platform_device *pdev) +{ + struct fpga_region *region = platform_get_drvdata(pdev); + struct fpga_manager *mgr = region->mgr; + + fpga_mgr_put(mgr); + fpga_bridges_put(®ion->bridge_list); + fpga_region_unregister(region); + + return 0; +} + +static struct platform_driver fake_fpga_region_drv = { + .driver = { + .name = FAKE_FPGA_REGION_DEV_NAME + }, + .probe = fake_fpga_region_probe, + .remove = fake_fpga_region_remove, +}; + +module_platform_driver(fake_fpga_region_drv); + +MODULE_AUTHOR("Marco Pagani "); +MODULE_DESCRIPTION("Fake FPGA Bridge"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/tests/fake-fpga-region.h b/drivers/fpga/tests/fake-fpga-region.h new file mode 100644 index 000000000000..9268ca335662 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-region.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for the fake FPGA region + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#ifndef __FPGA_FAKE_RGN_H +#define __FPGA_FAKE_RGN_H + +#include +#include +#include +#include + +/** + * struct fake_fpga_region - fake FPGA region context data structure + * + * @region: FPGA region. + * @pdev: platform device of the FPGA region. + */ +struct fake_fpga_region { + struct fpga_region *region; + struct platform_device *pdev; +}; + +int fake_fpga_region_register(struct fake_fpga_region *region_ctx, + struct fpga_manager *mgr, struct device *parent, + struct kunit *test); + +void fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, + struct fpga_bridge *bridge); + +void fake_fpga_region_unregister(struct fake_fpga_region *region_ctx); + +#endif /* __FPGA_FAKE_RGN_H */ From patchwork Fri Mar 10 17:04:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 67594 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp997039wrd; Fri, 10 Mar 2023 09:21:33 -0800 (PST) X-Google-Smtp-Source: AK7set+Y0th1xuRCxOw+8wweCwHQd57ViEchyvwmAFzc+a/hv3rqqaoJi59atGln8jPZY93Zt18Y X-Received: by 2002:a17:903:2344:b0:19e:6e29:2a8c with SMTP id c4-20020a170903234400b0019e6e292a8cmr32117029plh.5.1678468893539; Fri, 10 Mar 2023 09:21:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678468893; cv=none; d=google.com; s=arc-20160816; b=N4ujDxvctUsO7dgL2xRPT5Vmp3orQaYA4Dy+yrQiRf8oMWl6ecwO4ezGrHHacUU9Am seb7VFhNgwDe3cNrA5VS3tL77JjN90SzGAbFI4tN5szRERX4WqHFXq/Zsc7yVK5QTonK yWWTTtGhLEPyJdTXDN0bj/FkSplRysPmFqc7oLWk695FO5tc7njDakYgz5OAgC3dIQsA C9UwYI1d67NdSVs0EoOSwly9xFrf9pZmVzOtZRPaHGlOqOmkAc54QKQERe1IX+aZAuAx DhfnQIOKL/NaoGm6a1VgMpJrUV6OpuUBD7ffvgeWBMnmbcRRUgWkS4UxCfv9W+xIodnI QKfQ== 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=P1/AOQRjuwnPoYWKb6b44ay/ME45rBUeqXdCqnhj5qU=; b=Z92pPetknllVllEgythWkuGA/Sye8//p2XAIcmAvEi86laKnYT1PPu1LNvnYUlA4PI 8za+R+tGBsF47omNKx7lqGcsxhRMoapWu6AEX6k6Hx1SQY4baIcXQkCQzSkI9tLtKS+j uHIspNaRWd7upD1bArmpQKf6fLdtI/onhRpo3P9fJakMlhONWntaT6OSphCdF84Sixpj id2GwT98GQt8At0JTV6Z9YD26siF55Nl/D8cxLL1XMqqXfec5FoBwX7rMmEg094YdjGO qg+A7gMFMD0H5y2823T2C5VAvWbG5MT/RkkBBwUPbDoZiK+ZgxzI55ko13A6pl8xQkDZ FuHA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=C6TyCrLl; 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 y21-20020a1709027c9500b0019e8c3cd415si397227pll.260.2023.03.10.09.21.18; Fri, 10 Mar 2023 09:21:33 -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=C6TyCrLl; 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 S231577AbjCJRHM (ORCPT + 99 others); Fri, 10 Mar 2023 12:07:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231778AbjCJRGn (ORCPT ); Fri, 10 Mar 2023 12:06:43 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ABFC112EAF6 for ; Fri, 10 Mar 2023 09:04:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1678467864; 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=P1/AOQRjuwnPoYWKb6b44ay/ME45rBUeqXdCqnhj5qU=; b=C6TyCrLlxxh7m+7kWbj8Otpscu0WORP5yyQCpyMf4NTDU9+yqRcwCXFaCfE/YFvG5hE6MM gpeb79SIJXyOitkrtS1PFXU8lblNcWTuSL38WbHjkJ8ujEAh+u6fx0zufMf017T7gHPdE8 mI1cvRI49QjUcy4WTns2iZIyX+DXDbw= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-452-sWVD8oTRPcCkk-X6z8Fbbw-1; Fri, 10 Mar 2023 12:04:23 -0500 X-MC-Unique: sWVD8oTRPcCkk-X6z8Fbbw-1 Received: by mail-wm1-f70.google.com with SMTP id az39-20020a05600c602700b003e97eb80524so4124119wmb.4 for ; Fri, 10 Mar 2023 09:04:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678467862; 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=P1/AOQRjuwnPoYWKb6b44ay/ME45rBUeqXdCqnhj5qU=; b=1Sr1F3rgGqNvKp/Ss7pWp3JCbPzuqSmtHalwObWzeej+7eg0HGaRrRfb9UN/UuICyr WFIH3egg+kv37FnMpWrfCYOJeW4Dl9o29vkFsBH4w5rTKwRHvOkXVtJL6GxuplAR9nel UPameS7fYu+FQuuAS/7Ex/dRX2tXN6TVe1pQ756AxK6Gtpp/MCA8t5Dqlb94V2bfFbTk s7pMbaH3313Jjpmld+gezQHUyHXaqWXcf4VQ+sE6MwSR7ex7MijHZBljmg9xCrd5rTKT m3YmQP8BuC/6qRz3ux2Eywn68CJBQGY8FPCMtFQnL4nStGcWTdcGqHSSGg5FcGdmi4PF GewQ== X-Gm-Message-State: AO0yUKX33o1t2mk/7La7hQfaRerJEgYv59h9hVVt90oRG+RvcTj+38xl lEWNiF3C2JxaGvq61lxQ5uJHeE+WFaFy4aHDBslI5L3vZstQidr1ecwpIQfmrJEUkpkAzGL/smh 65NbbSrJKvuwzUbVynZ0D/SU= X-Received: by 2002:a05:600c:450b:b0:3eb:2de9:8aed with SMTP id t11-20020a05600c450b00b003eb2de98aedmr3244650wmo.41.1678467861961; Fri, 10 Mar 2023 09:04:21 -0800 (PST) X-Received: by 2002:a05:600c:450b:b0:3eb:2de9:8aed with SMTP id t11-20020a05600c450b00b003eb2de98aedmr3244612wmo.41.1678467861606; Fri, 10 Mar 2023 09:04:21 -0800 (PST) Received: from klayman.redhat.com (net-2-34-29-20.cust.vodafonedsl.it. [2.34.29.20]) by smtp.gmail.com with ESMTPSA id u10-20020a05600c00ca00b003eb192787bfsm417294wmm.25.2023.03.10.09.04.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Mar 2023 09:04:21 -0800 (PST) From: Marco Pagani To: Moritz Fischer , Wu Hao , Xu Yilun , Tom Rix Cc: Marco Pagani , linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [RFC PATCH v2 4/4] fpga: add initial KUnit test suites Date: Fri, 10 Mar 2023 18:04:12 +0100 Message-Id: <20230310170412.708363-5-marpagan@redhat.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230310170412.708363-1-marpagan@redhat.com> References: <20230310170412.708363-1-marpagan@redhat.com> MIME-Version: 1.0 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=unavailable 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: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1760002198160644526?= X-GMAIL-MSGID: =?utf-8?q?1760002198160644526?= Introduce initial KUnit tests for the FPGA subsystem. Tests are organized into three test suites. The first suite tests the FPGA Manager. The second suite tests the FPGA Bridge. Finally, the last test suite models a complete FPGA platform and tests static and partial reconfiguration. Signed-off-by: Marco Pagani --- drivers/fpga/Kconfig | 2 + drivers/fpga/Makefile | 3 + drivers/fpga/tests/.kunitconfig | 5 + drivers/fpga/tests/Kconfig | 11 + drivers/fpga/tests/Makefile | 6 + drivers/fpga/tests/fpga-test.c | 501 ++++++++++++++++++++++++++++++++ 6 files changed, 528 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-test.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 6ce143dafd04..469d5bdd1a05 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..1cbea75dd29b --- /dev/null +++ b/drivers/fpga/tests/Kconfig @@ -0,0 +1,11 @@ +config FPGA_KUNIT_TESTS + tristate "KUnit test for the FPGA subsystem" if !KUNIT_ALL_TESTS + depends on FPGA && FPGA_REGION && FPGA_BRIDGE && KUNIT + default KUNIT_ALL_TESTS + help + This builds unit tests for the FPGA subsystem + + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. diff --git a/drivers/fpga/tests/Makefile b/drivers/fpga/tests/Makefile new file mode 100644 index 000000000000..0b052570659b --- /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-test.o diff --git a/drivers/fpga/tests/fpga-test.c b/drivers/fpga/tests/fpga-test.c new file mode 100644 index 000000000000..df5f48dc2c54 --- /dev/null +++ b/drivers/fpga/tests/fpga-test.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for the FPGA subsystem + * + * Copyright (C) 2023 Red Hat, Inc. + * + * Author: Marco Pagani + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "fake-fpga-region.h" +#include "fake-fpga-bridge.h" +#include "fake-fpga-mgr.h" + +#define STATIC_IMG_BLOCKS 16 +#define STATIC_IMG_SIZE (FPGA_IMG_BLOCK * STATIC_IMG_BLOCKS) + +#define PARTIAL_IMG_BLOCKS 4 +#define PARTIAL_IMG_SIZE (FPGA_IMG_BLOCK * PARTIAL_IMG_BLOCKS) + +/** + * buf_img_alloc() - Allocate a fake FPGA image using a buffer. + * @test: KUnit test context object. + * @dev: owning device. + * @size: image size. + * + * Return: pointer to a struct fpga_image_info or NULL on failure. + */ +static struct fpga_image_info *buf_img_alloc(struct kunit *test, struct device *dev, + size_t size) +{ + struct fpga_image_info *img_info; + char *img_buf; + + img_buf = kunit_kzalloc(test, size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_buf); + fake_fpga_mgr_fill_header(img_buf); + + img_info = fpga_image_info_alloc(dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info); + + img_info->count = size; + img_info->buf = img_buf; + + kunit_info(test, "FPGA image allocated in a buffer, size: %zu\n", size); + + return img_info; +} + +/** + * sgt_img_alloc() - Allocate a fake FPGA image using a scatter gather table. + * @test: KUnit test context object. + * @dev: owning device. + * @size: image size. + * + * Return: pointer to a struct fpga_image_info or NULL on failure. + */ +static struct fpga_image_info *sgt_img_alloc(struct kunit *test, struct device *dev, + size_t size) +{ + struct fpga_image_info *img_info; + char *img_buf; + struct sg_table *sgt; + int ret; + + img_buf = kunit_kzalloc(test, size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_buf); + fake_fpga_mgr_fill_header(img_buf); + + sgt = kunit_kzalloc(test, sizeof(*sgt), GFP_KERNEL); + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + KUNIT_ASSERT_EQ(test, ret, 0); + sg_init_one(sgt->sgl, img_buf, size); + + img_info = fpga_image_info_alloc(dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info); + + img_info->sgt = sgt; + + kunit_info(test, "FPGA image allocated in a scatter gather table, size: %zu\n", + size); + + return img_info; +} + +/** + * img_free() - Free a fake FPGA image + * @img_info: fpga image information struct. + * + */ +static void img_free(struct fpga_image_info *img_info) +{ + if (!img_info) + return; + + if (img_info->sgt) + sg_free_table(img_info->sgt); + + fpga_image_info_free(img_info); +} + +static int fpga_mgr_test_init(struct kunit *test) +{ + struct fake_fpga_mgr *mgr_ctx; + int ret; + + mgr_ctx = kunit_kzalloc(test, sizeof(*mgr_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mgr_ctx); + + ret = fake_fpga_mgr_register(mgr_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + test->priv = mgr_ctx; + + return 0; +} + +static void fpga_mgr_test_img_load_buf(struct kunit *test) +{ + struct fake_fpga_mgr *mgr_ctx; + struct fpga_image_info *img_info; + int ret; + + mgr_ctx = test->priv; + + /* Allocate an FPGA image using a buffer */ + img_info = buf_img_alloc(test, &mgr_ctx->pdev->dev, STATIC_IMG_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(mgr_ctx)); + + ret = fpga_mgr_load(mgr_ctx->mgr, img_info); + 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)); + + img_free(img_info); +} + +static void fpga_mgr_test_img_load_sgt(struct kunit *test) +{ + struct fake_fpga_mgr *mgr_ctx; + struct fpga_image_info *img_info; + int ret; + + mgr_ctx = test->priv; + + /* Allocate an FPGA image using a scatter gather table */ + img_info = sgt_img_alloc(test, &mgr_ctx->pdev->dev, STATIC_IMG_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(mgr_ctx)); + + ret = fpga_mgr_load(mgr_ctx->mgr, img_info); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_sgt(mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(mgr_ctx)); + + img_free(img_info); +} + +static void fpga_mgr_test_exit(struct kunit *test) +{ + struct fake_fpga_mgr *mgr_ctx; + + mgr_ctx = test->priv; + + if (mgr_ctx) + fake_fpga_mgr_unregister(mgr_ctx); +} + +static struct kunit_case fpga_mgr_test_cases[] = { + KUNIT_CASE(fpga_mgr_test_img_load_buf), + KUNIT_CASE(fpga_mgr_test_img_load_sgt), + {} +}; + +static struct kunit_suite fpga_mgr_suite = { + .name = "fpga_mgr", + .init = fpga_mgr_test_init, + .exit = fpga_mgr_test_exit, + .test_cases = fpga_mgr_test_cases, +}; + +static int fpga_bridge_test_init(struct kunit *test) +{ + struct fake_fpga_bridge *bridge_ctx; + int ret; + + bridge_ctx = kunit_kzalloc(test, sizeof(*bridge_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_ctx); + + ret = fake_fpga_bridge_register(bridge_ctx, NULL, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + test->priv = bridge_ctx; + + return 0; +} + +static void fpga_bridge_test_exit(struct kunit *test) +{ + struct fake_fpga_bridge *bridge_ctx; + + bridge_ctx = test->priv; + + if (bridge_ctx) + fake_fpga_bridge_unregister(bridge_ctx); +} + +static void fpga_bridge_test_toggle(struct kunit *test) +{ + struct fake_fpga_bridge *bridge_ctx; + + bridge_ctx = test->priv; + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(bridge_ctx)); + + fpga_bridge_disable(bridge_ctx->bridge); + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_state(bridge_ctx)); + + fpga_bridge_enable(bridge_ctx->bridge); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(bridge_ctx)); +} + +static void fpga_bridge_test_get_put_list(struct kunit *test) +{ + struct list_head bridge_list; + struct fake_fpga_bridge *bridge_0_ctx, *bridge_1_ctx; + int ret; + + bridge_0_ctx = test->priv; + + /* Register another bridge for this test */ + bridge_1_ctx = kunit_kzalloc(test, sizeof(*bridge_1_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_1_ctx); + + ret = fake_fpga_bridge_register(bridge_1_ctx, NULL, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + INIT_LIST_HEAD(&bridge_list); + + /* Get bridge_0 and add it to the list */ + ret = fpga_bridge_get_to_list(bridge_1_ctx->bridge->dev.parent, NULL, + &bridge_list); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_PTR_EQ(test, bridge_1_ctx->bridge, + list_first_entry_or_null(&bridge_list, struct fpga_bridge, node)); + + /* Get bridge_1 and add it to the list */ + ret = fpga_bridge_get_to_list(bridge_0_ctx->bridge->dev.parent, NULL, + &bridge_list); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_PTR_EQ(test, bridge_0_ctx->bridge, + list_first_entry_or_null(&bridge_list, struct fpga_bridge, node)); + + /* Put and remove both bridges from the list */ + fpga_bridges_put(&bridge_list); + + KUNIT_EXPECT_TRUE(test, list_empty(&bridge_list)); + + fake_fpga_bridge_unregister(bridge_1_ctx); +} + +static struct kunit_case fpga_bridge_test_cases[] = { + KUNIT_CASE(fpga_bridge_test_toggle), + KUNIT_CASE(fpga_bridge_test_get_put_list), + {} +}; + +static struct kunit_suite fpga_bridge_suite = { + .name = "fpga_bridge", + .init = fpga_bridge_test_init, + .exit = fpga_bridge_test_exit, + .test_cases = fpga_bridge_test_cases, +}; + +struct fpga_base_ctx { + /* + * Base FPGA layout consisting of a single region + * controlled by a bridge and the FPGA manager + */ + struct fake_fpga_mgr *mgr_ctx; + struct fake_fpga_bridge *bridge_ctx; + struct fake_fpga_region *region_ctx; +}; + +static int fpga_test_init(struct kunit *test) +{ + struct fpga_base_ctx *base_ctx; + int ret; + + base_ctx = kunit_kzalloc(test, sizeof(*base_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, base_ctx); + test->priv = base_ctx; + + /* Build the base FPGA layout */ + base_ctx->mgr_ctx = kunit_kzalloc(test, sizeof(*base_ctx->mgr_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, base_ctx->mgr_ctx); + ret = fake_fpga_mgr_register(base_ctx->mgr_ctx, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + base_ctx->bridge_ctx = kunit_kzalloc(test, sizeof(*base_ctx->bridge_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, base_ctx->bridge_ctx); + ret = fake_fpga_bridge_register(base_ctx->bridge_ctx, NULL, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* The base region a child of the base bridge */ + base_ctx->region_ctx = kunit_kzalloc(test, sizeof(*base_ctx->region_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, base_ctx->region_ctx); + ret = fake_fpga_region_register(base_ctx->region_ctx, base_ctx->mgr_ctx->mgr, + &base_ctx->bridge_ctx->bridge->dev, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_region_add_bridge(base_ctx->region_ctx, base_ctx->bridge_ctx->bridge); + + kunit_info(test, "FPGA base system built\n"); + + KUNIT_EXPECT_EQ(test, 0, fake_fpga_mgr_get_rcfg_count(base_ctx->mgr_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(base_ctx->bridge_ctx)); + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(base_ctx->bridge_ctx)); + + return 0; +} + +static void fpga_test_exit(struct kunit *test) +{ + struct fpga_base_ctx *base_ctx; + + base_ctx = test->priv; + + if (!base_ctx) + return; + + if (base_ctx->region_ctx) + fake_fpga_region_unregister(base_ctx->region_ctx); + + if (base_ctx->bridge_ctx) + fake_fpga_bridge_unregister(base_ctx->bridge_ctx); + + if (base_ctx->mgr_ctx) + fake_fpga_mgr_unregister(base_ctx->mgr_ctx); +} + +static void fpga_test_static_cfg(struct kunit *test) +{ + struct fpga_base_ctx *base_ctx; + struct fpga_image_info *buf_img_info; + struct fpga_image_info *sgt_img_info; + int ret; + + base_ctx = test->priv; + + buf_img_info = buf_img_alloc(test, &base_ctx->mgr_ctx->pdev->dev, STATIC_IMG_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf_img_info); + + /* Configure the FPGA using the image in a buffer */ + base_ctx->region_ctx->region->info = buf_img_info; + ret = fpga_region_program_fpga(base_ctx->region_ctx->region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(base_ctx->mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(base_ctx->mgr_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(base_ctx->bridge_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(base_ctx->bridge_ctx)); + + kunit_info(test, "FPGA configuration completed using a buffer image\n"); + + sgt_img_info = sgt_img_alloc(test, &base_ctx->mgr_ctx->pdev->dev, STATIC_IMG_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt_img_info); + + /* Re-configure the FPGA using the image in a scatter list */ + base_ctx->region_ctx->region->info = sgt_img_info; + ret = fpga_region_program_fpga(base_ctx->region_ctx->region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_sgt(base_ctx->mgr_ctx); + + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(base_ctx->mgr_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(base_ctx->bridge_ctx)); + KUNIT_EXPECT_EQ(test, 2, fake_fpga_bridge_get_cycles_count(base_ctx->bridge_ctx)); + + kunit_info(test, "FPGA configuration completed using scatter gather table image\n"); + + img_free(sgt_img_info); +} + +static void fpga_test_partial_rcfg(struct kunit *test) +{ + struct fpga_base_ctx *base_ctx; + struct fake_fpga_region *sub_region_0_ctx, *sub_region_1_ctx; + struct fake_fpga_bridge *sub_bridge_0_ctx, *sub_bridge_1_ctx; + struct fpga_image_info *partial_img_info; + int ret; + + base_ctx = test->priv; + + /* + * Add two reconfigurable sub-regions, each controlled by a bridge. The + * reconfigurable sub-region are children of their bridges which are, + * in turn, children of the base region. For simplicity, the same image + * is used to configure reconfigurable regions + */ + sub_bridge_0_ctx = kunit_kzalloc(test, sizeof(*sub_bridge_0_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sub_bridge_0_ctx); + ret = fake_fpga_bridge_register(sub_bridge_0_ctx, + &base_ctx->region_ctx->region->dev, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + sub_region_0_ctx = kunit_kzalloc(test, sizeof(*sub_region_0_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sub_region_0_ctx); + ret = fake_fpga_region_register(sub_region_0_ctx, base_ctx->mgr_ctx->mgr, + &sub_bridge_0_ctx->bridge->dev, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_region_add_bridge(sub_region_0_ctx, sub_bridge_0_ctx->bridge); + + sub_bridge_1_ctx = kunit_kzalloc(test, sizeof(*sub_bridge_1_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sub_bridge_1_ctx); + ret = fake_fpga_bridge_register(sub_bridge_1_ctx, + &base_ctx->region_ctx->region->dev, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + sub_region_1_ctx = kunit_kzalloc(test, sizeof(*sub_region_1_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sub_region_1_ctx); + ret = fake_fpga_region_register(sub_region_1_ctx, base_ctx->mgr_ctx->mgr, + &sub_bridge_1_ctx->bridge->dev, test); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_region_add_bridge(sub_region_1_ctx, sub_bridge_1_ctx->bridge); + + /* Allocate a partial image using a buffer */ + partial_img_info = buf_img_alloc(test, &base_ctx->mgr_ctx->pdev->dev, + PARTIAL_IMG_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, partial_img_info); + partial_img_info->flags = FPGA_MGR_PARTIAL_RECONFIG; + + /* Re-configure sub-region 0 with the partial image */ + sub_region_0_ctx->region->info = partial_img_info; + ret = fpga_region_program_fpga(sub_region_0_ctx->region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(base_ctx->mgr_ctx); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_mgr_get_rcfg_count(base_ctx->mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(sub_bridge_0_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(sub_bridge_0_ctx)); + + /* Re-configure sub-region 1 with the partial image */ + sub_region_1_ctx->region->info = partial_img_info; + ret = fpga_region_program_fpga(sub_region_1_ctx->region); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write_buf(base_ctx->mgr_ctx); + KUNIT_EXPECT_EQ(test, 2, fake_fpga_mgr_get_rcfg_count(base_ctx->mgr_ctx)); + + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(sub_bridge_1_ctx)); + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_cycles_count(sub_bridge_1_ctx)); + + /* Check that the base bridge has not been disabled during reconfiguration */ + KUNIT_EXPECT_EQ(test, 1, fake_fpga_bridge_get_state(base_ctx->bridge_ctx)); + KUNIT_EXPECT_EQ(test, 0, fake_fpga_bridge_get_cycles_count(base_ctx->bridge_ctx)); + + img_free(partial_img_info); + fake_fpga_region_unregister(sub_region_0_ctx); + fake_fpga_bridge_unregister(sub_bridge_0_ctx); + fake_fpga_region_unregister(sub_region_1_ctx); + fake_fpga_bridge_unregister(sub_bridge_1_ctx); +} + +static struct kunit_case fpga_test_cases[] = { + KUNIT_CASE(fpga_test_static_cfg), + KUNIT_CASE(fpga_test_partial_rcfg), + {} +}; + +static struct kunit_suite fpga_suite = { + .name = "fpga", + .init = fpga_test_init, + .exit = fpga_test_exit, + .test_cases = fpga_test_cases, +}; + +kunit_test_suites(&fpga_mgr_suite, &fpga_bridge_suite, &fpga_suite); + +MODULE_LICENSE("GPL v2");