File Index
Files and directories
Sign in
FILE

loader.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hid/intel-ish-hid/ishtp/loader.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * ISHTP firmware loader function
  4 *
  5 * Copyright (c) 2024, Intel Corporation.
  6 *
  7 * This module implements the functionality to load the main ISH firmware from the host, starting
  8 * with the Lunar Lake generation. It leverages a new method that enhances space optimization and
  9 * flexibility by dividing the ISH firmware into a bootloader and main firmware.
 10 *
 11 * Please refer to the [Documentation](Documentation/hid/intel-ish-hid.rst) for the details on
 12 * flows.
 13 *
 14 * Additionally, address potential error scenarios to ensure graceful failure handling.
 15 * - Firmware Image Not Found:
 16 *   Occurs when `request_firmware()` cannot locate the firmware image. The ISH firmware will
 17 *   remain in a state awaiting firmware loading from the host, with no further action from
 18 *   the ISHTP driver.
 19 *   Recovery: Re-insmod the ISH drivers allows for a retry of the firmware loading from the host.
 20 *
 21 * - DMA Buffer Allocation Failure:
 22 *   This happens if allocating a DMA buffer during `prepare_dma_bufs()` fails. The ISH firmware
 23 *   will stay in a waiting state, and the ISHTP driver will release any allocated DMA buffers and
 24 *   firmware without further actions.
 25 *   Recovery: Re-insmod the ISH drivers allows for a retry of the firmware loading from the host.
 26 *
 27 * - Incorrect Firmware Image:
 28 *   Using an incorrect firmware image will initiate the firmware loading process but will
 29 *   eventually be refused by the ISH firmware after three unsuccessful attempts, indicated by
 30 *   returning an error code. The ISHTP driver will stop attempting after three tries.
 31 *   Recovery: A platform reset is required to retry firmware loading from the host.
 32 */
 33
 34#define dev_fmt(fmt) "ISH loader: " fmt
 35
 36#include <linux/cacheflush.h>
 37#include <linux/container_of.h>
 38#include <linux/crc32.h>
 39#include <linux/dev_printk.h>
 40#include <linux/dma-mapping.h>
 41#include <linux/dmi.h>
 42#include <linux/errno.h>
 43#include <linux/firmware.h>
 44#include <linux/gfp_types.h>
 45#include <linux/math.h>
 46#include <linux/module.h>
 47#include <linux/pfn.h>
 48#include <linux/sprintf.h>
 49#include <linux/string.h>
 50#include <linux/types.h>
 51#include <linux/wait.h>
 52
 53#include "hbm.h"
 54#include "loader.h"
 55
 56/**
 57 * loader_write_message() - Write a message to the ISHTP device
 58 * @dev: The ISHTP device
 59 * @buf: The buffer containing the message
 60 * @len: The length of the message
 61 *
 62 * Return: 0 on success, negative error code on failure
 63 */
 64static int loader_write_message(struct ishtp_device *dev, void *buf, int len)
 65{
 66	struct ishtp_msg_hdr ishtp_hdr = {
 67		.fw_addr = ISHTP_LOADER_CLIENT_ADDR,
 68		.length = len,
 69		.msg_complete = 1,
 70	};
 71
 72	dev->fw_loader_received = false;
 73
 74	return ishtp_write_message(dev, &ishtp_hdr, buf);
 75}
 76
 77/**
 78 * loader_xfer_cmd() - Transfer a command to the ISHTP device
 79 * @dev: The ISHTP device
 80 * @req: The request buffer
 81 * @req_len: The length of the request
 82 * @resp: The response buffer
 83 * @resp_len: The length of the response
 84 *
 85 * Return: 0 on success, negative error code on failure
 86 */
 87static int loader_xfer_cmd(struct ishtp_device *dev, void *req, int req_len,
 88			   void *resp, int resp_len)
 89{
 90	union loader_msg_header req_hdr;
 91	union loader_msg_header resp_hdr;
 92	struct device *devc = dev->devc;
 93	int rv;
 94
 95	dev->fw_loader_rx_buf = resp;
 96	dev->fw_loader_rx_size = resp_len;
 97
 98	rv = loader_write_message(dev, req, req_len);
 99	req_hdr.val32 = le32_to_cpup(req);
100
101	if (rv < 0) {
102		dev_err(devc, "write cmd %u failed:%d\n", req_hdr.command, rv);
103		return rv;
104	}
105
106	/* Wait the ACK */
107	wait_event_interruptible_timeout(dev->wait_loader_recvd_msg, dev->fw_loader_received,
108					 ISHTP_LOADER_TIMEOUT);
109	resp_hdr.val32 = le32_to_cpup(resp);
110	dev->fw_loader_rx_size = 0;
111	dev->fw_loader_rx_buf = NULL;
112	if (!dev->fw_loader_received) {
113		dev_err(devc, "wait response of cmd %u timeout\n", req_hdr.command);
114		return -ETIMEDOUT;
115	}
116
117	if (!resp_hdr.is_response) {
118		dev_err(devc, "not a response for %u\n", req_hdr.command);
119		return -EBADMSG;
120	}
121
122	if (req_hdr.command != resp_hdr.command) {
123		dev_err(devc, "unexpected cmd response %u:%u\n", req_hdr.command,
124			resp_hdr.command);
125		return -EBADMSG;
126	}
127
128	if (resp_hdr.status) {
129		dev_err(devc, "cmd %u failed %u\n", req_hdr.command, resp_hdr.status);
130		return -EIO;
131	}
132
133	return 0;
134}
135
136/**
137 * release_dma_bufs() - Release the DMA buffer for transferring firmware fragments
138 * @dev: The ISHTP device
139 * @fragment: The ISHTP firmware fragment descriptor
140 * @dma_bufs: The array of DMA fragment buffers
141 * @fragment_size: The size of a single DMA fragment
142 */
143static void release_dma_bufs(struct ishtp_device *dev,
144			     struct loader_xfer_dma_fragment *fragment,
145			     void **dma_bufs, u32 fragment_size)
146{
147	dma_addr_t dma_addr;
148	int i;
149
150	for (i = 0; i < FRAGMENT_MAX_NUM; i++) {
151		if (dma_bufs[i]) {
152			dma_addr = le64_to_cpu(fragment->fragment_tbl[i].ddr_adrs);
153			dma_free_coherent(dev->devc, fragment_size, dma_bufs[i], dma_addr);
154			dma_bufs[i] = NULL;
155		}
156	}
157}
158
159/**
160 * prepare_dma_bufs() - Prepare the DMA buffer for transferring firmware fragments
161 * @dev: The ISHTP device
162 * @ish_fw: The ISH firmware
163 * @fragment: The ISHTP firmware fragment descriptor
164 * @dma_bufs: The array of DMA fragment buffers
165 * @fragment_size: The size of a single DMA fragment
166 * @fragment_count: Number of fragments
167 *
168 * Return: 0 on success, negative error code on failure
169 */
170static int prepare_dma_bufs(struct ishtp_device *dev,
171			    const struct firmware *ish_fw,
172			    struct loader_xfer_dma_fragment *fragment,
173			    void **dma_bufs, u32 fragment_size, u32 fragment_count)
174{
175	dma_addr_t dma_addr;
176	u32 offset = 0;
177	u32 length;
178	int i;
179
180	for (i = 0; i < fragment_count && offset < ish_fw->size; i++) {
181		dma_bufs[i] = dma_alloc_coherent(dev->devc, fragment_size, &dma_addr, GFP_KERNEL);
182		if (!dma_bufs[i])
183			return -ENOMEM;
184
185		fragment->fragment_tbl[i].ddr_adrs = cpu_to_le64(dma_addr);
186		length = clamp(ish_fw->size - offset, 0, fragment_size);
187		fragment->fragment_tbl[i].length = cpu_to_le32(length);
188		fragment->fragment_tbl[i].fw_off = cpu_to_le32(offset);
189		memcpy(dma_bufs[i], ish_fw->data + offset, length);
190		clflush_cache_range(dma_bufs[i], fragment_size);
191
192		offset += length;
193	}
194
195	return 0;
196}
197
198#define ISH_FW_FILE_VENDOR_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin"
199#define ISH_FW_FILE_VENDOR_SKU_FMT "intel/ish/ish_%s_%08x_%08x.bin"
200#define ISH_FW_FILE_VENDOR_NAME_FMT "intel/ish/ish_%s_%08x_%08x.bin"
201#define ISH_FW_FILE_VENDOR_FMT "intel/ish/ish_%s_%08x.bin"
202#define ISH_FW_FILE_DEFAULT_FMT "intel/ish/ish_%s.bin"
203
204#define ISH_FW_FILENAME_LEN_MAX 56
205
206#define ISH_CRC_INIT (~0u)
207#define ISH_CRC_XOROUT (~0u)
208
209static int _request_ish_firmware(const struct firmware **firmware_p,
210					const char *name, struct device *dev)
211{
212	int ret;
213
214	dev_dbg(dev, "Try to load firmware: %s\n", name);
215	ret = firmware_request_nowarn(firmware_p, name, dev);
216	if (!ret)
217		dev_info(dev, "load firmware: %s\n", name);
218
219	return ret;
220}
221
222/**
223 * request_ish_firmware() - Request and load the ISH firmware.
224 * @firmware_p: Pointer to the firmware image.
225 * @dev: Device for which firmware is being requested.
226 *
227 * This function attempts to load the Integrated Sensor Hub (ISH) firmware
228 * for the given device in the following order, prioritizing custom firmware
229 * with more precise matching patterns:
230 *
231 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32)_${PRODUCT_SKU_CRC32}.bin
232 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin
233 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32).bin
234 *   ish_${fw_generation}_${SYS_VENDOR_CRC32}.bin
235 *   ish_${fw_generation}.bin
236 *
237 * The driver will load the first matching firmware and skip the rest. If no
238 * matching firmware is found, it will proceed to the next pattern in the
239 * specified order. If all searches fail, the default Intel firmware, listed
240 * last in the order above, will be loaded.
241 *
242 * The firmware file name is constructed using CRC32 checksums of strings.
243 * This is done to create a valid file name that does not contain spaces
244 * or special characters which may be present in the original strings.
245 *
246 * The CRC-32 algorithm uses the following parameters:
247 *   Poly: 0x04C11DB7
248 *   Init: 0xFFFFFFFF
249 *   RefIn: true
250 *   RefOut: true
251 *   XorOut: 0xFFFFFFFF
252 *
253 * Return: 0 on success, negative error code on failure.
254 */
255static int request_ish_firmware(const struct firmware **firmware_p,
256				struct device *dev)
257{
258	const char *gen, *sys_vendor, *product_name, *product_sku;
259	struct ishtp_device *ishtp = dev_get_drvdata(dev);
260	u32 vendor_crc, name_crc, sku_crc;
261	char filename[ISH_FW_FILENAME_LEN_MAX];
262	int ret;
263
264	gen = ishtp->driver_data->fw_generation;
265	sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
266	product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
267	product_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
268
269	if (sys_vendor)
270		vendor_crc = crc32(ISH_CRC_INIT, sys_vendor, strlen(sys_vendor)) ^ ISH_CRC_XOROUT;
271	if (product_name)
272		name_crc = crc32(ISH_CRC_INIT, product_name, strlen(product_name)) ^ ISH_CRC_XOROUT;
273	if (product_sku)
274		sku_crc = crc32(ISH_CRC_INIT, product_sku, strlen(product_sku)) ^ ISH_CRC_XOROUT;
275
276	if (sys_vendor && product_name && product_sku) {
277		snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_NAME_SKU_FMT, gen,
278			 vendor_crc, name_crc, sku_crc);
279		ret = _request_ish_firmware(firmware_p, filename, dev);
280		if (!ret)
281			return 0;
282	}
283
284	if (sys_vendor && product_sku) {
285		snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_SKU_FMT, gen, vendor_crc,
286			 sku_crc);
287		ret = _request_ish_firmware(firmware_p, filename, dev);
288		if (!ret)
289			return 0;
290	}
291
292	if (sys_vendor && product_name) {
293		snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_NAME_FMT, gen, vendor_crc,
294			 name_crc);
295		ret = _request_ish_firmware(firmware_p, filename, dev);
296		if (!ret)
297			return 0;
298	}
299
300	if (sys_vendor) {
301		snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_FMT, gen, vendor_crc);
302		ret = _request_ish_firmware(firmware_p, filename, dev);
303		if (!ret)
304			return 0;
305	}
306
307	snprintf(filename, sizeof(filename), ISH_FW_FILE_DEFAULT_FMT, gen);
308	return _request_ish_firmware(firmware_p, filename, dev);
309}
310
311static int copy_manifest(const struct firmware *fw, struct ish_global_manifest *manifest)
312{
313	u32 offset;
314
315	for (offset = 0; offset + sizeof(*manifest) < fw->size; offset += ISH_MANIFEST_ALIGNMENT) {
316		memcpy(manifest, fw->data + offset, sizeof(*manifest));
317
318		if (le32_to_cpu(manifest->sig_fourcc) == ISH_GLOBAL_SIG)
319			return 0;
320	}
321
322	return -1;
323}
324
325static void copy_ish_version(struct version_in_manifest *src, struct ish_version *dst)
326{
327	dst->major = le16_to_cpu(src->major);
328	dst->minor = le16_to_cpu(src->minor);
329	dst->hotfix = le16_to_cpu(src->hotfix);
330	dst->build = le16_to_cpu(src->build);
331}
332
333/**
334 * ishtp_loader_work() - Load the ISHTP firmware
335 * @work: The work structure
336 *
337 * The ISH Loader attempts to load firmware by sending a series of commands
338 * to the ISH device. If a command fails to be acknowledged by the ISH device,
339 * the loader will retry sending the command, up to a maximum of
340 * ISHTP_LOADER_RETRY_TIMES.
341 *
342 * After the maximum number of retries has been reached without success, the
343 * ISH bootloader will return an error status code and will no longer respond
344 * to the driver's commands. This behavior indicates that the ISH Loader has
345 * encountered a critical error during the firmware loading process.
346 *
347 * In such a case, where the ISH bootloader is unresponsive after all retries
348 * have been exhausted, a platform reset is required to restore communication
349 * with the ISH device and to recover from this error state.
350 */
351void ishtp_loader_work(struct work_struct *work)
352{
353	DEFINE_RAW_FLEX(struct loader_xfer_dma_fragment, fragment, fragment_tbl, FRAGMENT_MAX_NUM);
354	struct ishtp_device *dev = container_of(work, struct ishtp_device, work_fw_loader);
355	union loader_msg_header query_hdr = { .command = LOADER_CMD_XFER_QUERY, };
356	union loader_msg_header start_hdr = { .command = LOADER_CMD_START, };
357	union loader_msg_header fragment_hdr = { .command = LOADER_CMD_XFER_FRAGMENT, };
358	struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), };
359	struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), };
360	union loader_recv_message recv_msg;
361	struct ish_global_manifest manifest;
362	const struct firmware *ish_fw;
363	void *dma_bufs[FRAGMENT_MAX_NUM] = {};
364	u32 fragment_size;
365	u32 fragment_count;
366	int retry = ISHTP_LOADER_RETRY_TIMES;
367	int rv;
368
369	rv = request_ish_firmware(&ish_fw, dev->devc);
370	if (rv < 0) {
371		dev_err(dev->devc, "request ISH firmware failed:%d\n", rv);
372		return;
373	}
374
375	fragment->fragment.header = cpu_to_le32(fragment_hdr.val32);
376	fragment->fragment.xfer_mode = cpu_to_le32(LOADER_XFER_MODE_DMA);
377	fragment->fragment.is_last = cpu_to_le32(1);
378	fragment->fragment.size = cpu_to_le32(ish_fw->size);
379	/* Calculate the size of a single DMA fragment */
380	fragment_size = PFN_ALIGN(DIV_ROUND_UP(ish_fw->size, FRAGMENT_MAX_NUM));
381	/* Calculate the count of DMA fragments */
382	fragment_count = DIV_ROUND_UP(ish_fw->size, fragment_size);
383	fragment->fragment_cnt = cpu_to_le32(fragment_count);
384
385	rv = prepare_dma_bufs(dev, ish_fw, fragment, dma_bufs, fragment_size, fragment_count);
386	if (rv) {
387		dev_err(dev->devc, "prepare DMA buffer failed.\n");
388		goto out;
389	}
390
391	do {
392		query.image_size = cpu_to_le32(ish_fw->size);
393		rv = loader_xfer_cmd(dev, &query, sizeof(query), recv_msg.raw_data,
394				     sizeof(struct loader_xfer_query_ack));
395		if (rv)
396			continue; /* try again if failed */
397
398		dev_dbg(dev->devc, "ISH Bootloader Version %u.%u.%u.%u\n",
399			recv_msg.query_ack.version_major,
400			recv_msg.query_ack.version_minor,
401			recv_msg.query_ack.version_hotfix,
402			recv_msg.query_ack.version_build);
403
404		rv = loader_xfer_cmd(dev, fragment,
405				     struct_size(fragment, fragment_tbl, fragment_count),
406				     recv_msg.raw_data, sizeof(struct loader_xfer_fragment_ack));
407		if (rv)
408			continue; /* try again if failed */
409
410		rv = loader_xfer_cmd(dev, &start, sizeof(start), recv_msg.raw_data,
411				     sizeof(struct loader_start_ack));
412		if (rv)
413			continue; /* try again if failed */
414
415		dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size);
416		if (!copy_manifest(ish_fw, &manifest)) {
417			copy_ish_version(&manifest.base_ver, &dev->base_ver);
418			copy_ish_version(&manifest.prj_ver, &dev->prj_ver);
419			dev_info(dev->devc, "FW base version: %u.%u.%u.%u\n",
420				 dev->base_ver.major, dev->base_ver.minor,
421				 dev->base_ver.hotfix, dev->base_ver.build);
422			dev_info(dev->devc, "FW project version: %u.%u.%u.%u\n",
423				 dev->prj_ver.major, dev->prj_ver.minor,
424				 dev->prj_ver.hotfix, dev->prj_ver.build);
425		}
426		break;
427	} while (--retry);
428
429out:
430	release_dma_bufs(dev, fragment, dma_bufs, fragment_size);
431	release_firmware(ish_fw);
432}
~/ Read-only file preview.