~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sof/loader.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: (GPL-2.0-only 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
  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 "sof-priv.h"
 15 #include "ops.h"
 16 
 17 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
 18 {
 19         struct snd_sof_pdata *plat_data = sdev->pdata;
 20         const char *fw_filename;
 21         ssize_t ext_man_size;
 22         int ret;
 23 
 24         /* Don't request firmware again if firmware is already requested */
 25         if (sdev->basefw.fw)
 26                 return 0;
 27 
 28         fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
 29                                 plat_data->fw_filename_prefix,
 30                                 plat_data->fw_filename);
 31         if (!fw_filename)
 32                 return -ENOMEM;
 33 
 34         ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
 35 
 36         if (ret < 0) {
 37                 dev_err(sdev->dev,
 38                         "error: sof firmware file is missing, you might need to\n");
 39                 dev_err(sdev->dev,
 40                         "       download it from https://github.com/thesofproject/sof-bin/\n");
 41                 goto err;
 42         } else {
 43                 dev_dbg(sdev->dev, "request_firmware %s successful\n",
 44                         fw_filename);
 45         }
 46 
 47         /* check for extended manifest */
 48         ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
 49         if (ext_man_size > 0) {
 50                 /* when no error occurred, drop extended manifest */
 51                 sdev->basefw.payload_offset = ext_man_size;
 52         } else if (!ext_man_size) {
 53                 /* No extended manifest, so nothing to skip during FW load */
 54                 dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
 55         } else {
 56                 ret = ext_man_size;
 57                 dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
 58                         fw_filename, ret);
 59         }
 60 
 61 err:
 62         kfree(fw_filename);
 63 
 64         return ret;
 65 }
 66 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
 67 
 68 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
 69 {
 70         int ret;
 71 
 72         ret = snd_sof_load_firmware_raw(sdev);
 73         if (ret < 0)
 74                 return ret;
 75 
 76         /* make sure the FW header and file is valid */
 77         ret = sdev->ipc->ops->fw_loader->validate(sdev);
 78         if (ret < 0) {
 79                 dev_err(sdev->dev, "error: invalid FW header\n");
 80                 goto error;
 81         }
 82 
 83         /* prepare the DSP for FW loading */
 84         ret = snd_sof_dsp_reset(sdev);
 85         if (ret < 0) {
 86                 dev_err(sdev->dev, "error: failed to reset DSP\n");
 87                 goto error;
 88         }
 89 
 90         /* parse and load firmware modules to DSP */
 91         if (sdev->ipc->ops->fw_loader->load_fw_to_dsp) {
 92                 ret = sdev->ipc->ops->fw_loader->load_fw_to_dsp(sdev);
 93                 if (ret < 0) {
 94                         dev_err(sdev->dev, "Firmware loading failed\n");
 95                         goto error;
 96                 }
 97         }
 98 
 99         return 0;
100 
101 error:
102         release_firmware(sdev->basefw.fw);
103         sdev->basefw.fw = NULL;
104         return ret;
105 
106 }
107 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
108 
109 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
110 {
111         int ret;
112 
113         init_waitqueue_head(&sdev->boot_wait);
114 
115         /* (re-)enable dsp dump */
116         sdev->dbg_dump_printed = false;
117         sdev->ipc_dump_printed = false;
118 
119         /* create read-only fw_version debugfs to store boot version info */
120         if (sdev->first_boot) {
121                 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
122                                                sizeof(sdev->fw_version),
123                                                "fw_version", 0444);
124                 /* errors are only due to memory allocation, not debugfs */
125                 if (ret < 0) {
126                         dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n");
127                         return ret;
128                 }
129         }
130 
131         /* perform pre fw run operations */
132         ret = snd_sof_dsp_pre_fw_run(sdev);
133         if (ret < 0) {
134                 dev_err(sdev->dev, "failed pre fw run op\n");
135                 return ret;
136         }
137 
138         dev_dbg(sdev->dev, "booting DSP firmware\n");
139 
140         /* boot the firmware on the DSP */
141         ret = snd_sof_dsp_run(sdev);
142         if (ret < 0) {
143                 snd_sof_dsp_dbg_dump(sdev, "Failed to start DSP",
144                                      SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI);
145                 return ret;
146         }
147 
148         /*
149          * now wait for the DSP to boot. There are 3 possible outcomes:
150          * 1. Boot wait times out indicating FW boot failure.
151          * 2. FW boots successfully and fw_ready op succeeds.
152          * 3. FW boots but fw_ready op fails.
153          */
154         ret = wait_event_timeout(sdev->boot_wait,
155                                  sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
156                                  msecs_to_jiffies(sdev->boot_timeout));
157         if (ret == 0) {
158                 snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout",
159                                      SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX |
160                                      SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI);
161                 return -EIO;
162         }
163 
164         if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED)
165                 return -EIO; /* FW boots but fw_ready op failed */
166 
167         dev_dbg(sdev->dev, "firmware boot complete\n");
168         sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
169 
170         /* perform post fw run operations */
171         ret = snd_sof_dsp_post_fw_run(sdev);
172         if (ret < 0) {
173                 dev_err(sdev->dev, "error: failed post fw run op\n");
174                 return ret;
175         }
176 
177         if (sdev->ipc->ops->post_fw_boot)
178                 return sdev->ipc->ops->post_fw_boot(sdev);
179 
180         return 0;
181 }
182 EXPORT_SYMBOL(snd_sof_run_firmware);
183 
184 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
185 {
186         /* TODO: support module unloading at runtime */
187         release_firmware(sdev->basefw.fw);
188         sdev->basefw.fw = NULL;
189 }
190 EXPORT_SYMBOL(snd_sof_fw_unload);
191 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php