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() + */ + 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; +} + +static int fake_fpga_region_remove(struct platform_device *pdev) +{ + struct fpga_region *region = platform_get_drvdata(pdev); + struct fpga_manager *mgr = region->mgr; + + fpga_mgr_put(mgr); + fpga_bridges_put(®ion->bridge_list); + fpga_region_unregister(region); + + return 0; +} + +static struct platform_driver fake_fpga_region_drv = { + .driver = { + .name = FAKE_FPGA_REGION_DEV_NAME + }, + .probe = fake_fpga_region_probe, + .remove = fake_fpga_region_remove, +}; + +module_platform_driver(fake_fpga_region_drv); + +MODULE_AUTHOR("Marco Pagani <marpagan@xxxxxxxxxx>"); +MODULE_DESCRIPTION("Fake FPGA Bridge"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/tests/fake-fpga-region.h b/drivers/fpga/tests/fake-fpga-region.h new file mode 100644 index 000000000000..55b2df3f04ba --- /dev/null +++ b/drivers/fpga/tests/fake-fpga-region.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for fake FPGA region + * + * Copyright (C) 2023 Red Hat, Inc. All rights reserved. + * + * Author: Marco Pagani <marpagan@xxxxxxxxxx> + */ + +#ifndef __FPGA_FAKE_RGN_H +#define __FPGA_FAKE_RGN_H + +#include <linux/platform_device.h> +#include <kunit/test.h> +#include <linux/fpga/fpga-mgr.h> +#include <linux/fpga/fpga-bridge.h> + +/** + * struct fake_fpga_region - fake FPGA region context data structure + * + * @region: FPGA region. + * @pdev: platform device of the FPGA region. + */ +struct fake_fpga_region { + struct fpga_region *region; + struct platform_device *pdev; +}; + +int fake_fpga_region_register(struct fake_fpga_region *region_ctx, + struct fpga_manager *mgr, struct kunit *test); + +int fake_fpga_region_add_bridge(struct fake_fpga_region *region_ctx, + struct fpga_bridge *bridge); + +void fake_fpga_region_unregister(struct fake_fpga_region *region_ctx); + +#endif /* __FPGA_FAKE_RGN_H */ -- 2.39.1