File Index
Files and directories
Sign in
FILE

fw.c

File preview with syntax highlighting.

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