Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | |
2 | request_firmware() hotplug interface: | |
3 | ------------------------------------ | |
87d37a4f | 4 | Copyright (C) 2003 Manuel Estrada Sainz |
1da177e4 LT |
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 | ||
10bd4c75 ML |
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: | |
27602842 | 25 | User customized search path by module parameter 'path'[1] |
10bd4c75 ML |
26 | "/lib/firmware/updates/" UTS_RELEASE, |
27 | "/lib/firmware/updates", | |
28 | "/lib/firmware/" UTS_RELEASE, | |
29 | "/lib/firmware" | |
30 | - If found, goto 7), else goto 2) | |
31 | ||
27602842 ML |
32 | [1], the 'path' is a string parameter which length should be less |
33 | than 256, user should pass 'firmware_class.path=$CUSTOMIZED_PATH' | |
34 | if firmware_class is built in kernel(the general situation) | |
35 | ||
10bd4c75 | 36 | 2), userspace: |
1da177e4 LT |
37 | - /sys/class/firmware/xxx/{loading,data} appear. |
38 | - hotplug gets called with a firmware identifier in $FIRMWARE | |
39 | and the usual hotplug environment. | |
40 | - hotplug: echo 1 > /sys/class/firmware/xxx/loading | |
41 | ||
10bd4c75 | 42 | 3), kernel: Discard any previous partial load. |
1da177e4 | 43 | |
10bd4c75 | 44 | 4), userspace: |
1da177e4 LT |
45 | - hotplug: cat appropriate_firmware_image > \ |
46 | /sys/class/firmware/xxx/data | |
47 | ||
10bd4c75 | 48 | 5), kernel: grows a buffer in PAGE_SIZE increments to hold the image as it |
1da177e4 LT |
49 | comes in. |
50 | ||
10bd4c75 | 51 | 6), userspace: |
1da177e4 LT |
52 | - hotplug: echo 0 > /sys/class/firmware/xxx/loading |
53 | ||
10bd4c75 | 54 | 7), kernel: request_firmware() returns and the driver has the firmware |
1da177e4 LT |
55 | image in fw_entry->{data,size}. If something went wrong |
56 | request_firmware() returns non-zero and fw_entry is set to | |
57 | NULL. | |
58 | ||
10bd4c75 | 59 | 8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing |
1da177e4 LT |
60 | the firmware image and any related resource. |
61 | ||
62 | High level behavior (driver code): | |
63 | ================================== | |
64 | ||
65 | if(request_firmware(&fw_entry, $FIRMWARE, device) == 0) | |
66 | copy_fw_to_device(fw_entry->data, fw_entry->size); | |
67 | release(fw_entry); | |
68 | ||
69 | Sample/simple hotplug script: | |
70 | ============================ | |
71 | ||
72 | # Both $DEVPATH and $FIRMWARE are already provided in the environment. | |
73 | ||
74 | HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ | |
75 | ||
76 | echo 1 > /sys/$DEVPATH/loading | |
77 | cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data | |
78 | echo 0 > /sys/$DEVPATH/loading | |
79 | ||
80 | Random notes: | |
81 | ============ | |
82 | ||
83 | - "echo -1 > /sys/class/firmware/xxx/loading" will cancel the load at | |
84 | once and make request_firmware() return with error. | |
85 | ||
86 | - firmware_data_read() and firmware_loading_show() are just provided | |
87 | for testing and completeness, they are not called in normal use. | |
88 | ||
89 | - There is also /sys/class/firmware/timeout which holds a timeout in | |
90 | seconds for the whole load operation. | |
91 | ||
92 | - request_firmware_nowait() is also provided for convenience in | |
7fcab099 ML |
93 | user contexts to request firmware asynchronously, but can't be called |
94 | in atomic contexts. | |
1da177e4 LT |
95 | |
96 | ||
97 | about in-kernel persistence: | |
98 | --------------------------- | |
99 | Under some circumstances, as explained below, it would be interesting to keep | |
100 | firmware images in non-swappable kernel memory or even in the kernel image | |
101 | (probably within initramfs). | |
102 | ||
103 | Note that this functionality has not been implemented. | |
104 | ||
105 | - Why OPTIONAL in-kernel persistence may be a good idea sometimes: | |
106 | ||
107 | - If the device that needs the firmware is needed to access the | |
108 | filesystem. When upon some error the device has to be reset and the | |
109 | firmware reloaded, it won't be possible to get it from userspace. | |
110 | e.g.: | |
111 | - A diskless client with a network card that needs firmware. | |
112 | - The filesystem is stored in a disk behind an scsi device | |
113 | that needs firmware. | |
114 | - Replacing buggy DSDT/SSDT ACPI tables on boot. | |
115 | Note: this would require the persistent objects to be included | |
116 | within the kernel image, probably within initramfs. | |
117 | ||
118 | And the same device can be needed to access the filesystem or not depending | |
119 | on the setup, so I think that the choice on what firmware to make | |
120 | persistent should be left to userspace. | |
121 | ||
6a927857 ML |
122 | about firmware cache: |
123 | -------------------- | |
124 | After firmware cache mechanism is introduced during system sleep, | |
125 | request_firmware can be called safely inside device's suspend and | |
126 | resume callback, and callers need't cache the firmware by | |
127 | themselves any more for dealing with firmware loss during system | |
128 | resume. |