diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_guc.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_guc.c | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 230aea69385d..8660af3fd755 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c | |||
@@ -50,7 +50,8 @@ void intel_guc_init_send_regs(struct intel_guc *guc) | |||
50 | unsigned int i; | 50 | unsigned int i; |
51 | 51 | ||
52 | guc->send_regs.base = i915_mmio_reg_offset(SOFT_SCRATCH(0)); | 52 | guc->send_regs.base = i915_mmio_reg_offset(SOFT_SCRATCH(0)); |
53 | guc->send_regs.count = SOFT_SCRATCH_COUNT - 1; | 53 | guc->send_regs.count = GUC_MAX_MMIO_MSG_LEN; |
54 | BUILD_BUG_ON(GUC_MAX_MMIO_MSG_LEN > SOFT_SCRATCH_COUNT); | ||
54 | 55 | ||
55 | for (i = 0; i < guc->send_regs.count; i++) { | 56 | for (i = 0; i < guc->send_regs.count; i++) { |
56 | fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, | 57 | fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, |
@@ -521,6 +522,44 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset) | |||
521 | return intel_guc_send(guc, action, ARRAY_SIZE(action)); | 522 | return intel_guc_send(guc, action, ARRAY_SIZE(action)); |
522 | } | 523 | } |
523 | 524 | ||
525 | /* | ||
526 | * The ENTER/EXIT_S_STATE actions queue the save/restore operation in GuC FW and | ||
527 | * then return, so waiting on the H2G is not enough to guarantee GuC is done. | ||
528 | * When all the processing is done, GuC writes INTEL_GUC_SLEEP_STATE_SUCCESS to | ||
529 | * scratch register 14, so we can poll on that. Note that GuC does not ensure | ||
530 | * that the value in the register is different from | ||
531 | * INTEL_GUC_SLEEP_STATE_SUCCESS while the action is in progress so we need to | ||
532 | * take care of that ourselves as well. | ||
533 | */ | ||
534 | static int guc_sleep_state_action(struct intel_guc *guc, | ||
535 | const u32 *action, u32 len) | ||
536 | { | ||
537 | struct drm_i915_private *dev_priv = guc_to_i915(guc); | ||
538 | int ret; | ||
539 | u32 status; | ||
540 | |||
541 | I915_WRITE(SOFT_SCRATCH(14), INTEL_GUC_SLEEP_STATE_INVALID_MASK); | ||
542 | |||
543 | ret = intel_guc_send(guc, action, len); | ||
544 | if (ret) | ||
545 | return ret; | ||
546 | |||
547 | ret = __intel_wait_for_register(dev_priv, SOFT_SCRATCH(14), | ||
548 | INTEL_GUC_SLEEP_STATE_INVALID_MASK, | ||
549 | 0, 0, 10, &status); | ||
550 | if (ret) | ||
551 | return ret; | ||
552 | |||
553 | if (status != INTEL_GUC_SLEEP_STATE_SUCCESS) { | ||
554 | DRM_ERROR("GuC failed to change sleep state. " | ||
555 | "action=0x%x, err=%u\n", | ||
556 | action[0], status); | ||
557 | return -EIO; | ||
558 | } | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
524 | /** | 563 | /** |
525 | * intel_guc_suspend() - notify GuC entering suspend state | 564 | * intel_guc_suspend() - notify GuC entering suspend state |
526 | * @guc: the guc | 565 | * @guc: the guc |
@@ -533,7 +572,7 @@ int intel_guc_suspend(struct intel_guc *guc) | |||
533 | intel_guc_ggtt_offset(guc, guc->shared_data) | 572 | intel_guc_ggtt_offset(guc, guc->shared_data) |
534 | }; | 573 | }; |
535 | 574 | ||
536 | return intel_guc_send(guc, data, ARRAY_SIZE(data)); | 575 | return guc_sleep_state_action(guc, data, ARRAY_SIZE(data)); |
537 | } | 576 | } |
538 | 577 | ||
539 | /** | 578 | /** |
@@ -571,7 +610,7 @@ int intel_guc_resume(struct intel_guc *guc) | |||
571 | intel_guc_ggtt_offset(guc, guc->shared_data) | 610 | intel_guc_ggtt_offset(guc, guc->shared_data) |
572 | }; | 611 | }; |
573 | 612 | ||
574 | return intel_guc_send(guc, data, ARRAY_SIZE(data)); | 613 | return guc_sleep_state_action(guc, data, ARRAY_SIZE(data)); |
575 | } | 614 | } |
576 | 615 | ||
577 | /** | 616 | /** |