firmware_loader: Add firmware-upload support
Extend the firmware subsystem to support a persistent sysfs interface that userspace may use to initiate a firmware update. For example, FPGA based PCIe cards load firmware and FPGA images from local FLASH when the card boots. The images in FLASH may be updated with new images provided by the user at his/her convenience. A device driver may call firmware_upload_register() to expose persistent "loading" and "data" sysfs files. These files are used in the same way as the fallback sysfs "loading" and "data" files. When 0 is written to "loading" to complete the write of firmware data, the data is transferred to the lower-level driver using pre-registered call-back functions. The data transfer is done in the context of a kernel worker thread. Reviewed-by: Luis Chamberlain <mcgrof@kernel.org> Reviewed-by: Tianfei zhang <tianfei.zhang@intel.com> Tested-by: Matthew Gerlach <matthew.gerlach@linux.intel.com> Signed-off-by: Russ Weight <russell.h.weight@intel.com> Link: https://lore.kernel.org/r/20220421212204.36052-5-russell.h.weight@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e0c11a8b98
commit
97730bbb24
107
Documentation/driver-api/firmware/fw_upload.rst
Normal file
107
Documentation/driver-api/firmware/fw_upload.rst
Normal file
@@ -0,0 +1,107 @@
|
||||
.. 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.
|
||||
|
||||
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:
|
||||
|
||||
.. 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
|
||||
@@ -8,6 +8,7 @@ Linux Firmware API
|
||||
core
|
||||
efi/index
|
||||
request_firmware
|
||||
fw_upload
|
||||
other_interfaces
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Reference in New Issue
Block a user