127 lines
4.2 KiB
ReStructuredText
127 lines
4.2 KiB
ReStructuredText
.. 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(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
|