loader.c 4.8 KB

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