aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_guc_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_guc_loader.c')
-rw-r--r--drivers/gpu/drm/i915/intel_guc_loader.c105
1 files changed, 67 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 3541f76c65a7..550921f2ef7d 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -31,7 +31,7 @@
31#include "intel_guc.h" 31#include "intel_guc.h"
32 32
33/** 33/**
34 * DOC: GuC 34 * DOC: GuC-specific firmware loader
35 * 35 *
36 * intel_guc: 36 * intel_guc:
37 * Top level structure of guc. It handles firmware loading and manages client 37 * Top level structure of guc. It handles firmware loading and manages client
@@ -208,16 +208,6 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
208/* 208/*
209 * Transfer the firmware image to RAM for execution by the microcontroller. 209 * Transfer the firmware image to RAM for execution by the microcontroller.
210 * 210 *
211 * GuC Firmware layout:
212 * +-------------------------------+ ----
213 * | CSS header | 128B
214 * | contains major/minor version |
215 * +-------------------------------+ ----
216 * | uCode |
217 * +-------------------------------+ ----
218 * | RSA signature | 256B
219 * +-------------------------------+ ----
220 *
221 * Architecturally, the DMA engine is bidirectional, and can potentially even 211 * Architecturally, the DMA engine is bidirectional, and can potentially even
222 * transfer between GTT locations. This functionality is left out of the API 212 * transfer between GTT locations. This functionality is left out of the API
223 * for now as there is no need for it. 213 * for now as there is no need for it.
@@ -225,33 +215,29 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
225 * Note that GuC needs the CSS header plus uKernel code to be copied by the 215 * Note that GuC needs the CSS header plus uKernel code to be copied by the
226 * DMA engine in one operation, whereas the RSA signature is loaded via MMIO. 216 * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
227 */ 217 */
228
229#define UOS_CSS_HEADER_OFFSET 0
230#define UOS_VER_MINOR_OFFSET 0x44
231#define UOS_VER_MAJOR_OFFSET 0x46
232#define UOS_CSS_HEADER_SIZE 0x80
233#define UOS_RSA_SIG_SIZE 0x100
234
235static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv) 218static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
236{ 219{
237 struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; 220 struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
238 struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj; 221 struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
239 unsigned long offset; 222 unsigned long offset;
240 struct sg_table *sg = fw_obj->pages; 223 struct sg_table *sg = fw_obj->pages;
241 u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)]; 224 u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
242 int i, ret = 0; 225 int i, ret = 0;
243 226
244 /* uCode size, also is where RSA signature starts */ 227 /* where RSA signature starts */
245 offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE; 228 offset = guc_fw->rsa_offset;
246 I915_WRITE(DMA_COPY_SIZE, ucode_size);
247 229
248 /* Copy RSA signature from the fw image to HW for verification */ 230 /* Copy RSA signature from the fw image to HW for verification */
249 sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset); 231 sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset);
250 for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++) 232 for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++)
251 I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); 233 I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
252 234
235 /* The header plus uCode will be copied to WOPCM via DMA, excluding any
236 * other components */
237 I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
238
253 /* Set the source address for the new blob */ 239 /* Set the source address for the new blob */
254 offset = i915_gem_obj_ggtt_offset(fw_obj); 240 offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset;
255 I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); 241 I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
256 I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); 242 I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
257 243
@@ -322,8 +308,8 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
322 I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); 308 I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
323 309
324 /* WaDisableMinuteIaClockGating:skl,bxt */ 310 /* WaDisableMinuteIaClockGating:skl,bxt */
325 if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) || 311 if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
326 (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) { 312 IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
327 I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) & 313 I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
328 ~GUC_ENABLE_MIA_CLOCK_GATING)); 314 ~GUC_ENABLE_MIA_CLOCK_GATING));
329 } 315 }
@@ -378,6 +364,9 @@ int intel_guc_ucode_load(struct drm_device *dev)
378 struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; 364 struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
379 int err = 0; 365 int err = 0;
380 366
367 if (!i915.enable_guc_submission)
368 return 0;
369
381 DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n", 370 DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
382 intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status), 371 intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
383 intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); 372 intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
@@ -457,10 +446,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
457{ 446{
458 struct drm_i915_gem_object *obj; 447 struct drm_i915_gem_object *obj;
459 const struct firmware *fw; 448 const struct firmware *fw;
460 const u8 *css_header; 449 struct guc_css_header *css;
461 const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE; 450 size_t size;
462 const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
463 - 0x8000; /* 32k reserved (8K stack + 24k context) */
464 int err; 451 int err;
465 452
466 DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n", 453 DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
@@ -474,12 +461,52 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
474 461
475 DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n", 462 DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
476 guc_fw->guc_fw_path, fw); 463 guc_fw->guc_fw_path, fw);
477 DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
478 fw->size, minsize, maxsize);
479 464
480 /* Check the size of the blob befoe examining buffer contents */ 465 /* Check the size of the blob before examining buffer contents */
481 if (fw->size < minsize || fw->size > maxsize) 466 if (fw->size < sizeof(struct guc_css_header)) {
467 DRM_ERROR("Firmware header is missing\n");
482 goto fail; 468 goto fail;
469 }
470
471 css = (struct guc_css_header *)fw->data;
472
473 /* Firmware bits always start from header */
474 guc_fw->header_offset = 0;
475 guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
476 css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
477
478 if (guc_fw->header_size != sizeof(struct guc_css_header)) {
479 DRM_ERROR("CSS header definition mismatch\n");
480 goto fail;
481 }
482
483 /* then, uCode */
484 guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size;
485 guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
486
487 /* now RSA */
488 if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
489 DRM_ERROR("RSA key size is bad\n");
490 goto fail;
491 }
492 guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
493 guc_fw->rsa_size = css->key_size_dw * sizeof(u32);
494
495 /* At least, it should have header, uCode and RSA. Size of all three. */
496 size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
497 if (fw->size < size) {
498 DRM_ERROR("Missing firmware components\n");
499 goto fail;
500 }
501
502 /* Header and uCode will be loaded to WOPCM. Size of the two. */
503 size = guc_fw->header_size + guc_fw->ucode_size;
504
505 /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
506 if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
507 DRM_ERROR("Firmware is too large to fit in WOPCM\n");
508 goto fail;
509 }
483 510
484 /* 511 /*
485 * The GuC firmware image has the version number embedded at a well-known 512 * The GuC firmware image has the version number embedded at a well-known
@@ -487,9 +514,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
487 * TWO bytes each (i.e. u16), although all pointers and offsets are defined 514 * TWO bytes each (i.e. u16), although all pointers and offsets are defined
488 * in terms of bytes (u8). 515 * in terms of bytes (u8).
489 */ 516 */
490 css_header = fw->data + UOS_CSS_HEADER_OFFSET; 517 guc_fw->guc_fw_major_found = css->guc_sw_version >> 16;
491 guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET); 518 guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF;
492 guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
493 519
494 if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted || 520 if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
495 guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) { 521 guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
@@ -566,6 +592,9 @@ void intel_guc_ucode_init(struct drm_device *dev)
566 fw_path = ""; /* unknown device */ 592 fw_path = ""; /* unknown device */
567 } 593 }
568 594
595 if (!i915.enable_guc_submission)
596 return;
597
569 guc_fw->guc_dev = dev; 598 guc_fw->guc_dev = dev;
570 guc_fw->guc_fw_path = fw_path; 599 guc_fw->guc_fw_path = fw_path;
571 guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE; 600 guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;