linux/sound/soc/sof/loader.c
<<
>>
Prefs
   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
  17static 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 */
  36int 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}
  88EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
  89
  90/* generic module parser for mmaped DSPs */
  91int 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}
 165EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
 166
 167static 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
 194static 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
 248int 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}
 278EXPORT_SYMBOL(snd_sof_load_firmware_raw);
 279
 280int 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
 312error:
 313        release_firmware(plat_data->fw);
 314        plat_data->fw = NULL;
 315        return ret;
 316
 317}
 318EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
 319
 320int 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}
 328EXPORT_SYMBOL(snd_sof_load_firmware);
 329
 330int 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}
 394EXPORT_SYMBOL(snd_sof_run_firmware);
 395
 396void snd_sof_fw_unload(struct snd_sof_dev *sdev)
 397{
 398        /* TODO: support module unloading at runtime */
 399}
 400EXPORT_SYMBOL(snd_sof_fw_unload);
 401