xref: /openbmc/linux/Documentation/driver-api/firmware/fw_upload.rst (revision 97730bbb242cde22b7140acd202ffd88823886c9)
1*97730bbbSRuss Weight.. SPDX-License-Identifier: GPL-2.0
2*97730bbbSRuss Weight
3*97730bbbSRuss Weight===================
4*97730bbbSRuss WeightFirmware Upload API
5*97730bbbSRuss Weight===================
6*97730bbbSRuss Weight
7*97730bbbSRuss WeightA device driver that registers with the firmware loader will expose
8*97730bbbSRuss Weightpersistent sysfs nodes to enable users to initiate firmware updates for
9*97730bbbSRuss Weightthat device.  It is the responsibility of the device driver and/or the
10*97730bbbSRuss Weightdevice itself to perform any validation on the data received. Firmware
11*97730bbbSRuss Weightupload uses the same *loading* and *data* sysfs files described in the
12*97730bbbSRuss Weightdocumentation for firmware fallback.
13*97730bbbSRuss Weight
14*97730bbbSRuss WeightRegister for firmware upload
15*97730bbbSRuss Weight============================
16*97730bbbSRuss Weight
17*97730bbbSRuss WeightA device driver registers for firmware upload by calling
18*97730bbbSRuss Weightfirmware_upload_register(). Among the parameter list is a name to
19*97730bbbSRuss Weightidentify the device under /sys/class/firmware. A user may initiate a
20*97730bbbSRuss Weightfirmware upload by echoing a 1 to the *loading* sysfs file for the target
21*97730bbbSRuss Weightdevice. Next, the user writes the firmware image to the *data* sysfs
22*97730bbbSRuss Weightfile. After writing the firmware data, the user echos 0 to the *loading*
23*97730bbbSRuss Weightsysfs file to signal completion. Echoing 0 to *loading* also triggers the
24*97730bbbSRuss Weighttransfer of the firmware to the lower-lever device driver in the context
25*97730bbbSRuss Weightof a kernel worker thread.
26*97730bbbSRuss Weight
27*97730bbbSRuss WeightTo use the firmware upload API, write a driver that implements a set of
28*97730bbbSRuss Weightops.  The probe function calls firmware_upload_register() and the remove
29*97730bbbSRuss Weightfunction calls firmware_upload_unregister() such as::
30*97730bbbSRuss Weight
31*97730bbbSRuss Weight	static const struct fw_upload_ops m10bmc_ops = {
32*97730bbbSRuss Weight		.prepare = m10bmc_sec_prepare,
33*97730bbbSRuss Weight		.write = m10bmc_sec_write,
34*97730bbbSRuss Weight		.poll_complete = m10bmc_sec_poll_complete,
35*97730bbbSRuss Weight		.cancel = m10bmc_sec_cancel,
36*97730bbbSRuss Weight		.cleanup = m10bmc_sec_cleanup,
37*97730bbbSRuss Weight	};
38*97730bbbSRuss Weight
39*97730bbbSRuss Weight	static int m10bmc_sec_probe(struct platform_device *pdev)
40*97730bbbSRuss Weight	{
41*97730bbbSRuss Weight		const char *fw_name, *truncate;
42*97730bbbSRuss Weight		struct m10bmc_sec *sec;
43*97730bbbSRuss Weight		struct fw_upload *fwl;
44*97730bbbSRuss Weight		unsigned int len;
45*97730bbbSRuss Weight
46*97730bbbSRuss Weight		sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
47*97730bbbSRuss Weight		if (!sec)
48*97730bbbSRuss Weight			return -ENOMEM;
49*97730bbbSRuss Weight
50*97730bbbSRuss Weight		sec->dev = &pdev->dev;
51*97730bbbSRuss Weight		sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
52*97730bbbSRuss Weight		dev_set_drvdata(&pdev->dev, sec);
53*97730bbbSRuss Weight
54*97730bbbSRuss Weight		fw_name = dev_name(sec->dev);
55*97730bbbSRuss Weight		truncate = strstr(fw_name, ".auto");
56*97730bbbSRuss Weight		len = (truncate) ? truncate - fw_name : strlen(fw_name);
57*97730bbbSRuss Weight		sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL);
58*97730bbbSRuss Weight
59*97730bbbSRuss Weight		fwl = firmware_upload_register(sec->dev, sec->fw_name, &m10bmc_ops, sec);
60*97730bbbSRuss Weight		if (IS_ERR(fwl)) {
61*97730bbbSRuss Weight			dev_err(sec->dev, "Firmware Upload driver failed to start\n");
62*97730bbbSRuss Weight			kfree(sec->fw_name);
63*97730bbbSRuss Weight			return PTR_ERR(fwl);
64*97730bbbSRuss Weight		}
65*97730bbbSRuss Weight
66*97730bbbSRuss Weight		sec->fwl = fwl;
67*97730bbbSRuss Weight		return 0;
68*97730bbbSRuss Weight	}
69*97730bbbSRuss Weight
70*97730bbbSRuss Weight	static int m10bmc_sec_remove(struct platform_device *pdev)
71*97730bbbSRuss Weight	{
72*97730bbbSRuss Weight		struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
73*97730bbbSRuss Weight
74*97730bbbSRuss Weight		firmware_upload_unregister(sec->fwl);
75*97730bbbSRuss Weight		kfree(sec->fw_name);
76*97730bbbSRuss Weight		return 0;
77*97730bbbSRuss Weight	}
78*97730bbbSRuss Weight
79*97730bbbSRuss Weightfirmware_upload_register
80*97730bbbSRuss Weight------------------------
81*97730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c
82*97730bbbSRuss Weight   :identifiers: firmware_upload_register
83*97730bbbSRuss Weight
84*97730bbbSRuss Weightfirmware_upload_unregister
85*97730bbbSRuss Weight--------------------------
86*97730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c
87*97730bbbSRuss Weight   :identifiers: firmware_upload_unregister
88*97730bbbSRuss Weight
89*97730bbbSRuss WeightFirmware Upload Ops
90*97730bbbSRuss Weight-------------------
91*97730bbbSRuss Weight.. kernel-doc:: include/linux/firmware.h
92*97730bbbSRuss Weight   :identifiers: fw_upload_ops
93*97730bbbSRuss Weight
94*97730bbbSRuss WeightFirmware Upload Progress Codes
95*97730bbbSRuss Weight------------------------------
96*97730bbbSRuss WeightThe following progress codes are used internally by the firmware loader:
97*97730bbbSRuss Weight
98*97730bbbSRuss Weight.. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.h
99*97730bbbSRuss Weight   :identifiers: fw_upload_prog
100*97730bbbSRuss Weight
101*97730bbbSRuss WeightFirmware Upload Error Codes
102*97730bbbSRuss Weight---------------------------
103*97730bbbSRuss WeightThe following error codes may be returned by the driver ops in case of
104*97730bbbSRuss Weightfailure:
105*97730bbbSRuss Weight
106*97730bbbSRuss Weight.. kernel-doc:: include/linux/firmware.h
107*97730bbbSRuss Weight   :identifiers: fw_upload_err
108