From patchwork Thu May 11 14:19:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 92643 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:3046:b0:115:7a1d:dabb with SMTP id p6csp4475917rwl; Thu, 11 May 2023 07:24:01 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4tAaW7/MY2hsV2Y1mO5YWt3w42D2sTIUrvQEV4RYaydjJBp8cb5Vn7YJ2PZnSeZURWwEVl X-Received: by 2002:a17:90b:400a:b0:24e:1c3d:e624 with SMTP id ie10-20020a17090b400a00b0024e1c3de624mr19960098pjb.25.1683815040632; Thu, 11 May 2023 07:24:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683815040; cv=none; d=google.com; s=arc-20160816; b=klREEZFTDgwScJIQeW1XuZKD91+tGAc3fTC6uxh+M9OrMayiBjzdDWMSGPiQ/eFQJE +ba8hOfzRZajyf4UDjr1iHldVwHWGxFqsDSTRxF005gz66oPb/aLI4Lcnd0VffHUlwrU WkyLIfXXVZWrZets2SA51FASP0w+G19QdsE55Zb5M4SaOQ924vmC1QvFhrSOprmOnERE xe0NASWH32yYWHhfXL0LuDchIb5JjlnNCnqgMkbOgFy3gosOG7yAi7O8VPRG79IbwsVm Kjq5fxhTfZwicw8H86JgBnDFJFkCB1UzKRh/R9UKfE4S/61BDIvK+ydEx3HtU55Njzdy mR0w== 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=A3JyemX4wBKEk8PrT7a2ZLhtspMQc4S/1qp1M7U5InU=; b=ojs8ecKntShPiw+YinkhjNYqsxQLKgxgw7eOK1QCvih5ly8FW6nHz7dkisK6fe9M2S O3/BGnAiiin27Ftrb/4CgDxjPF2EAzu6ub+FdAKd+ObpjK531XfHp++NmugwikTwID8L WlYw7Jpn9fi9yVbNF6K8gdEBeChOT/1VHWuD00KI8LBu6n5iys8Ag5945iXjwZ9IqwsA cgoC9tG7dEsH2NB85nO+DNDtZXCq+v+ZhfkOfcFan/B5NfqAl6yGhWIp6WD4VURwHwtS RJwuawnMzO/9exOiUEzqE8o99ERJNOFwjKAMBAbmMYZbSsnNgfsqjhnIYWMLZvaC/QVN brJA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=F15GnB44; 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 x7-20020a17090aca0700b0024dd8ed1373si20138876pjt.185.2023.05.11.07.23.45; Thu, 11 May 2023 07:24:00 -0700 (PDT) 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=F15GnB44; 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 S237901AbjEKOUk (ORCPT + 99 others); Thu, 11 May 2023 10:20:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237928AbjEKOUi (ORCPT ); Thu, 11 May 2023 10:20:38 -0400 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 0934C1BF2 for ; Thu, 11 May 2023 07:19:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683814794; 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=A3JyemX4wBKEk8PrT7a2ZLhtspMQc4S/1qp1M7U5InU=; b=F15GnB44eIkyiPBs/KZzcsoZxeb5NQnYRy6wvh13NgJoI+PVPWRGECxzoKGlpsOT1unKwg ciZGtCXuvAEmW5oFI1VMgH8a0mNBvvWJoc196aHg/qmcgwB/Yebu/CXHs9voCC7584ZmK6 PWtLiACqnQv06nRRKITuPjMLwCudrEg= Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-495-DTktl4nWPPCA5wYrWXtQQg-1; Thu, 11 May 2023 10:19:53 -0400 X-MC-Unique: DTktl4nWPPCA5wYrWXtQQg-1 Received: by mail-qv1-f71.google.com with SMTP id 6a1803df08f44-61acaf012f0so49835846d6.1 for ; Thu, 11 May 2023 07:19:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683814792; x=1686406792; 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=A3JyemX4wBKEk8PrT7a2ZLhtspMQc4S/1qp1M7U5InU=; b=ChOVIR0/IYGAshG766HhUSNNXNWZEJgSf6gjAm4W6ldiMNNecg5Pvo/W4IKZA+xCip +a8BoljFXYItrCxTV5ahozk0+V6Zdh8gIL9BK8fkuKIfLqI6gmbFlneyEKyy01cwPsG9 +gb6aCB5+9SxWIdPAPSnkqXAB+oNEFU6i0Ie/lEr38q8+hHwV8jzwYFhUllG84hx7aKj VH9Dr3elMCXMOj4tHRbM9nSTgAKuZ0PjQgTdWynUiWu4JNUkidlw8tRTHnXRNIFcQzX4 TTL5d0iHWs0vqPllAqocrq1UCun/tYx2cqSwna1JPmfV+nr/68MQHiguJ/TY2V9mRbUs zQqg== X-Gm-Message-State: AC+VfDwDLI1vEKQEePxPosE9whbg2g9ptOCL4YRQa/eAtlorjAd4Sh4W kIMcL5hMADzu7M4JhduF2yORI+yILfr/TLNgsLWA/TCjV48hFS8Ad5qlGvoCh4ZU/L5hkhOpsHh tM9s3F3QroCEu6MRh3Rl7+Wk= X-Received: by 2002:a05:6214:628:b0:621:42c8:9bdd with SMTP id a8-20020a056214062800b0062142c89bddmr12976242qvx.29.1683814792430; Thu, 11 May 2023 07:19:52 -0700 (PDT) X-Received: by 2002:a05:6214:628:b0:621:42c8:9bdd with SMTP id a8-20020a056214062800b0062142c89bddmr12976197qvx.29.1683814791992; Thu, 11 May 2023 07:19:51 -0700 (PDT) Received: from klayman.redhat.com (net-2-34-28-169.cust.vodafonedsl.it. [2.34.28.169]) by smtp.gmail.com with ESMTPSA id oo11-20020a05620a530b00b0074db94ed42fsm965516qkn.116.2023.05.11.07.19.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 May 2023 07:19:51 -0700 (PDT) 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 v5 1/4] fpga: add fake FPGA manager Date: Thu, 11 May 2023 16:19:19 +0200 Message-Id: <20230511141922.437328-2-marpagan@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230511141922.437328-1-marpagan@redhat.com> References: <20230511141922.437328-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, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE 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?1765608040020028684?= X-GMAIL-MSGID: =?utf-8?q?1765608040020028684?= Add fake FPGA manager 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-mgr.c | 271 +++++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-mgr.h | 53 ++++++ 2 files changed, 324 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..1e994db10159 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-mgr.c @@ -0,0 +1,271 @@ +// 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 "fake-fpga-mgr.h" + +#define FAKE_FPGA_MGR_DEV_NAME "fake_fpga_mgr" + +struct fake_mgr_pdata { + struct kunit *test; + struct fake_fpga_mgr_stats *stats; +}; + +struct fake_mgr_priv { + int seq_num; + struct fake_mgr_pdata *pdata; +}; + +static bool check_header(struct kunit *test, const char *buf, size_t count) +{ + size_t i; + + for (i = 0; i < count; i++) + if (buf[i] != TEST_HEADER_MAGIC) + return false; + + return true; +} + +static enum fpga_mgr_states op_state(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + kunit_info(priv->pdata->test, "Fake FPGA manager: state\n"); + + return mgr->state; +} + +static u64 op_status(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + kunit_info(priv->pdata->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; + + /* Set header_size and data_size as expected */ + info->header_size = TEST_HEADER_SIZE; + info->data_size = info->count - TEST_HEADER_SIZE; + + priv->pdata->stats->header_done = check_header(priv->pdata->test, buf, + info->header_size); + priv->pdata->stats->op_parse_header_state = mgr->state; + priv->pdata->stats->op_parse_header_seq = priv->seq_num++; + + kunit_info(priv->pdata->test, "Fake FPGA manager: parse_header\n"); + + 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; + + priv->pdata->stats->op_write_init_state = mgr->state; + priv->pdata->stats->op_write_init_seq = priv->seq_num++; + + kunit_info(priv->pdata->test, "Fake FPGA manager: write_init\n"); + + return 0; +} + +static int op_write(struct fpga_manager *mgr, const char *buf, size_t count) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + priv->pdata->stats->op_write_state = mgr->state; + priv->pdata->stats->op_write_seq = priv->seq_num++; + + kunit_info(priv->pdata->test, "Fake FPGA manager: write\n"); + + return 0; +} + +static int op_write_sg(struct fpga_manager *mgr, struct sg_table *sgt) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + priv->pdata->stats->op_write_state = mgr->state; + priv->pdata->stats->op_write_seq = priv->seq_num++; + + kunit_info(priv->pdata->test, "Fake FPGA manager: write_sg\n"); + + return 0; +} + +static int op_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + priv->pdata->stats->op_write_complete_state = mgr->state; + priv->pdata->stats->op_write_complete_seq = priv->seq_num++; + priv->pdata->stats->prog_count++; + + kunit_info(priv->pdata->test, "Fake FPGA manager: write_complete\n"); + + return 0; +} + +static void op_fpga_remove(struct fpga_manager *mgr) +{ + struct fake_mgr_priv *priv; + + priv = mgr->priv; + + kunit_info(priv->pdata->test, "Fake FPGA manager: remove\n"); +} + +static const struct fpga_manager_ops fake_fpga_mgr_ops = { + .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. + * @test: KUnit test context object. + * @mgr_ctx: fake FPGA manager context data structure. + * + * Return: pointer to a new fake FPGA manager on success, an ERR_PTR() + * encoded error code on failure. + */ +struct fake_fpga_mgr * +fake_fpga_mgr_register(struct kunit *test, struct device *parent) +{ + struct fake_fpga_mgr *mgr_ctx; + struct fake_mgr_pdata pdata; + int ret; + + mgr_ctx = kunit_kzalloc(test, sizeof(*mgr_ctx), GFP_KERNEL); + if (!mgr_ctx) { + ret = -ENOMEM; + goto err_mem; + } + + mgr_ctx->pdev = platform_device_alloc(FAKE_FPGA_MGR_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (!mgr_ctx->pdev) { + kunit_err(test, "Fake FPGA manager device allocation failed\n"); + ret = -ENOMEM; + goto err_mem; + } + + pdata.test = test; + pdata.stats = &mgr_ctx->stats; + platform_device_add_data(mgr_ctx->pdev, &pdata, sizeof(pdata)); + + mgr_ctx->pdev->dev.parent = parent; + ret = platform_device_add(mgr_ctx->pdev); + if (ret) { + kunit_err(test, "Fake FPGA manager device add failed\n"); + goto err_pdev; + } + + mgr_ctx->mgr = platform_get_drvdata(mgr_ctx->pdev); + + kunit_info(test, "Fake FPGA manager registered\n"); + + return mgr_ctx; + +err_pdev: + platform_device_put(mgr_ctx->pdev); +err_mem: + return ERR_PTR(ret); +} +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->pdata->test; + + platform_device_unregister(mgr_ctx->pdev); + + kunit_info(test, "Fake FPGA manager unregistered\n"); +} +EXPORT_SYMBOL_GPL(fake_fpga_mgr_unregister); + +static int fake_fpga_mgr_probe(struct platform_device *pdev) +{ + struct device *dev; + struct fake_mgr_pdata *pdata; + struct fpga_manager *mgr; + struct fake_mgr_priv *priv; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdata = pdata; + + 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_LICENSE("GPL"); diff --git a/drivers/fpga/tests/fake-fpga-mgr.h b/drivers/fpga/tests/fake-fpga-mgr.h new file mode 100644 index 000000000000..282c20d8e40c --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-mgr.h @@ -0,0 +1,53 @@ +/* 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 +#include + +#define FPGA_IMG_BLOCK 1024 +#define TEST_HEADER_MAGIC 0x3f +#define TEST_HEADER_SIZE FPGA_IMG_BLOCK + +struct fake_fpga_mgr_stats { + u32 prog_count; + bool header_done; + u32 op_parse_header_seq; + u32 op_write_init_seq; + u32 op_write_seq; + u32 op_write_complete_seq; + enum fpga_mgr_states op_parse_header_state; + enum fpga_mgr_states op_write_init_state; + enum fpga_mgr_states op_write_state; + enum fpga_mgr_states op_write_complete_state; +}; + +/** + * struct fake_fpga_mgr - fake FPGA manager context data structure + * + * @mgr: FPGA manager. + * @pdev: platform device of the FPGA manager. + * @stats: info from the low level driver. + */ +struct fake_fpga_mgr { + struct fpga_manager *mgr; + struct platform_device *pdev; + struct fake_fpga_mgr_stats stats; +}; + +struct fake_fpga_mgr * +fake_fpga_mgr_register(struct kunit *test, struct device *parent); + +void fake_fpga_mgr_unregister(struct fake_fpga_mgr *mgr_ctx); + +#endif /* __FPGA_FAKE_MGR_H */ From patchwork Thu May 11 14:19:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 92645 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:3046:b0:115:7a1d:dabb with SMTP id p6csp4476857rwl; Thu, 11 May 2023 07:25:20 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4jciYW4E1hl7T77Iwsy3dGYUrcFlhcCpH1yDLa8U4gnTPpKfrpI1cTlzCdaFKGFt5NhJRt X-Received: by 2002:a05:6a00:234f:b0:643:59cd:6cad with SMTP id j15-20020a056a00234f00b0064359cd6cadmr27220193pfj.24.1683815120233; Thu, 11 May 2023 07:25:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683815120; cv=none; d=google.com; s=arc-20160816; b=qXHG1S1+PaaEMyC0RV40d6MOfmbJJLM/hHjHHbXCobAPn4vZ5nvEJAgDzFgxmDC/tc F1WpugBIrcuTFMvFB5vLpfzMBmHU910XdXdC3RygN5oqL2OxExuDkwth4pYOkeltM6eY uvzV0GkBM5ABj7XJFI1US1c8MrtTBTeoZxo3C7UV3xM6HER2np/Rqp+GTgED/mx35hZS 9bMiKdQKYgGojWQzaH4A0XlO5S2IFBfMc5Y5MBxcuQ8QjtGd+2q1278IIJMyOv2EN0dd M4EIRBg1xVs43w4lW8p7l8sBu09KVGs2Qd/i563IgGLKNUDznQoqYxUHCPJZ9qv24Xhs jIWg== 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=y7yrARP0OaOnDRJGgagTj/prTEpIs9t+1o9Qdk5PnIg=; b=ZHI55FqaO3Rne5852FbAD0zYxEOTz3xqKxAHL46sAYl/iMHehj0c3MRVncbdjDodMY nxY5HcH3KTgG8xHgaf66XU1eqx2biLb7IkLNfvKhf0k8Jd1iAz6ePMqjeVoM0IuglkuO s3leXj6fhsysXJaPoK3uzsyy0rPUBtrJ5td15P7LrfHmokrvuGuiNyIMYzLdZ7Xtc9Wi 48UQXkUxI3TS45nKwWcWeD2PuOMzeccvg1C6fEN0b8EgLGCUSY2EHNWfBdp7CYbGyfs8 9rXP5jlruFGsUfeHlhXFMhlcYwC+egTsbeUNSODMJJ+2UfIz8LzMxt0VOgNtwPCiiRdj 5KWw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=YEa2O6t3; 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 e5-20020aa79805000000b006367f3bb8a9si7544013pfl.249.2023.05.11.07.24.43; Thu, 11 May 2023 07:25:20 -0700 (PDT) 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=YEa2O6t3; 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 S238270AbjEKOU5 (ORCPT + 99 others); Thu, 11 May 2023 10:20:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238169AbjEKOUs (ORCPT ); Thu, 11 May 2023 10:20:48 -0400 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 6291C1BFF for ; Thu, 11 May 2023 07:20:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683814799; 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=y7yrARP0OaOnDRJGgagTj/prTEpIs9t+1o9Qdk5PnIg=; b=YEa2O6t3RL2YJIKfqBmu9DwNFsdG8Y7pRW0/6XO2IY5Su8/vNuiRP0YEE9gP76zkaoHG9Q cVQpJ9QJ955eR4sEUwHgDVkQIU7QPO4TuhlktXws3lKfbWvqYV9bZwCWkcHn8oc0UNd3kq /TWTR9URPf98e5tqw7M1nm0Ypm5G41c= Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-652-7WMy54S9OeiM798loCMD2Q-1; Thu, 11 May 2023 10:19:58 -0400 X-MC-Unique: 7WMy54S9OeiM798loCMD2Q-1 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-3f4e2e7c742so13076111cf.0 for ; Thu, 11 May 2023 07:19:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683814798; x=1686406798; 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=y7yrARP0OaOnDRJGgagTj/prTEpIs9t+1o9Qdk5PnIg=; b=f0MtOld9jnL22r64blX8kQXscFUW5X7PSYY0st4DpQKyTXpRRWQOhaId3w2FQ3ARgo /nxDi9lMdTBM2E7tXcv21rnQgXUv2mLBnzsU+NtwbgzSXZ6XGO8jN4RAbxcSBacjhSb2 eCwhpaZsKjB5IF57V0L+26P8hYMnXe+mHJ4JEmwIl+8otEMyB+0MDZ1OKxeGIf16ntae uC5z3jdfJuOwEO7jqBm3l9lWxunBEkvWgTdfQSwltsTWXgRtJwgGr9+NL26SzGAMb1Yp b5hMzOgeFLe7l7GeNzWZ2k++YSBWbQocc882GoNAlya5tqyhSbD9BrqpdoDleBQWUj4c KoxA== X-Gm-Message-State: AC+VfDw39iEvaSwHCMdrOeqFtPUo0Hi3EMtcXdVJR1d+Ce9S/q39MJKQ afG3rBwzV3piYBl2Vnnc0OqGQuUAzBOtkrZObH1jH3vr4IwqKzEkfPG0qeLpERhIhHJnzvelvy0 VstBffL1JjOZoackafnhLvp8= X-Received: by 2002:a05:622a:651:b0:3f3:8f4a:a5e1 with SMTP id a17-20020a05622a065100b003f38f4aa5e1mr22159272qtb.19.1683814798090; Thu, 11 May 2023 07:19:58 -0700 (PDT) X-Received: by 2002:a05:622a:651:b0:3f3:8f4a:a5e1 with SMTP id a17-20020a05622a065100b003f38f4aa5e1mr22159231qtb.19.1683814797771; Thu, 11 May 2023 07:19:57 -0700 (PDT) Received: from klayman.redhat.com (net-2-34-28-169.cust.vodafonedsl.it. [2.34.28.169]) by smtp.gmail.com with ESMTPSA id oo11-20020a05620a530b00b0074db94ed42fsm965516qkn.116.2023.05.11.07.19.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 May 2023 07:19:57 -0700 (PDT) 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 v5 2/4] fpga: add fake FPGA bridge Date: Thu, 11 May 2023 16:19:20 +0200 Message-Id: <20230511141922.437328-3-marpagan@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230511141922.437328-1-marpagan@redhat.com> References: <20230511141922.437328-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,T_SCC_BODY_TEXT_LINE 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?1765608123589351398?= X-GMAIL-MSGID: =?utf-8?q?1765608123589351398?= Add fake FPGA bridge 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-bridge.c | 203 ++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-bridge.h | 40 +++++ 2 files changed, 243 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..e5db0a809ee3 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-bridge.c @@ -0,0 +1,203 @@ +// 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_pdata { + struct kunit *test; + struct fake_fpga_bridge_stats *stats; +}; + +struct fake_bridge_priv { + bool state; + struct fake_bridge_pdata *pdata; +}; + +static int op_enable_show(struct fpga_bridge *bridge) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + kunit_info(priv->pdata->test, "Fake FPGA bridge %u: enable_show\n", + bridge->dev.id); + + return priv->state; +} + +static int op_enable_set(struct fpga_bridge *bridge, bool enable) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + if (enable && !priv->state) + priv->pdata->stats->cycles_count++; + + priv->state = enable; + priv->pdata->stats->enable = priv->state; + + kunit_info(priv->pdata->test, "Fake FPGA bridge %u: enable_set: %d\n", + bridge->dev.id, enable); + + return 0; +} + +static void op_remove(struct fpga_bridge *bridge) +{ + struct fake_bridge_priv *priv; + + priv = bridge->priv; + + kunit_info(priv->pdata->test, "Fake FPGA bridge %u: remove\n", + bridge->dev.id); +} + +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. + * @test: KUnit test context object. + * @parent: parent device. + * + * Return: pointer to a new fake FPGA bridge on success, an ERR_PTR() + * encoded error code on failure. + */ +struct fake_fpga_bridge * +fake_fpga_bridge_register(struct kunit *test, struct device *parent) +{ + struct fake_fpga_bridge *bridge_ctx; + struct fake_bridge_pdata pdata; + struct fake_bridge_priv *priv; + int ret; + + bridge_ctx = kunit_kzalloc(test, sizeof(*bridge_ctx), GFP_KERNEL); + if (!bridge_ctx) { + ret = -ENOMEM; + goto err_mem; + } + + bridge_ctx->pdev = platform_device_alloc(FAKE_FPGA_BRIDGE_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (!bridge_ctx->pdev) { + pr_err("Fake FPGA bridge device allocation failed\n"); + ret = -ENOMEM; + goto err_mem; + } + + pdata.test = test; + pdata.stats = &bridge_ctx->stats; + platform_device_add_data(bridge_ctx->pdev, &pdata, sizeof(pdata)); + + bridge_ctx->pdev->dev.parent = parent; + ret = platform_device_add(bridge_ctx->pdev); + if (ret) { + pr_err("Fake FPGA bridge device add failed\n"); + goto err_pdev; + } + + bridge_ctx->bridge = platform_get_drvdata(bridge_ctx->pdev); + + priv = bridge_ctx->bridge->priv; + bridge_ctx->stats.enable = priv->state; + + kunit_info(test, "Fake FPGA bridge %u: registered\n", + bridge_ctx->bridge->dev.id); + + return bridge_ctx; + +err_pdev: + platform_device_put(bridge_ctx->pdev); +err_mem: + return ERR_PTR(ret); +} +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; + u32 id; + + if (!bridge_ctx) + return; + + id = bridge_ctx->bridge->dev.id; + priv = bridge_ctx->bridge->priv; + test = priv->pdata->test; + + platform_device_unregister(bridge_ctx->pdev); + + kunit_info(test, "Fake FPGA bridge %u: unregistered\n", id); +} +EXPORT_SYMBOL_GPL(fake_fpga_bridge_unregister); + +static int fake_fpga_bridge_probe(struct platform_device *pdev) +{ + struct device *dev; + struct fake_bridge_pdata *pdata; + struct fpga_bridge *bridge; + struct fake_bridge_priv *priv; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdata = pdata; + priv->state = true; + + 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_LICENSE("GPL"); diff --git a/drivers/fpga/tests/fake-fpga-bridge.h b/drivers/fpga/tests/fake-fpga-bridge.h new file mode 100644 index 000000000000..3ecfab7e2890 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-bridge.h @@ -0,0 +1,40 @@ +/* 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 +#include + +struct fake_fpga_bridge_stats { + bool enable; + u32 cycles_count; +}; + +/** + * struct fake_fpga_bridge - fake FPGA bridge context data structure + * + * @bridge: FPGA bridge. + * @pdev: platform device of the FPGA bridge. + * @stats: info from the low level driver. + */ +struct fake_fpga_bridge { + struct fpga_bridge *bridge; + struct platform_device *pdev; + struct fake_fpga_bridge_stats stats; +}; + +struct fake_fpga_bridge * +fake_fpga_bridge_register(struct kunit *test, struct device *parent); + +void fake_fpga_bridge_unregister(struct fake_fpga_bridge *bridge_ctx); + +#endif /* __FPGA_FAKE_BRIDGE_H */ From patchwork Thu May 11 14:19:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 92646 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:3046:b0:115:7a1d:dabb with SMTP id p6csp4478039rwl; Thu, 11 May 2023 07:27:15 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4xzgKhysmZvsY2GDUThwCq56Y3NTFbkylzshlTnGEN0F2OjWxsExVQ2E3JgRpH658QCaYq X-Received: by 2002:a17:902:f683:b0:1ac:8148:8c3e with SMTP id l3-20020a170902f68300b001ac81488c3emr17556037plg.32.1683815235472; Thu, 11 May 2023 07:27:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683815235; cv=none; d=google.com; s=arc-20160816; b=ZoQRnKhPsIsw0xjjMQC7f/d72ghZGAeP3DY2/6vTBbLdBJY7p8vLF76N1KTs5ixHFL BfC3hTugcXczxLVV7Aw6AWdn2/svjv84z5fH+2DxmIZxC27/N3N/rXhxrjsml9uX9kXL AhNzf5cnTWN8xIY/PJFdDoeVSB/Fuho1ID5KI1jmF5rKzuYLgm8KH2Xuy+tpp2OYD3v4 0LS+BWbS813a6+Dy9fCKVlZgLu84hjy/eF8cPylpYrbGxa9g4oNty+FNkAxQ5QysAIx5 vMlJRspTMXGH8JfXwYJ4sFZD2PDDyGSVChgiL4C1SYBr/OVtjGkzsuLSBZs55yueXPL/ PQow== 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=tQ5Ey0GxlvfOuwjDlz/RC7ExtmJfITLgsdhieZAj2To=; b=NtT/XsRtA8FdbQoNSLjOlwVLTTXbUKk3Oj8DMPgfmh9nztYYo2utE/kN491uXM2rsE uOzy7hWEDZuScy043s5u3gEGH4Crifd2pWAOLSvKi43/GEYpkE1AlVcm22r337QI5xa/ Qo2Pq2sGEpHbQqZgJz20k5XTN2odpbQo8F18/6pwFuXSJSZiMSAw7qbuV4BhDPuWK2nW 7Vwil2qjekSHGL4uAITC9trzgOnO7U2szpanx2y4FKPgAx7vSLOYHZ9YyR0Xplr7RREL uzPNzdzCd21XTpl0YXLXjy2tn9vhV+R169SKYfbz78oOxDin/giI8W2MsWN6o6GgedGs WE7A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=aSXm2XUw; 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 w10-20020a170902904a00b001a63a7b7025si6631322plz.30.2023.05.11.07.26.59; Thu, 11 May 2023 07:27:15 -0700 (PDT) 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=aSXm2XUw; 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 S237928AbjEKOVA (ORCPT + 99 others); Thu, 11 May 2023 10:21:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37654 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238200AbjEKOUt (ORCPT ); Thu, 11 May 2023 10:20:49 -0400 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 677272711 for ; Thu, 11 May 2023 07:20:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683814804; 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=tQ5Ey0GxlvfOuwjDlz/RC7ExtmJfITLgsdhieZAj2To=; b=aSXm2XUwB6QacW6hEVrt6w+6OAiM+QSQG+7DAs+yKC3WNHu5D8z7AAyy/jh0G36GnQr3F/ sQTRyaSnjUoX/qA2h8t3ID4duyseZiHYt9MHAb6fCbR6lzUUDmc5ZVhpff5h6qr6i5Nvta Ly4xtawkXKpBZ/h6b9u1j2Ju9duZvmE= Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-50-OPH85rrYOH2N3rYJ7EZTyA-1; Thu, 11 May 2023 10:20:03 -0400 X-MC-Unique: OPH85rrYOH2N3rYJ7EZTyA-1 Received: by mail-qt1-f199.google.com with SMTP id d75a77b69052e-3f38fe55146so31487021cf.3 for ; Thu, 11 May 2023 07:20:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683814802; x=1686406802; 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=tQ5Ey0GxlvfOuwjDlz/RC7ExtmJfITLgsdhieZAj2To=; b=G0VXHkXA30t/6YKavICFk8ne0jcSGA61BgtaGqsl0DV/ZBqUYWtMqAS8FwgLpt4NaG mDnpg6aYvktQAPf18aRNMuJGSlAqepanjnbON7XbHLLYfNfX20CThCGBXirOnPUhePCO pGmD997sblCrvR4MvNcQBQNJNzKlk3pVPqYcAxe9gTnez1zKBf3TbR/gHlXlxT9wJ93s tly5V6Z6FgX2WYzAsP7K1dH9ZMT+zbXV5GM1+/pWYhWQiF1KhhKzlVxTnNXKEg6sz+qQ yH9IBBu3++8vRyZPs5uj3l01tlnAhDMJzDE9SBe0ahJrKPKQMYWOCnDOzTMUbTeNwMGv WJUA== X-Gm-Message-State: AC+VfDwAHy6NfeL4DkzG50xHYJrZOP8LUcheyiHWtCrby8JkzJr8D2vg eOr8JeGmMtIr/JIzq/z67josA7AKV3fVxDJYjYd3lsBUMJcAibFP2uPWUw+cqFn7Mn7ntjJBC/F 5xChhE2CbllC9hiHXv+oR4g4= X-Received: by 2002:a05:622a:1b92:b0:3f3:a36d:1bd with SMTP id bp18-20020a05622a1b9200b003f3a36d01bdmr11928283qtb.44.1683814802073; Thu, 11 May 2023 07:20:02 -0700 (PDT) X-Received: by 2002:a05:622a:1b92:b0:3f3:a36d:1bd with SMTP id bp18-20020a05622a1b9200b003f3a36d01bdmr11928248qtb.44.1683814801750; Thu, 11 May 2023 07:20:01 -0700 (PDT) Received: from klayman.redhat.com (net-2-34-28-169.cust.vodafonedsl.it. [2.34.28.169]) by smtp.gmail.com with ESMTPSA id oo11-20020a05620a530b00b0074db94ed42fsm965516qkn.116.2023.05.11.07.20.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 May 2023 07:20:01 -0700 (PDT) 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 v5 3/4] fpga: add fake FPGA region Date: Thu, 11 May 2023 16:19:21 +0200 Message-Id: <20230511141922.437328-4-marpagan@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230511141922.437328-1-marpagan@redhat.com> References: <20230511141922.437328-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,T_SCC_BODY_TEXT_LINE 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?1765608244400929717?= X-GMAIL-MSGID: =?utf-8?q?1765608244400929717?= 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 | 245 ++++++++++++++++++++++++++ drivers/fpga/tests/fake-fpga-region.h | 40 +++++ 2 files changed, 285 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..020c3ad13812 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-region.c @@ -0,0 +1,245 @@ +// 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_pdata { + struct kunit *test; + struct fpga_manager *mgr; +}; + +struct bridge_elem { + struct fpga_bridge *bridge; + struct list_head node; +}; + +struct fake_region_priv { + struct list_head bridge_list; + struct fake_region_pdata *pdata; +}; + +/** + * fake_fpga_region_register() - register a fake FPGA region. + * @mgr: associated FPGA manager. + * @parent: parent device. + * @test: KUnit test context object. + * + * Return: pointer to a new fake FPGA region on success, an ERR_PTR() encoded + * error code on failure. + */ +struct fake_fpga_region * +fake_fpga_region_register(struct kunit *test, struct fpga_manager *mgr, + struct device *parent) +{ + struct fake_fpga_region *region_ctx; + struct fake_region_pdata pdata; + int ret; + + region_ctx = kunit_kzalloc(test, sizeof(*region_ctx), GFP_KERNEL); + if (!region_ctx) { + ret = -ENOMEM; + goto err_mem; + } + + region_ctx->pdev = platform_device_alloc(FAKE_FPGA_REGION_DEV_NAME, + PLATFORM_DEVID_AUTO); + if (!region_ctx->pdev) { + pr_err("Fake FPGA region device allocation failed\n"); + ret = -ENOMEM; + goto err_mem; + } + + pdata.mgr = mgr; + pdata.test = test; + platform_device_add_data(region_ctx->pdev, &pdata, sizeof(pdata)); + + region_ctx->pdev->dev.parent = parent; + ret = platform_device_add(region_ctx->pdev); + if (ret) { + pr_err("Fake FPGA region device add failed\n"); + goto err_pdev; + } + + region_ctx->region = platform_get_drvdata(region_ctx->pdev); + + kunit_info(test, "Fake FPGA region %u: registered\n", + region_ctx->region->dev.id); + + return region_ctx; + +err_pdev: + platform_device_put(region_ctx->pdev); +err_mem: + return ERR_PTR(ret); +} +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; + u32 id; + + if (!region_ctx) + return; + + id = region_ctx->region->dev.id; + priv = region_ctx->region->priv; + test = priv->pdata->test; + + platform_device_unregister(region_ctx->pdev); + + kunit_info(test, "Fake FPGA region %u: 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. + */ +int fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, + struct fpga_bridge *bridge) +{ + struct fake_region_priv *priv; + struct bridge_elem *elem; + + priv = region_ctx->region->priv; + + elem = devm_kzalloc(®ion_ctx->pdev->dev, sizeof(*elem), GFP_KERNEL); + if (!elem) + return -ENOMEM; + + /* Add bridge to the list of bridges in the private context */ + elem->bridge = bridge; + list_add(&elem->node, &priv->bridge_list); + + kunit_info(priv->pdata->test, "Bridge: %u added to fake FPGA region: %u\n", + bridge->dev.id, region_ctx->region->dev.id); + + return 0; +} +EXPORT_SYMBOL_GPL(fake_fpga_region_add_bridge); + +int fake_fpga_region_program(struct fake_fpga_region *region_ctx) +{ + int ret; + + ret = fpga_region_program_fpga(region_ctx->region); + + /* fpga_region_program_fpga() already puts the bridges in case of errors */ + if (!ret) + fpga_bridges_put(®ion_ctx->region->bridge_list); + + return ret; +} +EXPORT_SYMBOL_GPL(fake_fpga_region_program); + +static int fake_region_get_bridges(struct fpga_region *region) +{ + struct fake_region_priv *priv; + struct bridge_elem *elem; + int ret; + + priv = region->priv; + + /* Copy the list of bridges from the private context to the region */ + list_for_each_entry(elem, &priv->bridge_list, node) { + ret = fpga_bridge_get_to_list(elem->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_pdata *pdata; + struct fake_region_priv *priv; + struct fpga_region_info info; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + + if (!pdata) { + dev_err(&pdev->dev, "Fake FPGA region probe: 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); + + priv->pdata = pdata; + INIT_LIST_HEAD(&priv->bridge_list); + + 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_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_LICENSE("GPL"); diff --git a/drivers/fpga/tests/fake-fpga-region.h b/drivers/fpga/tests/fake-fpga-region.h new file mode 100644 index 000000000000..c72992cbb218 --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-region.h @@ -0,0 +1,40 @@ +/* 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; +}; + +struct fake_fpga_region * +fake_fpga_region_register(struct kunit *test, struct fpga_manager *mgr, + struct device *parent); + +int fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, + struct fpga_bridge *bridge); + +int fake_fpga_region_program(struct fake_fpga_region *region_ctx); + +void fake_fpga_region_unregister(struct fake_fpga_region *region_ctx); + +#endif /* __FPGA_FAKE_RGN_H */ From patchwork Thu May 11 14:19:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Pagani X-Patchwork-Id: 92644 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:3046:b0:115:7a1d:dabb with SMTP id p6csp4476351rwl; Thu, 11 May 2023 07:24:36 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ675Vm+ERIzI/aefySAYxFAAlXO1BKxMtj22Z4vrpuR5gwPUn5h1W2hea629RQjuHbJwfhf X-Received: by 2002:a17:902:934c:b0:1ac:9885:9f54 with SMTP id g12-20020a170902934c00b001ac98859f54mr8820130plp.63.1683815075943; Thu, 11 May 2023 07:24:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683815075; cv=none; d=google.com; s=arc-20160816; b=tYQ3NozEms3h7PDc+IG4rNOccdirLs3qahXbLSOQtWs1IDKgKe+KvAHU1SidPlVwpc PUScsPvpiRYrNgVSDt6iHs8Wsdb6ycQqO5oQSK+baE/zJBEKki4cJISQAgLQTLYB0bOJ DaXygyKFaAHN7g8m/7QZMSLcus5fWq/9cOm6beUDzdjGJtNClKF5+xi+EHZ5qdpOwJaB hP+rk693y2v1QZGMXiYHfSQXwgd2p9H+jLCCV/sUxzGv4wU7eaUueGIKvWtmCViqln8z o0t+I+TohwMNvaqoZOzFj6Ply6uOHHIpCyUmJGHu//tp2Pas10Msx7WAPIEhH6M2FBOD Ncsw== 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=Cy50tcOwyhJl9w4VDR4Ihi1a/Hg/nhiGVz2Fg1EhbRw=; b=GBbvrmzEY6bs10E0Tv9DXEkEuJJA+mN+qHPjP2i45p9HulM6U+buUfPcgh3RCQ0PwH s6slaI04mboy1M8lXxT8o7szW2lI/2Noj8/z5TQIRs9AOpuITSTfdbAUxUVQsN21kSsi eZR1h+NS6umdaScFEGoQ30Y7O/NIdTV0YzllBxj5bPqQQR6vm+3Twe5rww0jdGGdES69 9pMWWMRIyPEE5jhZ6YtXoJMGHdDfhNurZc38sFawrlGgxgXzKZmjd2vRHHOaMRjqm1EA skV1x0YjBxFh32M2fxAaiGE8NSM3NggSMiRiwEwTbeQGj3b0W3xKUM6xnKm75LeiAnyF SOTw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=HzLCtFPr; 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 s28-20020a63525c000000b00519c3475f12si6535842pgl.572.2023.05.11.07.24.08; Thu, 11 May 2023 07:24:35 -0700 (PDT) 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=HzLCtFPr; 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 S238353AbjEKOVJ (ORCPT + 99 others); Thu, 11 May 2023 10:21:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37732 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238278AbjEKOU5 (ORCPT ); Thu, 11 May 2023 10:20:57 -0400 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 6FF362680 for ; Thu, 11 May 2023 07:20:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683814808; 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=Cy50tcOwyhJl9w4VDR4Ihi1a/Hg/nhiGVz2Fg1EhbRw=; b=HzLCtFPrGHTX6A1CN0yBuMUj+knI3U/FWblksJ2WMqjG35hkjqlAQW8dGttT7+lLNL6Rb/ cjWhXLpvWgl0tH0pP7E4NiCUE3Bch2LWm2swJlG3edqqSCPui55cq2o3TP94DGIPlahsqC 3TsIXmp4GbspHWWbP+S6Fka6UHiul2k= Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-139-uOyEJstuOpK86T8fzRdvtQ-1; Thu, 11 May 2023 10:20:07 -0400 X-MC-Unique: uOyEJstuOpK86T8fzRdvtQ-1 Received: by mail-qt1-f197.google.com with SMTP id d75a77b69052e-3ef6c0a9212so52371101cf.2 for ; Thu, 11 May 2023 07:20:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683814807; x=1686406807; 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=Cy50tcOwyhJl9w4VDR4Ihi1a/Hg/nhiGVz2Fg1EhbRw=; b=FoewqJsE83nZ1PChV55JC7mzh6bDMJhJW0esbTgQPgUcliSOxNvxZTRy26o44Omu/v MsgvFgS4bYPa/VYO4Vk1EF3rAazKKwaZcL/Q0BsiD3YiIuQY1KM3gP5NvtfADEMAw5v3 6tWPrqbZ9efwXRtBb9swRBOlJAEumxfscJRhbEDGUzbJICDkHBAPk2BS9v2rUgCLP7KX IEe6gWLkP8+QxAmJc5vn0kF6g05XXGVfzeyDYp5mbFoMwaoVKbxzhq9x5eLViWowJ9vY zTyl8yjPMW/LhuI+1opAc6torTZcC1iZpRvywPJLtOqlduisbeHf8+cPTdbAoJEB6gWz hHUw== X-Gm-Message-State: AC+VfDzXT/LeNU0Pk08Q310uAbg+RGkgXZwS9iXuMJtbqa1f58GnKgcd zn3YZ+nb2URCTWpAxd2Gui3TxVWXJvSsr5eiEcCJ5R2e/TtAKToeC51TFXlRiJ0u8V7cBzHGE8W yYyXaKkUXTXNYFkuQxtn5lII= X-Received: by 2002:ac8:5a85:0:b0:3f0:ab4e:df6b with SMTP id c5-20020ac85a85000000b003f0ab4edf6bmr29206007qtc.67.1683814806662; Thu, 11 May 2023 07:20:06 -0700 (PDT) X-Received: by 2002:ac8:5a85:0:b0:3f0:ab4e:df6b with SMTP id c5-20020ac85a85000000b003f0ab4edf6bmr29205956qtc.67.1683814806218; Thu, 11 May 2023 07:20:06 -0700 (PDT) Received: from klayman.redhat.com (net-2-34-28-169.cust.vodafonedsl.it. [2.34.28.169]) by smtp.gmail.com with ESMTPSA id oo11-20020a05620a530b00b0074db94ed42fsm965516qkn.116.2023.05.11.07.20.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 May 2023 07:20:06 -0700 (PDT) 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 v5 4/4] fpga: add initial KUnit test suites Date: Thu, 11 May 2023 16:19:22 +0200 Message-Id: <20230511141922.437328-5-marpagan@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230511141922.437328-1-marpagan@redhat.com> References: <20230511141922.437328-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, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE 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?1765608077220068863?= X-GMAIL-MSGID: =?utf-8?q?1765608077220068863?= 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 | 551 ++++++++++++++++++++++++++++++++ 6 files changed, 578 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 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..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..929684c1337e --- /dev/null +++ b/drivers/fpga/tests/fpga-test.c @@ -0,0 +1,551 @@ +// 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) + +/** + * fill_test_header() - fill a buffer with the test header data. + * @buf: image buffer. + * @count: length of the header. + */ +static void fill_test_header(u8 *buf, size_t count) +{ + size_t i; + + for (i = 0; i < count; i++) + buf[i] = TEST_HEADER_MAGIC; +} + +/** + * buf_img_alloc() - Allocate a test 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); + fill_test_header(img_buf, TEST_HEADER_SIZE); + + 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; + img_info->header_size = TEST_HEADER_SIZE; + + kunit_info(test, "FPGA image allocated in a buffer, size: %zu\n", size); + + return img_info; +} + +/** + * sgt_img_alloc() - Allocate a test 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); + fill_test_header(img_buf, TEST_HEADER_SIZE); + + 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; + img_info->header_size = TEST_HEADER_SIZE; + + kunit_info(test, "FPGA image allocated in a scatter gather table, size: %zu\n", + size); + + return img_info; +} + +/** + * img_free() - Free a test 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); +} + +/** + * fake_fpga_mgr_check_write() - check if the programming sequence is correct. + * @test: KUnit test context object. + * @mgr_ctx: fake FPGA manager context data structure. + */ +static void fake_fpga_mgr_check_write(struct kunit *test, + const struct fake_fpga_mgr *mgr_ctx) +{ + KUNIT_EXPECT_TRUE(test, mgr_ctx->stats.header_done); + + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_parse_header_state, + FPGA_MGR_STATE_PARSE_HEADER); + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_init_state, + FPGA_MGR_STATE_WRITE_INIT); + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_state, + FPGA_MGR_STATE_WRITE); + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_complete_state, + FPGA_MGR_STATE_WRITE_COMPLETE); + + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_init_seq, + mgr_ctx->stats.op_parse_header_seq + 1); + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_seq, + mgr_ctx->stats.op_parse_header_seq + 2); + KUNIT_EXPECT_EQ(test, mgr_ctx->stats.op_write_complete_seq, + mgr_ctx->stats.op_parse_header_seq + 3); +} + +static int fpga_mgr_test_init(struct kunit *test) +{ + struct fake_fpga_mgr *mgr_ctx; + + mgr_ctx = fake_fpga_mgr_register(test, NULL); + KUNIT_ASSERT_FALSE(test, IS_ERR(mgr_ctx)); + + 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, mgr_ctx->stats.prog_count); + + ret = fpga_mgr_load(mgr_ctx->mgr, img_info); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, mgr_ctx->stats.prog_count); + + 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, mgr_ctx->stats.prog_count); + + ret = fpga_mgr_load(mgr_ctx->mgr, img_info); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, mgr_ctx->stats.prog_count); + + 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; + + bridge_ctx = fake_fpga_bridge_register(test, NULL); + KUNIT_ASSERT_FALSE(test, IS_ERR(bridge_ctx)); + + 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; + int ret; + + bridge_ctx = test->priv; + + KUNIT_EXPECT_TRUE(test, bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, bridge_ctx->stats.cycles_count); + + ret = fpga_bridge_disable(bridge_ctx->bridge); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_FALSE(test, bridge_ctx->stats.enable); + + ret = fpga_bridge_enable(bridge_ctx->bridge); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_TRUE(test, bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, bridge_ctx->stats.cycles_count); +} + +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 = fake_fpga_bridge_register(test, NULL); + KUNIT_ASSERT_FALSE(test, IS_ERR(bridge_1_ctx)); + + 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)); + + /* Disable an then enable both bridges from the list */ + KUNIT_EXPECT_TRUE(test, bridge_0_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, bridge_0_ctx->stats.cycles_count); + + KUNIT_EXPECT_TRUE(test, bridge_1_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, bridge_1_ctx->stats.cycles_count); + + ret = fpga_bridges_disable(&bridge_list); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_FALSE(test, bridge_0_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, bridge_0_ctx->stats.cycles_count); + + KUNIT_EXPECT_FALSE(test, bridge_1_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, bridge_1_ctx->stats.cycles_count); + + ret = fpga_bridges_enable(&bridge_list); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_TRUE(test, bridge_0_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, bridge_0_ctx->stats.cycles_count); + + KUNIT_EXPECT_TRUE(test, bridge_1_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, bridge_1_ctx->stats.cycles_count); + + /* 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 = fake_fpga_mgr_register(test, NULL); + KUNIT_ASSERT_FALSE(test, IS_ERR(base_ctx->mgr_ctx)); + + base_ctx->bridge_ctx = fake_fpga_bridge_register(test, NULL); + KUNIT_ASSERT_FALSE(test, IS_ERR(base_ctx->bridge_ctx)); + + /* The base region a child of the base bridge */ + base_ctx->region_ctx = fake_fpga_region_register(test, base_ctx->mgr_ctx->mgr, + &base_ctx->bridge_ctx->bridge->dev); + KUNIT_ASSERT_FALSE(test, IS_ERR(base_ctx->region_ctx)); + + ret = fake_fpga_region_add_bridge(base_ctx->region_ctx, base_ctx->bridge_ctx->bridge); + KUNIT_ASSERT_EQ(test, ret, 0); + + kunit_info(test, "FPGA base system built\n"); + + KUNIT_EXPECT_EQ(test, 0, base_ctx->mgr_ctx->stats.prog_count); + KUNIT_EXPECT_TRUE(test, base_ctx->bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, base_ctx->bridge_ctx->stats.cycles_count); + + 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 = fake_fpga_region_program(base_ctx->region_ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, base_ctx->mgr_ctx); + + KUNIT_EXPECT_EQ(test, 1, base_ctx->mgr_ctx->stats.prog_count); + KUNIT_EXPECT_TRUE(test, base_ctx->bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, base_ctx->bridge_ctx->stats.cycles_count); + + 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 = fake_fpga_region_program(base_ctx->region_ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, base_ctx->mgr_ctx); + + KUNIT_EXPECT_EQ(test, 2, base_ctx->mgr_ctx->stats.prog_count); + KUNIT_EXPECT_TRUE(test, base_ctx->bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 2, base_ctx->bridge_ctx->stats.cycles_count); + + 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 = fake_fpga_bridge_register(test, + &base_ctx->region_ctx->region->dev); + KUNIT_ASSERT_FALSE(test, IS_ERR(sub_bridge_0_ctx)); + + sub_region_0_ctx = fake_fpga_region_register(test, base_ctx->mgr_ctx->mgr, + &sub_bridge_0_ctx->bridge->dev); + KUNIT_ASSERT_FALSE(test, IS_ERR(sub_region_0_ctx)); + + ret = fake_fpga_region_add_bridge(sub_region_0_ctx, sub_bridge_0_ctx->bridge); + KUNIT_ASSERT_EQ(test, ret, 0); + + sub_bridge_1_ctx = fake_fpga_bridge_register(test, + &base_ctx->region_ctx->region->dev); + KUNIT_ASSERT_FALSE(test, IS_ERR(sub_bridge_1_ctx)); + + sub_region_1_ctx = fake_fpga_region_register(test, base_ctx->mgr_ctx->mgr, + &sub_bridge_1_ctx->bridge->dev); + KUNIT_ASSERT_FALSE(test, IS_ERR(sub_region_1_ctx)); + + ret = fake_fpga_region_add_bridge(sub_region_1_ctx, sub_bridge_1_ctx->bridge); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* 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 = fake_fpga_region_program(sub_region_0_ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, base_ctx->mgr_ctx); + KUNIT_EXPECT_EQ(test, 1, base_ctx->mgr_ctx->stats.prog_count); + + KUNIT_EXPECT_TRUE(test, sub_bridge_0_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, sub_bridge_0_ctx->stats.cycles_count); + + /* Re-configure sub-region 1 with the partial image */ + sub_region_1_ctx->region->info = partial_img_info; + ret = fake_fpga_region_program(sub_region_1_ctx); + KUNIT_ASSERT_EQ(test, ret, 0); + + fake_fpga_mgr_check_write(test, base_ctx->mgr_ctx); + KUNIT_EXPECT_EQ(test, 2, base_ctx->mgr_ctx->stats.prog_count); + + KUNIT_EXPECT_TRUE(test, sub_bridge_1_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 1, sub_bridge_1_ctx->stats.cycles_count); + + /* Check that the base bridge has not been disabled during reconfiguration */ + KUNIT_EXPECT_TRUE(test, base_ctx->bridge_ctx->stats.enable); + KUNIT_EXPECT_EQ(test, 0, base_ctx->bridge_ctx->stats.cycles_count); + + 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");