On 2023-02-03 at 18:06:51 +0100, Marco Pagani wrote: > Add fake FPGA region platform driver with support functions. This > module is part of the KUnit test suite for the FPGA subsystem. > > Signed-off-by: Marco Pagani <marpagan@xxxxxxxxxx> > --- > drivers/fpga/tests/fake-fpga-region.c | 186 ++++++++++++++++++++++++++ > drivers/fpga/tests/fake-fpga-region.h | 37 +++++ > 2 files changed, 223 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..095397e41837 > --- /dev/null > +++ b/drivers/fpga/tests/fake-fpga-region.c > @@ -0,0 +1,186 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Driver for fake FPGA region > + * > + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. > + * > + * Author: Marco Pagani <marpagan@xxxxxxxxxx> > + */ > + > +#include <linux/device.h> > +#include <linux/platform_device.h> > +#include <linux/fpga/fpga-mgr.h> > +#include <linux/fpga/fpga-region.h> > +#include <linux/fpga/fpga-bridge.h> > +#include <kunit/test.h> > + > +#include "fake-fpga-region.h" > + > +#define FAKE_FPGA_REGION_DEV_NAME "fake_fpga_region" > + > +struct fake_region_priv { > + int id; > + struct kunit *test; > +}; > + > +struct fake_region_data { > + struct fpga_manager *mgr; > + struct kunit *test; > +}; > + > +/** > + * fake_fpga_region_register - register a fake FPGA region > + * @region_ctx: fake FPGA region context data structure. > + * @test: KUnit test context object. > + * > + * Return: 0 if registration succeeded, an error code otherwise. > + */ > +int fake_fpga_region_register(struct fake_fpga_region *region_ctx, > + struct fpga_manager *mgr, struct kunit *test) > +{ > + struct fake_region_data pdata; > + struct fake_region_priv *priv; > + int ret; > + > + pdata.mgr = mgr; > + pdata.test = test; > + > + region_ctx->pdev = platform_device_alloc(FAKE_FPGA_REGION_DEV_NAME, > + PLATFORM_DEVID_AUTO); > + if (IS_ERR(region_ctx->pdev)) { > + pr_err("Fake FPGA region device allocation failed\n"); > + return -ENOMEM; > + } > + > + platform_device_add_data(region_ctx->pdev, &pdata, sizeof(pdata)); > + > + ret = platform_device_add(region_ctx->pdev); > + if (ret) { > + pr_err("Fake FPGA region device add failed\n"); > + platform_device_put(region_ctx->pdev); > + return ret; > + } > + > + region_ctx->region = platform_get_drvdata(region_ctx->pdev); > + > + if (test) { > + priv = region_ctx->region->priv; > + kunit_info(test, "Fake FPGA region %d registered\n", priv->id); > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(fake_fpga_region_register); > + > +/** > + * fake_fpga_region_unregister - unregister a fake FPGA region > + * @region_ctx: fake FPGA region context data structure. > + */ > +void fake_fpga_region_unregister(struct fake_fpga_region *region_ctx) > +{ > + struct fake_region_priv *priv; > + struct kunit *test; > + int id; > + > + priv = region_ctx->region->priv; > + test = priv->test; > + id = priv->id; > + > + if (region_ctx->pdev) { > + platform_device_unregister(region_ctx->pdev); > + if (test) > + kunit_info(test, "Fake FPGA region %d unregistered\n", id); > + } > +} > +EXPORT_SYMBOL_GPL(fake_fpga_region_unregister); > + > +/** > + * fake_fpga_region_add_bridge - add a bridge to a fake FPGA region > + * @region_ctx: fake FPGA region context data structure. > + * @bridge: FPGA bridge. > + * > + * Return: 0 if registration succeeded, an error code otherwise. > + */ > +int fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, > + struct fpga_bridge *bridge) > +{ > + struct fake_region_priv *priv; > + int ret; > + > + priv = region_ctx->region->priv; > + > + ret = fpga_bridge_get_to_list(bridge->dev.parent, NULL, > + ®ion_ctx->region->bridge_list); > + > + if (priv->test && !ret) > + kunit_info(priv->test, "Bridge added to fake FPGA region %d\n", > + priv->id); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(fake_fpga_region_add_bridge); > + > +static int fake_fpga_region_probe(struct platform_device *pdev) > +{ > + struct device *dev; > + struct fpga_region *region; > + struct fpga_manager *mgr; > + struct fake_region_data *pdata; > + struct fake_region_priv *priv; > + static int id_count; > + > + dev = &pdev->dev; > + pdata = dev_get_platdata(dev); > + > + 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); > + > + /* > + * No get_bridges() method since the bridges list is > + * pre-built using fake_fpga_region_add_bridge() > + */ This is not the common use for drivers to associate the region & bridge, Better to realize the get_bridges() method. Thanks, Yilun > + region = fpga_region_register(dev, mgr, NULL); > + if (IS_ERR(region)) { > + fpga_mgr_put(mgr); > + return PTR_ERR(region); > + } > + > + priv->test = pdata->test; > + priv->id = id_count++; > + region->priv = priv; > + > + platform_set_drvdata(pdev, region); > + > + return 0; > +}