xref: /openbmc/linux/Documentation/driver-api/firmware/fw_upload.rst (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
197730bbbSRuss Weight.. SPDX-License-Identifier: GPL-2.0
297730bbbSRuss Weight
397730bbbSRuss Weight===================
497730bbbSRuss WeightFirmware Upload API
597730bbbSRuss Weight===================
697730bbbSRuss Weight
797730bbbSRuss WeightA device driver that registers with the firmware loader will expose
897730bbbSRuss Weightpersistent sysfs nodes to enable users to initiate firmware updates for
997730bbbSRuss Weightthat device.  It is the responsibility of the device driver and/or the
1097730bbbSRuss Weightdevice itself to perform any validation on the data received. Firmware
1197730bbbSRuss Weightupload uses the same *loading* and *data* sysfs files described in the
12536fd818SRuss Weightdocumentation for firmware fallback. It also adds additional sysfs files
13536fd818SRuss Weightto provide status on the transfer of the firmware image to the device.
1497730bbbSRuss Weight
1597730bbbSRuss WeightRegister for firmware upload
1697730bbbSRuss Weight============================
1797730bbbSRuss Weight
1897730bbbSRuss WeightA device driver registers for firmware upload by calling
1997730bbbSRuss Weightfirmware_upload_register(). Among the parameter list is a name to
2097730bbbSRuss Weightidentify the device under /sys/class/firmware. A user may initiate a
2197730bbbSRuss Weightfirmware upload by echoing a 1 to the *loading* sysfs file for the target
2297730bbbSRuss Weightdevice. Next, the user writes the firmware image to the *data* sysfs
2397730bbbSRuss Weightfile. After writing the firmware data, the user echos 0 to the *loading*
2497730bbbSRuss Weightsysfs file to signal completion. Echoing 0 to *loading* also triggers the
2597730bbbSRuss Weighttransfer of the firmware to the lower-lever device driver in the context
2697730bbbSRuss Weightof a kernel worker thread.
2797730bbbSRuss Weight
2897730bbbSRuss WeightTo use the firmware upload API, write a driver that implements a set of
2997730bbbSRuss Weightops.  The probe function calls firmware_upload_register() and the remove
3097730bbbSRuss Weightfunction calls firmware_upload_unregister() such as::
3197730bbbSRuss Weight
3297730bbbSRuss Weight	static const struct fw_upload_ops m10bmc_ops = {
3397730bbbSRuss Weight		.prepare = m10bmc_sec_prepare,
3497730bbbSRuss Weight		.write = m10bmc_sec_write,
3597730bbbSRuss Weight		.poll_complete = m10bmc_sec_poll_complete,
3697730bbbSRuss Weight		.cancel = m10bmc_sec_cancel,
3797730bbbSRuss Weight		.cleanup = m10bmc_sec_cleanup,
3897730bbbSRuss Weight	};
3997730bbbSRuss Weight
4097730bbbSRuss Weight	static int m10bmc_sec_probe(struct platform_device *pdev)
4197730bbbSRuss Weight	{
4297730bbbSRuss Weight		const char *fw_name, *truncate;
4397730bbbSRuss Weight		struct m10bmc_sec *sec;
4497730bbbSRuss Weight		struct fw_upload *fwl;
4597730bbbSRuss Weight		unsigned int len;
4697730bbbSRuss Weight
4797730bbbSRuss Weight		sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
4897730bbbSRuss Weight		if (!sec)
4997730bbbSRuss Weight			return -ENOMEM;
5097730bbbSRuss Weight
5197730bbbSRuss Weight		sec->dev = &pdev->dev;
5297730bbbSRuss Weight		sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
5397730bbbSRuss Weight		dev_set_drvdata(&pdev->dev, sec);
5497730bbbSRuss Weight
5597730bbbSRuss Weight		fw_name = dev_name(sec->dev);
5697730bbbSRuss Weight		truncate = strstr(fw_name, ".auto");
5797730bbbSRuss Weight		len = (truncate) ? truncate - fw_name : strlen(fw_name);
5897730bbbSRuss Weight		sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL);
5997730bbbSRuss Weight
60*61f21988SConor Dooley		fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name,
61*61f21988SConor Dooley					       &m10bmc_ops, sec);
6297730bbbSRuss Weight		if (IS_ERR(fwl)) {
6397730bbbSRuss Weight			dev_err(sec->dev, "Firmware Upload driver failed to start\n");
6497730bbbSRuss Weight			kfree(sec->fw_name);
6597730bbbSRuss Weight			return PTR_ERR(fwl);
6697730bbbSRuss Weight		}
6797730bbbSRuss Weight
6897730bbbSRuss Weight		sec->fwl = fwl;
6997730bbbSRuss Weight		return 0;
7097730bbbSRuss Weight	}
7197730bbbSRuss Weight
7297730bbbSRuss Weight	static int m10bmc_sec_remove(struct platform_device *pdev)
7397730bbbSRuss Weight	{
7497730bbbSRuss Weight		struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
7597730bbbSRuss Weight
7697730bbbSRuss Weight		firmware_upload_unregister(sec->fwl);
7797730bbbSRuss Weight		kfree(sec->fw_name);
7897730bbbSRuss Weight		return 0;
7997730bbbSRuss Weight	}
8097730bbbSRuss Weight
8197730bbbSRuss Weightfirmware_upload_register
8297730bbbSRuss Weight------------------------
8397730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c
8497730bbbSRuss Weight   :identifiers: firmware_upload_register
8597730bbbSRuss Weight
8697730bbbSRuss Weightfirmware_upload_unregister
8797730bbbSRuss Weight--------------------------
8897730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c
8997730bbbSRuss Weight   :identifiers: firmware_upload_unregister
9097730bbbSRuss Weight
9197730bbbSRuss WeightFirmware Upload Ops
9297730bbbSRuss Weight-------------------
9397730bbbSRuss Weight.. kernel-doc:: include/linux/firmware.h
9497730bbbSRuss Weight   :identifiers: fw_upload_ops
9597730bbbSRuss Weight
9697730bbbSRuss WeightFirmware Upload Progress Codes
9797730bbbSRuss Weight------------------------------
98536fd818SRuss WeightThe following progress codes are used internally by the firmware loader.
99536fd818SRuss WeightCorresponding strings are reported through the status sysfs node that
100536fd818SRuss Weightis described below and are documented in the ABI documentation.
10197730bbbSRuss Weight
10297730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.h
10397730bbbSRuss Weight   :identifiers: fw_upload_prog
10497730bbbSRuss Weight
10597730bbbSRuss WeightFirmware Upload Error Codes
10697730bbbSRuss Weight---------------------------
10797730bbbSRuss WeightThe following error codes may be returned by the driver ops in case of
10897730bbbSRuss Weightfailure:
10997730bbbSRuss Weight
11097730bbbSRuss Weight.. kernel-doc:: include/linux/firmware.h
11197730bbbSRuss Weight   :identifiers: fw_upload_err
112536fd818SRuss Weight
113536fd818SRuss WeightSysfs Attributes
114536fd818SRuss Weight================
115536fd818SRuss Weight
116536fd818SRuss WeightIn addition to the *loading* and *data* sysfs files, there are additional
117536fd818SRuss Weightsysfs files to monitor the status of the data transfer to the target
118536fd818SRuss Weightdevice and to determine the final pass/fail status of the transfer.
119536fd818SRuss WeightDepending on the device and the size of the firmware image, a firmware
120536fd818SRuss Weightupdate could take milliseconds or minutes.
121536fd818SRuss Weight
122536fd818SRuss WeightThe additional sysfs files are:
123536fd818SRuss Weight
124536fd818SRuss Weight* status - provides an indication of the progress of a firmware update
125536fd818SRuss Weight* error - provides error information for a failed firmware update
126536fd818SRuss Weight* remaining_size - tracks the data transfer portion of an update
127536fd818SRuss Weight* cancel - echo 1 to this file to cancel the update
128