Skip to content

Commit 1b6ff73

Browse files
author
Benjamin Tissoires
committed
Merge branch 'for-6.12/intel-ish' into for-linus
- Add support for vendor customized firmware loading (Zhang Lixu)
2 parents b169410 + aa4674c commit 1b6ff73

File tree

4 files changed

+159
-9
lines changed

4 files changed

+159
-9
lines changed

Documentation/hid/intel-ish-hid.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,35 @@ For more detailed information, please refer to the flow descriptions provided be
404404
| ISHTP Driver | | ISH Bootloader |
405405
+---------------+ +-----------------+
406406

407+
Vendor Custom Firmware Loading
408+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
409+
410+
The firmware running inside ISH can be provided by Intel or developed by vendors using the Firmware Development Kit (FDK) provided by Intel.
411+
Intel will upstream the Intel-built firmware to the ``linux-firmware.git`` repository, located under the path ``intel/ish/``. For the Lunar Lake platform, the Intel-built ISH firmware will be named ``ish_lnlm.bin``.
412+
Vendors who wish to upstream their custom firmware should follow these guidelines for naming their firmware files:
413+
414+
- The firmware filename should use one of the following patterns:
415+
416+
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
417+
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
418+
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
419+
- ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
420+
421+
- ``${intel_plat_gen}`` indicates the Intel platform generation (e.g., ``lnlm`` for Lunar Lake) and must not exceed 8 characters in length.
422+
- ``${SYS_VENDOR_CRC32}`` is the CRC32 checksum of the ``sys_vendor`` value from the DMI field ``DMI_SYS_VENDOR``.
423+
- ``${PRODUCT_NAME_CRC32}`` is the CRC32 checksum of the ``product_name`` value from the DMI field ``DMI_PRODUCT_NAME``.
424+
- ``${PRODUCT_SKU_CRC32}`` is the CRC32 checksum of the ``product_sku`` value from the DMI field ``DMI_PRODUCT_SKU``.
425+
426+
During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns:
427+
428+
1. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``
429+
2. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``
430+
3. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``
431+
4. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``
432+
5. ``intel/ish/ish_${intel_plat_gen}.bin``
433+
434+
The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded.
435+
407436
ISH Debugging
408437
-------------
409438

drivers/hid/intel-ish-hid/ipc/pci-ish.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ enum ishtp_driver_data_index {
2828
ISHTP_DRIVER_DATA_LNL_M,
2929
};
3030

31-
#define ISH_FW_FILENAME_LNL_M "intel/ish/ish_lnlm.bin"
31+
#define ISH_FW_GEN_LNL_M "lnlm"
32+
33+
#define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
34+
#define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
3235

3336
static struct ishtp_driver_data ishtp_driver_data[] = {
3437
[ISHTP_DRIVER_DATA_LNL_M] = {
35-
.fw_filename = ISH_FW_FILENAME_LNL_M,
38+
.fw_generation = ISH_FW_GEN_LNL_M,
3639
},
3740
};
3841

@@ -397,4 +400,5 @@ MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
397400
MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
398401
MODULE_LICENSE("GPL");
399402

400-
MODULE_FIRMWARE(ISH_FW_FILENAME_LNL_M);
403+
MODULE_FIRMWARE(ISH_FIRMWARE_PATH(ISH_FW_GEN_LNL_M));
404+
MODULE_FIRMWARE(ISH_FIRMWARE_PATH_ALL);

drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,15 @@ struct ishtp_hw_ops {
129129
* ISHTP device instance. It allows for the storage of data that is unique to
130130
* a particular driver or hardware variant.
131131
*
132-
* @fw_filename: The firmware filename associated with a specific hardware
132+
* @fw_generation: The generation name associated with a specific hardware
133133
* variant of the Intel Integrated Sensor Hub (ISH). This allows
134134
* the driver to load the correct firmware based on the device's
135-
* hardware variant.
135+
* hardware variant. For example, "lnlm" for the Lunar Lake-M
136+
* platform. The generation name must not exceed 8 characters
137+
* in length.
136138
*/
137139
struct ishtp_driver_data {
138-
char *fw_filename;
140+
char *fw_generation;
139141
};
140142

141143
/**

drivers/hid/intel-ish-hid/ishtp/loader.c

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,17 @@
3535

3636
#include <linux/cacheflush.h>
3737
#include <linux/container_of.h>
38+
#include <linux/crc32.h>
3839
#include <linux/dev_printk.h>
3940
#include <linux/dma-mapping.h>
41+
#include <linux/dmi.h>
4042
#include <linux/errno.h>
4143
#include <linux/firmware.h>
4244
#include <linux/gfp_types.h>
4345
#include <linux/math.h>
4446
#include <linux/module.h>
4547
#include <linux/pfn.h>
48+
#include <linux/sprintf.h>
4649
#include <linux/string.h>
4750
#include <linux/types.h>
4851
#include <linux/wait.h>
@@ -192,6 +195,119 @@ static int prepare_dma_bufs(struct ishtp_device *dev,
192195
return 0;
193196
}
194197

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+
209+
static 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+
*/
255+
static 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+
195311
/**
196312
* ishtp_loader_work() - Load the ISHTP firmware
197313
* @work: The work structure
@@ -220,17 +336,16 @@ void ishtp_loader_work(struct work_struct *work)
220336
struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), };
221337
struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), };
222338
union loader_recv_message recv_msg;
223-
char *filename = dev->driver_data->fw_filename;
224339
const struct firmware *ish_fw;
225340
void *dma_bufs[FRAGMENT_MAX_NUM] = {};
226341
u32 fragment_size;
227342
u32 fragment_count;
228343
int retry = ISHTP_LOADER_RETRY_TIMES;
229344
int rv;
230345

231-
rv = request_firmware(&ish_fw, filename, dev->devc);
346+
rv = request_ish_firmware(&ish_fw, dev->devc);
232347
if (rv < 0) {
233-
dev_err(dev->devc, "request firmware %s failed:%d\n", filename, rv);
348+
dev_err(dev->devc, "request ISH firmware failed:%d\n", rv);
234349
return;
235350
}
236351

0 commit comments

Comments
 (0)