Linux Test Project
 help / color / mirror / Atom feed
* [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API
@ 2026-06-11 13:44 Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Andrea Cervesato @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Linux Test Project

Support immutable distribution by splitting test in two:

- fw_load01 triggers request_firmware on /lib/firmware (read-only on
  immutable distributions) and it doesn't support read-only filesystems
- fw_load02 triggers request_firmware on custom path (always supported
  by any distribution)

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Changes in v6:
- add commit for `git mv` mergin both test and kernel module into
  fw_load folder
- fix fw_load02 fw_path setup
- Link to v5: https://lore.kernel.org/r/20260611-fw_load-v5-0-7e21d40ae54a@suse.com

Changes in v5:
- rebase since apply is failing
- Link to v4: https://lore.kernel.org/r/20260611-fw_load-v4-0-109a0f524be4@suse.com

Changes in v4:
- verify /lib/firmware/update was created by our test
- fix algorithm op order in fw_load02
- Link to v3: https://lore.kernel.org/r/20260610-fw_load-v3-0-eef32edfe8d5@suse.com

Changes in v3:
- fix bisecting
- fix algorithm op order
- Link to v2: https://lore.kernel.org/r/20260610-fw_load-v2-0-fca6faa237ab@suse.com

Changes in v2:
- fix fw_load.h define
- fix Makefile copyright position
- fix year in the firmware file
- Link to v1: https://lore.kernel.org/r/20260610-fw_load-v1-0-df9d38315e38@suse.com

---
Andrea Cervesato (4):
      fw_load: Modernize ltp_fw_load kernel module
      fw_load: rewrite test using new LTP API
      fw_load: merge module and test into fw_load folder
      fw_load: add fw_load02 for custom firmware path

 runtest/kernel_misc                                |   3 +-
 .../{fw_load_kernel => fw_load}/.gitignore         |   2 +
 testcases/kernel/firmware/fw_load/Makefile         |  25 +++
 testcases/kernel/firmware/fw_load/fw_load.h        |  18 ++
 testcases/kernel/firmware/fw_load/fw_load01.c      | 165 ++++++++++++++++
 testcases/kernel/firmware/fw_load/fw_load02.c      | 138 +++++++++++++
 testcases/kernel/firmware/fw_load/ltp_fw_load.c    | 178 +++++++++++++++++
 testcases/kernel/firmware/fw_load_kernel/Makefile  |  35 ----
 testcases/kernel/firmware/fw_load_kernel/README    |  16 --
 .../kernel/firmware/fw_load_kernel/ltp_fw_load.c   | 164 ----------------
 testcases/kernel/firmware/fw_load_user/.gitignore  |   1 -
 testcases/kernel/firmware/fw_load_user/Makefile    |  20 --
 testcases/kernel/firmware/fw_load_user/README      |  11 --
 testcases/kernel/firmware/fw_load_user/fw_load.c   | 213 ---------------------
 14 files changed, 528 insertions(+), 461 deletions(-)
---
base-commit: c685f1b774fab694c42dfb7522bc42d999904373
change-id: 20260609-fw_load-2882088bec8e

Best regards,
-- 
Andrea Cervesato <andrea.cervesato@suse.com>


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module
  2026-06-11 13:44 [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API Andrea Cervesato
@ 2026-06-11 13:44 ` Andrea Cervesato
  2026-06-11 14:44   ` [LTP] " linuxtestproject.agent
  2026-06-15 11:03   ` [LTP] [PATCH v6 1/4] " Cyril Hrubis
  2026-06-11 13:44 ` [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API Andrea Cervesato
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 11+ messages in thread
From: Andrea Cervesato @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Fix VLA (banned since kernel v4.20), replace sscanf() with
kstrtoint(), reset test_result between invocations, make the
loop variable local and pass expected data explicitly.

Update license headers, fix brace style, drop obsolete README
in favour of the in-source documentation.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/firmware/fw_load_kernel/Makefile  |  16 +--
 testcases/kernel/firmware/fw_load_kernel/README    |  16 ---
 .../kernel/firmware/fw_load_kernel/ltp_fw_load.c   | 114 ++++++++++++---------
 3 files changed, 66 insertions(+), 80 deletions(-)

diff --git a/testcases/kernel/firmware/fw_load_kernel/Makefile b/testcases/kernel/firmware/fw_load_kernel/Makefile
index 73996996f3397fb0a7f4616457168213587e654f..e81b300faaa6b4056d4b5f3d1417c381a000256d 100644
--- a/testcases/kernel/firmware/fw_load_kernel/Makefile
+++ b/testcases/kernel/firmware/fw_load_kernel/Makefile
@@ -1,18 +1,6 @@
 # Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it would be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write the Free Software Foundation,
-# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# Copyright (c) Linux Test Project, 2026
+# SPDX-License-Identifier: GPL-2.0-or-later
 
 ifneq ($(KERNELRELEASE),)
 
diff --git a/testcases/kernel/firmware/fw_load_kernel/README b/testcases/kernel/firmware/fw_load_kernel/README
deleted file mode 100644
index 97507fd99aa3bead708cd4bf599f4abf9ec6e2da..0000000000000000000000000000000000000000
--- a/testcases/kernel/firmware/fw_load_kernel/README
+++ /dev/null
@@ -1,16 +0,0 @@
-The aim of the test is to check device firmware loading. Since kernel 3.7
-firmware loading changed to direct loading (by-pass udev). The test consists
-of the two parts:
- - userspace part
- - kernelspace part
-
-This is a kernel module, which is a part of the device firmware loading test.
-It allows to call request_firmware kernel function with specified parameters.
-Template firmware file name and expected firmware file's data size are passed
-as the insmod command line parameters. Then, the number of firmware test files
-should be written to sysfs file 'fwnum' (the maximum number is 32). This write
-will initiate request firmware procedure. In the end, results can be read from
-'result' device sysfs file. Also, some information regarding module loading,
-can be obtained by looking at kernel log file.
-
-It is automatically used by userspace part of the test.
diff --git a/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c b/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
index b7397e8f13154a16c2626517545c3c14d153a043..8aac0fc9691f85970be12fca360a17473474365b 100644
--- a/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
+++ b/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
@@ -1,25 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * Copyright (c) 2023 Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*
+ * Kernel module helper for the fw_load test.
  *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Registers a virtual device (ltp_fw_load) that exposes two sysfs
+ * attributes:
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *   fwnum  (write-only) - accepts the number of firmware files to
+ *           request (1-32). Writing triggers request_firmware() for
+ *           each file named n<i>_<fw_name> (i = 0 .. fwnum-1).
+ *           Each loaded blob is verified against the expected size
+ *           (fw_size) and byte pattern (every byte == i).
  *
- * Author:
- * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *   result (read-only)  - bitmask of per-file pass/fail results.
+ *           Bit i is set when n<i>_<fw_name> was loaded and
+ *           verified successfully.
  *
- * This module is trying to load external test firmware files (n#_load_tst.fw).
- * In the end, it writes results to /sys/devices/ltp_fw_load/result file.
+ * Module parameters:
+ *   fw_name  - template firmware file name (default: load_tst.fw)
+ *   fw_size  - expected firmware blob size  (default: 0x1000)
  */
 
 #include <linux/module.h>
@@ -33,12 +38,11 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexey Kodanev <alexey.kodanev@oracle.com>");
 MODULE_DESCRIPTION("This module is checking device firmware loading");
 
-#define TCID	"ltp_fw_load"
+#define MODULE_NAME	"ltp_fw_load"
+#define MAX_NAME	64
 
 static char *fw_name	= "load_tst.fw";
 static int fw_size	= 0x1000;
-static int max_name	= 64;
-static int fw;
 
 module_param(fw_name, charp, 0444);
 MODULE_PARM_DESC(fw_name, "Template firmware file name: n#_name");
@@ -54,47 +58,53 @@ static int test_result;
 
 static void device_release(struct device *dev)
 {
-	pr_info(TCID ": device released\n");
+	pr_info(MODULE_NAME ": device released\n");
 }
 
 static struct device tdev = {
-	.init_name	= TCID,
+	.init_name	= MODULE_NAME,
 	.release	= device_release,
 };
 
-/* read and print firmware data */
-static int fw_read(const u8 *data, size_t size)
+/* read and verify firmware data */
+static int fw_read(const u8 *data, size_t size, u8 expected)
 {
 	size_t i;
-	pr_info(TCID ": Firmware has size '%zu'\n", size);
+
+	pr_info(MODULE_NAME ": Firmware has size '%zu'\n", size);
 	if (size != fw_size) {
-		pr_err(TCID ": Expected firmware size '%d'\n", fw_size);
+		pr_err(MODULE_NAME ": Expected firmware size '%d'\n", fw_size);
 		return -1;
 	}
+
 	for (i = 0; i < size; ++i) {
-		if (data[i] != (u8)fw) {
-			pr_err(TCID ": Unexpected firmware data\n");
+		if (data[i] != expected) {
+			pr_err(MODULE_NAME ": Unexpected firmware data\n");
 			return -1;
 		}
 	}
+
 	return 0;
 }
 
-static int try_request_fw(const char *name)
+static int try_request_fw(const char *name, u8 expected)
 {
 	int err;
 	const struct firmware *fw_entry = NULL;
+
 	err = request_firmware(&fw_entry, name, &tdev);
 	if (!err) {
-		pr_info(TCID ": firmware '%s' requested\n", name);
-		err = fw_read(fw_entry->data, fw_entry->size);
-	} else
-		pr_err(TCID ": Can't request firmware '%s'\n", name);
+		pr_info(MODULE_NAME ": firmware '%s' requested\n", name);
+		err = fw_read(fw_entry->data, fw_entry->size, expected);
+	} else {
+		pr_err(MODULE_NAME ": Can't request firmware '%s'\n", name);
+	}
+
 	release_firmware(fw_entry);
 	return err;
 }
 
-/* print test result to sysfs file */
+/* Print test result to sysfs file. */
 static ssize_t sys_result(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -102,26 +112,28 @@ static ssize_t sys_result(struct device *dev,
 }
 static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL);
 
-/*
- * get the number of firmware files and
- * perform firmware requests
- */
+/* Get the number of firmware files and perform firmware requests. */
 static ssize_t sys_fwnum(struct device *dev,
-	struct device_attribute *attr,  const char *buf, size_t count)
+	struct device_attribute *attr, const char *buf, size_t count)
 {
-	int err, fw_num = 0;
+	int err, fw, fw_num;
 
-	sscanf(buf, "%d", &fw_num);
-	if (fw_num <= 0 || fw_num > 32) {
-		pr_err(TCID ": Unexpected number of firmwares '%d'", fw_num);
-		return count;
+	err = kstrtoint(buf, 10, &fw_num);
+	if (err || fw_num <= 0 || fw_num > 32) {
+		pr_err(MODULE_NAME ": Unexpected number of firmwares '%s'", buf);
+		return err ? err : -EINVAL;
 	}
+
+	test_result = 0;
+
 	for (fw = 0; fw < fw_num; ++fw) {
-		char name[max_name];
-		snprintf(name, max_name, "n%d_%s", fw, fw_name);
-		err = try_request_fw(name);
+		char name[MAX_NAME];
+
+		snprintf(name, sizeof(name), "n%d_%s", fw, fw_name);
+		err = try_request_fw(name, (u8)fw);
 		test_result |= (err == 0) << fw;
 	}
+
 	return count;
 }
 static DEVICE_ATTR(fwnum, S_IWUSR, NULL, sys_fwnum);
@@ -132,23 +144,25 @@ static int test_init(void)
 
 	err = device_register(&tdev);
 	if (err) {
-		pr_err(TCID ": Unable to register device\n");
+		pr_err(MODULE_NAME ": Unable to register device\n");
 		return err;
 	}
-	pr_info(TCID ": device registered\n");
+	pr_info(MODULE_NAME ": device registered\n");
 
 	err = device_create_file(&tdev, &dev_attr_result);
 	if (err) {
-		pr_err(TCID ": Can't create sysfs file 'result'\n");
+		pr_err(MODULE_NAME ": Can't create sysfs file 'result'\n");
 		device_unregister(&tdev);
 		return err;
 	}
+
 	err = device_create_file(&tdev, &dev_attr_fwnum);
 	if (err) {
-		pr_err(TCID ": Can't create sysfs file 'fwnum'\n");
+		pr_err(MODULE_NAME ": Can't create sysfs file 'fwnum'\n");
 		device_remove_file(&tdev, &dev_attr_result);
 		device_unregister(&tdev);
 	}
+
 	return err;
 }
 module_init(test_init);
@@ -159,6 +173,6 @@ static void test_exit(void)
 	device_remove_file(&tdev, &dev_attr_fwnum);
 
 	device_unregister(&tdev);
-	pr_info(TCID ": module exited\n");
+	pr_info(MODULE_NAME ": module exited\n");
 }
 module_exit(test_exit);

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API
  2026-06-11 13:44 [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
@ 2026-06-11 13:44 ` Andrea Cervesato
  2026-06-15 11:33   ` Cyril Hrubis
  2026-06-11 13:44 ` [LTP] [PATCH v6 3/4] fw_load: merge module and test into fw_load folder Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path Andrea Cervesato
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Remove the obsolete user-helper and create a fw_load.h where to
store the firmware support information.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/firmware/fw_load_user/Makefile  |  18 +-
 testcases/kernel/firmware/fw_load_user/README    |  11 -
 testcases/kernel/firmware/fw_load_user/fw_load.c | 286 ++++++++++-------------
 testcases/kernel/firmware/fw_load_user/fw_load.h |  18 ++
 4 files changed, 140 insertions(+), 193 deletions(-)

diff --git a/testcases/kernel/firmware/fw_load_user/Makefile b/testcases/kernel/firmware/fw_load_user/Makefile
index effd5dae5c05e9115c391093af523ab36ebfc8d6..5b031e2eb81597689ff5eab70246fb20ad02e77d 100644
--- a/testcases/kernel/firmware/fw_load_user/Makefile
+++ b/testcases/kernel/firmware/fw_load_user/Makefile
@@ -1,20 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it would be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write the Free Software Foundation,
-# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# Copyright (c) Linux Test Project, 2026
 
-top_srcdir		?= ../../../..
+top_srcdir	?= ../../../..
 
 include $(top_srcdir)/include/mk/testcases.mk
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/firmware/fw_load_user/README b/testcases/kernel/firmware/fw_load_user/README
deleted file mode 100644
index 702fac90a2ccb41612ea8dc1010b468588cd3446..0000000000000000000000000000000000000000
--- a/testcases/kernel/firmware/fw_load_user/README
+++ /dev/null
@@ -1,11 +0,0 @@
-The aim of the test is to check device firmware loading. Since kernel 3.7
-firmware loading changed to direct loading (by-pass udev). The test consists
-of the two parts:
- - userspace part
- - kernelspace part
-
-This is the userspace part, its tasks are:
- - create firmware files in the standard firmware paths
- - load the module and initiate firmware request procedure
- - read device's result file and print final results
- - unload the module.
diff --git a/testcases/kernel/firmware/fw_load_user/fw_load.c b/testcases/kernel/firmware/fw_load_user/fw_load.c
index 1f68f2ad67cb34af5bfe19f77482cd032bdbad3f..0659c84215f37c06bdb589bed6a4012b3b4fbf90 100644
--- a/testcases/kernel/firmware/fw_load_user/fw_load.c
+++ b/testcases/kernel/firmware/fw_load_user/fw_load.c
@@ -1,213 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *	Alexey Kodanev <alexey.kodanev@oracle.com>
+ * Copyright (c) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Verifies that the kernel firmware loader (``CONFIG_FW_LOADER``)
+ * can find and load firmware files from the standard search paths.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * A helper kernel module (``ltp_fw_load.ko``) registers a virtual
+ * device that calls :kernel_doc:`request_firmware` for a set of
+ * numbered firmware blobs. Each blob is verified in-kernel against
+ * its expected size and byte pattern.
  *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * [Algorithm]
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * - Load the helper module with ``fw_size`` matching the blob size
+ * - Create firmware files in the standard firmware search
+ *   directories:
  *
- * Author:
- * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *   - ``/lib/firmware/``
+ *   - ``/lib/firmware/<kernel-release>/``
+ *   - ``/lib/firmware/updates/``
+ *   - ``/lib/firmware/updates/<kernel-release>/``
  *
- * Test checks device firmware loading.
+ * - Add one fake firmware entry that has no file on disk
+ * - Write the firmware count to ``/sys/devices/ltp_fw_load/fwnum``
+ *   to trigger :kernel_doc:`request_firmware` calls in-kernel
+ * - Read the result bitmask from ``/sys/devices/ltp_fw_load/result``
+ * - Verify that every real firmware file was loaded successfully
+ *   and that the fake entry was correctly rejected
  */
 
-#define _GNU_SOURCE
 #include <sys/utsname.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "test.h"
-#include "tst_security.h"
-#include "tso_safe_macros.h"
-#include "tso_module.h"
-
-/* number of test firmware files */
-#define FW_FILES	5
-
-char *TCID = "fw_load";
-int TST_TOTAL = FW_FILES;
+#include "tst_test.h"
+#include "tst_module.h"
+#include "fw_load.h"
 
-static int fw_size = 0x1000;
+static int module_loaded;
+static int fw_count;
 
-static const char fw_name[]	= "load_tst.fw";
-static const char module_name[]	= "ltp_fw_load.ko";
-
-/* paths to module's sysfs files */
-static const char dev_fwnum[]	= "/sys/devices/ltp_fw_load/fwnum";
-static const char dev_result[]	= "/sys/devices/ltp_fw_load/result";
-
-struct fw_file_info {
-	char *file;
-	char *dir;
+static struct fw_data {
+	char dir[PATH_MAX];
+	char file[PATH_MAX];
 	int fake;
-	int remove_dir;
-	int remove_file;
-};
+	int created_dir;
+} firmware[FW_NUM];
 
-static struct fw_file_info fw[FW_FILES];
-static int fw_num;
-
-/* test options */
-static char *narg;
-static int nflag;
-static int skip_cleanup;
-static int verbose;
-static const option_t options[] = {
-	{"n:", &nflag, &narg},
-	{"s", &skip_cleanup, NULL},
-	{"v", &verbose, NULL},
-	{NULL, NULL, NULL}
-};
+static void create_firmware(const char *dir)
+{
+	struct fw_data *fw = &firmware[fw_count];
+	char buf[FW_SIZE];
+	int fd = -1;
+
+	snprintf(fw->dir, sizeof(fw->dir), "%s", dir);
+	if (access(dir, X_OK) == -1) {
+		SAFE_MKDIR(dir, 0755);
+		fw->created_dir = 1;
+	}
 
-static void help(void);
-static void setup(int argc, char *argv[]);
-static void test_run(void);
-static void cleanup(void);
+	snprintf(fw->file, sizeof(fw->file), "%s/n%d_%s", dir, fw_count, FW_NAME);
+	memset(buf, fw_count, FW_SIZE);
 
-/*
- * create firmware files in the fw_paths
- * @fw_paths: it must be termintated by a NULL pointer
- */
-static void create_firmware(char *const fw_paths[]);
+	fd = SAFE_OPEN(fw->file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, FW_SIZE);
+	SAFE_CLOSE(fd);
 
-int main(int argc, char *argv[])
+	fw_count++;
+}
+
+static void run(void)
 {
-	setup(argc, argv);
+	struct fw_data *fw;
+	int result = 0;
+	int fail, offset;
 
-	test_run();
+	SAFE_FILE_PRINTF(DEV_FWNUM, "%d", fw_count);
+	SAFE_FILE_SCANF(DEV_RESULT, "%d", &result);
 
-	cleanup();
+	for (int i = 0; i < fw_count; i++) {
+		fw = &firmware[i];
 
-	tst_exit();
-}
+		fail = (result & (1 << i)) == 0 && !fw->fake;
+		offset = fw->dir[0] ? strlen(fw->dir) : 0;
 
-static void help(void)
-{
-	printf("  -n x    Write x bytes to firmware file, default is %d\n",
-		fw_size);
-	printf("  -s      Skip cleanup\n");
-	printf("  -v      Verbose\n");
+		if (fw->fake) {
+			tst_res(result & (1 << i) ? TFAIL : TPASS,
+				"Firmware '%s' correctly not loaded",
+				fw->file + offset);
+		} else {
+			tst_res(fail ? TFAIL : TPASS,
+				"Firmware '%s' loaded",
+				fw->file + offset);
+		}
+	}
 }
 
-void setup(int argc, char *argv[])
+static void setup(void)
 {
-	if (tst_lockdown_enabled() > 0 || tst_secureboot_enabled() > 0)
-		tst_brkm(TCONF, NULL, "Cannot load unsigned modules in Lockdown/Secure Boot");
-
-	tst_parse_opts(argc, argv, options, help);
+	char fw_dir[PATH_MAX];
+	char fw_size_param[32];
+	struct utsname name;
 
-	if (nflag) {
-		if (sscanf(narg, "%i", &fw_size) != 1)
-			tst_brkm(TBROK, NULL, "-n option arg is not a number");
-		if (fw_size < 0)
-			tst_brkm(TBROK, NULL, "-n option arg is less than 0");
-	}
+	if (access(LIB_PATH, W_OK) == -1)
+		tst_brk(TCONF, "Skipping test due to read-only %s", LIB_PATH);
 
-	tst_require_root();
 	tst_requires_module_signature_disabled();
 
-	char fw_size_param[19];
-	snprintf(fw_size_param, 19, "fw_size=%d", fw_size);
-	char *const mod_params[2] = { fw_size_param, NULL };
-	tst_module_load(NULL, module_name, mod_params);
+	snprintf(fw_size_param, sizeof(fw_size_param), "fw_size=%d", FW_SIZE);
+	char *const mod_params[] = {fw_size_param, NULL};
 
-	tst_sig(FORK, DEF_HANDLER, cleanup);
+	tst_module_load(MNAME_KO, mod_params);
+	module_loaded = 1;
 
-	/* get current Linux version and make firmware paths */
-	struct utsname uts_name;
-	uname(&uts_name);
+	create_firmware(LIB_PATH);
 
-	/* 4 firmware paths + NULL */
-	char *fw_paths[5] = { "/lib/firmware", "/lib/firmware/updates" };
-	SAFE_ASPRINTF(cleanup, &fw_paths[2], "%s/%s", fw_paths[0], uts_name.release);
-	SAFE_ASPRINTF(cleanup, &fw_paths[3], "%s/%s", fw_paths[1], uts_name.release);
+	uname(&name);
 
-	/* create firmware in the hard coded firmware search paths */
-	create_firmware(fw_paths);
+	snprintf(fw_dir, sizeof(fw_dir), "%s/%s", LIB_PATH, name.release);
+	create_firmware(fw_dir);
 
-	free(fw_paths[2]);
-	free(fw_paths[3]);
+	snprintf(fw_dir, sizeof(fw_dir), "%s/updates", LIB_PATH);
+	create_firmware(fw_dir);
 
-	/* make non-existent firmware file */
-	SAFE_ASPRINTF(cleanup, &fw[fw_num].file, "/n%d_%s", fw_num, fw_name);
-	fw[fw_num].fake = 1;
-	++fw_num;
-}
+	snprintf(fw_dir, sizeof(fw_dir), "%s/updates/%s", LIB_PATH, name.release);
+	create_firmware(fw_dir);
 
-static void test_run(void)
-{
-	/* initiate firmware requests */
-	SAFE_FILE_PRINTF(cleanup, dev_fwnum, "%d", fw_num);
+	/* add a fake file */
+	snprintf(firmware[fw_count].file, sizeof(firmware[fw_count].file),
+		 "/n%d_%s", fw_count, FW_NAME);
 
-	/* get module results by reading result bit mask */
-	int result = 0;
-	SAFE_FILE_SCANF(cleanup, dev_result, "%d", &result);
-
-	int i, fail, offset;
-	for (i = 0; i < fw_num; ++i) {
-		fail = (result & (1 << i)) == 0 && !fw[i].fake;
-		offset = (fw[i].dir) ? strlen(fw[i].dir) : 0;
-		tst_resm((fail) ? TFAIL : TPASS,
-			"Expect: %s load firmware '...%s'",
-			(fw[i].fake) ? "can't" : "can",
-			fw[i].file + offset);
-	}
+	firmware[fw_count].fake = 1;
+	fw_count++;
 }
 
 static void cleanup(void)
 {
-	if (skip_cleanup)
-		return;
-
-	int i;
-	/* remove subdirs first and then upper level dirs */
-	for (i = fw_num - 1; i >= 0; --i) {
-		if (fw[i].remove_file && remove(fw[i].file) == -1)
-			tst_resm(TWARN, "Can't remove: %s", fw[i].file);
-		free(fw[i].file);
-
-		if (fw[i].remove_dir && remove(fw[i].dir) == -1)
-			tst_resm(TWARN, "Can't remove %s", fw[i].dir);
-		free(fw[i].dir);
-	}
+	struct fw_data *fw;
 
-	tst_module_unload(NULL, module_name);
-}
+	for (int i = fw_count - 1; i >= 0; i--) {
+		fw = &firmware[i];
 
-static void create_firmware(char *const fw_paths[])
-{
-	int i = 0;
-	while (fw_paths[i] != NULL) {
-		struct fw_file_info *fi = &fw[fw_num];
-		fi->dir = strdup(fw_paths[i]);
-		if (access(fi->dir, X_OK) == -1) {
-			/* create dir */
-			SAFE_MKDIR(cleanup, fi->dir, 0755);
-			fi->remove_dir = 1;
-		}
+		if (access(fw->file, F_OK) != -1)
+			SAFE_UNLINK(fw->file);
 
-		/* create test firmware file */
-		SAFE_ASPRINTF(cleanup, &fi->file, "%s/n%d_%s", fi->dir, fw_num, fw_name);
-
-		FILE *f = SAFE_FOPEN(cleanup, fi->file, "w");
-		fi->remove_file = 1;
-		int k, byte = fw_num;
-		++fw_num;
-		for (k = 0; k < fw_size; ++k)
-			fputc(byte, f);
-		SAFE_FCLOSE(cleanup, f);
-		++i;
+		if (fw->created_dir)
+			remove(fw->dir);
 	}
+
+	if (module_loaded)
+		tst_module_unload(MNAME_KO);
 }
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_FW_LOADER=y|CONFIG_FW_LOADER=m",
+		NULL,
+	},
+};
diff --git a/testcases/kernel/firmware/fw_load_user/fw_load.h b/testcases/kernel/firmware/fw_load_user/fw_load.h
new file mode 100644
index 0000000000000000000000000000000000000000..39f207cc30810e2ed9ea76176cedd98aa902d887
--- /dev/null
+++ b/testcases/kernel/firmware/fw_load_user/fw_load.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+#ifndef FW_LOAD_H
+#define FW_LOAD_H
+
+#define MNAME_KO "ltp_fw_load.ko"
+#define FW_NAME	"load_tst.fw"
+#define FW_SIZE	0x1000
+#define FW_NUM 5
+#define FW_PATH "/sys/module/firmware_class/parameters/path"
+#define DEV_FWNUM "/sys/devices/ltp_fw_load/fwnum"
+#define DEV_RESULT "/sys/devices/ltp_fw_load/result"
+#define LIB_PATH "/lib/firmware"
+
+#endif

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [LTP] [PATCH v6 3/4] fw_load: merge module and test into fw_load folder
  2026-06-11 13:44 [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API Andrea Cervesato
@ 2026-06-11 13:44 ` Andrea Cervesato
  2026-06-11 13:44 ` [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path Andrea Cervesato
  3 siblings, 0 replies; 11+ messages in thread
From: Andrea Cervesato @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Rename fw_load test into fw_load01 and move it into the fw_load folder
within ltp_fw_load.ko module.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 runtest/kernel_misc                                               | 2 +-
 testcases/kernel/firmware/{fw_load_kernel => fw_load}/.gitignore  | 1 +
 testcases/kernel/firmware/{fw_load_kernel => fw_load}/Makefile    | 8 +++++---
 testcases/kernel/firmware/{fw_load_user => fw_load}/fw_load.h     | 0
 .../firmware/{fw_load_user/fw_load.c => fw_load/fw_load01.c}      | 0
 .../kernel/firmware/{fw_load_kernel => fw_load}/ltp_fw_load.c     | 0
 testcases/kernel/firmware/fw_load_user/.gitignore                 | 1 -
 testcases/kernel/firmware/fw_load_user/Makefile                   | 8 --------
 8 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index 78f00d305fea10367fb4fd2845f25dd151a833ea..19caee1d81da9cf0503088138ecfda13436b96cf 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -1,6 +1,6 @@
 cn_pec_sh cn_pec.sh
 kmsg01 kmsg01
-fw_load fw_load
+fw_load01 fw_load01
 rtc01 rtc01
 rtc02 rtc02
 block_dev block_dev
diff --git a/testcases/kernel/firmware/fw_load_kernel/.gitignore b/testcases/kernel/firmware/fw_load/.gitignore
similarity index 91%
rename from testcases/kernel/firmware/fw_load_kernel/.gitignore
rename to testcases/kernel/firmware/fw_load/.gitignore
index 6fc82952c7f5406c04195e1064375d0c2bd53909..57eca444c161e6ba642561664cc7de3a8f134841 100644
--- a/testcases/kernel/firmware/fw_load_kernel/.gitignore
+++ b/testcases/kernel/firmware/fw_load/.gitignore
@@ -5,3 +5,4 @@
 /ltp_fw_load.mod.c
 /.tmp_versions/
 modules.livepatch
+fw_load01
diff --git a/testcases/kernel/firmware/fw_load_kernel/Makefile b/testcases/kernel/firmware/fw_load/Makefile
similarity index 82%
rename from testcases/kernel/firmware/fw_load_kernel/Makefile
rename to testcases/kernel/firmware/fw_load/Makefile
index e81b300faaa6b4056d4b5f3d1417c381a000256d..91e8d8d153b43c459a899aff2124db612ec9e960 100644
--- a/testcases/kernel/firmware/fw_load_kernel/Makefile
+++ b/testcases/kernel/firmware/fw_load/Makefile
@@ -1,6 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
 # Copyright (c) Linux Test Project, 2026
-# SPDX-License-Identifier: GPL-2.0-or-later
 
 ifneq ($(KERNELRELEASE),)
 
@@ -11,11 +11,13 @@ endif
 else
 
 top_srcdir	?= ../../../..
-include $(top_srcdir)/include/mk/env_pre.mk
+
+include $(top_srcdir)/include/mk/testcases.mk
 
 REQ_VERSION_MAJOR   := 3
 REQ_VERSION_PATCH   := 7
-MAKE_TARGETS	:= ltp_fw_load.ko
+
+MAKE_TARGETS	:= fw_load01 ltp_fw_load.ko
 
 include $(top_srcdir)/include/mk/module.mk
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/firmware/fw_load_user/fw_load.h b/testcases/kernel/firmware/fw_load/fw_load.h
similarity index 100%
rename from testcases/kernel/firmware/fw_load_user/fw_load.h
rename to testcases/kernel/firmware/fw_load/fw_load.h
diff --git a/testcases/kernel/firmware/fw_load_user/fw_load.c b/testcases/kernel/firmware/fw_load/fw_load01.c
similarity index 100%
rename from testcases/kernel/firmware/fw_load_user/fw_load.c
rename to testcases/kernel/firmware/fw_load/fw_load01.c
diff --git a/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c b/testcases/kernel/firmware/fw_load/ltp_fw_load.c
similarity index 100%
rename from testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
rename to testcases/kernel/firmware/fw_load/ltp_fw_load.c
diff --git a/testcases/kernel/firmware/fw_load_user/.gitignore b/testcases/kernel/firmware/fw_load_user/.gitignore
deleted file mode 100644
index 1d0814980660f34b64bd49ba16c25dc1d99e9d07..0000000000000000000000000000000000000000
--- a/testcases/kernel/firmware/fw_load_user/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/fw_load
diff --git a/testcases/kernel/firmware/fw_load_user/Makefile b/testcases/kernel/firmware/fw_load_user/Makefile
deleted file mode 100644
index 5b031e2eb81597689ff5eab70246fb20ad02e77d..0000000000000000000000000000000000000000
--- a/testcases/kernel/firmware/fw_load_user/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
-# Copyright (c) Linux Test Project, 2026
-
-top_srcdir	?= ../../../..
-
-include $(top_srcdir)/include/mk/testcases.mk
-include $(top_srcdir)/include/mk/generic_leaf_target.mk

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path
  2026-06-11 13:44 [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API Andrea Cervesato
                   ` (2 preceding siblings ...)
  2026-06-11 13:44 ` [LTP] [PATCH v6 3/4] fw_load: merge module and test into fw_load folder Andrea Cervesato
@ 2026-06-11 13:44 ` Andrea Cervesato
  2026-06-15 11:49   ` Cyril Hrubis
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Linux Test Project

From: Andrea Cervesato <andrea.cervesato@suse.com>

Add fw_load02 which points the kernel firmware loader at the writable
LTP temporary directory via /sys/module/firmware_class/parameters/path.
Unlike fw_load01, it does not rely on a writable /lib/firmware and so
works on read-only and immutable root filesystems while still exercising
request_firmware() for both successful loads and the not-found case.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 runtest/kernel_misc                           |   1 +
 testcases/kernel/firmware/fw_load/.gitignore  |   1 +
 testcases/kernel/firmware/fw_load/Makefile    |   2 +-
 testcases/kernel/firmware/fw_load/fw_load02.c | 138 ++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index 19caee1d81da9cf0503088138ecfda13436b96cf..cc3562cb78cfa9b657692fcbd8fb732f2879092e 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -1,6 +1,7 @@
 cn_pec_sh cn_pec.sh
 kmsg01 kmsg01
 fw_load01 fw_load01
+fw_load02 fw_load02
 rtc01 rtc01
 rtc02 rtc02
 block_dev block_dev
diff --git a/testcases/kernel/firmware/fw_load/.gitignore b/testcases/kernel/firmware/fw_load/.gitignore
index 57eca444c161e6ba642561664cc7de3a8f134841..0bacefd371fc3ac6cf043102398b5a0c74b0b66d 100644
--- a/testcases/kernel/firmware/fw_load/.gitignore
+++ b/testcases/kernel/firmware/fw_load/.gitignore
@@ -6,3 +6,4 @@
 /.tmp_versions/
 modules.livepatch
 fw_load01
+fw_load02
diff --git a/testcases/kernel/firmware/fw_load/Makefile b/testcases/kernel/firmware/fw_load/Makefile
index 91e8d8d153b43c459a899aff2124db612ec9e960..bf6f9abd7517654066a5a92ac481e8eb1f959a41 100644
--- a/testcases/kernel/firmware/fw_load/Makefile
+++ b/testcases/kernel/firmware/fw_load/Makefile
@@ -17,7 +17,7 @@ include $(top_srcdir)/include/mk/testcases.mk
 REQ_VERSION_MAJOR   := 3
 REQ_VERSION_PATCH   := 7
 
-MAKE_TARGETS	:= fw_load01 ltp_fw_load.ko
+MAKE_TARGETS	:= fw_load01 fw_load02 ltp_fw_load.ko
 
 include $(top_srcdir)/include/mk/module.mk
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/firmware/fw_load/fw_load02.c b/testcases/kernel/firmware/fw_load/fw_load02.c
new file mode 100644
index 0000000000000000000000000000000000000000..20de8383078bf637dd48499fecc89754fdbaec67
--- /dev/null
+++ b/testcases/kernel/firmware/fw_load/fw_load02.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *	Alexey Kodanev <alexey.kodanev@oracle.com>
+ * Copyright (c) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Verifies that the kernel firmware loader (``CONFIG_FW_LOADER``)
+ * can find and load firmware files from a custom firmware search
+ * path.
+ *
+ * A helper kernel module (``ltp_fw_load.ko``) registers a virtual
+ * device that calls :kernel_doc:`request_firmware` for a set of
+ * numbered firmware blobs. Each blob is verified in-kernel against
+ * its expected size and byte pattern.
+ *
+ * The kernel firmware loader is pointed at the writable LTP temporary
+ * directory through ``/sys/module/firmware_class/parameters/path``.
+ * This avoids writing into ``/lib/firmware`` and therefore works on
+ * read-only or immutable root filesystems. The original value is
+ * saved and restored automatically.
+ *
+ * [Algorithm]
+ *
+ * - Set the firmware search path to the LTP temporary directory
+ * - Load the helper module with ``fw_size`` matching the blob size
+ * - Create ``FW_NUM - 1`` firmware files there, each named
+ *   ``n<i>_load_tst.fw`` and filled with a known byte pattern
+ * - Add one fake firmware entry that has no file on disk
+ * - Write the firmware count to ``/sys/devices/ltp_fw_load/fwnum``
+ *   to trigger :kernel_doc:`request_firmware` calls in-kernel
+ * - Read the result bitmask from ``/sys/devices/ltp_fw_load/result``
+ * - Verify that every real firmware file was loaded successfully
+ *   and that the fake entry was correctly rejected
+ */
+
+#include "tst_test.h"
+#include "tst_module.h"
+#include "fw_load.h"
+
+#define MAX_NAME 64
+
+static int module_loaded;
+static int fw_count;
+
+static struct fw_data {
+	char file[PATH_MAX];
+	char name[MAX_NAME];
+	int fake;
+} firmware[FW_NUM];
+
+static void create_firmware(const char *dir)
+{
+	struct fw_data *fw = &firmware[fw_count];
+	char buf[FW_SIZE];
+	int fd;
+
+	snprintf(fw->name, sizeof(fw->name), "n%d_%s", fw_count, FW_NAME);
+	snprintf(fw->file, sizeof(fw->file), "%s/n%d_%s", dir, fw_count, FW_NAME);
+	memset(buf, fw_count, FW_SIZE);
+
+	fd = SAFE_OPEN(fw->file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, FW_SIZE);
+	SAFE_CLOSE(fd);
+
+	fw_count++;
+}
+
+static void run(void)
+{
+	struct fw_data *fw;
+	int result = 0;
+	int fail;
+
+	SAFE_FILE_PRINTF(DEV_FWNUM, "%d", fw_count);
+	SAFE_FILE_SCANF(DEV_RESULT, "%d", &result);
+
+	for (int i = 0; i < fw_count; i++) {
+		fw = &firmware[i];
+
+		if (fw->fake) {
+			tst_res(result & (1 << i) ? TFAIL : TPASS,
+				"Firmware '%s' correctly not loaded", fw->name);
+		} else {
+			fail = (result & (1 << i)) == 0;
+			tst_res(fail ? TFAIL : TPASS,
+				"Firmware '%s' loaded", fw->name);
+		}
+	}
+}
+
+static void setup(void)
+{
+	char fw_size_param[32];
+	char *tmpdir = tst_tmpdir_path();
+
+	tst_requires_module_signature_disabled();
+
+	SAFE_FILE_PRINTF(FW_PATH, "%s", tmpdir);
+
+	snprintf(fw_size_param, sizeof(fw_size_param), "fw_size=%d", FW_SIZE);
+	char *const mod_params[] = {fw_size_param, NULL};
+
+	tst_module_load(MNAME_KO, mod_params);
+	module_loaded = 1;
+
+	for (int i = 0; i < FW_NUM - 1; i++)
+		create_firmware(tmpdir);
+
+	/* add a fake file that is never created on disk */
+	snprintf(firmware[fw_count].name, sizeof(firmware[fw_count].name),
+		 "n%d_%s", fw_count, FW_NAME);
+	firmware[fw_count].fake = 1;
+	fw_count++;
+}
+
+static void cleanup(void)
+{
+	if (module_loaded)
+		tst_module_unload(MNAME_KO);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.needs_tmpdir = 1,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_FW_LOADER=y|CONFIG_FW_LOADER=m",
+		NULL,
+	},
+	.save_restore = (const struct tst_path_val[]) {
+		{FW_PATH, NULL, TST_SR_TCONF},
+		{},
+	},
+};

-- 
2.51.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [LTP] fw_load: Modernize ltp_fw_load kernel module
  2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
@ 2026-06-11 14:44   ` linuxtestproject.agent
  2026-06-15 11:03   ` [LTP] [PATCH v6 1/4] " Cyril Hrubis
  1 sibling, 0 replies; 11+ messages in thread
From: linuxtestproject.agent @ 2026-06-11 14:44 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi Andrea,

On Thu, 11 Jun 2026 15:44:19 +0200, Andrea Cervesato wrote:
> fw_load: Modernize ltp_fw_load kernel module

Verdict: Reviewed

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module
  2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
  2026-06-11 14:44   ` [LTP] " linuxtestproject.agent
@ 2026-06-15 11:03   ` Cyril Hrubis
  1 sibling, 0 replies; 11+ messages in thread
From: Cyril Hrubis @ 2026-06-15 11:03 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi!
> diff --git a/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c b/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
> index b7397e8f13154a16c2626517545c3c14d153a043..8aac0fc9691f85970be12fca360a17473474365b 100644
> --- a/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
> +++ b/testcases/kernel/firmware/fw_load_kernel/ltp_fw_load.c
> @@ -1,25 +1,30 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
>  /*
>   * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
> + * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
>   *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation; either version 2 of
> - * the License, or (at your option) any later version.
> + * Copyright (c) 2023 Andrea Cervesato <andrea.cervesato@suse.com>
                     ^
		Shouldn't that be 2026?

Otherwise:

Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API
  2026-06-11 13:44 ` [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API Andrea Cervesato
@ 2026-06-15 11:33   ` Cyril Hrubis
  2026-06-15 11:50     ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 11+ messages in thread
From: Cyril Hrubis @ 2026-06-15 11:33 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi!
> +static void run(void)
>  {
> -	setup(argc, argv);
> +	struct fw_data *fw;
> +	int result = 0;
> +	int fail, offset;
>  
> -	test_run();
> +	SAFE_FILE_PRINTF(DEV_FWNUM, "%d", fw_count);
> +	SAFE_FILE_SCANF(DEV_RESULT, "%d", &result);
>  
> -	cleanup();
> +	for (int i = 0; i < fw_count; i++) {
> +		fw = &firmware[i];
>  
> -	tst_exit();
> -}
> +		fail = (result & (1 << i)) == 0 && !fw->fake;
> +		offset = fw->dir[0] ? strlen(fw->dir) : 0;
>  
> -static void help(void)
> -{
> -	printf("  -n x    Write x bytes to firmware file, default is %d\n",
> -		fw_size);
> -	printf("  -s      Skip cleanup\n");
> -	printf("  -v      Verbose\n");
> +		if (fw->fake) {
> +			tst_res(result & (1 << i) ? TFAIL : TPASS,
> +				"Firmware '%s' correctly not loaded",
> +				fw->file + offset);
> +		} else {
> +			tst_res(fail ? TFAIL : TPASS,
> +				"Firmware '%s' loaded",
> +				fw->file + offset);
> +		}

If you are splitting the tst_res() by the fw->fake then do it right. We
should drop the && !fw->fake from the fail above and use a variable
only to get the right bit from the result:

int pass = result && (1<<i);

if (fw->fake)
	tst_res(pass ? TFAIL : TPASS, ...)
else
	tst_res(pass ? TPASS : TFAIL, ...)


> +	}
>  }
>  
> -void setup(int argc, char *argv[])
> +static void setup(void)
>  {
> -	if (tst_lockdown_enabled() > 0 || tst_secureboot_enabled() > 0)
> -		tst_brkm(TCONF, NULL, "Cannot load unsigned modules in Lockdown/Secure Boot");

I assume that we dropped this because we have
tst_requires_module_signature_disabled() later in the setup() right?


The rest looks good.

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path
  2026-06-11 13:44 ` [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path Andrea Cervesato
@ 2026-06-15 11:49   ` Cyril Hrubis
  2026-06-15 12:01     ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 11+ messages in thread
From: Cyril Hrubis @ 2026-06-15 11:49 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

Hi!
> +static struct fw_data {
> +	char file[PATH_MAX];
> +	char name[MAX_NAME];
> +	int fake;
> +} firmware[FW_NUM];
> +
> +static void create_firmware(const char *dir)
> +{
> +	struct fw_data *fw = &firmware[fw_count];
> +	char buf[FW_SIZE];
> +	int fd;
> +
> +	snprintf(fw->name, sizeof(fw->name), "n%d_%s", fw_count, FW_NAME);
> +	snprintf(fw->file, sizeof(fw->file), "%s/n%d_%s", dir, fw_count, FW_NAME);
> +	memset(buf, fw_count, FW_SIZE);
> +
> +	fd = SAFE_OPEN(fw->file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
> +	SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, FW_SIZE);
> +	SAFE_CLOSE(fd);
> +
> +	fw_count++;
> +}
> +
> +static void run(void)
> +{
> +	struct fw_data *fw;
> +	int result = 0;
> +	int fail;
> +
> +	SAFE_FILE_PRINTF(DEV_FWNUM, "%d", fw_count);
> +	SAFE_FILE_SCANF(DEV_RESULT, "%d", &result);
> +
> +	for (int i = 0; i < fw_count; i++) {
> +		fw = &firmware[i];
> +
> +		if (fw->fake) {
> +			tst_res(result & (1 << i) ? TFAIL : TPASS,
> +				"Firmware '%s' correctly not loaded", fw->name);
> +		} else {
> +			fail = (result & (1 << i)) == 0;
> +			tst_res(fail ? TFAIL : TPASS,
> +				"Firmware '%s' loaded", fw->name);
> +		}
> +	}
> +}

These functions are nearly identical to the fw_load01.c maybe we should
put them into a header and include it into both tests instead?

I guess that we can have a static inline function do_test() that would
take the fw_data and fw_count as an argument and call it from run(). The
same for create_firmare(). We can pas sthe fw_data pointer that would be
initialized instead of acting on globals and put it into the shared
header.

> +static void setup(void)
> +{
> +	char fw_size_param[32];
> +	char *tmpdir = tst_tmpdir_path();
> +
> +	tst_requires_module_signature_disabled();
> +
> +	SAFE_FILE_PRINTF(FW_PATH, "%s", tmpdir);
> +
> +	snprintf(fw_size_param, sizeof(fw_size_param), "fw_size=%d", FW_SIZE);
> +	char *const mod_params[] = {fw_size_param, NULL};
> +
> +	tst_module_load(MNAME_KO, mod_params);
> +	module_loaded = 1;
> +
> +	for (int i = 0; i < FW_NUM - 1; i++)
> +		create_firmware(tmpdir);
> +
> +	/* add a fake file that is never created on disk */
> +	snprintf(firmware[fw_count].name, sizeof(firmware[fw_count].name),
> +		 "n%d_%s", fw_count, FW_NAME);
> +	firmware[fw_count].fake = 1;
> +	fw_count++;

And most of the setup code can be shared as well.

> +}
> +
> +static void cleanup(void)
> +{
> +	if (module_loaded)
> +		tst_module_unload(MNAME_KO);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.needs_tmpdir = 1,
> +	.needs_kconfigs = (const char *[]) {
> +		"CONFIG_FW_LOADER=y|CONFIG_FW_LOADER=m",
> +		NULL,
> +	},
> +	.save_restore = (const struct tst_path_val[]) {
> +		{FW_PATH, NULL, TST_SR_TCONF},
> +		{},
> +	},
> +};
> 
> -- 
> 2.51.0
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API
  2026-06-15 11:33   ` Cyril Hrubis
@ 2026-06-15 11:50     ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2026-06-15 11:50 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: Linux Test Project

Hi Cyril,

> If you are splitting the tst_res() by the fw->fake then do it right. We
> should drop the && !fw->fake from the fail above and use a variable
> only to get the right bit from the result:
> 
> int pass = result && (1<<i);
> 
> if (fw->fake)
> 	tst_res(pass ? TFAIL : TPASS, ...)
> else
> 	tst_res(pass ? TPASS : TFAIL, ...)

Much cleaner indeed, I will fix it.

> 
> I assume that we dropped this because we have
> tst_requires_module_signature_disabled() later in the setup() right?

Exactly.

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path
  2026-06-15 11:49   ` Cyril Hrubis
@ 2026-06-15 12:01     ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2026-06-15 12:01 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: Linux Test Project

Hi Cyril,

> These functions are nearly identical to the fw_load01.c maybe we should
> put them into a header and include it into both tests instead?
> 
> I guess that we can have a static inline function do_test() that would
> take the fw_data and fw_count as an argument and call it from run(). The
> same for create_firmare(). We can pas sthe fw_data pointer that would be
> initialized instead of acting on globals and put it into the shared
> header.

We can simply share a do_test() in the header indeed, but the setup() part
should stay like it is now, because only a tiny bit is actually overlapping.

I will send a new patch.

Regards,
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-06-15 12:01 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-11 13:44 [LTP] [PATCH v6 0/4] Rewrite fw_load test using new API Andrea Cervesato
2026-06-11 13:44 ` [LTP] [PATCH v6 1/4] fw_load: Modernize ltp_fw_load kernel module Andrea Cervesato
2026-06-11 14:44   ` [LTP] " linuxtestproject.agent
2026-06-15 11:03   ` [LTP] [PATCH v6 1/4] " Cyril Hrubis
2026-06-11 13:44 ` [LTP] [PATCH v6 2/4] fw_load: rewrite test using new LTP API Andrea Cervesato
2026-06-15 11:33   ` Cyril Hrubis
2026-06-15 11:50     ` Andrea Cervesato via ltp
2026-06-11 13:44 ` [LTP] [PATCH v6 3/4] fw_load: merge module and test into fw_load folder Andrea Cervesato
2026-06-11 13:44 ` [LTP] [PATCH v6 4/4] fw_load: add fw_load02 for custom firmware path Andrea Cervesato
2026-06-15 11:49   ` Cyril Hrubis
2026-06-15 12:01     ` Andrea Cervesato via ltp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox