aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/firmware.940
-rw-r--r--sys/kern/subr_firmware.c45
-rw-r--r--sys/sys/firmware.h5
3 files changed, 69 insertions, 21 deletions
diff --git a/share/man/man9/firmware.9 b/share/man/man9/firmware.9
index b0d429573cf6..6d91beb3ddd1 100644
--- a/share/man/man9/firmware.9
+++ b/share/man/man9/firmware.9
@@ -23,13 +23,14 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 14, 2019
+.Dd January 27, 2021
.Dt FIRMWARE 9
.Os
.Sh NAME
.Nm firmware_register ,
.Nm firmware_unregister ,
.Nm firmware_get ,
+.Nm firmware_get_flags ,
.Nm firmware_put
.Nd firmware image loading and management
.Sh SYNOPSIS
@@ -57,6 +58,8 @@ struct firmware {
.Fn firmware_unregister "const char *imagename"
.Ft "const struct firmware *"
.Fn firmware_get "const char *imagename"
+.Ft "const struct firmware *"
+.Fn firmware_get_flags "const char *imagename" "uint32_t flags"
.Ft void
.Fn firmware_put "const struct firmware *fp" "int flags"
.Sh DESCRIPTION
@@ -97,7 +100,13 @@ by calling the function
.Fn firmware_get
with the
.Nm imagename
-they want as an argument.
+they want as an argument, or by calling
+.Fn firmware_get_flags
+with the
+.Nm imagename
+and
+.Nm flags
+they want as an arguments.
If a matching image is not already registered,
the firmware subsystem will try to load it using the
mechanisms specified below (typically, a kernel module
@@ -134,11 +143,22 @@ if there are no pending references to the image, otherwise
it does not unregister the image and returns EBUSY.
.Pp
.Fn firmware_get
-returns the requested firmware image.
+and
+.Fn firmware_get_flags
+return the requested firmware image.
+The
+.Fa flags
+argument may be set to
+.Dv FIRMWARE_GET_NOWARN
+to indicate that errors on firmware load or registration should
+only be logged in case of
+.Nm booverbose .
If the image is not yet registered with the system,
-the function tries to load it.
+the functions try to load it.
This involves the linker subsystem and disk access, so
.Fn firmware_get
+or
+.Fn firmware_get_flags
must not be called with any locks (except for
.Va Giant ) .
Note also that if the firmware image is loaded from a filesystem
@@ -149,9 +169,11 @@ already mounted.
.Pp
On success,
.Fn firmware_get
-returns a pointer to the image description and increases the reference count
+and
+.Fn firmware_get_flags
+return a pointer to the image description and increase the reference count
for this image.
-On failure, the function returns NULL.
+On failure, the functions return NULL.
.Pp
.Fn firmware_put
drops a reference to a firmware image.
@@ -183,10 +205,12 @@ these images in memory before calling
.Pp
When
.Fn firmware_get
+or
+.Fn firmware_get_flags
does not find the requested image, it tries to load it using
one of the available loading mechanisms.
At the moment, there is only one, namely
-.Nm Loadable kernel modules :
+.Nm Loadable kernel modules .
.Pp
A firmware image named
.Nm foo
@@ -203,6 +227,8 @@ which on most systems defaults to
Note that in case a module contains multiple images,
the caller should first request a
.Fn firmware_get
+or
+.Fn firmware_get_flags
for the first image contained in the module, followed by requests
for the other images.
.Sh BUILDING FIRMWARE LOADABLE MODULES
diff --git a/sys/kern/subr_firmware.c b/sys/kern/subr_firmware.c
index db262c121918..0465f2a88483 100644
--- a/sys/kern/subr_firmware.c
+++ b/sys/kern/subr_firmware.c
@@ -238,36 +238,42 @@ firmware_unregister(const char *imagename)
return (err);
}
+struct fw_loadimage {
+ const char *imagename;
+ uint32_t flags;
+};
+
static void
-loadimage(void *arg, int npending)
+loadimage(void *arg, int npending __unused)
{
- char *imagename = arg;
+ struct fw_loadimage *fwli = arg;
struct priv_fw *fp;
linker_file_t result;
int error;
- error = linker_reference_module(imagename, NULL, &result);
+ error = linker_reference_module(fwli->imagename, NULL, &result);
if (error != 0) {
- printf("%s: could not load firmware image, error %d\n",
- imagename, error);
+ if (bootverbose || (fwli->flags & FIRMWARE_GET_NOWARN) == 0)
+ printf("%s: could not load firmware image, error %d\n",
+ fwli->imagename, error);
mtx_lock(&firmware_mtx);
goto done;
}
mtx_lock(&firmware_mtx);
- fp = lookup(imagename);
+ fp = lookup(fwli->imagename);
if (fp == NULL || fp->file != NULL) {
mtx_unlock(&firmware_mtx);
if (fp == NULL)
printf("%s: firmware image loaded, "
- "but did not register\n", imagename);
- (void) linker_release_module(imagename, NULL, NULL);
+ "but did not register\n", fwli->imagename);
+ (void) linker_release_module(fwli->imagename, NULL, NULL);
mtx_lock(&firmware_mtx);
goto done;
}
fp->file = result; /* record the module identity */
done:
- wakeup_one(imagename);
+ wakeup_one(arg);
mtx_unlock(&firmware_mtx);
}
@@ -279,7 +285,7 @@ done:
* release this reference for the image to be eligible for removal/unload.
*/
const struct firmware *
-firmware_get(const char *imagename)
+firmware_get_flags(const char *imagename, uint32_t flags)
{
struct task fwload_task;
struct thread *td;
@@ -306,11 +312,15 @@ firmware_get(const char *imagename)
* Also we must not hold any mtx's over this call which is problematic.
*/
if (!cold) {
- TASK_INIT(&fwload_task, 0, loadimage, __DECONST(void *,
- imagename));
+ struct fw_loadimage fwli;
+
+ fwli.imagename = imagename;
+ fwli.flags = flags;
+ TASK_INIT(&fwload_task, 0, loadimage, (void *)&fwli);
taskqueue_enqueue(firmware_tq, &fwload_task);
- msleep(__DECONST(void *, imagename), &firmware_mtx, 0,
- "fwload", 0);
+ PHOLD(curproc);
+ msleep((void *)&fwli, &firmware_mtx, 0, "fwload", 0);
+ PRELE(curproc);
}
/*
* After attempting to load the module, see if the image is registered.
@@ -328,6 +338,13 @@ found: /* common exit point on success */
return &fp->fw;
}
+const struct firmware *
+firmware_get(const char *imagename)
+{
+
+ return (firmware_get_flags(imagename, 0));
+}
+
/*
* Release a reference to a firmware image returned by firmware_get.
* The caller may specify, with the FIRMWARE_UNLOAD flag, its desire
diff --git a/sys/sys/firmware.h b/sys/sys/firmware.h
index 8a9b2cf23bd7..0d74a749f4fc 100644
--- a/sys/sys/firmware.h
+++ b/sys/sys/firmware.h
@@ -60,7 +60,12 @@ struct firmware {
const struct firmware *firmware_register(const char *,
const void *, size_t, unsigned int, const struct firmware *);
int firmware_unregister(const char *);
+
+#define FIRMWARE_GET_NOWARN 0x0001 /* Do not warn if firmware not found. */
+const struct firmware *firmware_get_flags(const char *, uint32_t flags);
const struct firmware *firmware_get(const char *);
+
#define FIRMWARE_UNLOAD 0x0001 /* unload if unreferenced */
void firmware_put(const struct firmware *, int);
+
#endif /* _SYS_FIRMWARE_H_ */