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/dev_printk.h> 39 #include <linux/dma-mapping.h> 40 #include <linux/errno.h> 41 #include <linux/firmware.h> 42 #include <linux/gfp_types.h> 43 #include <linux/math.h> 44 #include <linux/module.h> 45 #include <linux/pfn.h> 46 #include <linux/string.h> 47 #include <linux/types.h> 48 #include <linux/wait.h> 49 50 #include "hbm.h" 51 #include "loader.h" 52 53 /** 54 * loader_write_message() - Write a message to the ISHTP device 55 * @dev: The ISHTP device 56 * @buf: The buffer containing the message 57 * @len: The length of the message 58 * 59 * Return: 0 on success, negative error code on failure 60 */ 61 static int loader_write_message(struct ishtp_device *dev, void *buf, int len) 62 { 63 struct ishtp_msg_hdr ishtp_hdr = { 64 .fw_addr = ISHTP_LOADER_CLIENT_ADDR, 65 .length = len, 66 .msg_complete = 1, 67 }; 68 69 dev->fw_loader_received = false; 70 71 return ishtp_write_message(dev, &ishtp_hdr, buf); 72 } 73 74 /** 75 * loader_xfer_cmd() - Transfer a command to the ISHTP device 76 * @dev: The ISHTP device 77 * @req: The request buffer 78 * @req_len: The length of the request 79 * @resp: The response buffer 80 * @resp_len: The length of the response 81 * 82 * Return: 0 on success, negative error code on failure 83 */ 84 static int loader_xfer_cmd(struct ishtp_device *dev, void *req, int req_len, 85 void *resp, int resp_len) 86 { 87 union loader_msg_header req_hdr; 88 union loader_msg_header resp_hdr; 89 struct device *devc = dev->devc; 90 int rv; 91 92 dev->fw_loader_rx_buf = resp; 93 dev->fw_loader_rx_size = resp_len; 94 95 rv = loader_write_message(dev, req, req_len); 96 req_hdr.val32 = le32_to_cpup(req); 97 98 if (rv < 0) { 99 dev_err(devc, "write cmd %u failed:%d\n", req_hdr.command, rv); 100 return rv; 101 } 102 103 /* Wait the ACK */ 104 wait_event_interruptible_timeout(dev->wait_loader_recvd_msg, dev->fw_loader_received, 105 ISHTP_LOADER_TIMEOUT); 106 resp_hdr.val32 = le32_to_cpup(resp); 107 dev->fw_loader_rx_size = 0; 108 dev->fw_loader_rx_buf = NULL; 109 if (!dev->fw_loader_received) { 110 dev_err(devc, "wait response of cmd %u timeout\n", req_hdr.command); 111 return -ETIMEDOUT; 112 } 113 114 if (!resp_hdr.is_response) { 115 dev_err(devc, "not a response for %u\n", req_hdr.command); 116 return -EBADMSG; 117 } 118 119 if (req_hdr.command != resp_hdr.command) { 120 dev_err(devc, "unexpected cmd response %u:%u\n", req_hdr.command, 121 resp_hdr.command); 122 return -EBADMSG; 123 } 124 125 if (resp_hdr.status) { 126 dev_err(devc, "cmd %u failed %u\n", req_hdr.command, resp_hdr.status); 127 return -EIO; 128 } 129 130 return 0; 131 } 132 133 /** 134 * release_dma_bufs() - Release the DMA buffer for transferring firmware fragments 135 * @dev: The ISHTP device 136 * @fragment: The ISHTP firmware fragment descriptor 137 * @dma_bufs: The array of DMA fragment buffers 138 * @fragment_size: The size of a single DMA fragment 139 */ 140 static void release_dma_bufs(struct ishtp_device *dev, 141 struct loader_xfer_dma_fragment *fragment, 142 void **dma_bufs, u32 fragment_size) 143 { 144 dma_addr_t dma_addr; 145 int i; 146 147 for (i = 0; i < FRAGMENT_MAX_NUM; i++) { 148 if (dma_bufs[i]) { 149 dma_addr = le64_to_cpu(fragment->fragment_tbl[i].ddr_adrs); 150 dma_free_coherent(dev->devc, fragment_size, dma_bufs[i], dma_addr); 151 dma_bufs[i] = NULL; 152 } 153 } 154 } 155 156 /** 157 * prepare_dma_bufs() - Prepare the DMA buffer for transferring firmware fragments 158 * @dev: The ISHTP device 159 * @ish_fw: The ISH firmware 160 * @fragment: The ISHTP firmware fragment descriptor 161 * @dma_bufs: The array of DMA fragment buffers 162 * @fragment_size: The size of a single DMA fragment 163 * @fragment_count: Number of fragments 164 * 165 * Return: 0 on success, negative error code on failure 166 */ 167 static int prepare_dma_bufs(struct ishtp_device *dev, 168 const struct firmware *ish_fw, 169 struct loader_xfer_dma_fragment *fragment, 170 void **dma_bufs, u32 fragment_size, u32 fragment_count) 171 { 172 dma_addr_t dma_addr; 173 u32 offset = 0; 174 u32 length; 175 int i; 176 177 for (i = 0; i < fragment_count && offset < ish_fw->size; i++) { 178 dma_bufs[i] = dma_alloc_coherent(dev->devc, fragment_size, &dma_addr, GFP_KERNEL); 179 if (!dma_bufs[i]) 180 return -ENOMEM; 181 182 fragment->fragment_tbl[i].ddr_adrs = cpu_to_le64(dma_addr); 183 length = clamp(ish_fw->size - offset, 0, fragment_size); 184 fragment->fragment_tbl[i].length = cpu_to_le32(length); 185 fragment->fragment_tbl[i].fw_off = cpu_to_le32(offset); 186 memcpy(dma_bufs[i], ish_fw->data + offset, length); 187 clflush_cache_range(dma_bufs[i], fragment_size); 188 189 offset += length; 190 } 191 192 return 0; 193 } 194 195 /** 196 * ishtp_loader_work() - Load the ISHTP firmware 197 * @work: The work structure 198 * 199 * The ISH Loader attempts to load firmware by sending a series of commands 200 * to the ISH device. If a command fails to be acknowledged by the ISH device, 201 * the loader will retry sending the command, up to a maximum of 202 * ISHTP_LOADER_RETRY_TIMES. 203 * 204 * After the maximum number of retries has been reached without success, the 205 * ISH bootloader will return an error status code and will no longer respond 206 * to the driver's commands. This behavior indicates that the ISH Loader has 207 * encountered a critical error during the firmware loading process. 208 * 209 * In such a case, where the ISH bootloader is unresponsive after all retries 210 * have been exhausted, a platform reset is required to restore communication 211 * with the ISH device and to recover from this error state. 212 */ 213 void ishtp_loader_work(struct work_struct *work) 214 { 215 DEFINE_RAW_FLEX(struct loader_xfer_dma_fragment, fragment, fragment_tbl, FRAGMENT_MAX_NUM); 216 struct ishtp_device *dev = container_of(work, struct ishtp_device, work_fw_loader); 217 union loader_msg_header query_hdr = { .command = LOADER_CMD_XFER_QUERY, }; 218 union loader_msg_header start_hdr = { .command = LOADER_CMD_START, }; 219 union loader_msg_header fragment_hdr = { .command = LOADER_CMD_XFER_FRAGMENT, }; 220 struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), }; 221 struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), }; 222 union loader_recv_message recv_msg; 223 char *filename = dev->driver_data->fw_filename; 224 const struct firmware *ish_fw; 225 void *dma_bufs[FRAGMENT_MAX_NUM] = {}; 226 u32 fragment_size; 227 u32 fragment_count; 228 int retry = ISHTP_LOADER_RETRY_TIMES; 229 int rv; 230 231 rv = request_firmware(&ish_fw, filename, dev->devc); 232 if (rv < 0) { 233 dev_err(dev->devc, "request firmware %s failed:%d\n", filename, rv); 234 return; 235 } 236 237 fragment->fragment.header = cpu_to_le32(fragment_hdr.val32); 238 fragment->fragment.xfer_mode = cpu_to_le32(LOADER_XFER_MODE_DMA); 239 fragment->fragment.is_last = cpu_to_le32(1); 240 fragment->fragment.size = cpu_to_le32(ish_fw->size); 241 /* Calculate the size of a single DMA fragment */ 242 fragment_size = PFN_ALIGN(DIV_ROUND_UP(ish_fw->size, FRAGMENT_MAX_NUM)); 243 /* Calculate the count of DMA fragments */ 244 fragment_count = DIV_ROUND_UP(ish_fw->size, fragment_size); 245 fragment->fragment_cnt = cpu_to_le32(fragment_count); 246 247 rv = prepare_dma_bufs(dev, ish_fw, fragment, dma_bufs, fragment_size, fragment_count); 248 if (rv) { 249 dev_err(dev->devc, "prepare DMA buffer failed.\n"); 250 goto out; 251 } 252 253 do { 254 query.image_size = cpu_to_le32(ish_fw->size); 255 rv = loader_xfer_cmd(dev, &query, sizeof(query), recv_msg.raw_data, 256 sizeof(struct loader_xfer_query_ack)); 257 if (rv) 258 continue; /* try again if failed */ 259 260 dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", 261 recv_msg.query_ack.version_major, 262 recv_msg.query_ack.version_minor, 263 recv_msg.query_ack.version_hotfix, 264 recv_msg.query_ack.version_build); 265 266 rv = loader_xfer_cmd(dev, fragment, 267 struct_size(fragment, fragment_tbl, fragment_count), 268 recv_msg.raw_data, sizeof(struct loader_xfer_fragment_ack)); 269 if (rv) 270 continue; /* try again if failed */ 271 272 rv = loader_xfer_cmd(dev, &start, sizeof(start), recv_msg.raw_data, 273 sizeof(struct loader_start_ack)); 274 if (rv) 275 continue; /* try again if failed */ 276 277 dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); 278 break; 279 } while (--retry); 280 281 out: 282 release_dma_bufs(dev, fragment, dma_bufs, fragment_size); 283 release_firmware(ish_fw); 284 } 285