123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- request_firmware() hotplug interface:
- ------------------------------------
- Copyright (C) 2003 Manuel Estrada Sainz
- Why:
- ---
- Today, the most extended way to use firmware in the Linux kernel is linking
- it statically in a header file. Which has political and technical issues:
- 1) Some firmware is not legal to redistribute.
- 2) The firmware occupies memory permanently, even though it often is just
- used once.
- 3) Some people, like the Debian crowd, don't consider some firmware free
- enough and remove entire drivers (e.g.: keyspan).
- High level behavior (mixed):
- ============================
- 1), kernel(driver):
- - calls request_firmware(&fw_entry, $FIRMWARE, device)
- - kernel searches the firmware image with name $FIRMWARE directly
- in the below search path of root filesystem:
- User customized search path by module parameter 'path'[1]
- "/lib/firmware/updates/" UTS_RELEASE,
- "/lib/firmware/updates",
- "/lib/firmware/" UTS_RELEASE,
- "/lib/firmware"
- - If found, goto 7), else goto 2)
- [1], the 'path' is a string parameter which length should be less
- than 256, user should pass 'firmware_class.path=$CUSTOMIZED_PATH'
- if firmware_class is built in kernel(the general situation)
- 2), userspace:
- - /sys/class/firmware/xxx/{loading,data} appear.
- - hotplug gets called with a firmware identifier in $FIRMWARE
- and the usual hotplug environment.
- - hotplug: echo 1 > /sys/class/firmware/xxx/loading
- 3), kernel: Discard any previous partial load.
- 4), userspace:
- - hotplug: cat appropriate_firmware_image > \
- /sys/class/firmware/xxx/data
- 5), kernel: grows a buffer in PAGE_SIZE increments to hold the image as it
- comes in.
- 6), userspace:
- - hotplug: echo 0 > /sys/class/firmware/xxx/loading
- 7), kernel: request_firmware() returns and the driver has the firmware
- image in fw_entry->{data,size}. If something went wrong
- request_firmware() returns non-zero and fw_entry is set to
- NULL.
- 8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing
- the firmware image and any related resource.
- High level behavior (driver code):
- ==================================
- if(request_firmware(&fw_entry, $FIRMWARE, device) == 0)
- copy_fw_to_device(fw_entry->data, fw_entry->size);
- release_firmware(fw_entry);
- Sample/simple hotplug script:
- ============================
- # Both $DEVPATH and $FIRMWARE are already provided in the environment.
- HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
- echo 1 > /sys/$DEVPATH/loading
- cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
- echo 0 > /sys/$DEVPATH/loading
- Random notes:
- ============
- - "echo -1 > /sys/class/firmware/xxx/loading" will cancel the load at
- once and make request_firmware() return with error.
- - firmware_data_read() and firmware_loading_show() are just provided
- for testing and completeness, they are not called in normal use.
- - There is also /sys/class/firmware/timeout which holds a timeout in
- seconds for the whole load operation.
- - request_firmware_nowait() is also provided for convenience in
- user contexts to request firmware asynchronously, but can't be called
- in atomic contexts.
- about in-kernel persistence:
- ---------------------------
- Under some circumstances, as explained below, it would be interesting to keep
- firmware images in non-swappable kernel memory or even in the kernel image
- (probably within initramfs).
- Note that this functionality has not been implemented.
- - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
-
- - If the device that needs the firmware is needed to access the
- filesystem. When upon some error the device has to be reset and the
- firmware reloaded, it won't be possible to get it from userspace.
- e.g.:
- - A diskless client with a network card that needs firmware.
- - The filesystem is stored in a disk behind an scsi device
- that needs firmware.
- - Replacing buggy DSDT/SSDT ACPI tables on boot.
- Note: this would require the persistent objects to be included
- within the kernel image, probably within initramfs.
-
- And the same device can be needed to access the filesystem or not depending
- on the setup, so I think that the choice on what firmware to make
- persistent should be left to userspace.
- about firmware cache:
- --------------------
- After firmware cache mechanism is introduced during system sleep,
- request_firmware can be called safely inside device's suspend and
- resume callback, and callers needn't cache the firmware by
- themselves any more for dealing with firmware loss during system
- resume.
|