brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 9a09bd3 Raw
466 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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		51218/* 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 or55	 * release-fw request later. Lets block the id we allocated for this56	 * request, so that the AP doesn't refer to a later fw-request (with57	 * 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 new62	 * firmware downloads. But what else can we do in that case anyway? Lets63	 * 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 possible73 * 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 and76 * get_fw_req() increments the reference count before returning a fw_req pointer77 * 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 and81 * 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 it310	 * doesn't, then we might have a buggy Module on the other side. Abort311	 * 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 they449	 * 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}466