aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Gordon <david.s.gordon@intel.com>2016-06-13 12:57:34 -0400
committerTvrtko Ursulin <tvrtko.ursulin@intel.com>2016-06-14 10:04:08 -0400
commit4d75787b8752cc5113462bc9a3c212ff726928ae (patch)
tree786cf8a5eacec5b547c046021af5928e7adb5797
parentf10d69a76b11c9a2137393b042d18cd903dbd9e3 (diff)
drm/i915/guc: (re)initialise doorbell h/w when enabling GuC submission
During a hibernate/resume cycle, the whole system is reset, including the GuC and the doorbell hardware. Then the system is booted up, drivers are loaded, etc -- the GuC firmware may be loaded and set running at this point. But then, the booted kernel is replaced by the hibernated image, and this resumed kernel will also try to reload the GuC firmware (which will fail). To recover, we reset the GuC and try again (which should work). But this GuC reset doesn't also reset the doorbell hardware, so it can be left in a state inconsistent with that assumed by the driver and/or the newly-loaded GuC firmware. It would be better if the GuC reset also cleared all doorbell state, but that's not how the hardware currently works; also, the driver cannot directly reprogram the doorbell hardware (only the GuC can do that). So this patch cycles through all doorbells, assigning and releasing each in turn, so that all the doorbell hardware is left in a consistent state, no matter how it was programmed by the previously-running kernel and/or GuC firmware. v2: don't use kmap_atomic() now that client page 0 is kept mapped. Signed-off-by: Dave Gordon <david.s.gordon@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1465837054-16245-2-git-send-email-david.s.gordon@intel.com
-rw-r--r--drivers/gpu/drm/i915/i915_guc_submission.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index a25250570bb5..22a55ac4e51c 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -693,6 +693,48 @@ guc_client_free(struct drm_i915_private *dev_priv,
693 kfree(client); 693 kfree(client);
694} 694}
695 695
696/*
697 * Borrow the first client to set up & tear down every doorbell
698 * in turn, to ensure that all doorbell h/w is (re)initialised.
699 */
700static void guc_init_doorbell_hw(struct intel_guc *guc)
701{
702 struct drm_i915_private *dev_priv = guc_to_i915(guc);
703 struct i915_guc_client *client = guc->execbuf_client;
704 uint16_t db_id, i;
705 int err;
706
707 db_id = client->doorbell_id;
708
709 for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
710 i915_reg_t drbreg = GEN8_DRBREGL(i);
711 u32 value = I915_READ(drbreg);
712
713 err = guc_update_doorbell_id(guc, client, i);
714
715 /* Report update failure or unexpectedly active doorbell */
716 if (err || (i != db_id && (value & GUC_DOORBELL_ENABLED)))
717 DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) was 0x%x, err %d\n",
718 i, drbreg.reg, value, err);
719 }
720
721 /* Restore to original value */
722 err = guc_update_doorbell_id(guc, client, db_id);
723 if (err)
724 DRM_ERROR("Failed to restore doorbell to %d, err %d\n",
725 db_id, err);
726
727 for (i = 0; i < GUC_MAX_DOORBELLS; ++i) {
728 i915_reg_t drbreg = GEN8_DRBREGL(i);
729 u32 value = I915_READ(drbreg);
730
731 if (i != db_id && (value & GUC_DOORBELL_ENABLED))
732 DRM_DEBUG_DRIVER("Doorbell %d (reg 0x%x) finally 0x%x\n",
733 i, drbreg.reg, value);
734
735 }
736}
737
696/** 738/**
697 * guc_client_alloc() - Allocate an i915_guc_client 739 * guc_client_alloc() - Allocate an i915_guc_client
698 * @dev_priv: driver private data structure 740 * @dev_priv: driver private data structure
@@ -956,8 +998,8 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
956 } 998 }
957 999
958 guc->execbuf_client = client; 1000 guc->execbuf_client = client;
959
960 host2guc_sample_forcewake(guc, client); 1001 host2guc_sample_forcewake(guc, client);
1002 guc_init_doorbell_hw(guc);
961 1003
962 return 0; 1004 return 0;
963} 1005}