[PATCH v12 07/17] drm/i915/guc/slpc: Send RESET event to restart/enable SLPC tasks

Sagar Arun Kamble sagar.a.kamble at intel.com
Thu Mar 29 18:59:27 UTC 2018


Host to GuC actions for SLPC receive additional data as output through
scratch registers currently. intel_guc_send_and_receive handles this.
We need to define SLPC specific Host to GuC send action (slpc_send) as
wrapper on top of it to process the SLPC status that is received in
SOFT_SCRATCH(1).

Send host2guc SLPC reset event to GuC post GuC load for enabling SLPC.
Post this, i915 can ascertain if SLPC has started running successfully
through shared data. This check is done by waiting for maximum 5ms.
SLPC reset event also needs to be sent when parameters in shared data
are updated.

v1: Extract host2guc_slpc to handle slpc status code and style changes.
    (Paulo). Removed WARN_ON for checking msb of gtt address of shared
     gem obj. (Chris). host2guc_action to i915_guc_action change.(Sagar)
    Updating SLPC enabled status. (Sagar)

v2: Commit message update. (David)

v3: Rebase.

v4: Added DRM_INFO message when SLPC is enabled.

v5: Updated patch as host2guc_slpc is moved to earlier patch. SLPC
    activation status message put after checking the state from shared
    data during intel_init_gt_powersave.

v6: Added definition of host2guc_slpc and clflush the shared data only
    for required size. Setting state to NOT_RUNNING before sending RESET
    event. Output data for SLPC actions is to be retrieved during
    intel_guc_send with lock protection so created wrapper
    __intel_guc_send that outputs GuC output data if needed. Clearing
    pm_rps_events on confirming SLPC RUNNING status so that even if
    host touches any of the PM registers by mistake it should not have
    any effect. (Sagar)

v7: Added save/restore_default_rps as Uncore sanitize will clear the
    RP_CONTROL setup by BIOS. s/i915_ggtt_offset/guc_ggtt_offset.

v8: Added support for handling TDR based SLPC reset. Added functions
    host2guc_slpc_tdr_reset, intel_slpc_reset_prepare and
    intel_slpc_tdr_reset to handle TDR based SLPC reset.

v9: Moved TDR support to later patch. Removed intel_slpc_get_status
    and waiting for maximum of 5ms for SLPC state to turn RUNNING instead
    of hiding the latency across uc_init_hw and init_gt_powersave.
    s/if..else/switch..case in intel_guc_slpc_get_state_str. Removed SLPC
    sanitization from init_gt_powersave. (Michal Wajdeczko)

v10: Rebase.

v11: Rebase. Created slpc_send func as wrapper on guc_send_and_receive.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg at intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
Cc: Sujaritha Sundaresan <sujaritha.sundaresan at intel.com>
Cc: Jeff McGee <jeff.mcgee at intel.com>
---
 drivers/gpu/drm/i915/intel_guc_slpc.c | 158 ++++++++++++++++++++++++++++++++++
 1 file changed, 158 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.c b/drivers/gpu/drm/i915/intel_guc_slpc.c
index 974a3c0..ab367af 100644
--- a/drivers/gpu/drm/i915/intel_guc_slpc.c
+++ b/drivers/gpu/drm/i915/intel_guc_slpc.c
@@ -163,6 +163,130 @@ static void slpc_shared_data_init(struct intel_guc_slpc *slpc)
 	kunmap_atomic(data);
 }
 
+static void slpc_send(struct intel_guc_slpc *slpc,
+		      struct slpc_event_input *input, u32 in_len)
+{
+	struct intel_guc *guc = slpc_to_guc(slpc);
+	struct slpc_event_output output;
+	u32 out_len = 1;
+	u32 *action;
+	int ret;
+
+	action = (u32 *)input;
+	action[0] = INTEL_GUC_ACTION_SLPC_REQUEST;
+
+	ret = intel_guc_send_and_receive(guc, action, in_len,
+					 (u32 *)&output.header, out_len);
+
+	/*
+	 * Currently output data from Host to GuC SLPC actions is populated
+	 * in scratch registers SOFT_SCRATCH(1) to SOFT_SCRATCH(14) based
+	 * on event. Currently only SLPC action status in GuC is meaningful
+	 * as Host can query only overridden parameters and that are fetched
+	 * from Host-GuC SLPC shared data. Other parameters can be read through
+	 * output data but that is available only for debug GuC firmwares.
+	 */
+	if (!ret)
+		ret = output.header.status;
+
+	if (ret)
+		DRM_ERROR("event 0x%x status %s\n",
+			  ((output.header.value & 0xFF00) >> 8),
+			  slpc_status[ret]);
+}
+
+static void host2guc_slpc_reset(struct intel_guc_slpc *slpc)
+{
+	struct intel_guc *guc = slpc_to_guc(slpc);
+	u32 shared_data_gtt_offset = intel_guc_ggtt_offset(guc, slpc->vma);
+	struct slpc_event_input data = {0};
+
+	data.header.value = SLPC_EVENT(SLPC_EVENT_RESET, 2);
+	data.args[0] = shared_data_gtt_offset;
+	data.args[1] = 0;
+
+	slpc_send(slpc, &data, 4);
+}
+
+static void host2guc_slpc_query_task_state(struct intel_guc_slpc *slpc)
+{
+	struct intel_guc *guc = slpc_to_guc(slpc);
+	u32 shared_data_gtt_offset = intel_guc_ggtt_offset(guc, slpc->vma);
+	struct slpc_event_input data = {0};
+
+	data.header.value = SLPC_EVENT(SLPC_EVENT_QUERY_TASK_STATE, 2);
+	data.args[0] = shared_data_gtt_offset;
+	data.args[1] = 0;
+
+	slpc_send(slpc, &data, 4);
+}
+
+static void slpc_read_shared_data(struct intel_guc_slpc *slpc,
+				  struct slpc_shared_data *data)
+{
+	struct page *page;
+	void *pv = NULL;
+
+	host2guc_slpc_query_task_state(slpc);
+
+	page = i915_vma_first_page(slpc->vma);
+	pv = kmap_atomic(page);
+
+	drm_clflush_virt_range(pv, sizeof(struct slpc_shared_data));
+	memcpy(data, pv, sizeof(struct slpc_shared_data));
+
+	kunmap_atomic(pv);
+}
+
+static const char *slpc_state_stringify(enum slpc_global_state state)
+{
+	const char *str = NULL;
+
+	switch (state) {
+	case SLPC_GLOBAL_STATE_NOT_RUNNING:
+		str = "not running";
+		break;
+	case SLPC_GLOBAL_STATE_INITIALIZING:
+		str = "initializing";
+		break;
+	case SLPC_GLOBAL_STATE_RESETTING:
+		str = "resetting";
+		break;
+	case SLPC_GLOBAL_STATE_RUNNING:
+		str = "running";
+		break;
+	case SLPC_GLOBAL_STATE_SHUTTING_DOWN:
+		str = "shutting down";
+		break;
+	case SLPC_GLOBAL_STATE_ERROR:
+		str = "error";
+		break;
+	default:
+		str = "unknown";
+		break;
+	}
+
+	return str;
+}
+
+static const char *slpc_get_state(struct intel_guc_slpc *slpc)
+{
+	struct slpc_shared_data data;
+
+	slpc_read_shared_data(slpc, &data);
+
+	return slpc_state_stringify(data.global_state);
+}
+
+static bool slpc_running(struct intel_guc_slpc *slpc)
+{
+	struct slpc_shared_data data;
+
+	slpc_read_shared_data(slpc, &data);
+
+	return (data.global_state == SLPC_GLOBAL_STATE_RUNNING);
+}
+
 /**
  * intel_guc_slpc_init() - Initialize the SLPC shared data structure.
  * @slpc: pointer to intel_guc_slpc.
@@ -204,8 +328,42 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc)
 	return 0;
 }
 
+/**
+ * intel_guc_slpc_enable() - Start SLPC.
+ * @slpc: pointer to intel_guc_slpc.
+ *
+ * This function will start GuC SLPC by sending Host to GuC action.
+ * SLPC shared data has to be initialized prior to this by
+ * intel_guc_slpc_init().
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
 int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
 {
+	struct slpc_shared_data *data;
+	struct page *page;
+
+	mutex_lock(&slpc->lock);
+
+	page = i915_vma_first_page(slpc->vma);
+	data = kmap_atomic(page);
+	data->global_state = SLPC_GLOBAL_STATE_NOT_RUNNING;
+	kunmap_atomic(data);
+
+	host2guc_slpc_reset(slpc);
+
+	/* Check whether SLPC is running */
+	if (wait_for(slpc_running(slpc), 5)) {
+		DRM_ERROR("SLPC not enabled! State = %s\n",
+			  slpc_get_state(slpc));
+		mutex_unlock(&slpc->lock);
+		return -EIO;
+	}
+
+	DRM_INFO("SLPC state: %s\n", slpc_get_state(slpc));
+
+	mutex_unlock(&slpc->lock);
+
 	return 0;
 }
 
-- 
2.7.4



More information about the Intel-gfx-trybot mailing list