1ca017409SIvan Vecera // SPDX-License-Identifier: GPL-2.0-or-later
2ca017409SIvan Vecera
3ca017409SIvan Vecera #include <linux/array_size.h>
4ca017409SIvan Vecera #include <linux/build_bug.h>
5ca017409SIvan Vecera #include <linux/dev_printk.h>
6ca017409SIvan Vecera #include <linux/err.h>
7ca017409SIvan Vecera #include <linux/errno.h>
8ca017409SIvan Vecera #include <linux/netlink.h>
9ca017409SIvan Vecera #include <linux/slab.h>
10ca017409SIvan Vecera #include <linux/string.h>
11ca017409SIvan Vecera
12ca017409SIvan Vecera #include "core.h"
13ca017409SIvan Vecera #include "flash.h"
14ca017409SIvan Vecera #include "fw.h"
15ca017409SIvan Vecera
16ca017409SIvan Vecera #define ZL3073X_FW_ERR_PFX "FW load failed: "
17ca017409SIvan Vecera #define ZL3073X_FW_ERR_MSG(_extack, _msg, ...) \
18ca017409SIvan Vecera NL_SET_ERR_MSG_FMT_MOD((_extack), ZL3073X_FW_ERR_PFX _msg, \
19ca017409SIvan Vecera ## __VA_ARGS__)
20ca017409SIvan Vecera
21ca017409SIvan Vecera enum zl3073x_flash_type {
22ca017409SIvan Vecera ZL3073X_FLASH_TYPE_NONE = 0,
23ca017409SIvan Vecera ZL3073X_FLASH_TYPE_SECTORS,
24ca017409SIvan Vecera ZL3073X_FLASH_TYPE_PAGE,
25ca017409SIvan Vecera ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
26ca017409SIvan Vecera };
27ca017409SIvan Vecera
28ca017409SIvan Vecera struct zl3073x_fw_component_info {
29ca017409SIvan Vecera const char *name;
30ca017409SIvan Vecera size_t max_size;
31ca017409SIvan Vecera enum zl3073x_flash_type flash_type;
32ca017409SIvan Vecera u32 load_addr;
33ca017409SIvan Vecera u32 dest_page;
34ca017409SIvan Vecera u32 copy_page;
35ca017409SIvan Vecera };
36ca017409SIvan Vecera
37ca017409SIvan Vecera static const struct zl3073x_fw_component_info component_info[] = {
38ca017409SIvan Vecera [ZL_FW_COMPONENT_UTIL] = {
39ca017409SIvan Vecera .name = "utility",
40*f3426ac5SIvan Vecera .max_size = 0x4000,
41ca017409SIvan Vecera .load_addr = 0x20000000,
42ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_NONE,
43ca017409SIvan Vecera },
44ca017409SIvan Vecera [ZL_FW_COMPONENT_FW1] = {
45ca017409SIvan Vecera .name = "firmware1",
46ca017409SIvan Vecera .max_size = 0x35000,
47ca017409SIvan Vecera .load_addr = 0x20002000,
48ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_SECTORS,
49ca017409SIvan Vecera .dest_page = 0x020,
50ca017409SIvan Vecera },
51ca017409SIvan Vecera [ZL_FW_COMPONENT_FW2] = {
52ca017409SIvan Vecera .name = "firmware2",
53ca017409SIvan Vecera .max_size = 0x0040,
54ca017409SIvan Vecera .load_addr = 0x20000000,
55ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
56ca017409SIvan Vecera .dest_page = 0x3e0,
57ca017409SIvan Vecera .copy_page = 0x000,
58ca017409SIvan Vecera },
59ca017409SIvan Vecera [ZL_FW_COMPONENT_FW3] = {
60ca017409SIvan Vecera .name = "firmware3",
61ca017409SIvan Vecera .max_size = 0x0248,
62ca017409SIvan Vecera .load_addr = 0x20000400,
63ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
64ca017409SIvan Vecera .dest_page = 0x3e4,
65ca017409SIvan Vecera .copy_page = 0x004,
66ca017409SIvan Vecera },
67ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG0] = {
68ca017409SIvan Vecera .name = "config0",
69ca017409SIvan Vecera .max_size = 0x1000,
70ca017409SIvan Vecera .load_addr = 0x20000000,
71ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
72ca017409SIvan Vecera .dest_page = 0x3d0,
73ca017409SIvan Vecera },
74ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG1] = {
75ca017409SIvan Vecera .name = "config1",
76ca017409SIvan Vecera .max_size = 0x1000,
77ca017409SIvan Vecera .load_addr = 0x20000000,
78ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
79ca017409SIvan Vecera .dest_page = 0x3c0,
80ca017409SIvan Vecera },
81ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG2] = {
82ca017409SIvan Vecera .name = "config2",
83ca017409SIvan Vecera .max_size = 0x1000,
84ca017409SIvan Vecera .load_addr = 0x20000000,
85ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
86ca017409SIvan Vecera .dest_page = 0x3b0,
87ca017409SIvan Vecera },
88ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG3] = {
89ca017409SIvan Vecera .name = "config3",
90ca017409SIvan Vecera .max_size = 0x1000,
91ca017409SIvan Vecera .load_addr = 0x20000000,
92ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
93ca017409SIvan Vecera .dest_page = 0x3a0,
94ca017409SIvan Vecera },
95ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG4] = {
96ca017409SIvan Vecera .name = "config4",
97ca017409SIvan Vecera .max_size = 0x1000,
98ca017409SIvan Vecera .load_addr = 0x20000000,
99ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
100ca017409SIvan Vecera .dest_page = 0x390,
101ca017409SIvan Vecera },
102ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG5] = {
103ca017409SIvan Vecera .name = "config5",
104ca017409SIvan Vecera .max_size = 0x1000,
105ca017409SIvan Vecera .load_addr = 0x20000000,
106ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
107ca017409SIvan Vecera .dest_page = 0x380,
108ca017409SIvan Vecera },
109ca017409SIvan Vecera [ZL_FW_COMPONENT_CFG6] = {
110ca017409SIvan Vecera .name = "config6",
111ca017409SIvan Vecera .max_size = 0x1000,
112ca017409SIvan Vecera .load_addr = 0x20000000,
113ca017409SIvan Vecera .flash_type = ZL3073X_FLASH_TYPE_PAGE,
114ca017409SIvan Vecera .dest_page = 0x370,
115ca017409SIvan Vecera },
116ca017409SIvan Vecera };
117ca017409SIvan Vecera
118ca017409SIvan Vecera /* Sanity check */
119ca017409SIvan Vecera static_assert(ARRAY_SIZE(component_info) == ZL_FW_NUM_COMPONENTS);
120ca017409SIvan Vecera
121ca017409SIvan Vecera /**
122ca017409SIvan Vecera * zl3073x_fw_component_alloc - Alloc structure to hold firmware component
123ca017409SIvan Vecera * @size: size of buffer to store data
124ca017409SIvan Vecera *
125ca017409SIvan Vecera * Return: pointer to allocated component structure or NULL on error.
126ca017409SIvan Vecera */
127ca017409SIvan Vecera static struct zl3073x_fw_component *
zl3073x_fw_component_alloc(size_t size)128ca017409SIvan Vecera zl3073x_fw_component_alloc(size_t size)
129ca017409SIvan Vecera {
130ca017409SIvan Vecera struct zl3073x_fw_component *comp;
131ca017409SIvan Vecera
132ca017409SIvan Vecera comp = kzalloc(sizeof(*comp), GFP_KERNEL);
133ca017409SIvan Vecera if (!comp)
134ca017409SIvan Vecera return NULL;
135ca017409SIvan Vecera
136ca017409SIvan Vecera comp->size = size;
137ca017409SIvan Vecera comp->data = kzalloc(size, GFP_KERNEL);
138ca017409SIvan Vecera if (!comp->data) {
139ca017409SIvan Vecera kfree(comp);
140ca017409SIvan Vecera return NULL;
141ca017409SIvan Vecera }
142ca017409SIvan Vecera
143ca017409SIvan Vecera return comp;
144ca017409SIvan Vecera }
145ca017409SIvan Vecera
146ca017409SIvan Vecera /**
147ca017409SIvan Vecera * zl3073x_fw_component_free - Free allocated component structure
148ca017409SIvan Vecera * @comp: pointer to allocated component
149ca017409SIvan Vecera */
150ca017409SIvan Vecera static void
zl3073x_fw_component_free(struct zl3073x_fw_component * comp)151ca017409SIvan Vecera zl3073x_fw_component_free(struct zl3073x_fw_component *comp)
152ca017409SIvan Vecera {
153ca017409SIvan Vecera if (comp)
154ca017409SIvan Vecera kfree(comp->data);
155ca017409SIvan Vecera
156ca017409SIvan Vecera kfree(comp);
157ca017409SIvan Vecera }
158ca017409SIvan Vecera
159ca017409SIvan Vecera /**
160ca017409SIvan Vecera * zl3073x_fw_component_id_get - Get ID for firmware component name
161ca017409SIvan Vecera * @name: input firmware component name
162ca017409SIvan Vecera *
163ca017409SIvan Vecera * Return:
164ca017409SIvan Vecera * - ZL3073X_FW_COMPONENT_* ID for known component name
165ca017409SIvan Vecera * - ZL3073X_FW_COMPONENT_INVALID if the given name is unknown
166ca017409SIvan Vecera */
167ca017409SIvan Vecera static enum zl3073x_fw_component_id
zl3073x_fw_component_id_get(const char * name)168ca017409SIvan Vecera zl3073x_fw_component_id_get(const char *name)
169ca017409SIvan Vecera {
170ca017409SIvan Vecera enum zl3073x_fw_component_id id;
171ca017409SIvan Vecera
172ca017409SIvan Vecera for (id = 0; id < ZL_FW_NUM_COMPONENTS; id++)
173ca017409SIvan Vecera if (!strcasecmp(name, component_info[id].name))
174ca017409SIvan Vecera return id;
175ca017409SIvan Vecera
176ca017409SIvan Vecera return ZL_FW_COMPONENT_INVALID;
177ca017409SIvan Vecera }
178ca017409SIvan Vecera
179ca017409SIvan Vecera /**
180ca017409SIvan Vecera * zl3073x_fw_component_load - Load component from firmware source
181ca017409SIvan Vecera * @zldev: zl3073x device structure
182ca017409SIvan Vecera * @pcomp: pointer to loaded component
183ca017409SIvan Vecera * @psrc: data pointer to load component from
184ca017409SIvan Vecera * @psize: remaining bytes in buffer
185ca017409SIvan Vecera * @extack: netlink extack pointer to report errors
186ca017409SIvan Vecera *
187ca017409SIvan Vecera * The function allocates single firmware component and loads the data from
188ca017409SIvan Vecera * the buffer specified by @psrc and @psize. Pointer to allocated component
189ca017409SIvan Vecera * is stored in output @pcomp. Source data pointer @psrc and remaining bytes
190ca017409SIvan Vecera * @psize are updated accordingly.
191ca017409SIvan Vecera *
192ca017409SIvan Vecera * Return:
193ca017409SIvan Vecera * * 1 when component was allocated and loaded
194ca017409SIvan Vecera * * 0 when there is no component to load
195ca017409SIvan Vecera * * <0 on error
196ca017409SIvan Vecera */
197ca017409SIvan Vecera static ssize_t
zl3073x_fw_component_load(struct zl3073x_dev * zldev,struct zl3073x_fw_component ** pcomp,const char ** psrc,size_t * psize,struct netlink_ext_ack * extack)198ca017409SIvan Vecera zl3073x_fw_component_load(struct zl3073x_dev *zldev,
199ca017409SIvan Vecera struct zl3073x_fw_component **pcomp,
200ca017409SIvan Vecera const char **psrc, size_t *psize,
201ca017409SIvan Vecera struct netlink_ext_ack *extack)
202ca017409SIvan Vecera {
203ca017409SIvan Vecera const struct zl3073x_fw_component_info *info;
204ca017409SIvan Vecera struct zl3073x_fw_component *comp = NULL;
205ca017409SIvan Vecera struct device *dev = zldev->dev;
206ca017409SIvan Vecera enum zl3073x_fw_component_id id;
207ca017409SIvan Vecera char buf[32], name[16];
208ca017409SIvan Vecera u32 count, size, *dest;
209ca017409SIvan Vecera int pos, rc;
210ca017409SIvan Vecera
211ca017409SIvan Vecera /* Fetch image name and size from input */
212ca017409SIvan Vecera strscpy(buf, *psrc, min(sizeof(buf), *psize));
213ca017409SIvan Vecera rc = sscanf(buf, "%15s %u %n", name, &count, &pos);
214ca017409SIvan Vecera if (!rc) {
215ca017409SIvan Vecera /* No more data */
216ca017409SIvan Vecera return 0;
217ca017409SIvan Vecera } else if (rc == 1 || count > U32_MAX / sizeof(u32)) {
218ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack, "invalid component size");
219ca017409SIvan Vecera return -EINVAL;
220ca017409SIvan Vecera }
221ca017409SIvan Vecera *psrc += pos;
222ca017409SIvan Vecera *psize -= pos;
223ca017409SIvan Vecera
224ca017409SIvan Vecera dev_dbg(dev, "Firmware component '%s' found\n", name);
225ca017409SIvan Vecera
226ca017409SIvan Vecera id = zl3073x_fw_component_id_get(name);
227ca017409SIvan Vecera if (id == ZL_FW_COMPONENT_INVALID) {
228ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack, "unknown component type '%s'", name);
229ca017409SIvan Vecera return -EINVAL;
230ca017409SIvan Vecera }
231ca017409SIvan Vecera
232ca017409SIvan Vecera info = &component_info[id];
233ca017409SIvan Vecera size = count * sizeof(u32); /* get size in bytes */
234ca017409SIvan Vecera
235ca017409SIvan Vecera /* Check image size validity */
236ca017409SIvan Vecera if (size > component_info[id].max_size) {
237ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack,
238ca017409SIvan Vecera "[%s] component is too big (%u bytes)\n",
239ca017409SIvan Vecera info->name, size);
240ca017409SIvan Vecera return -EINVAL;
241ca017409SIvan Vecera }
242ca017409SIvan Vecera
243ca017409SIvan Vecera dev_dbg(dev, "Indicated component image size: %u bytes\n", size);
244ca017409SIvan Vecera
245ca017409SIvan Vecera /* Alloc component */
246ca017409SIvan Vecera comp = zl3073x_fw_component_alloc(size);
247ca017409SIvan Vecera if (!comp) {
248ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack, "failed to alloc memory");
249ca017409SIvan Vecera return -ENOMEM;
250ca017409SIvan Vecera }
251ca017409SIvan Vecera comp->id = id;
252ca017409SIvan Vecera
253ca017409SIvan Vecera /* Load component data from firmware source */
254ca017409SIvan Vecera for (dest = comp->data; count; count--, dest++) {
255ca017409SIvan Vecera strscpy(buf, *psrc, min(sizeof(buf), *psize));
256ca017409SIvan Vecera rc = sscanf(buf, "%x %n", dest, &pos);
257ca017409SIvan Vecera if (!rc)
258ca017409SIvan Vecera goto err_data;
259ca017409SIvan Vecera
260ca017409SIvan Vecera *psrc += pos;
261ca017409SIvan Vecera *psize -= pos;
262ca017409SIvan Vecera }
263ca017409SIvan Vecera
264ca017409SIvan Vecera *pcomp = comp;
265ca017409SIvan Vecera
266ca017409SIvan Vecera return 1;
267ca017409SIvan Vecera
268ca017409SIvan Vecera err_data:
269ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack, "[%s] invalid or missing data", info->name);
270ca017409SIvan Vecera
271ca017409SIvan Vecera zl3073x_fw_component_free(comp);
272ca017409SIvan Vecera
273ca017409SIvan Vecera return -ENODATA;
274ca017409SIvan Vecera }
275ca017409SIvan Vecera
276ca017409SIvan Vecera /**
277ca017409SIvan Vecera * zl3073x_fw_free - Free allocated firmware
278ca017409SIvan Vecera * @fw: firmware pointer
279ca017409SIvan Vecera *
280ca017409SIvan Vecera * The function frees existing firmware allocated by @zl3073x_fw_load.
281ca017409SIvan Vecera */
zl3073x_fw_free(struct zl3073x_fw * fw)282ca017409SIvan Vecera void zl3073x_fw_free(struct zl3073x_fw *fw)
283ca017409SIvan Vecera {
284ca017409SIvan Vecera size_t i;
285ca017409SIvan Vecera
286ca017409SIvan Vecera if (!fw)
287ca017409SIvan Vecera return;
288ca017409SIvan Vecera
289ca017409SIvan Vecera for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++)
290ca017409SIvan Vecera zl3073x_fw_component_free(fw->component[i]);
291ca017409SIvan Vecera
292ca017409SIvan Vecera kfree(fw);
293ca017409SIvan Vecera }
294ca017409SIvan Vecera
295ca017409SIvan Vecera /**
296ca017409SIvan Vecera * zl3073x_fw_load - Load all components from source
297ca017409SIvan Vecera * @zldev: zl3073x device structure
298ca017409SIvan Vecera * @data: source buffer pointer
299ca017409SIvan Vecera * @size: size of source buffer
300ca017409SIvan Vecera * @extack: netlink extack pointer to report errors
301ca017409SIvan Vecera *
302ca017409SIvan Vecera * The functions allocate firmware structure and loads all components from
303ca017409SIvan Vecera * the given buffer specified by @data and @size.
304ca017409SIvan Vecera *
305ca017409SIvan Vecera * Return: pointer to firmware on success, error pointer on error
306ca017409SIvan Vecera */
zl3073x_fw_load(struct zl3073x_dev * zldev,const char * data,size_t size,struct netlink_ext_ack * extack)307ca017409SIvan Vecera struct zl3073x_fw *zl3073x_fw_load(struct zl3073x_dev *zldev, const char *data,
308ca017409SIvan Vecera size_t size, struct netlink_ext_ack *extack)
309ca017409SIvan Vecera {
310ca017409SIvan Vecera struct zl3073x_fw_component *comp;
311ca017409SIvan Vecera enum zl3073x_fw_component_id id;
312ca017409SIvan Vecera struct zl3073x_fw *fw;
313ca017409SIvan Vecera ssize_t rc;
314ca017409SIvan Vecera
315ca017409SIvan Vecera /* Allocate firmware structure */
316ca017409SIvan Vecera fw = kzalloc(sizeof(*fw), GFP_KERNEL);
317ca017409SIvan Vecera if (!fw)
318ca017409SIvan Vecera return ERR_PTR(-ENOMEM);
319ca017409SIvan Vecera
320ca017409SIvan Vecera do {
321ca017409SIvan Vecera /* Load single component */
322ca017409SIvan Vecera rc = zl3073x_fw_component_load(zldev, &comp, &data, &size,
323ca017409SIvan Vecera extack);
324ca017409SIvan Vecera if (rc <= 0)
325ca017409SIvan Vecera /* Everything was read or error occurred */
326ca017409SIvan Vecera break;
327ca017409SIvan Vecera
328ca017409SIvan Vecera id = comp->id;
329ca017409SIvan Vecera
330ca017409SIvan Vecera /* Report error if the given component is present twice
331ca017409SIvan Vecera * or more.
332ca017409SIvan Vecera */
333ca017409SIvan Vecera if (fw->component[id]) {
334ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack,
335ca017409SIvan Vecera "duplicate component '%s' detected",
336ca017409SIvan Vecera component_info[id].name);
337ca017409SIvan Vecera zl3073x_fw_component_free(comp);
338ca017409SIvan Vecera rc = -EINVAL;
339ca017409SIvan Vecera break;
340ca017409SIvan Vecera }
341ca017409SIvan Vecera
342ca017409SIvan Vecera fw->component[id] = comp;
343ca017409SIvan Vecera } while (true);
344ca017409SIvan Vecera
345ca017409SIvan Vecera if (rc) {
346ca017409SIvan Vecera /* Free allocated firmware in case of error */
347ca017409SIvan Vecera zl3073x_fw_free(fw);
348ca017409SIvan Vecera return ERR_PTR(rc);
349ca017409SIvan Vecera }
350ca017409SIvan Vecera
351ca017409SIvan Vecera return fw;
352ca017409SIvan Vecera }
353ca017409SIvan Vecera
354ca017409SIvan Vecera /**
355ca017409SIvan Vecera * zl3073x_flash_bundle_flash - Flash all components
356ca017409SIvan Vecera * @zldev: zl3073x device structure
357ca017409SIvan Vecera * @components: pointer to components array
358ca017409SIvan Vecera * @extack: netlink extack pointer to report errors
359ca017409SIvan Vecera *
360ca017409SIvan Vecera * Returns 0 in case of success or negative number otherwise.
361ca017409SIvan Vecera */
362ca017409SIvan Vecera static int
zl3073x_fw_component_flash(struct zl3073x_dev * zldev,struct zl3073x_fw_component * comp,struct netlink_ext_ack * extack)363ca017409SIvan Vecera zl3073x_fw_component_flash(struct zl3073x_dev *zldev,
364ca017409SIvan Vecera struct zl3073x_fw_component *comp,
365ca017409SIvan Vecera struct netlink_ext_ack *extack)
366ca017409SIvan Vecera {
367ca017409SIvan Vecera const struct zl3073x_fw_component_info *info;
368ca017409SIvan Vecera int rc;
369ca017409SIvan Vecera
370ca017409SIvan Vecera info = &component_info[comp->id];
371ca017409SIvan Vecera
372ca017409SIvan Vecera switch (info->flash_type) {
373ca017409SIvan Vecera case ZL3073X_FLASH_TYPE_NONE:
374ca017409SIvan Vecera /* Non-flashable component - used for utility */
375ca017409SIvan Vecera return 0;
376ca017409SIvan Vecera case ZL3073X_FLASH_TYPE_SECTORS:
377ca017409SIvan Vecera rc = zl3073x_flash_sectors(zldev, info->name, info->dest_page,
378ca017409SIvan Vecera info->load_addr, comp->data,
379ca017409SIvan Vecera comp->size, extack);
380ca017409SIvan Vecera break;
381ca017409SIvan Vecera case ZL3073X_FLASH_TYPE_PAGE:
382ca017409SIvan Vecera rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
383ca017409SIvan Vecera info->load_addr, comp->data, comp->size,
384ca017409SIvan Vecera extack);
385ca017409SIvan Vecera break;
386ca017409SIvan Vecera case ZL3073X_FLASH_TYPE_PAGE_AND_COPY:
387ca017409SIvan Vecera rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
388ca017409SIvan Vecera info->load_addr, comp->data, comp->size,
389ca017409SIvan Vecera extack);
390ca017409SIvan Vecera if (!rc)
391ca017409SIvan Vecera rc = zl3073x_flash_page_copy(zldev, info->name,
392ca017409SIvan Vecera info->dest_page,
393ca017409SIvan Vecera info->copy_page, extack);
394ca017409SIvan Vecera break;
395ca017409SIvan Vecera }
396ca017409SIvan Vecera if (rc)
397ca017409SIvan Vecera ZL3073X_FW_ERR_MSG(extack, "Failed to flash component '%s'",
398ca017409SIvan Vecera info->name);
399ca017409SIvan Vecera
400ca017409SIvan Vecera return rc;
401ca017409SIvan Vecera }
402ca017409SIvan Vecera
zl3073x_fw_flash(struct zl3073x_dev * zldev,struct zl3073x_fw * zlfw,struct netlink_ext_ack * extack)403ca017409SIvan Vecera int zl3073x_fw_flash(struct zl3073x_dev *zldev, struct zl3073x_fw *zlfw,
404ca017409SIvan Vecera struct netlink_ext_ack *extack)
405ca017409SIvan Vecera {
406ca017409SIvan Vecera int i, rc = 0;
407ca017409SIvan Vecera
408ca017409SIvan Vecera for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++) {
409ca017409SIvan Vecera if (!zlfw->component[i])
410ca017409SIvan Vecera continue; /* Component is not present */
411ca017409SIvan Vecera
412ca017409SIvan Vecera rc = zl3073x_fw_component_flash(zldev, zlfw->component[i],
413ca017409SIvan Vecera extack);
414ca017409SIvan Vecera if (rc)
415ca017409SIvan Vecera break;
416ca017409SIvan Vecera }
417ca017409SIvan Vecera
418ca017409SIvan Vecera return rc;
419ca017409SIvan Vecera }
420