1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
|