1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2018 Intel Corporation. All rights reserved. 7 // 8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // 10 // Generic firmware loader. 11 // 12 13 #include <linux/firmware.h> 14 #include <sound/sof.h> 15 #include "ops.h" 16 17 static int get_ext_windows(struct snd_sof_dev *sdev, 18 struct sof_ipc_ext_data_hdr *ext_hdr) 19 { 20 struct sof_ipc_window *w = 21 container_of(ext_hdr, struct sof_ipc_window, ext_hdr); 22 23 if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) 24 return -EINVAL; 25 26 /* keep a local copy of the data */ 27 sdev->info_window = kmemdup(w, struct_size(w, window, w->num_windows), 28 GFP_KERNEL); 29 if (!sdev->info_window) 30 return -ENOMEM; 31 32 return 0; 33 } 34 35 /* parse the extended FW boot data structures from FW boot message */ 36 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) 37 { 38 struct sof_ipc_ext_data_hdr *ext_hdr; 39 void *ext_data; 40 int ret = 0; 41 42 ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL); 43 if (!ext_data) 44 return -ENOMEM; 45 46 /* get first header */ 47 snd_sof_dsp_block_read(sdev, bar, offset, ext_data, 48 sizeof(*ext_hdr)); 49 ext_hdr = ext_data; 50 51 while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { 52 /* read in ext structure */ 53 offset += sizeof(*ext_hdr); 54 snd_sof_dsp_block_read(sdev, bar, offset, 55 (void *)((u8 *)ext_data + sizeof(*ext_hdr)), 56 ext_hdr->hdr.size - sizeof(*ext_hdr)); 57 58 dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n", 59 ext_hdr->type, ext_hdr->hdr.size); 60 61 /* process structure data */ 62 switch (ext_hdr->type) { 63 case SOF_IPC_EXT_DMA_BUFFER: 64 break; 65 case SOF_IPC_EXT_WINDOW: 66 ret = get_ext_windows(sdev, ext_hdr); 67 break; 68 default: 69 break; 70 } 71 72 if (ret < 0) { 73 dev_err(sdev->dev, "error: failed to parse ext data type %d\n", 74 ext_hdr->type); 75 break; 76 } 77 78 /* move to next header */ 79 offset += ext_hdr->hdr.size; 80 snd_sof_dsp_block_read(sdev, bar, offset, ext_data, 81 sizeof(*ext_hdr)); 82 ext_hdr = ext_data; 83 } 84 85 kfree(ext_data); 86 return ret; 87 } 88 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); 89 90 /* generic module parser for mmaped DSPs */ 91 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, 92 struct snd_sof_mod_hdr *module) 93 { 94 struct snd_sof_blk_hdr *block; 95 int count; 96 u32 offset; 97 size_t remaining; 98 99 dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", 100 module->size, module->num_blocks, module->type); 101 102 block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module)); 103 104 /* module->size doesn't include header size */ 105 remaining = module->size; 106 for (count = 0; count < module->num_blocks; count++) { 107 /* check for wrap */ 108 if (remaining < sizeof(*block)) { 109 dev_err(sdev->dev, "error: not enough data remaining\n"); 110 return -EINVAL; 111 } 112 113 /* minus header size of block */ 114 remaining -= sizeof(*block); 115 116 if (block->size == 0) { 117 dev_warn(sdev->dev, 118 "warning: block %d size zero\n", count); 119 dev_warn(sdev->dev, " type 0x%x offset 0x%x\n", 120 block->type, block->offset); 121 continue; 122 } 123 124 switch (block->type) { 125 case SOF_FW_BLK_TYPE_RSRVD0: 126 case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: 127 continue; /* not handled atm */ 128 case SOF_FW_BLK_TYPE_IRAM: 129 case SOF_FW_BLK_TYPE_DRAM: 130 offset = block->offset; 131 break; 132 default: 133 dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", 134 block->type, count); 135 return -EINVAL; 136 } 137 138 dev_dbg(sdev->dev, 139 "block %d type 0x%x size 0x%x ==> offset 0x%x\n", 140 count, block->type, block->size, offset); 141 142 /* checking block->size to avoid unaligned access */ 143 if (block->size % sizeof(u32)) { 144 dev_err(sdev->dev, "error: invalid block size 0x%x\n", 145 block->size); 146 return -EINVAL; 147 } 148 snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, 149 block + 1, block->size); 150 151 if (remaining < block->size) { 152 dev_err(sdev->dev, "error: not enough data remaining\n"); 153 return -EINVAL; 154 } 155 156 /* minus body size of block */ 157 remaining -= block->size; 158 /* next block */ 159 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block) 160 + block->size); 161 } 162 163 return 0; 164 } 165 EXPORT_SYMBOL(snd_sof_parse_module_memcpy); 166 167 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw) 168 { 169 struct snd_sof_fw_header *header; 170 171 /* Read the header information from the data pointer */ 172 header = (struct snd_sof_fw_header *)fw->data; 173 174 /* verify FW sig */ 175 if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) { 176 dev_err(sdev->dev, "error: invalid firmware signature\n"); 177 return -EINVAL; 178 } 179 180 /* check size is valid */ 181 if (fw->size != header->file_size + sizeof(*header)) { 182 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n", 183 fw->size, header->file_size + sizeof(*header)); 184 return -EINVAL; 185 } 186 187 dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n", 188 header->file_size, header->num_modules, 189 header->abi, sizeof(*header)); 190 191 return 0; 192 } 193 194 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) 195 { 196 struct snd_sof_fw_header *header; 197 struct snd_sof_mod_hdr *module; 198 int (*load_module)(struct snd_sof_dev *sof_dev, 199 struct snd_sof_mod_hdr *hdr); 200 int ret, count; 201 size_t remaining; 202 203 header = (struct snd_sof_fw_header *)fw->data; 204 load_module = sof_ops(sdev)->load_module; 205 if (!load_module) 206 return -EINVAL; 207 208 /* parse each module */ 209 module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header)); 210 remaining = fw->size - sizeof(*header); 211 /* check for wrap */ 212 if (remaining > fw->size) { 213 dev_err(sdev->dev, "error: fw size smaller than header size\n"); 214 return -EINVAL; 215 } 216 217 for (count = 0; count < header->num_modules; count++) { 218 /* check for wrap */ 219 if (remaining < sizeof(*module)) { 220 dev_err(sdev->dev, "error: not enough data remaining\n"); 221 return -EINVAL; 222 } 223 224 /* minus header size of module */ 225 remaining -= sizeof(*module); 226 227 /* module */ 228 ret = load_module(sdev, module); 229 if (ret < 0) { 230 dev_err(sdev->dev, "error: invalid module %d\n", count); 231 return ret; 232 } 233 234 if (remaining < module->size) { 235 dev_err(sdev->dev, "error: not enough data remaining\n"); 236 return -EINVAL; 237 } 238 239 /* minus body size of module */ 240 remaining -= module->size; 241 module = (struct snd_sof_mod_hdr *)((u8 *)module 242 + sizeof(*module) + module->size); 243 } 244 245 return 0; 246 } 247 248 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) 249 { 250 struct snd_sof_pdata *plat_data = sdev->pdata; 251 const char *fw_filename; 252 int ret; 253 254 /* set code loading condition to true */ 255 sdev->code_loading = 1; 256 257 /* Don't request firmware again if firmware is already requested */ 258 if (plat_data->fw) 259 return 0; 260 261 fw_filename = kasprintf(GFP_KERNEL, "%s/%s", 262 plat_data->fw_filename_prefix, 263 plat_data->fw_filename); 264 if (!fw_filename) 265 return -ENOMEM; 266 267 ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); 268 269 if (ret < 0) { 270 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", 271 fw_filename, ret); 272 } 273 274 kfree(fw_filename); 275 276 return ret; 277 } 278 EXPORT_SYMBOL(snd_sof_load_firmware_raw); 279 280 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) 281 { 282 struct snd_sof_pdata *plat_data = sdev->pdata; 283 int ret; 284 285 ret = snd_sof_load_firmware_raw(sdev); 286 if (ret < 0) 287 return ret; 288 289 /* make sure the FW header and file is valid */ 290 ret = check_header(sdev, plat_data->fw); 291 if (ret < 0) { 292 dev_err(sdev->dev, "error: invalid FW header\n"); 293 goto error; 294 } 295 296 /* prepare the DSP for FW loading */ 297 ret = snd_sof_dsp_reset(sdev); 298 if (ret < 0) { 299 dev_err(sdev->dev, "error: failed to reset DSP\n"); 300 goto error; 301 } 302 303 /* parse and load firmware modules to DSP */ 304 ret = load_modules(sdev, plat_data->fw); 305 if (ret < 0) { 306 dev_err(sdev->dev, "error: invalid FW modules\n"); 307 goto error; 308 } 309 310 return 0; 311 312 error: 313 release_firmware(plat_data->fw); 314 plat_data->fw = NULL; 315 return ret; 316 317 } 318 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); 319 320 int snd_sof_load_firmware(struct snd_sof_dev *sdev) 321 { 322 dev_dbg(sdev->dev, "loading firmware\n"); 323 324 if (sof_ops(sdev)->load_firmware) 325 return sof_ops(sdev)->load_firmware(sdev); 326 return 0; 327 } 328 EXPORT_SYMBOL(snd_sof_load_firmware); 329 330 int snd_sof_run_firmware(struct snd_sof_dev *sdev) 331 { 332 int ret; 333 int init_core_mask; 334 335 init_waitqueue_head(&sdev->boot_wait); 336 sdev->boot_complete = false; 337 338 /* create read-only fw_version debugfs to store boot version info */ 339 if (sdev->first_boot) { 340 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version, 341 sizeof(sdev->fw_version), 342 "fw_version", 0444); 343 /* errors are only due to memory allocation, not debugfs */ 344 if (ret < 0) { 345 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); 346 return ret; 347 } 348 } 349 350 /* perform pre fw run operations */ 351 ret = snd_sof_dsp_pre_fw_run(sdev); 352 if (ret < 0) { 353 dev_err(sdev->dev, "error: failed pre fw run op\n"); 354 return ret; 355 } 356 357 dev_dbg(sdev->dev, "booting DSP firmware\n"); 358 359 /* boot the firmware on the DSP */ 360 ret = snd_sof_dsp_run(sdev); 361 if (ret < 0) { 362 dev_err(sdev->dev, "error: failed to reset DSP\n"); 363 return ret; 364 } 365 366 init_core_mask = ret; 367 368 /* now wait for the DSP to boot */ 369 ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, 370 msecs_to_jiffies(sdev->boot_timeout)); 371 if (ret == 0) { 372 dev_err(sdev->dev, "error: firmware boot failure\n"); 373 /* after this point FW_READY msg should be ignored */ 374 sdev->boot_complete = true; 375 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | 376 SOF_DBG_TEXT | SOF_DBG_PCI); 377 return -EIO; 378 } 379 380 dev_info(sdev->dev, "firmware boot complete\n"); 381 382 /* perform post fw run operations */ 383 ret = snd_sof_dsp_post_fw_run(sdev); 384 if (ret < 0) { 385 dev_err(sdev->dev, "error: failed post fw run op\n"); 386 return ret; 387 } 388 389 /* fw boot is complete. Update the active cores mask */ 390 sdev->enabled_cores_mask = init_core_mask; 391 392 return 0; 393 } 394 EXPORT_SYMBOL(snd_sof_run_firmware); 395 396 void snd_sof_fw_unload(struct snd_sof_dev *sdev) 397 { 398 /* TODO: support module unloading at runtime */ 399 } 400 EXPORT_SYMBOL(snd_sof_fw_unload); 401