| 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: | 
| Ming Lei | 2760284 | 2012-11-03 17:47:58 +0800 | [diff] [blame] | 25 | 		User customized search path by module parameter 'path'[1] | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 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) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 |  | 
| Ming Lei | 2760284 | 2012-11-03 17:47:58 +0800 | [diff] [blame] | 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 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 36 |  2), userspace: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 42 |  3), kernel: Discard any previous partial load. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 44 |  4), userspace: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | 		- hotplug: cat appropriate_firmware_image > \ | 
 | 46 | 					/sys/class/firmware/xxx/data | 
 | 47 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 48 |  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] | 49 | 	 comes in. | 
 | 50 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 51 |  6), userspace: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | 		- hotplug: echo 0 > /sys/class/firmware/xxx/loading | 
 | 53 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 54 |  7), kernel: request_firmware() returns and the driver has the firmware | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Ming Lei | 10bd4c7 | 2012-10-24 10:49:33 +0800 | [diff] [blame] | 59 |  8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 
| Ming Lei | 7fcab09 | 2009-05-29 11:33:19 +0800 | [diff] [blame] | 93 |    user contexts to request firmware asynchronously, but can't be called | 
 | 94 |    in atomic contexts. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Ming Lei | 6a92785 | 2012-11-03 17:48:16 +0800 | [diff] [blame] | 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. |