Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | |
| 2 | request_firmware() hotplug interface: |
| 3 | ------------------------------------ |
Markus Rechberger | 87d37a4 | 2007-06-04 18:45:44 +0200 | [diff] [blame] | 4 | Copyright (C) 2003 Manuel Estrada Sainz |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5 | |
| 6 | Why: |
| 7 | --- |
| 8 | |
| 9 | Today, the most extended way to use firmware in the Linux kernel is linking |
| 10 | it statically in a header file. Which has political and technical issues: |
| 11 | |
| 12 | 1) Some firmware is not legal to redistribute. |
| 13 | 2) The firmware occupies memory permanently, even though it often is just |
| 14 | used once. |
| 15 | 3) Some people, like the Debian crowd, don't consider some firmware free |
| 16 | enough and remove entire drivers (e.g.: keyspan). |
| 17 | |
| 18 | High level behavior (mixed): |
| 19 | ============================ |
| 20 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 21 | 1), kernel(driver): |
| 22 | - calls request_firmware(&fw_entry, $FIRMWARE, device) |
| 23 | - kernel searchs the fimware image with name $FIRMWARE directly |
| 24 | in the below search path of root filesystem: |
| 25 | "/lib/firmware/updates/" UTS_RELEASE, |
| 26 | "/lib/firmware/updates", |
| 27 | "/lib/firmware/" UTS_RELEASE, |
| 28 | "/lib/firmware" |
| 29 | - If found, goto 7), else goto 2) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 31 | 2), userspace: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | - /sys/class/firmware/xxx/{loading,data} appear. |
| 33 | - hotplug gets called with a firmware identifier in $FIRMWARE |
| 34 | and the usual hotplug environment. |
| 35 | - hotplug: echo 1 > /sys/class/firmware/xxx/loading |
| 36 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 37 | 3), kernel: Discard any previous partial load. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 39 | 4), userspace: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | - hotplug: cat appropriate_firmware_image > \ |
| 41 | /sys/class/firmware/xxx/data |
| 42 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 43 | 5), kernel: grows a buffer in PAGE_SIZE increments to hold the image as it |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | comes in. |
| 45 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 46 | 6), userspace: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | - hotplug: echo 0 > /sys/class/firmware/xxx/loading |
| 48 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 49 | 7), kernel: request_firmware() returns and the driver has the firmware |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 | image in fw_entry->{data,size}. If something went wrong |
| 51 | request_firmware() returns non-zero and fw_entry is set to |
| 52 | NULL. |
| 53 | |
Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame^] | 54 | 8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 | the firmware image and any related resource. |
| 56 | |
| 57 | High level behavior (driver code): |
| 58 | ================================== |
| 59 | |
| 60 | if(request_firmware(&fw_entry, $FIRMWARE, device) == 0) |
| 61 | copy_fw_to_device(fw_entry->data, fw_entry->size); |
| 62 | release(fw_entry); |
| 63 | |
| 64 | Sample/simple hotplug script: |
| 65 | ============================ |
| 66 | |
| 67 | # Both $DEVPATH and $FIRMWARE are already provided in the environment. |
| 68 | |
| 69 | HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ |
| 70 | |
| 71 | echo 1 > /sys/$DEVPATH/loading |
| 72 | cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data |
| 73 | echo 0 > /sys/$DEVPATH/loading |
| 74 | |
| 75 | Random notes: |
| 76 | ============ |
| 77 | |
| 78 | - "echo -1 > /sys/class/firmware/xxx/loading" will cancel the load at |
| 79 | once and make request_firmware() return with error. |
| 80 | |
| 81 | - firmware_data_read() and firmware_loading_show() are just provided |
| 82 | for testing and completeness, they are not called in normal use. |
| 83 | |
| 84 | - There is also /sys/class/firmware/timeout which holds a timeout in |
| 85 | seconds for the whole load operation. |
| 86 | |
| 87 | - request_firmware_nowait() is also provided for convenience in |
Ming Lei | 7fcab09 | 2009-05-29 11:33:19 +0800 | [diff] [blame] | 88 | user contexts to request firmware asynchronously, but can't be called |
| 89 | in atomic contexts. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | |
| 91 | |
| 92 | about in-kernel persistence: |
| 93 | --------------------------- |
| 94 | Under some circumstances, as explained below, it would be interesting to keep |
| 95 | firmware images in non-swappable kernel memory or even in the kernel image |
| 96 | (probably within initramfs). |
| 97 | |
| 98 | Note that this functionality has not been implemented. |
| 99 | |
| 100 | - Why OPTIONAL in-kernel persistence may be a good idea sometimes: |
| 101 | |
| 102 | - If the device that needs the firmware is needed to access the |
| 103 | filesystem. When upon some error the device has to be reset and the |
| 104 | firmware reloaded, it won't be possible to get it from userspace. |
| 105 | e.g.: |
| 106 | - A diskless client with a network card that needs firmware. |
| 107 | - The filesystem is stored in a disk behind an scsi device |
| 108 | that needs firmware. |
| 109 | - Replacing buggy DSDT/SSDT ACPI tables on boot. |
| 110 | Note: this would require the persistent objects to be included |
| 111 | within the kernel image, probably within initramfs. |
| 112 | |
| 113 | And the same device can be needed to access the filesystem or not depending |
| 114 | on the setup, so I think that the choice on what firmware to make |
| 115 | persistent should be left to userspace. |
| 116 | |