| 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 |  | 
|  | 21 | kernel(driver): calls request_firmware(&fw_entry, $FIRMWARE, device) | 
|  | 22 |  | 
|  | 23 | userspace: | 
|  | 24 | - /sys/class/firmware/xxx/{loading,data} appear. | 
|  | 25 | - hotplug gets called with a firmware identifier in $FIRMWARE | 
|  | 26 | and the usual hotplug environment. | 
|  | 27 | - hotplug: echo 1 > /sys/class/firmware/xxx/loading | 
|  | 28 |  | 
|  | 29 | kernel: Discard any previous partial load. | 
|  | 30 |  | 
|  | 31 | userspace: | 
|  | 32 | - hotplug: cat appropriate_firmware_image > \ | 
|  | 33 | /sys/class/firmware/xxx/data | 
|  | 34 |  | 
|  | 35 | kernel: grows a buffer in PAGE_SIZE increments to hold the image as it | 
|  | 36 | comes in. | 
|  | 37 |  | 
|  | 38 | userspace: | 
|  | 39 | - hotplug: echo 0 > /sys/class/firmware/xxx/loading | 
|  | 40 |  | 
|  | 41 | kernel: request_firmware() returns and the driver has the firmware | 
|  | 42 | image in fw_entry->{data,size}. If something went wrong | 
|  | 43 | request_firmware() returns non-zero and fw_entry is set to | 
|  | 44 | NULL. | 
|  | 45 |  | 
|  | 46 | kernel(driver): Driver code calls release_firmware(fw_entry) releasing | 
|  | 47 | the firmware image and any related resource. | 
|  | 48 |  | 
|  | 49 | High level behavior (driver code): | 
|  | 50 | ================================== | 
|  | 51 |  | 
|  | 52 | if(request_firmware(&fw_entry, $FIRMWARE, device) == 0) | 
|  | 53 | copy_fw_to_device(fw_entry->data, fw_entry->size); | 
|  | 54 | release(fw_entry); | 
|  | 55 |  | 
|  | 56 | Sample/simple hotplug script: | 
|  | 57 | ============================ | 
|  | 58 |  | 
|  | 59 | # Both $DEVPATH and $FIRMWARE are already provided in the environment. | 
|  | 60 |  | 
|  | 61 | HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ | 
|  | 62 |  | 
|  | 63 | echo 1 > /sys/$DEVPATH/loading | 
|  | 64 | cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data | 
|  | 65 | echo 0 > /sys/$DEVPATH/loading | 
|  | 66 |  | 
|  | 67 | Random notes: | 
|  | 68 | ============ | 
|  | 69 |  | 
|  | 70 | - "echo -1 > /sys/class/firmware/xxx/loading" will cancel the load at | 
|  | 71 | once and make request_firmware() return with error. | 
|  | 72 |  | 
|  | 73 | - firmware_data_read() and firmware_loading_show() are just provided | 
|  | 74 | for testing and completeness, they are not called in normal use. | 
|  | 75 |  | 
|  | 76 | - There is also /sys/class/firmware/timeout which holds a timeout in | 
|  | 77 | seconds for the whole load operation. | 
|  | 78 |  | 
|  | 79 | - request_firmware_nowait() is also provided for convenience in | 
|  | 80 | non-user contexts. | 
|  | 81 |  | 
|  | 82 |  | 
|  | 83 | about in-kernel persistence: | 
|  | 84 | --------------------------- | 
|  | 85 | Under some circumstances, as explained below, it would be interesting to keep | 
|  | 86 | firmware images in non-swappable kernel memory or even in the kernel image | 
|  | 87 | (probably within initramfs). | 
|  | 88 |  | 
|  | 89 | Note that this functionality has not been implemented. | 
|  | 90 |  | 
|  | 91 | - Why OPTIONAL in-kernel persistence may be a good idea sometimes: | 
|  | 92 |  | 
|  | 93 | - If the device that needs the firmware is needed to access the | 
|  | 94 | filesystem. When upon some error the device has to be reset and the | 
|  | 95 | firmware reloaded, it won't be possible to get it from userspace. | 
|  | 96 | e.g.: | 
|  | 97 | - A diskless client with a network card that needs firmware. | 
|  | 98 | - The filesystem is stored in a disk behind an scsi device | 
|  | 99 | that needs firmware. | 
|  | 100 | - Replacing buggy DSDT/SSDT ACPI tables on boot. | 
|  | 101 | Note: this would require the persistent objects to be included | 
|  | 102 | within the kernel image, probably within initramfs. | 
|  | 103 |  | 
|  | 104 | And the same device can be needed to access the filesystem or not depending | 
|  | 105 | on the setup, so I think that the choice on what firmware to make | 
|  | 106 | persistent should be left to userspace. | 
|  | 107 |  |