Skip to content

Commit 12b0591

Browse files
committed
dpll: zl3073x: Implement devlink flash callback
JIRA: https://issues.redhat.com/browse/RHEL-115367 commit a1e891f Author: Ivan Vecera <ivecera@redhat.com> Date: Tue Sep 9 11:15:32 2025 +0200 dpll: zl3073x: Implement devlink flash callback Use the introduced functionality to read firmware files and flash their contents into the device's internal flash memory to implement the devlink flash update callback. Sample output on EDS2 development board: # devlink -j dev info i2c/1-0070 | jq '.[][]["versions"]["running"]' { "fw": "6026" } # devlink dev flash i2c/1-0070 file firmware_fw2.hex [utility] Prepare flash mode [utility] Downloading image 100% [utility] Flash mode enabled [firmware1-part1] Downloading image 100% [firmware1-part1] Flashing image [firmware1-part2] Downloading image 100% [firmware1-part2] Flashing image [firmware1] Flashing done [firmware2] Downloading image 100% [firmware2] Flashing image 100% [firmware2] Flashing done [utility] Leaving flash mode Flashing done # devlink -j dev info i2c/1-0070 | jq '.[][]["versions"]["running"]' { "fw": "7006" } Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Link: https://patch.msgid.link/20250909091532.11790-6-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent 3f0457e commit 12b0591

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

Documentation/networking/devlink/zl3073x.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,17 @@ The ``zl3073x`` driver reports the following versions
4949
- running
5050
- 1.3.0.1
5151
- Device configuration version customized by OEM
52+
53+
Flash Update
54+
============
55+
56+
The ``zl3073x`` driver implements support for flash update using the
57+
``devlink-flash`` interface. It supports updating the device flash using a
58+
combined flash image ("bundle") that contains multiple components (firmware
59+
parts and configurations).
60+
61+
During the flash procedure, the standard firmware interface is not available,
62+
so the driver unregisters all DPLLs and associated pins, and re-registers them
63+
once the flash procedure is complete.
64+
65+
The driver does not support any overwrite mask flags.

drivers/dpll/zl3073x/devlink.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "core.h"
1010
#include "devlink.h"
1111
#include "dpll.h"
12+
#include "flash.h"
13+
#include "fw.h"
1214
#include "regs.h"
1315

1416
/**
@@ -141,11 +143,138 @@ void zl3073x_devlink_flash_notify(struct zl3073x_dev *zldev, const char *msg,
141143
total);
142144
}
143145

146+
/**
147+
* zl3073x_devlink_flash_prepare - Prepare and enter flash mode
148+
* @zldev: zl3073x device pointer
149+
* @zlfw: pointer to loaded firmware
150+
* @extack: netlink extack pointer to report errors
151+
*
152+
* The function stops normal operation and switches the device to flash mode.
153+
* If an error occurs the normal operation is resumed.
154+
*
155+
* Return: 0 on success, <0 on error
156+
*/
157+
static int
158+
zl3073x_devlink_flash_prepare(struct zl3073x_dev *zldev,
159+
struct zl3073x_fw *zlfw,
160+
struct netlink_ext_ack *extack)
161+
{
162+
struct zl3073x_fw_component *util;
163+
int rc;
164+
165+
util = zlfw->component[ZL_FW_COMPONENT_UTIL];
166+
if (!util) {
167+
zl3073x_devlink_flash_notify(zldev,
168+
"Utility is missing in firmware",
169+
NULL, 0, 0);
170+
zl3073x_fw_free(zlfw);
171+
return -ENOEXEC;
172+
}
173+
174+
/* Stop normal operation prior entering flash mode */
175+
zl3073x_dev_stop(zldev);
176+
177+
rc = zl3073x_flash_mode_enter(zldev, util->data, util->size, extack);
178+
if (rc) {
179+
zl3073x_devlink_flash_notify(zldev,
180+
"Failed to enter flash mode",
181+
NULL, 0, 0);
182+
183+
/* Resume normal operation */
184+
zl3073x_dev_start(zldev, true);
185+
186+
return rc;
187+
}
188+
189+
return 0;
190+
}
191+
192+
/**
193+
* zl3073x_devlink_flash_finish - Leave flash mode and resume normal operation
194+
* @zldev: zl3073x device pointer
195+
* @extack: netlink extack pointer to report errors
196+
*
197+
* The function switches the device back to standard mode and resumes normal
198+
* operation.
199+
*
200+
* Return: 0 on success, <0 on error
201+
*/
202+
static int
203+
zl3073x_devlink_flash_finish(struct zl3073x_dev *zldev,
204+
struct netlink_ext_ack *extack)
205+
{
206+
int rc;
207+
208+
/* Reset device CPU to normal mode */
209+
zl3073x_flash_mode_leave(zldev, extack);
210+
211+
/* Resume normal operation */
212+
rc = zl3073x_dev_start(zldev, true);
213+
if (rc)
214+
zl3073x_devlink_flash_notify(zldev,
215+
"Failed to start normal operation",
216+
NULL, 0, 0);
217+
218+
return rc;
219+
}
220+
221+
/**
222+
* zl3073x_devlink_flash_update - Devlink flash update callback
223+
* @devlink: devlink structure pointer
224+
* @params: flashing parameters pointer
225+
* @extack: netlink extack pointer to report errors
226+
*
227+
* Return: 0 on success, <0 on error
228+
*/
229+
static int
230+
zl3073x_devlink_flash_update(struct devlink *devlink,
231+
struct devlink_flash_update_params *params,
232+
struct netlink_ext_ack *extack)
233+
{
234+
struct zl3073x_dev *zldev = devlink_priv(devlink);
235+
struct zl3073x_fw *zlfw;
236+
int rc = 0;
237+
238+
zlfw = zl3073x_fw_load(zldev, params->fw->data, params->fw->size,
239+
extack);
240+
if (IS_ERR(zlfw)) {
241+
zl3073x_devlink_flash_notify(zldev, "Failed to load firmware",
242+
NULL, 0, 0);
243+
rc = PTR_ERR(zlfw);
244+
goto finish;
245+
}
246+
247+
/* Stop normal operation and enter flash mode */
248+
rc = zl3073x_devlink_flash_prepare(zldev, zlfw, extack);
249+
if (rc)
250+
goto finish;
251+
252+
rc = zl3073x_fw_flash(zldev, zlfw, extack);
253+
if (rc) {
254+
zl3073x_devlink_flash_finish(zldev, extack);
255+
goto finish;
256+
}
257+
258+
/* Resume normal mode */
259+
rc = zl3073x_devlink_flash_finish(zldev, extack);
260+
261+
finish:
262+
if (!IS_ERR(zlfw))
263+
zl3073x_fw_free(zlfw);
264+
265+
zl3073x_devlink_flash_notify(zldev,
266+
rc ? "Flashing failed" : "Flashing done",
267+
NULL, 0, 0);
268+
269+
return rc;
270+
}
271+
144272
static const struct devlink_ops zl3073x_devlink_ops = {
145273
.info_get = zl3073x_devlink_info_get,
146274
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
147275
.reload_down = zl3073x_devlink_reload_down,
148276
.reload_up = zl3073x_devlink_reload_up,
277+
.flash_update = zl3073x_devlink_flash_update,
149278
};
150279

151280
static void

0 commit comments

Comments
 (0)