@@ -576,27 +576,80 @@ int intel_guc_suspend(struct intel_guc *guc)
return intel_guc_send(guc, data, ARRAY_SIZE(data));
}
+static inline void
+guc_set_class_under_reset(struct intel_guc *guc, unsigned int guc_class)
+{
+ GEM_BUG_ON(guc_class >= GUC_MAX_ENGINE_CLASSES);
+ bitmap32_set_bit(&guc->engine_class_under_reset, guc_class);
+}
+
+static inline void
+guc_clear_class_under_reset(struct intel_guc *guc, unsigned int guc_class)
+{
+ GEM_BUG_ON(guc_class >= GUC_MAX_ENGINE_CLASSES);
+ bitmap32_clear_bit(&guc->engine_class_under_reset, guc_class);
+}
+
+static inline bool
+guc_is_class_under_reset(struct intel_guc *guc, unsigned int guc_class)
+{
+ return bitmap32_test_bit(&guc->engine_class_under_reset, guc_class);
+}
+
+static int __guc_action_reset_engine(struct intel_guc *guc,
+ u32 guc_class,
+ u32 stage_id)
+{
+ u32 action[] = {
+ INTEL_GUC_ACTION_REQUEST_ENGINE_RESET,
+ guc_class,
+ stage_id,
+ };
+
+ return intel_guc_send(guc, action, ARRAY_SIZE(action));
+}
+
+#define GUC_ENGINE_RESET_COMPLETE_WAIT_MS 100
+
/**
* intel_guc_reset_engine() - ask GuC to reset an engine
* @guc: intel_guc structure
* @engine: engine to be reset
+ *
+ * Ask GuC to reset an engine. The firmware will send a separate
+ * ENGINE_RESET_COMPLETE message (with the engine's guc_class)
+ * to confirm that the reset has been completed.
*/
int intel_guc_reset_engine(struct intel_guc *guc,
struct intel_engine_cs *engine)
{
- u32 data[7];
+ struct intel_guc_client *client = guc->execbuf_client;
+ u32 guc_class = engine->guc_class;
+ int ret;
- GEM_BUG_ON(!guc->execbuf_client);
+ GEM_BUG_ON(guc_is_class_under_reset(guc, guc_class));
+ guc_set_class_under_reset(guc, guc_class);
- data[0] = INTEL_GUC_ACTION_REQUEST_ENGINE_RESET;
- data[1] = engine->guc_id;
- data[2] = 0;
- data[3] = 0;
- data[4] = 0;
- data[5] = guc->execbuf_client->stage_id;
- data[6] = intel_guc_ggtt_offset(guc, guc->shared_data);
+ ret = __guc_action_reset_engine(guc, guc_class, client->stage_id);
+ if (ret)
+ goto out;
- return intel_guc_send(guc, data, ARRAY_SIZE(data));
+ if ((wait_for(!guc_is_class_under_reset(guc, guc_class),
+ GUC_ENGINE_RESET_COMPLETE_WAIT_MS))) {
+ DRM_ERROR("reset_complete timed out, engine class %d\n",
+ engine->guc_class);
+ ret = -ETIMEDOUT;
+ }
+
+out:
+ /*
+ * Clear flag on any failure, we fall back to full reset in
+ * case of timeout/error.
+ */
+ if (ret)
+ guc_clear_class_under_reset(guc, guc_class);
+
+ return ret;
}
/**
@@ -74,6 +74,12 @@ struct intel_guc {
/* Cyclic counter mod pagesize */
u32 db_cacheline;
+ /*
+ * Track outstanding request-engine-reset h2g commands,
+ * accessed by set/clear/is_engine_class_under_reset
+ */
+ u32 engine_class_under_reset;
+
/* GuC's FW specific registers used in MMIO send */
struct {
u32 base;
Format of the ENGINE_RESET H2G message has been updated. Additionally, the firmware will send a G2H ENGINE_RESET_COMPLETE message (with the engine's guc_class in data[2]) to confirm that the reset has been completed (but this will be handled in a other patch). Requires GuC fw v25.161+. Credits-to: Michel Thierry <michel.thierry@intel.com> Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com> Cc: Michal Winiarski <michal.winiarski@intel.com> Cc: Tomasz Lis <tomasz.lis@intel.com> --- drivers/gpu/drm/i915/intel_guc.c | 73 ++++++++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_guc.h | 6 ++++ 2 files changed, 69 insertions(+), 10 deletions(-)