Message ID | 20230310170412.708363-3-marpagan@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | fpga: add initial KUnit tests for the subsystem | expand |
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@redhat.com> > --- > 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@redhat.com> > + */ > + > +#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. > + > + 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 > +{ > + 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@redhat.com>"); > +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@redhat.com> > + */ > + > +#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 >
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@redhat.com> >> --- >> 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@redhat.com> >> + */ >> + >> +#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@redhat.com>"); >> +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@redhat.com> >> + */ >> + >> +#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
On 2023-03-21 at 18:33:05 +0100, Marco Pagani wrote: > > > 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@redhat.com> > >> --- > >> 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@redhat.com> > >> + */ > >> + > >> +#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(). OK, on second thought, it's good to me. Thanks, Yilun
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@redhat.com> + */ + +#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); + + 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 <marpagan@redhat.com>"); +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@redhat.com> + */ + +#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 */
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@redhat.com> --- 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