Document a little more the firmware subsystem.
Apart from minor cleanup of the text, it should document in reasonable detail what the status of the code is. RELENG_6 has some minor differences there in the way automatic loading/unloading is handled, but hopefully this should be fixed by MFC time. The examples come from Max Laier and Sam Leffler. MFC after: 1 week
This commit is contained in:
parent
983f970981
commit
97070dd5e0
@ -65,55 +65,203 @@ struct firmware {
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm firmware
|
||||
abstraction provides a convenient interface for loading firmware
|
||||
images into the kernel.
|
||||
Specially crafted kernel modules are used to hold the firmware images.
|
||||
abstraction provides a convenient interface for loading
|
||||
.Nm firmware images
|
||||
into the kernel, and for accessing such images from kernel components.
|
||||
.Pp
|
||||
The function
|
||||
.Fn firmware_register
|
||||
is used on load of such modules to register contained firmware images.
|
||||
The arguments to
|
||||
.Fn firmware_register
|
||||
include a name that identifies the image for later requests to the
|
||||
A
|
||||
.Nm firmware image
|
||||
(or
|
||||
.Nm image
|
||||
for brevity)
|
||||
is an opaque block of data residing in kernel memory.
|
||||
It is associated to a unique
|
||||
.Nm imagename
|
||||
which constitutes a search key, and to an integer
|
||||
.Nm version
|
||||
number, which is also an opaque piece of information for the
|
||||
firmware subsystem.
|
||||
.Pp
|
||||
An image is registered with the
|
||||
.Nm firmware
|
||||
system, a pointer to the actual image, the size of the image and an optional
|
||||
parent image.
|
||||
The parent image is used to keep track of references to a given module so that
|
||||
it can be unloaded on last reference.
|
||||
subsystem by calling the function
|
||||
.Fn firmware_register ,
|
||||
and unregistered by calling
|
||||
.Fn firmware_unregister .
|
||||
These functions are usually (but not exclusively) performed by
|
||||
specially crafted kernel modules that contain the firmware image.
|
||||
The modules can be statically compiled in the kernel, or loaded by
|
||||
.Nm /boot/loader ,
|
||||
manually at runtime, or on demand by the firmware subsystem.
|
||||
.Pp
|
||||
.Nm Clients
|
||||
of the firmware subsystem can request access to a given image
|
||||
by calling the function
|
||||
.Fn firmware_get
|
||||
with the
|
||||
.Nm imagename
|
||||
they want as an argument. 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
|
||||
with
|
||||
.Nm the same name
|
||||
as the image).
|
||||
.Sh API DESCRIPTION
|
||||
The kernel
|
||||
.Nm firmware API
|
||||
is made of the following functions:
|
||||
.Pp
|
||||
.Fn firmware_register
|
||||
registers with the kernel an image of size
|
||||
.Nm datasize
|
||||
located at address
|
||||
.Nm data ,
|
||||
under the name
|
||||
.Nm imagename .
|
||||
.Nm parent
|
||||
is and a pointer to the parent image, if any.
|
||||
.Pp
|
||||
The function returns NULL on error (e.g. because an
|
||||
image with the same name already exists, or the image
|
||||
table is full), or a
|
||||
.Ft const struct firmware *
|
||||
pointer to the image requested.
|
||||
.Pp
|
||||
The function
|
||||
.Fn firmware_unregister
|
||||
removes the firmware image identified by the name from the system if there
|
||||
are no pending references or returns an error otherwise.
|
||||
tries to unregister the firmware image
|
||||
.Nm imagename
|
||||
from the system. The function is successful and returns 0
|
||||
if there are no pending references to the image, otherwise
|
||||
it does not unregister the image and returns EBUSY.
|
||||
.Pp
|
||||
The function
|
||||
.Fn firmware_get
|
||||
returns the requested firmware image.
|
||||
If the image is not yet registered with the system,
|
||||
.Fn firmware_get
|
||||
tries to load a module with the corresponding name.
|
||||
This involves the linker subsystem and disk access which is why
|
||||
the function tries to load it.
|
||||
This involves the linker subsystem and disk access, so
|
||||
.Fn firmware_get
|
||||
must not be called with any locks (except for
|
||||
.Va Giant ) .
|
||||
The caller must also have a process context so filesystem state such as
|
||||
the root vnode is defined (e.g. you cannot load from a taskqueue thread).
|
||||
.Pp
|
||||
On success,
|
||||
.Fn firmware_get
|
||||
returns a pointer to the image description and increases the reference count
|
||||
for this image.
|
||||
for this image. On failure, the function returns NULL.
|
||||
.Pp
|
||||
The function
|
||||
.Fn firmware_put
|
||||
is used to drop the reference to a firmware image.
|
||||
drops a reference to a firmware image.
|
||||
The
|
||||
.Fa flags
|
||||
argument may be set to
|
||||
.Dv FIRMWARE_UNLOAD
|
||||
to indicate that the caller wishes to unload the corresponding module if the
|
||||
image becomes unreferenced.
|
||||
.Sh SEE ALSO
|
||||
.Xr module 9
|
||||
to indicate that
|
||||
firmware_put is free to reclaim resources associated with
|
||||
the firmware image if this is the last reference.
|
||||
.Sh FIRMWARE LOADING MECHANISMS
|
||||
As mentioned before, any component of the system can register
|
||||
firmware images at any time by simply calling
|
||||
.Fn firmware_register .
|
||||
.Pp
|
||||
.Pa /usr/share/examples/kld
|
||||
This is typically done when a module containing
|
||||
a firmware image is given control,
|
||||
whether compiled in, or preloaded by
|
||||
.Nm /boot/loader ,
|
||||
or manually loaded with
|
||||
.Xr kldload 8 .
|
||||
However, a system can implement additional mechanisms to bring
|
||||
these images in memory before calling
|
||||
.Fn firmware_register .
|
||||
.Pp
|
||||
When
|
||||
.Fn firmware_get
|
||||
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 :
|
||||
.Pp
|
||||
A firmware image named
|
||||
.Nm foo
|
||||
is looked up by trying to load the module named
|
||||
.Nm foo.ko ,
|
||||
using the facilities described in
|
||||
.Xr kld 4 .
|
||||
In particular, images are looked up in the directories specified
|
||||
by the sysctl variable
|
||||
.Nm kern.module_path
|
||||
which on most systems defaults to
|
||||
.Nm /boot/kernel;/boot/modules .
|
||||
.Pp
|
||||
Note that in case a module contains multiple images,
|
||||
the caller should first request a
|
||||
.Fn firmware_get
|
||||
for the first image contained in the module, followed by requests
|
||||
for the other images.
|
||||
.Sh BUILDING FIRMWARE LOADABLE MODULES
|
||||
A firmware module is built by embedding the
|
||||
.Nm firmware image
|
||||
into a suitable loadable kernel module that calls
|
||||
.Fn firmware_register
|
||||
on loading, and
|
||||
.Fn firmware_unregister
|
||||
on unloading.
|
||||
.Pp
|
||||
Various system scripts and makefiles let you build a module
|
||||
by simply writing a Makefile with the following entries:
|
||||
.Bd -literal
|
||||
|
||||
KMOD= imagename
|
||||
FIRMWS= image_file:imagename[:version]
|
||||
.include <bsd.kmod.mk>
|
||||
|
||||
.Ed
|
||||
where KMOD is the basename of the module; FIRMWS is a list of
|
||||
colon-separated tuples indicating the image_file's to be embedded
|
||||
in the module, the imagename and version of each firmware image.
|
||||
.Pp
|
||||
If you need to embed firmware images into a system, you should write
|
||||
appropriate entries in the <files.arch> file, e.g. this example is
|
||||
from
|
||||
.Nm sys/arm/xscale/ixp425/files.ixp425:
|
||||
.Bd -literal
|
||||
ixp425_npe_fw.c optional npe_fw \\
|
||||
compile-with "${AWK} -f $S/tools/fw_stub.awk \\
|
||||
IxNpeMicrocode.dat:npe_fw -mnpe -c${.TARGET}" \\
|
||||
no-implicit-rule before-depend local \\
|
||||
clean "ixp425_npe_fw.c"
|
||||
#
|
||||
# NB: ld encodes the path in the binary symbols generated for the
|
||||
# firmware image so link the file to the object directory to
|
||||
# get known values for reference in the _fw.c file.
|
||||
#
|
||||
IxNpeMicrocode.fwo optional npe_fw \\
|
||||
dependency "IxNpeMicrocode.dat" \\
|
||||
compile-with "${LD} -b binary -d -warn-common \\
|
||||
-r -d -o ${.TARGET} IxNpeMicrocode.dat" \\
|
||||
no-implicit-rule \\
|
||||
clean "IxNpeMicrocode.fwo"
|
||||
IxNpeMicrocode.dat optional npe_fw \\
|
||||
dependency ".PHONY" \\
|
||||
compile-with "if [ -e $S/arm/xscale/ixp425/IxNpeMicrocode.dat ]; \\
|
||||
then \\
|
||||
ln -sf $S/arm/xscale/ixp425/IxNpeMicrocode.dat .; \\
|
||||
else echo 'WARNING, no IxNpeMicrocode.dat file; you must obtain this from the Intel web site'; false; \\
|
||||
fi" \\
|
||||
no-obj no-implicit-rule \\
|
||||
clean "IxNpeMicrocode.dat"
|
||||
.Ed
|
||||
.Pp
|
||||
Note that generating the firmware modules in this way requires
|
||||
the availability of the following tools:
|
||||
.Xr awk ,
|
||||
.Xr Make ,
|
||||
the compiler and the linker.
|
||||
.Sh SEE ALSO
|
||||
.Xr module 9 ,
|
||||
.Xr kld 4
|
||||
.Pp
|
||||
.Pa /usr/share/examples/kld/firmware
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm firmware
|
||||
|
Loading…
x
Reference in New Issue
Block a user