On 2023-03-17 09:32, Xu Yilun wrote: > On 2023-03-10 at 18:04:10 +0100, Marco Pagani wrote: >> 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 <marpagan@xxxxxxxxxx> >> --- >> 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 <marpagan@xxxxxxxxxx> >> + */ >> + >> +#include <linux/types.h> >> +#include <linux/device.h> >> +#include <linux/platform_device.h> >> +#include <linux/fpga/fpga-bridge.h> >> +#include <kunit/test.h> >> + >> +#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); > > Why check the kunit pointer every time? I remember you mentioned that > the fake fpga modules are expected to be used out of Kunit test, so the > priv->test may be NULL? I suggest you work on these usecases in separate > patchsets. For now just check priv->test on probe is fine. > The idea was to provide additional info messages, tied with the test, if the fake bridge is registered with a test instance. If you believe these prints are unnecessary, I can remove them or replace them with generic dev_info(). >> + >> + 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_fpga_bridge *fake_fpga_bridge_register(struct device *parent, ...) > > Is it better? > > Thanks, > Yilun Agreed, it is better. I'll change the registration functions for the fake bridge, manager, and region in the next version. > >> +{ >> + 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 <marpagan@xxxxxxxxxx>"); >> +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 <marpagan@xxxxxxxxxx> >> + */ >> + >> +#ifndef __FPGA_FAKE_BRIDGE_H >> +#define __FPGA_FAKE_BRIDGE_H >> + >> +#include <linux/platform_device.h> >> +#include <kunit/test.h> >> + >> +/** >> + * 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 */ >> -- >> 2.39.2 >> Thanks, Marco