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 >

