On Sun, 27 Sept 2026 at 11:24, Sailesh Nandanavanam
<[email protected]> wrote:
>
> Add a KUnit test suite covering rproc_check_carveout_da(), the
> internal helper that validates a resource-table-requested (da, len)
> pair against an already-allocated carveout's bounds.
>
> The test is #include'd directly into remoteproc_core.c (a pattern
> already used by mm/damon/) rather than built as a separate module,
> since rproc_check_carveout_da() is static and this avoids adding an
> exported symbol purely for test visibility.
>
> Six cases are included, exercising every branch of the function:
> requested length exceeding the carveout, a specific da requested
> against a carveout with none set, a da before the carveout's start,
> a (da + len) past the carveout's end, an exact boundary fit, and the
> FW_RSC_ADDR_ANY skip-check path.
>

I will look at this patch when I have reviewed other patches in my backlog.

Thanks,
Mathieu

> Verified via:
>  - QEMU (x86_64), booting a kernel with CONFIG_REMOTEPROC_KUNIT_TEST=y
>  - tools/testing/kunit/kunit.py under UML
>
> All 6 cases pass in both environments:
>
>     # remoteproc_core: pass:6 fail:0 skip:0 total:6
>
> This is posted as an RFC to check whether this structure (test
> headers embedded per-file, DAMON-style) is the preferred approach for
> remoteproc before expanding coverage to other files in the driver
> (remoteproc_virtio.c, remoteproc_sysfs.c, etc.).
>
> Signed-off-by: Sailesh Nandanavanam <[email protected]>
> ---
>  drivers/remoteproc/Kconfig                    |  10 ++
>  drivers/remoteproc/remoteproc_core.c          |   4 +
>  .../remoteproc/tests/remoteproc_core-kunit.h  | 130 ++++++++++++++++++
>  3 files changed, 144 insertions(+)
>  create mode 100644 drivers/remoteproc/tests/remoteproc_core-kunit.h
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 5b56b2dcc725..dc5a8f483693 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -390,6 +390,16 @@ config XLNX_R5_REMOTEPROC
>
>           It's safe to say N if not interested in using RPU r5f cores.
>
> +config REMOTEPROC_KUNIT_TEST
> +       bool "KUnit tests for remoteproc core" if !KUNIT_ALL_TESTS
> +       depends on REMOTEPROC && KUNIT=y
> +       default KUNIT_ALL_TESTS
> +       help
> +         Enable KUnit tests for the remoteproc core, covering internal
> +         helpers such as carveout/address-translation logic.
> +
> +         If unsure, say N.
> +
>  endif # REMOTEPROC
>
>  endmenu
> diff --git a/drivers/remoteproc/remoteproc_core.c 
> b/drivers/remoteproc/remoteproc_core.c
> index 1ed406714849..4f0ad28305d2 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -2839,3 +2839,7 @@ static void __exit remoteproc_exit(void)
>  module_exit(remoteproc_exit);
>
>  MODULE_DESCRIPTION("Generic Remote Processor Framework");
> +
> +#if IS_ENABLED(CONFIG_REMOTEPROC_KUNIT_TEST)
> +#include "tests/remoteproc_core-kunit.h"
> +#endif
> diff --git a/drivers/remoteproc/tests/remoteproc_core-kunit.h 
> b/drivers/remoteproc/tests/remoteproc_core-kunit.h
> new file mode 100644
> index 000000000000..615a854fffbf
> --- /dev/null
> +++ b/drivers/remoteproc/tests/remoteproc_core-kunit.h
> @@ -0,0 +1,130 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _REMOTEPROC_CORE_KUNIT_H
> +#define _REMOTEPROC_CORE_KUNIT_H
> +
> +#include <kunit/test.h>
> +
> +/*
> + * Tests for rproc_check_carveout_da().
> + *
> + * The function is static, so this header is #include'd directly at the
> + * bottom of remoteproc_core.c (see CONFIG_REMOTEPROC_KUNIT_TEST), giving
> + * it access to the symbol despite the lack of external linkage.
> + *
> + * rproc_check_carveout_da() only touches &rproc->dev for dev_err() on
> + * its failure paths, so a zeroed struct rproc is sufficient here -- no
> + * device registration needed. dev_err()'s formatting chain
> + * (dev_driver_string() -> "" on NULL driver/bus/class, dev_name() ->
> + * NULL on an unregistered device, and the kernel's own %s NULL guard
> + * in lib/vsprintf.c) is safe end-to-end against a bare zeroed device.
> + */
> +
> +static void rproc_test_check_carveout_len_exceeds(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /* mem->len = 0x100; request len 0x200 with no da constraint */
> +       mem.da = FW_RSC_ADDR_ANY;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, FW_RSC_ADDR_ANY, 0x200);
> +       KUNIT_EXPECT_EQ(test, ret, -EINVAL);
> +}
> +
> +static void rproc_test_check_carveout_da_any_mismatch(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /* caller wants a specific da, but the carveout itself has none set */
> +       mem.da = FW_RSC_ADDR_ANY;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, 0x1000, 0x50);
> +       KUNIT_EXPECT_EQ(test, ret, -EINVAL);
> +}
> +
> +static void rproc_test_check_carveout_da_negative_delta(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /* requested da (0x1000) lies before the carveout's da (0x2000) */
> +       mem.da = 0x2000;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, 0x1000, 0x10);
> +       KUNIT_EXPECT_EQ(test, ret, -EINVAL);
> +}
> +
> +static void rproc_test_check_carveout_da_exceeds_end(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /* delta (0x80) + len (0x100) = 0x180, one byte over mem->len (0x100) 
> -> 0x180 > 0x100 */
> +       mem.da = 0x1000;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, 0x1080, 0x100);
> +       KUNIT_EXPECT_EQ(test, ret, -EINVAL);
> +}
> +
> +static void rproc_test_check_carveout_da_exact_fit(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /*
> +        * Boundary case: delta (0xf0) + len (0x10) == mem->len (0x100)
> +        * exactly. The check is "> mem->len", so this must pass -- this
> +        * is exactly the kind of edge an off-by-one would break.
> +        */
> +       mem.da = 0x1000;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, 0x10f0, 0x10);
> +       KUNIT_EXPECT_EQ(test, ret, 0);
> +}
> +
> +static void rproc_test_check_carveout_da_any_skip_check(struct kunit *test)
> +{
> +       struct rproc rproc = { 0 };
> +       struct rproc_mem_entry mem = { 0 };
> +       int ret;
> +
> +       /*
> +        * da == FW_RSC_ADDR_ANY -> address check is skipped entirely,
> +        * only len is validated against mem->len.
> +        */
> +       mem.da = 0x1000;
> +       mem.len = 0x100;
> +
> +       ret = rproc_check_carveout_da(&rproc, &mem, FW_RSC_ADDR_ANY, 0x50);
> +       KUNIT_EXPECT_EQ(test, ret, 0);
> +}
> +
> +static struct kunit_case rproc_core_test_cases[] = {
> +       KUNIT_CASE(rproc_test_check_carveout_len_exceeds),
> +       KUNIT_CASE(rproc_test_check_carveout_da_any_mismatch),
> +       KUNIT_CASE(rproc_test_check_carveout_da_negative_delta),
> +       KUNIT_CASE(rproc_test_check_carveout_da_exceeds_end),
> +       KUNIT_CASE(rproc_test_check_carveout_da_exact_fit),
> +       KUNIT_CASE(rproc_test_check_carveout_da_any_skip_check),
> +       {}
> +};
> +
> +static struct kunit_suite rproc_core_test_suite = {
> +       .name = "remoteproc_core",
> +       .test_cases = rproc_core_test_cases,
> +};
> +
> +kunit_test_suite(rproc_core_test_suite);
> +
> +#endif /* _REMOTEPROC_CORE_KUNIT_H */
> --
> 2.34.1
>

Reply via email to