| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |  request_firmware() hotplug interface: | 
					
						
							|  |  |  |  ------------------------------------ | 
					
						
							| 
									
										
										
										
											2007-06-04 18:45:44 +02:00
										 |  |  | 	Copyright (C) 2003 Manuel Estrada Sainz | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |  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): | 
					
						
							|  |  |  |  ============================ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  1), kernel(driver): | 
					
						
							|  |  |  | 	- calls request_firmware(&fw_entry, $FIRMWARE, device) | 
					
						
							|  |  |  | 	- kernel searchs the fimware image with name $FIRMWARE directly | 
					
						
							|  |  |  | 	in the below search path of root filesystem: | 
					
						
							| 
									
										
										
										
											2012-11-03 17:47:58 +08:00
										 |  |  | 		User customized search path by module parameter 'path'[1] | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  | 		"/lib/firmware/updates/" UTS_RELEASE, | 
					
						
							|  |  |  | 		"/lib/firmware/updates", | 
					
						
							|  |  |  | 		"/lib/firmware/" UTS_RELEASE, | 
					
						
							|  |  |  | 		"/lib/firmware" | 
					
						
							|  |  |  | 	- If found, goto 7), else goto 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-03 17:47:58 +08:00
										 |  |  | 	[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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  2), userspace: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  	- /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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  3), kernel: Discard any previous partial load. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  4), userspace: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		- hotplug: cat appropriate_firmware_image > \ | 
					
						
							|  |  |  | 					/sys/class/firmware/xxx/data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  5), kernel: grows a buffer in PAGE_SIZE increments to hold the image as it | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 comes in. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  6), userspace: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		- hotplug: echo 0 > /sys/class/firmware/xxx/loading | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  7), kernel: request_firmware() returns and the driver has the firmware | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 image in fw_entry->{data,size}. If something went wrong | 
					
						
							|  |  |  | 	 request_firmware() returns non-zero and fw_entry is set to | 
					
						
							|  |  |  | 	 NULL. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-24 10:49:33 +08:00
										 |  |  |  8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		 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(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 > /sysfs/$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 | 
					
						
							| 
									
										
										
										
											2009-05-29 11:33:19 +08:00
										 |  |  |    user contexts to request firmware asynchronously, but can't be called | 
					
						
							|  |  |  |    in atomic contexts. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-03 17:48:16 +08:00
										 |  |  |  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 need't cache the firmware by | 
					
						
							|  |  |  |  themselves any more for dealing with firmware loss during system | 
					
						
							|  |  |  |  resume. |