fw.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // SPDX-License-Identifier: BSD-3-Clause-Clear
  2. /*
  3. * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  4. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  5. */
  6. #include <linux/export.h>
  7. #include "core.h"
  8. #include "debug.h"
  9. static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab,
  10. const char *name)
  11. {
  12. size_t magic_len, len, ie_len;
  13. int ie_id, i, index, bit, ret;
  14. struct ath11k_fw_ie *hdr;
  15. const u8 *data;
  16. __le32 *timestamp;
  17. ab->fw.fw = ath11k_core_firmware_request(ab, name);
  18. if (IS_ERR(ab->fw.fw)) {
  19. ret = PTR_ERR(ab->fw.fw);
  20. ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to load %s: %d\n", name, ret);
  21. ab->fw.fw = NULL;
  22. return ret;
  23. }
  24. data = ab->fw.fw->data;
  25. len = ab->fw.fw->size;
  26. /* magic also includes the null byte, check that as well */
  27. magic_len = strlen(ATH11K_FIRMWARE_MAGIC) + 1;
  28. if (len < magic_len) {
  29. ath11k_err(ab, "firmware image too small to contain magic: %zu\n",
  30. len);
  31. ret = -EINVAL;
  32. goto err;
  33. }
  34. if (memcmp(data, ATH11K_FIRMWARE_MAGIC, magic_len) != 0) {
  35. ath11k_err(ab, "Invalid firmware magic\n");
  36. ret = -EINVAL;
  37. goto err;
  38. }
  39. /* jump over the padding */
  40. magic_len = ALIGN(magic_len, 4);
  41. /* make sure there's space for padding */
  42. if (magic_len > len) {
  43. ath11k_err(ab, "No space for padding after magic\n");
  44. ret = -EINVAL;
  45. goto err;
  46. }
  47. len -= magic_len;
  48. data += magic_len;
  49. /* loop elements */
  50. while (len > sizeof(struct ath11k_fw_ie)) {
  51. hdr = (struct ath11k_fw_ie *)data;
  52. ie_id = le32_to_cpu(hdr->id);
  53. ie_len = le32_to_cpu(hdr->len);
  54. len -= sizeof(*hdr);
  55. data += sizeof(*hdr);
  56. if (len < ie_len) {
  57. ath11k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n",
  58. ie_id, len, ie_len);
  59. ret = -EINVAL;
  60. goto err;
  61. }
  62. switch (ie_id) {
  63. case ATH11K_FW_IE_TIMESTAMP:
  64. if (ie_len != sizeof(u32))
  65. break;
  66. timestamp = (__le32 *)data;
  67. ath11k_dbg(ab, ATH11K_DBG_BOOT, "found fw timestamp %d\n",
  68. le32_to_cpup(timestamp));
  69. break;
  70. case ATH11K_FW_IE_FEATURES:
  71. ath11k_dbg(ab, ATH11K_DBG_BOOT,
  72. "found firmware features ie (%zd B)\n",
  73. ie_len);
  74. for (i = 0; i < ATH11K_FW_FEATURE_COUNT; i++) {
  75. index = i / 8;
  76. bit = i % 8;
  77. if (index == ie_len)
  78. break;
  79. if (data[index] & (1 << bit))
  80. __set_bit(i, ab->fw.fw_features);
  81. }
  82. ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "features", "",
  83. ab->fw.fw_features,
  84. sizeof(ab->fw.fw_features));
  85. break;
  86. case ATH11K_FW_IE_AMSS_IMAGE:
  87. ath11k_dbg(ab, ATH11K_DBG_BOOT,
  88. "found fw image ie (%zd B)\n",
  89. ie_len);
  90. ab->fw.amss_data = data;
  91. ab->fw.amss_len = ie_len;
  92. break;
  93. case ATH11K_FW_IE_M3_IMAGE:
  94. ath11k_dbg(ab, ATH11K_DBG_BOOT,
  95. "found m3 image ie (%zd B)\n",
  96. ie_len);
  97. ab->fw.m3_data = data;
  98. ab->fw.m3_len = ie_len;
  99. break;
  100. default:
  101. ath11k_warn(ab, "Unknown FW IE: %u\n", ie_id);
  102. break;
  103. }
  104. /* jump over the padding */
  105. ie_len = ALIGN(ie_len, 4);
  106. /* make sure there's space for padding */
  107. if (ie_len > len)
  108. break;
  109. len -= ie_len;
  110. data += ie_len;
  111. }
  112. return 0;
  113. err:
  114. release_firmware(ab->fw.fw);
  115. ab->fw.fw = NULL;
  116. return ret;
  117. }
  118. int ath11k_fw_pre_init(struct ath11k_base *ab)
  119. {
  120. int ret;
  121. ret = ath11k_fw_request_firmware_api_n(ab, ATH11K_FW_API2_FILE);
  122. if (ret == 0) {
  123. ab->fw.api_version = 2;
  124. goto out;
  125. }
  126. ab->fw.api_version = 1;
  127. out:
  128. ath11k_dbg(ab, ATH11K_DBG_BOOT, "using fw api %d\n",
  129. ab->fw.api_version);
  130. return 0;
  131. }
  132. void ath11k_fw_destroy(struct ath11k_base *ab)
  133. {
  134. release_firmware(ab->fw.fw);
  135. }
  136. EXPORT_SYMBOL(ath11k_fw_destroy);