intel_uc_fw.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright © 2016-2017 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. *
  23. */
  24. #include <linux/firmware.h>
  25. #include <drm/drm_print.h>
  26. #include "intel_uc_fw.h"
  27. #include "i915_drv.h"
  28. /**
  29. * intel_uc_fw_fetch - fetch uC firmware
  30. *
  31. * @dev_priv: device private
  32. * @uc_fw: uC firmware
  33. *
  34. * Fetch uC firmware into GEM obj.
  35. */
  36. void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
  37. struct intel_uc_fw *uc_fw)
  38. {
  39. struct pci_dev *pdev = dev_priv->drm.pdev;
  40. struct drm_i915_gem_object *obj;
  41. const struct firmware *fw = NULL;
  42. struct uc_css_header *css;
  43. size_t size;
  44. int err;
  45. DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  46. intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
  47. if (!uc_fw->path)
  48. return;
  49. uc_fw->fetch_status = INTEL_UC_FIRMWARE_PENDING;
  50. DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  51. intel_uc_fw_type_repr(uc_fw->type),
  52. intel_uc_fw_status_repr(uc_fw->fetch_status));
  53. err = request_firmware(&fw, uc_fw->path, &pdev->dev);
  54. if (err) {
  55. DRM_DEBUG_DRIVER("%s fw request_firmware err=%d\n",
  56. intel_uc_fw_type_repr(uc_fw->type), err);
  57. goto fail;
  58. }
  59. DRM_DEBUG_DRIVER("%s fw size %zu ptr %p\n",
  60. intel_uc_fw_type_repr(uc_fw->type), fw->size, fw);
  61. /* Check the size of the blob before examining buffer contents */
  62. if (fw->size < sizeof(struct uc_css_header)) {
  63. DRM_WARN("%s: Unexpected firmware size (%zu, min %zu)\n",
  64. intel_uc_fw_type_repr(uc_fw->type),
  65. fw->size, sizeof(struct uc_css_header));
  66. err = -ENODATA;
  67. goto fail;
  68. }
  69. css = (struct uc_css_header *)fw->data;
  70. /* Firmware bits always start from header */
  71. uc_fw->header_offset = 0;
  72. uc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
  73. css->key_size_dw - css->exponent_size_dw) *
  74. sizeof(u32);
  75. if (uc_fw->header_size != sizeof(struct uc_css_header)) {
  76. DRM_WARN("%s: Mismatched firmware header definition\n",
  77. intel_uc_fw_type_repr(uc_fw->type));
  78. err = -ENOEXEC;
  79. goto fail;
  80. }
  81. /* then, uCode */
  82. uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size;
  83. uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
  84. /* Header and uCode will be loaded to WOPCM */
  85. size = uc_fw->header_size + uc_fw->ucode_size;
  86. if (size > intel_guc_wopcm_size(dev_priv)) {
  87. DRM_WARN("%s: Firmware is too large to fit in WOPCM\n",
  88. intel_uc_fw_type_repr(uc_fw->type));
  89. err = -E2BIG;
  90. goto fail;
  91. }
  92. /* now RSA */
  93. if (css->key_size_dw != UOS_RSA_SCRATCH_COUNT) {
  94. DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n",
  95. intel_uc_fw_type_repr(uc_fw->type), css->key_size_dw);
  96. err = -ENOEXEC;
  97. goto fail;
  98. }
  99. uc_fw->rsa_offset = uc_fw->ucode_offset + uc_fw->ucode_size;
  100. uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
  101. /* At least, it should have header, uCode and RSA. Size of all three. */
  102. size = uc_fw->header_size + uc_fw->ucode_size + uc_fw->rsa_size;
  103. if (fw->size < size) {
  104. DRM_WARN("%s: Truncated firmware (%zu, expected %zu)\n",
  105. intel_uc_fw_type_repr(uc_fw->type), fw->size, size);
  106. err = -ENOEXEC;
  107. goto fail;
  108. }
  109. /*
  110. * The GuC firmware image has the version number embedded at a
  111. * well-known offset within the firmware blob; note that major / minor
  112. * version are TWO bytes each (i.e. u16), although all pointers and
  113. * offsets are defined in terms of bytes (u8).
  114. */
  115. switch (uc_fw->type) {
  116. case INTEL_UC_FW_TYPE_GUC:
  117. uc_fw->major_ver_found = css->guc.sw_version >> 16;
  118. uc_fw->minor_ver_found = css->guc.sw_version & 0xFFFF;
  119. break;
  120. case INTEL_UC_FW_TYPE_HUC:
  121. uc_fw->major_ver_found = css->huc.sw_version >> 16;
  122. uc_fw->minor_ver_found = css->huc.sw_version & 0xFFFF;
  123. break;
  124. default:
  125. MISSING_CASE(uc_fw->type);
  126. break;
  127. }
  128. DRM_DEBUG_DRIVER("%s fw version %u.%u (wanted %u.%u)\n",
  129. intel_uc_fw_type_repr(uc_fw->type),
  130. uc_fw->major_ver_found, uc_fw->minor_ver_found,
  131. uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
  132. if (uc_fw->major_ver_wanted == 0 && uc_fw->minor_ver_wanted == 0) {
  133. DRM_NOTE("%s: Skipping firmware version check\n",
  134. intel_uc_fw_type_repr(uc_fw->type));
  135. } else if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
  136. uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
  137. DRM_NOTE("%s: Wrong firmware version (%u.%u, required %u.%u)\n",
  138. intel_uc_fw_type_repr(uc_fw->type),
  139. uc_fw->major_ver_found, uc_fw->minor_ver_found,
  140. uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
  141. err = -ENOEXEC;
  142. goto fail;
  143. }
  144. obj = i915_gem_object_create_from_data(dev_priv, fw->data, fw->size);
  145. if (IS_ERR(obj)) {
  146. err = PTR_ERR(obj);
  147. DRM_DEBUG_DRIVER("%s fw object_create err=%d\n",
  148. intel_uc_fw_type_repr(uc_fw->type), err);
  149. goto fail;
  150. }
  151. uc_fw->obj = obj;
  152. uc_fw->size = fw->size;
  153. uc_fw->fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
  154. DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  155. intel_uc_fw_type_repr(uc_fw->type),
  156. intel_uc_fw_status_repr(uc_fw->fetch_status));
  157. release_firmware(fw);
  158. return;
  159. fail:
  160. uc_fw->fetch_status = INTEL_UC_FIRMWARE_FAIL;
  161. DRM_DEBUG_DRIVER("%s fw fetch %s\n",
  162. intel_uc_fw_type_repr(uc_fw->type),
  163. intel_uc_fw_status_repr(uc_fw->fetch_status));
  164. DRM_WARN("%s: Failed to fetch firmware %s (error %d)\n",
  165. intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
  166. DRM_INFO("%s: Firmware can be downloaded from %s\n",
  167. intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
  168. release_firmware(fw); /* OK even if fw is NULL */
  169. }
  170. /**
  171. * intel_uc_fw_upload - load uC firmware using custom loader
  172. *
  173. * @uc_fw: uC firmware
  174. * @loader: custom uC firmware loader function
  175. *
  176. * Loads uC firmware using custom loader and updates internal flags.
  177. */
  178. int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
  179. int (*xfer)(struct intel_uc_fw *uc_fw,
  180. struct i915_vma *vma))
  181. {
  182. struct i915_vma *vma;
  183. int err;
  184. DRM_DEBUG_DRIVER("%s fw load %s\n",
  185. intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
  186. if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
  187. return -ENOEXEC;
  188. uc_fw->load_status = INTEL_UC_FIRMWARE_PENDING;
  189. DRM_DEBUG_DRIVER("%s fw load %s\n",
  190. intel_uc_fw_type_repr(uc_fw->type),
  191. intel_uc_fw_status_repr(uc_fw->load_status));
  192. /* Pin object with firmware */
  193. err = i915_gem_object_set_to_gtt_domain(uc_fw->obj, false);
  194. if (err) {
  195. DRM_DEBUG_DRIVER("%s fw set-domain err=%d\n",
  196. intel_uc_fw_type_repr(uc_fw->type), err);
  197. goto fail;
  198. }
  199. vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0,
  200. PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
  201. if (IS_ERR(vma)) {
  202. err = PTR_ERR(vma);
  203. DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
  204. intel_uc_fw_type_repr(uc_fw->type), err);
  205. goto fail;
  206. }
  207. /* Call custom loader */
  208. err = xfer(uc_fw, vma);
  209. /*
  210. * We keep the object pages for reuse during resume. But we can unpin it
  211. * now that DMA has completed, so it doesn't continue to take up space.
  212. */
  213. i915_vma_unpin(vma);
  214. if (err)
  215. goto fail;
  216. uc_fw->load_status = INTEL_UC_FIRMWARE_SUCCESS;
  217. DRM_DEBUG_DRIVER("%s fw load %s\n",
  218. intel_uc_fw_type_repr(uc_fw->type),
  219. intel_uc_fw_status_repr(uc_fw->load_status));
  220. DRM_INFO("%s: Loaded firmware %s (version %u.%u)\n",
  221. intel_uc_fw_type_repr(uc_fw->type),
  222. uc_fw->path,
  223. uc_fw->major_ver_found, uc_fw->minor_ver_found);
  224. return 0;
  225. fail:
  226. uc_fw->load_status = INTEL_UC_FIRMWARE_FAIL;
  227. DRM_DEBUG_DRIVER("%s fw load %s\n",
  228. intel_uc_fw_type_repr(uc_fw->type),
  229. intel_uc_fw_status_repr(uc_fw->load_status));
  230. DRM_WARN("%s: Failed to load firmware %s (error %d)\n",
  231. intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
  232. return err;
  233. }
  234. /**
  235. * intel_uc_fw_fini - cleanup uC firmware
  236. *
  237. * @uc_fw: uC firmware
  238. *
  239. * Cleans up uC firmware by releasing the firmware GEM obj.
  240. */
  241. void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
  242. {
  243. struct drm_i915_gem_object *obj;
  244. obj = fetch_and_zero(&uc_fw->obj);
  245. if (obj)
  246. i915_gem_object_put(obj);
  247. uc_fw->fetch_status = INTEL_UC_FIRMWARE_NONE;
  248. }
  249. /**
  250. * intel_uc_fw_dump - dump information about uC firmware
  251. * @uc_fw: uC firmware
  252. * @p: the &drm_printer
  253. *
  254. * Pretty printer for uC firmware.
  255. */
  256. void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
  257. {
  258. drm_printf(p, "%s firmware: %s\n",
  259. intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
  260. drm_printf(p, "\tstatus: fetch %s, load %s\n",
  261. intel_uc_fw_status_repr(uc_fw->fetch_status),
  262. intel_uc_fw_status_repr(uc_fw->load_status));
  263. drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
  264. uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
  265. uc_fw->major_ver_found, uc_fw->minor_ver_found);
  266. drm_printf(p, "\theader: offset %u, size %u\n",
  267. uc_fw->header_offset, uc_fw->header_size);
  268. drm_printf(p, "\tuCode: offset %u, size %u\n",
  269. uc_fw->ucode_offset, uc_fw->ucode_size);
  270. drm_printf(p, "\tRSA: offset %u, size %u\n",
  271. uc_fw->rsa_offset, uc_fw->rsa_size);
  272. }