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 struct loader_msg_header *req_hdr = req; 88 struct loader_msg_header *resp_hdr = resp; 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 if (rv < 0) { 97 dev_err(devc, "write cmd %u failed:%d\n", req_hdr->command, rv); 98 return rv; 99 } 100 101 /* Wait the ACK */ 102 wait_event_interruptible_timeout(dev->wait_loader_recvd_msg, dev->fw_loader_received, 103 ISHTP_LOADER_TIMEOUT); 104 dev->fw_loader_rx_size = 0; 105 dev->fw_loader_rx_buf = NULL; 106 if (!dev->fw_loader_received) { 107 dev_err(devc, "wait response of cmd %u timeout\n", req_hdr->command); 108 return -ETIMEDOUT; 109 } 110 111 if (!resp_hdr->is_response) { 112 dev_err(devc, "not a response for %u\n", req_hdr->command); 113 return -EBADMSG; 114 } 115 116 if (req_hdr->command != resp_hdr->command) { 117 dev_err(devc, "unexpected cmd response %u:%u\n", req_hdr->command, 118 resp_hdr->command); 119 return -EBADMSG; 120 } 121 122 if (resp_hdr->status) { 123 dev_err(devc, "cmd %u failed %u\n", req_hdr->command, resp_hdr->status); 124 return -EIO; 125 } 126 127 return 0; 128 } 129 130 /** 131 * release_dma_bufs() - Release the DMA buffer for transferring firmware fragments 132 * @dev: The ISHTP device 133 * @fragment: The ISHTP firmware fragment descriptor 134 * @dma_bufs: The array of DMA fragment buffers 135 * @fragment_size: The size of a single DMA fragment 136 */ 137 static void release_dma_bufs(struct ishtp_device *dev, 138 struct loader_xfer_dma_fragment *fragment, 139 void **dma_bufs, u32 fragment_size) 140 { 141 int i; 142 143 for (i = 0; i < FRAGMENT_MAX_NUM; i++) { 144 if (dma_bufs[i]) { 145 dma_free_coherent(dev->devc, fragment_size, dma_bufs[i], 146 fragment->fragment_tbl[i].ddr_adrs); 147 dma_bufs[i] = NULL; 148 } 149 } 150 } 151 152 /** 153 * prepare_dma_bufs() - Prepare the DMA buffer for transferring firmware fragments 154 * @dev: The ISHTP device 155 * @ish_fw: The ISH firmware 156 * @fragment: The ISHTP firmware fragment descriptor 157 * @dma_bufs: The array of DMA fragment buffers 158 * @fragment_size: The size of a single DMA fragment 159 * 160 * Return: 0 on success, negative error code on failure 161 */ 162 static int prepare_dma_bufs(struct ishtp_device *dev, 163 const struct firmware *ish_fw, 164 struct loader_xfer_dma_fragment *fragment, 165 void **dma_bufs, u32 fragment_size) 166 { 167 u32 offset = 0; 168 int i; 169 170 for (i = 0; i < fragment->fragment_cnt && offset < ish_fw->size; i++) { 171 dma_bufs[i] = dma_alloc_coherent(dev->devc, fragment_size, 172 &fragment->fragment_tbl[i].ddr_adrs, GFP_KERNEL); 173 if (!dma_bufs[i]) 174 return -ENOMEM; 175 176 fragment->fragment_tbl[i].length = clamp(ish_fw->size - offset, 0, fragment_size); 177 fragment->fragment_tbl[i].fw_off = offset; 178 memcpy(dma_bufs[i], ish_fw->data + offset, fragment->fragment_tbl[i].length); 179 clflush_cache_range(dma_bufs[i], fragment_size); 180 181 offset += fragment->fragment_tbl[i].length; 182 } 183 184 return 0; 185 } 186 187 /** 188 * ishtp_loader_work() - Load the ISHTP firmware 189 * @work: The work structure 190 * 191 * The ISH Loader attempts to load firmware by sending a series of commands 192 * to the ISH device. If a command fails to be acknowledged by the ISH device, 193 * the loader will retry sending the command, up to a maximum of 194 * ISHTP_LOADER_RETRY_TIMES. 195 * 196 * After the maximum number of retries has been reached without success, the 197 * ISH bootloader will return an error status code and will no longer respond 198 * to the driver's commands. This behavior indicates that the ISH Loader has 199 * encountered a critical error during the firmware loading process. 200 * 201 * In such a case, where the ISH bootloader is unresponsive after all retries 202 * have been exhausted, a platform reset is required to restore communication 203 * with the ISH device and to recover from this error state. 204 */ 205 void ishtp_loader_work(struct work_struct *work) 206 { 207 DEFINE_RAW_FLEX(struct loader_xfer_dma_fragment, fragment, fragment_tbl, FRAGMENT_MAX_NUM); 208 struct ishtp_device *dev = container_of(work, struct ishtp_device, work_fw_loader); 209 struct loader_xfer_query query = { 210 .header.command = LOADER_CMD_XFER_QUERY, 211 }; 212 struct loader_start start = { 213 .header.command = LOADER_CMD_START, 214 }; 215 union loader_recv_message recv_msg; 216 char *filename = dev->driver_data->fw_filename; 217 const struct firmware *ish_fw; 218 void *dma_bufs[FRAGMENT_MAX_NUM] = {}; 219 u32 fragment_size; 220 int retry = ISHTP_LOADER_RETRY_TIMES; 221 int rv; 222 223 rv = request_firmware(&ish_fw, filename, dev->devc); 224 if (rv < 0) { 225 dev_err(dev->devc, "request firmware %s failed:%d\n", filename, rv); 226 return; 227 } 228 229 fragment->fragment.header.command = LOADER_CMD_XFER_FRAGMENT; 230 fragment->fragment.xfer_mode = LOADER_XFER_MODE_DMA; 231 fragment->fragment.is_last = 1; 232 fragment->fragment.size = ish_fw->size; 233 /* Calculate the size of a single DMA fragment */ 234 fragment_size = PFN_ALIGN(DIV_ROUND_UP(ish_fw->size, FRAGMENT_MAX_NUM)); 235 /* Calculate the count of DMA fragments */ 236 fragment->fragment_cnt = DIV_ROUND_UP(ish_fw->size, fragment_size); 237 238 rv = prepare_dma_bufs(dev, ish_fw, fragment, dma_bufs, fragment_size); 239 if (rv) { 240 dev_err(dev->devc, "prepare DMA buffer failed.\n"); 241 goto out; 242 } 243 244 do { 245 query.image_size = ish_fw->size; 246 rv = loader_xfer_cmd(dev, &query, sizeof(query), recv_msg.raw_data, 247 sizeof(struct loader_xfer_query_ack)); 248 if (rv) 249 continue; /* try again if failed */ 250 251 dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", 252 recv_msg.query_ack.version_major, 253 recv_msg.query_ack.version_minor, 254 recv_msg.query_ack.version_hotfix, 255 recv_msg.query_ack.version_build); 256 257 rv = loader_xfer_cmd(dev, fragment, 258 struct_size(fragment, fragment_tbl, fragment->fragment_cnt), 259 recv_msg.raw_data, sizeof(struct loader_xfer_fragment_ack)); 260 if (rv) 261 continue; /* try again if failed */ 262 263 rv = loader_xfer_cmd(dev, &start, sizeof(start), recv_msg.raw_data, 264 sizeof(struct loader_start_ack)); 265 if (rv) 266 continue; /* try again if failed */ 267 268 dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); 269 break; 270 } while (--retry); 271 272 out: 273 release_dma_bufs(dev, fragment, dma_bufs, fragment_size); 274 release_firmware(ish_fw); 275 } 276