| .. SPDX-License-Identifier: GPL-2.0 | |
| =================== | |
| Firmware Upload API | |
| =================== | |
| A device driver that registers with the firmware loader will expose | |
| persistent sysfs nodes to enable users to initiate firmware updates for | |
| that device. It is the responsibility of the device driver and/or the | |
| device itself to perform any validation on the data received. Firmware | |
| upload uses the same *loading* and *data* sysfs files described in the | |
| documentation for firmware fallback. It also adds additional sysfs files | |
| to provide status on the transfer of the firmware image to the device. | |
| Register for firmware upload | |
| ============================ | |
| A device driver registers for firmware upload by calling | |
| firmware_upload_register(). Among the parameter list is a name to | |
| identify the device under /sys/class/firmware. A user may initiate a | |
| firmware upload by echoing a 1 to the *loading* sysfs file for the target | |
| device. Next, the user writes the firmware image to the *data* sysfs | |
| file. After writing the firmware data, the user echos 0 to the *loading* | |
| sysfs file to signal completion. Echoing 0 to *loading* also triggers the | |
| transfer of the firmware to the lower-lever device driver in the context | |
| of a kernel worker thread. | |
| To use the firmware upload API, write a driver that implements a set of | |
| ops. The probe function calls firmware_upload_register() and the remove | |
| function calls firmware_upload_unregister() such as:: | |
| static const struct fw_upload_ops m10bmc_ops = { | |
| .prepare = m10bmc_sec_prepare, | |
| .write = m10bmc_sec_write, | |
| .poll_complete = m10bmc_sec_poll_complete, | |
| .cancel = m10bmc_sec_cancel, | |
| .cleanup = m10bmc_sec_cleanup, | |
| }; | |
| static int m10bmc_sec_probe(struct platform_device *pdev) | |
| { | |
| const char *fw_name, *truncate; | |
| struct m10bmc_sec *sec; | |
| struct fw_upload *fwl; | |
| unsigned int len; | |
| sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL); | |
| if (!sec) | |
| return -ENOMEM; | |
| sec->dev = &pdev->dev; | |
| sec->m10bmc = dev_get_drvdata(pdev->dev.parent); | |
| dev_set_drvdata(&pdev->dev, sec); | |
| fw_name = dev_name(sec->dev); | |
| truncate = strstr(fw_name, ".auto"); | |
| len = (truncate) ? truncate - fw_name : strlen(fw_name); | |
| sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL); | |
| fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name, | |
| &m10bmc_ops, sec); | |
| if (IS_ERR(fwl)) { | |
| dev_err(sec->dev, "Firmware Upload driver failed to start\n"); | |
| kfree(sec->fw_name); | |
| return PTR_ERR(fwl); | |
| } | |
| sec->fwl = fwl; | |
| return 0; | |
| } | |
| static int m10bmc_sec_remove(struct platform_device *pdev) | |
| { | |
| struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev); | |
| firmware_upload_unregister(sec->fwl); | |
| kfree(sec->fw_name); | |
| return 0; | |
| } | |
| firmware_upload_register | |
| ------------------------ | |
| .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c | |
| :identifiers: firmware_upload_register | |
| firmware_upload_unregister | |
| -------------------------- | |
| .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c | |
| :identifiers: firmware_upload_unregister | |
| Firmware Upload Ops | |
| ------------------- | |
| .. kernel-doc:: include/linux/firmware.h | |
| :identifiers: fw_upload_ops | |
| Firmware Upload Progress Codes | |
| ------------------------------ | |
| The following progress codes are used internally by the firmware loader. | |
| Corresponding strings are reported through the status sysfs node that | |
| is described below and are documented in the ABI documentation. | |
| .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.h | |
| :identifiers: fw_upload_prog | |
| Firmware Upload Error Codes | |
| --------------------------- | |
| The following error codes may be returned by the driver ops in case of | |
| failure: | |
| .. kernel-doc:: include/linux/firmware.h | |
| :identifiers: fw_upload_err | |
| Sysfs Attributes | |
| ================ | |
| In addition to the *loading* and *data* sysfs files, there are additional | |
| sysfs files to monitor the status of the data transfer to the target | |
| device and to determine the final pass/fail status of the transfer. | |
| Depending on the device and the size of the firmware image, a firmware | |
| update could take milliseconds or minutes. | |
| The additional sysfs files are: | |
| * status - provides an indication of the progress of a firmware update | |
| * error - provides error information for a failed firmware update | |
| * remaining_size - tracks the data transfer portion of an update | |
| * cancel - echo 1 to this file to cancel the update |