File Index
Files and directories
Sign in
FILE

fw-download.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/greybus/fw-download.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Greybus Firmware Download Protocol Driver.
  4 *
  5 * Copyright 2016 Google Inc.
  6 * Copyright 2016 Linaro Ltd.
  7 */
  8
  9#include <linux/firmware.h>
 10#include <linux/jiffies.h>
 11#include <linux/mutex.h>
 12#include <linux/workqueue.h>
 13#include <linux/greybus.h>
 14#include "firmware.h"
 15
 16/* Estimated minimum buffer size, actual size can be smaller than this */
 17#define MIN_FETCH_SIZE		512
 18/* Timeout, in jiffies, within which fetch or release firmware must be called */
 19#define NEXT_REQ_TIMEOUT_J	msecs_to_jiffies(1000)
 20
 21struct fw_request {
 22	u8			firmware_id;
 23	bool			disabled;
 24	bool			timedout;
 25	char			name[FW_NAME_SIZE];
 26	const struct firmware	*fw;
 27	struct list_head	node;
 28
 29	struct delayed_work	dwork;
 30	/* Timeout, in jiffies, within which the firmware shall download */
 31	unsigned long		release_timeout_j;
 32	struct kref		kref;
 33	struct fw_download	*fw_download;
 34};
 35
 36struct fw_download {
 37	struct device		*parent;
 38	struct gb_connection	*connection;
 39	struct list_head	fw_requests;
 40	struct ida		id_map;
 41	struct mutex		mutex;
 42};
 43
 44static void fw_req_release(struct kref *kref)
 45{
 46	struct fw_request *fw_req = container_of(kref, struct fw_request, kref);
 47
 48	dev_dbg(fw_req->fw_download->parent, "firmware %s released\n",
 49		fw_req->name);
 50
 51	release_firmware(fw_req->fw);
 52
 53	/*
 54	 * The request timed out and the module may send a fetch-fw or
 55	 * release-fw request later. Lets block the id we allocated for this
 56	 * request, so that the AP doesn't refer to a later fw-request (with
 57	 * same firmware_id) for the old timedout fw-request.
 58	 *
 59	 * NOTE:
 60	 *
 61	 * This also means that after 255 timeouts we will fail to service new
 62	 * firmware downloads. But what else can we do in that case anyway? Lets
 63	 * just hope that it never happens.
 64	 */
 65	if (!fw_req->timedout)
 66		ida_free(&fw_req->fw_download->id_map, fw_req->firmware_id);
 67
 68	kfree(fw_req);
 69}
 70
 71/*
 72 * Incoming requests are serialized for a connection, and the only race possible
 73 * is between the timeout handler freeing this and an incoming request.
 74 *
 75 * The operations on the fw-request list are protected by the mutex and
 76 * get_fw_req() increments the reference count before returning a fw_req pointer
 77 * to the users.
 78 *
 79 * free_firmware() also takes the mutex while removing an entry from the list,
 80 * it guarantees that every user of fw_req has taken a kref-reference by now and
 81 * we wouldn't have any new users.
 82 *
 83 * Once the last user drops the reference, the fw_req structure is freed.
 84 */
 85static void put_fw_req(struct fw_request *fw_req)
 86{
 87	kref_put(&fw_req->kref, fw_req_release);
 88}
 89
 90/* Caller must call put_fw_req() after using struct fw_request */
 91static struct fw_request *get_fw_req(struct fw_download *fw_download,
 92				     u8 firmware_id)
 93{
 94	struct fw_request *fw_req;
 95
 96	mutex_lock(&fw_download->mutex);
 97
 98	list_for_each_entry(fw_req, &fw_download->fw_requests, node) {
 99		if (fw_req->firmware_id == firmware_id) {
100			kref_get(&fw_req->kref);
101			goto unlock;
102		}
103	}
104
105	fw_req = NULL;
106
107unlock:
108	mutex_unlock(&fw_download->mutex);
109
110	return fw_req;
111}
112
113static void free_firmware(struct fw_download *fw_download,
114			  struct fw_request *fw_req)
115{
116	/* Already disabled from timeout handlers */
117	if (fw_req->disabled)
118		return;
119
120	mutex_lock(&fw_download->mutex);
121	list_del(&fw_req->node);
122	mutex_unlock(&fw_download->mutex);
123
124	fw_req->disabled = true;
125	put_fw_req(fw_req);
126}
127
128static void fw_request_timedout(struct work_struct *work)
129{
130	struct delayed_work *dwork = to_delayed_work(work);
131	struct fw_request *fw_req = container_of(dwork,
132						 struct fw_request, dwork);
133	struct fw_download *fw_download = fw_req->fw_download;
134
135	dev_err(fw_download->parent,
136		"Timed out waiting for fetch / release firmware requests: %u\n",
137		fw_req->firmware_id);
138
139	fw_req->timedout = true;
140	free_firmware(fw_download, fw_req);
141}
142
143static int exceeds_release_timeout(struct fw_request *fw_req)
144{
145	struct fw_download *fw_download = fw_req->fw_download;
146
147	if (time_before(jiffies, fw_req->release_timeout_j))
148		return 0;
149
150	dev_err(fw_download->parent,
151		"Firmware download didn't finish in time, abort: %d\n",
152		fw_req->firmware_id);
153
154	fw_req->timedout = true;
155	free_firmware(fw_download, fw_req);
156
157	return -ETIMEDOUT;
158}
159
160/* This returns path of the firmware blob on the disk */
161static struct fw_request *find_firmware(struct fw_download *fw_download,
162					const char *tag)
163{
164	struct gb_interface *intf = fw_download->connection->bundle->intf;
165	struct fw_request *fw_req;
166	int ret, req_count;
167
168	fw_req = kzalloc(sizeof(*fw_req), GFP_KERNEL);
169	if (!fw_req)
170		return ERR_PTR(-ENOMEM);
171
172	/* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
173	ret = ida_alloc_range(&fw_download->id_map, 1, 255, GFP_KERNEL);
174	if (ret < 0) {
175		dev_err(fw_download->parent,
176			"failed to allocate firmware id (%d)\n", ret);
177		goto err_free_req;
178	}
179	fw_req->firmware_id = ret;
180
181	snprintf(fw_req->name, sizeof(fw_req->name),
182		 FW_NAME_PREFIX "%08x_%08x_%08x_%08x_%s.tftf",
183		 intf->ddbl1_manufacturer_id, intf->ddbl1_product_id,
184		 intf->vendor_id, intf->product_id, tag);
185
186	dev_info(fw_download->parent, "Requested firmware package '%s'\n",
187		 fw_req->name);
188
189	ret = request_firmware(&fw_req->fw, fw_req->name, fw_download->parent);
190	if (ret) {
191		dev_err(fw_download->parent,
192			"firmware request failed for %s (%d)\n", fw_req->name,
193			ret);
194		goto err_free_id;
195	}
196
197	fw_req->fw_download = fw_download;
198	kref_init(&fw_req->kref);
199
200	mutex_lock(&fw_download->mutex);
201	list_add(&fw_req->node, &fw_download->fw_requests);
202	mutex_unlock(&fw_download->mutex);
203
204	/* Timeout, in jiffies, within which firmware should get loaded */
205	req_count = DIV_ROUND_UP(fw_req->fw->size, MIN_FETCH_SIZE);
206	fw_req->release_timeout_j = jiffies + req_count * NEXT_REQ_TIMEOUT_J;
207
208	INIT_DELAYED_WORK(&fw_req->dwork, fw_request_timedout);
209	schedule_delayed_work(&fw_req->dwork, NEXT_REQ_TIMEOUT_J);
210
211	return fw_req;
212
213err_free_id:
214	ida_free(&fw_download->id_map, fw_req->firmware_id);
215err_free_req:
216	kfree(fw_req);
217
218	return ERR_PTR(ret);
219}
220
221static int fw_download_find_firmware(struct gb_operation *op)
222{
223	struct gb_connection *connection = op->connection;
224	struct fw_download *fw_download = gb_connection_get_data(connection);
225	struct gb_fw_download_find_firmware_request *request;
226	struct gb_fw_download_find_firmware_response *response;
227	struct fw_request *fw_req;
228	const char *tag;
229
230	if (op->request->payload_size != sizeof(*request)) {
231		dev_err(fw_download->parent,
232			"illegal size of find firmware request (%zu != %zu)\n",
233			op->request->payload_size, sizeof(*request));
234		return -EINVAL;
235	}
236
237	request = op->request->payload;
238	tag = (const char *)request->firmware_tag;
239
240	/* firmware_tag must be null-terminated */
241	if (strnlen(tag, GB_FIRMWARE_TAG_MAX_SIZE) ==
242	    GB_FIRMWARE_TAG_MAX_SIZE) {
243		dev_err(fw_download->parent,
244			"firmware-tag is not null-terminated\n");
245		return -EINVAL;
246	}
247
248	fw_req = find_firmware(fw_download, tag);
249	if (IS_ERR(fw_req))
250		return PTR_ERR(fw_req);
251
252	if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL)) {
253		dev_err(fw_download->parent, "error allocating response\n");
254		free_firmware(fw_download, fw_req);
255		return -ENOMEM;
256	}
257
258	response = op->response->payload;
259	response->firmware_id = fw_req->firmware_id;
260	response->size = cpu_to_le32(fw_req->fw->size);
261
262	dev_dbg(fw_download->parent,
263		"firmware size is %zu bytes\n", fw_req->fw->size);
264
265	return 0;
266}
267
268static int fw_download_fetch_firmware(struct gb_operation *op)
269{
270	struct gb_connection *connection = op->connection;
271	struct fw_download *fw_download = gb_connection_get_data(connection);
272	struct gb_fw_download_fetch_firmware_request *request;
273	struct fw_request *fw_req;
274	const struct firmware *fw;
275	unsigned int offset, size;
276	u8 firmware_id;
277	u8 *response;
278	int ret = 0;
279
280	if (op->request->payload_size != sizeof(*request)) {
281		dev_err(fw_download->parent,
282			"Illegal size of fetch firmware request (%zu %zu)\n",
283			op->request->payload_size, sizeof(*request));
284		return -EINVAL;
285	}
286
287	request = op->request->payload;
288	offset = le32_to_cpu(request->offset);
289	size = le32_to_cpu(request->size);
290	firmware_id = request->firmware_id;
291
292	fw_req = get_fw_req(fw_download, firmware_id);
293	if (!fw_req) {
294		dev_err(fw_download->parent,
295			"firmware not available for id: %02u\n", firmware_id);
296		return -EINVAL;
297	}
298
299	/* Make sure work handler isn't running in parallel */
300	cancel_delayed_work_sync(&fw_req->dwork);
301
302	/* We timed-out before reaching here ? */
303	if (fw_req->disabled) {
304		ret = -ETIMEDOUT;
305		goto put_fw;
306	}
307
308	/*
309	 * Firmware download must finish within a limited time interval. If it
310	 * doesn't, then we might have a buggy Module on the other side. Abort
311	 * download.
312	 */
313	ret = exceeds_release_timeout(fw_req);
314	if (ret)
315		goto put_fw;
316
317	fw = fw_req->fw;
318
319	if (offset >= fw->size || size > fw->size - offset) {
320		dev_err(fw_download->parent,
321			"bad fetch firmware request (offs = %u, size = %u)\n",
322			offset, size);
323		ret = -EINVAL;
324		goto put_fw;
325	}
326
327	/* gb_fw_download_fetch_firmware_response contains only a byte array */
328	if (!gb_operation_response_alloc(op, size, GFP_KERNEL)) {
329		dev_err(fw_download->parent,
330			"error allocating fetch firmware response\n");
331		ret = -ENOMEM;
332		goto put_fw;
333	}
334
335	response = op->response->payload;
336	memcpy(response, fw->data + offset, size);
337
338	dev_dbg(fw_download->parent,
339		"responding with firmware (offs = %u, size = %u)\n", offset,
340		size);
341
342	/* Refresh timeout */
343	schedule_delayed_work(&fw_req->dwork, NEXT_REQ_TIMEOUT_J);
344
345put_fw:
346	put_fw_req(fw_req);
347
348	return ret;
349}
350
351static int fw_download_release_firmware(struct gb_operation *op)
352{
353	struct gb_connection *connection = op->connection;
354	struct fw_download *fw_download = gb_connection_get_data(connection);
355	struct gb_fw_download_release_firmware_request *request;
356	struct fw_request *fw_req;
357	u8 firmware_id;
358
359	if (op->request->payload_size != sizeof(*request)) {
360		dev_err(fw_download->parent,
361			"Illegal size of release firmware request (%zu %zu)\n",
362			op->request->payload_size, sizeof(*request));
363		return -EINVAL;
364	}
365
366	request = op->request->payload;
367	firmware_id = request->firmware_id;
368
369	fw_req = get_fw_req(fw_download, firmware_id);
370	if (!fw_req) {
371		dev_err(fw_download->parent,
372			"firmware not available for id: %02u\n", firmware_id);
373		return -EINVAL;
374	}
375
376	cancel_delayed_work_sync(&fw_req->dwork);
377
378	free_firmware(fw_download, fw_req);
379	put_fw_req(fw_req);
380
381	dev_dbg(fw_download->parent, "release firmware\n");
382
383	return 0;
384}
385
386int gb_fw_download_request_handler(struct gb_operation *op)
387{
388	u8 type = op->type;
389
390	switch (type) {
391	case GB_FW_DOWNLOAD_TYPE_FIND_FIRMWARE:
392		return fw_download_find_firmware(op);
393	case GB_FW_DOWNLOAD_TYPE_FETCH_FIRMWARE:
394		return fw_download_fetch_firmware(op);
395	case GB_FW_DOWNLOAD_TYPE_RELEASE_FIRMWARE:
396		return fw_download_release_firmware(op);
397	default:
398		dev_err(&op->connection->bundle->dev,
399			"unsupported request: %u\n", type);
400		return -EINVAL;
401	}
402}
403
404int gb_fw_download_connection_init(struct gb_connection *connection)
405{
406	struct fw_download *fw_download;
407	int ret;
408
409	if (!connection)
410		return 0;
411
412	fw_download = kzalloc(sizeof(*fw_download), GFP_KERNEL);
413	if (!fw_download)
414		return -ENOMEM;
415
416	fw_download->parent = &connection->bundle->dev;
417	INIT_LIST_HEAD(&fw_download->fw_requests);
418	ida_init(&fw_download->id_map);
419	gb_connection_set_data(connection, fw_download);
420	fw_download->connection = connection;
421	mutex_init(&fw_download->mutex);
422
423	ret = gb_connection_enable(connection);
424	if (ret)
425		goto err_destroy_id_map;
426
427	return 0;
428
429err_destroy_id_map:
430	ida_destroy(&fw_download->id_map);
431	kfree(fw_download);
432
433	return ret;
434}
435
436void gb_fw_download_connection_exit(struct gb_connection *connection)
437{
438	struct fw_download *fw_download;
439	struct fw_request *fw_req, *tmp;
440
441	if (!connection)
442		return;
443
444	fw_download = gb_connection_get_data(connection);
445	gb_connection_disable(fw_download->connection);
446
447	/*
448	 * Make sure we have a reference to the pending requests, before they
449	 * are freed from the timeout handler.
450	 */
451	mutex_lock(&fw_download->mutex);
452	list_for_each_entry(fw_req, &fw_download->fw_requests, node)
453		kref_get(&fw_req->kref);
454	mutex_unlock(&fw_download->mutex);
455
456	/* Release pending firmware packages */
457	list_for_each_entry_safe(fw_req, tmp, &fw_download->fw_requests, node) {
458		cancel_delayed_work_sync(&fw_req->dwork);
459		free_firmware(fw_download, fw_req);
460		put_fw_req(fw_req);
461	}
462
463	ida_destroy(&fw_download->id_map);
464	kfree(fw_download);
465}
~/ Read-only file preview.