[v12,10/17] drm/i915/guc/slpc: Add parameter set/unset/get, task control/status functions
diff mbox

Message ID 1522398722-12161-11-git-send-email-sagar.a.kamble@intel.com
State New
Headers show

Commit Message

sagar.a.kamble@intel.com March 30, 2018, 8:31 a.m. UTC
SLPC behavior can be changed through set of parameters. These parameters
can be updated and queried from i915 though Host to GuC SLPC events. This
patch adds parameter update events for setting/unsetting/getting params.
Setting parameter leads to overridding of default parameter value. Unset
leads to restoring of default value by communicating with GuC SLPC through
parameter updates in the shared data.
i915 can only query/get parameters that it overrides, so getting parameter
value is done by only reading from the shared data.

SLPC has various tasks, GTPERF, BALANCER and DCC. These can be controlled
through pair of GuC SLPC parameters. Enable/disable of these tasks require
combined update to both parameters hence new actions are added to control
and query the status of tasks.

v1: Use host2guc_slpc. Update slcp_param_id enum values for SLPC 2015.2.4
    Return void instead of ignored error code (Paulo)

v2: Checkpatch update.

v3: Rebase.

v4: Updated with GuC firmware v9.

v5: Updated input structure to host2guc_slpc. Added functions to update
    only parameters in the SLPC shared memory. This will allow to setup
    shared data with all parameters and send single event to SLPC take
    them into effect. Commit message update. (Sagar)

v6: Rearranged helpers to use them in slpc_shared_data_init. Added defn.
    of SLPC_KMD_MAX_PARAM.

v7: Added definition of host2guc_slpc with rearrangement of patches. Added
    task control/status functions.

v8: Rebase w.r.t s/intel_guc_send/intel_guc_send_mmio.

v9: Created intel_guc_slpc_send_mmio with SLPC specific H2G action send
    function. Rebase. Defined slpc_statuslist and using the same in
    intel_guc_slpc_send_mmio. (Michal Wajdeczko)

v10: Rebase. Added kernel documentation to the task control functions.

Signed-off-by: Tom O'Rourke <Tom.O'Rourke@intel.com>
Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com>
Cc: Jeff McGee <jeff.mcgee@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_slpc.c | 173 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_slpc.h |   5 +
 2 files changed, 178 insertions(+)

Comments

Michal Wajdeczko May 14, 2018, 11:26 a.m. UTC | #1
On Fri, 30 Mar 2018 10:31:55 +0200, Sagar Arun Kamble  
<sagar.a.kamble@intel.com> wrote:

> SLPC behavior can be changed through set of parameters. These parameters
> can be updated and queried from i915 though Host to GuC SLPC events. This
> patch adds parameter update events for setting/unsetting/getting params.
> Setting parameter leads to overridding of default parameter value. Unset
> leads to restoring of default value by communicating with GuC SLPC  
> through
> parameter updates in the shared data.
> i915 can only query/get parameters that it overrides, so getting  
> parameter
> value is done by only reading from the shared data.
>
> SLPC has various tasks, GTPERF, BALANCER and DCC. These can be controlled
> through pair of GuC SLPC parameters. Enable/disable of these tasks  
> require
> combined update to both parameters hence new actions are added to control
> and query the status of tasks.
>
> v1: Use host2guc_slpc. Update slcp_param_id enum values for SLPC 2015.2.4
>     Return void instead of ignored error code (Paulo)
>
> v2: Checkpatch update.
>
> v3: Rebase.
>
> v4: Updated with GuC firmware v9.
>
> v5: Updated input structure to host2guc_slpc. Added functions to update
>     only parameters in the SLPC shared memory. This will allow to setup
>     shared data with all parameters and send single event to SLPC take
>     them into effect. Commit message update. (Sagar)
>
> v6: Rearranged helpers to use them in slpc_shared_data_init. Added defn.
>     of SLPC_KMD_MAX_PARAM.
>
> v7: Added definition of host2guc_slpc with rearrangement of patches.  
> Added
>     task control/status functions.
>
> v8: Rebase w.r.t s/intel_guc_send/intel_guc_send_mmio.
>
> v9: Created intel_guc_slpc_send_mmio with SLPC specific H2G action send
>     function. Rebase. Defined slpc_statuslist and using the same in
>     intel_guc_slpc_send_mmio. (Michal Wajdeczko)
>
> v10: Rebase. Added kernel documentation to the task control functions.
>
> Signed-off-by: Tom O'Rourke <Tom.O'Rourke@intel.com>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg@intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
> Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com>
> Cc: Jeff McGee <jeff.mcgee@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc_slpc.c | 173  
> ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_guc_slpc.h |   5 +
>  2 files changed, 178 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.c  
> b/drivers/gpu/drm/i915/intel_guc_slpc.c
> index bdafbaa..011e442 100644
> --- a/drivers/gpu/drm/i915/intel_guc_slpc.c
> +++ b/drivers/gpu/drm/i915/intel_guc_slpc.c
> @@ -404,6 +404,179 @@ static void host2guc_slpc_tdr_reset(struct  
> intel_guc_slpc *slpc)
>  	slpc_send(slpc, &data, 5);
>  }
> +static void host2guc_slpc_set_param(struct intel_guc_slpc *slpc,
> +				    u32 id, u32 value)

s/host2guc_slpc_set_param/slpc_send_set_param

and in general (not sure if already discussed this):
s/host2guc_slpc_/slpc_send_


> +{
> +	struct slpc_event_input data = {0};
> +
> +	data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_SET, 2);
> +	data.args[0] = id;
> +	data.args[1] = value;
> +
> +	slpc_send(slpc, &data, 4);
> +}
> +
> +static void host2guc_slpc_unset_param(struct intel_guc_slpc *slpc,
> +				      u32 id)
> +{
> +	struct slpc_event_input data = {0};
> +
> +	data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1);
> +	data.args[0] = id;
> +
> +	slpc_send(slpc, &data, 3);
> +}
> +
> +static void slpc_set_param(struct intel_guc_slpc *slpc, u32 id, u32  
> value)
> +{
> +	struct slpc_shared_data *data = NULL;
> +	struct page *page;
> +
> +	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
> +	GEM_BUG_ON(!slpc->vma);
> +
> +	lockdep_assert_held(&slpc->lock);
> +
> +	page = i915_vma_first_page(slpc->vma);
> +	data = kmap_atomic(page);
> +	slpc_mem_set_param(data, id, value);

hmm, why we have to pass param value by two mechanisms?
what if 'send' fails or slpc rejects that value?

> +	kunmap_atomic(data);
> +
> +	host2guc_slpc_set_param(slpc, id, value);
> +}
> +
> +static void slpc_unset_param(struct intel_guc_slpc *slpc, u32 id)
> +{
> +	struct slpc_shared_data *data = NULL;
> +	struct page *page;
> +
> +	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
> +	GEM_BUG_ON(!slpc->vma);
> +
> +	lockdep_assert_held(&slpc->lock);
> +
> +	page = i915_vma_first_page(slpc->vma);
> +	data = kmap_atomic(page);
> +	slpc_mem_unset_param(data, id);
> +	kunmap_atomic(data);
> +
> +	host2guc_slpc_unset_param(slpc, id);
> +}
> +
> +static void slpc_get_param(struct intel_guc_slpc *slpc, u32 id,
> +			   int *overriding, u32 *value)
> +{
> +	struct slpc_shared_data *data = NULL;
> +	struct page *page;
> +	u32 bits;
> +
> +	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
> +	GEM_BUG_ON(!slpc->vma);
> +
> +	lockdep_assert_held(&slpc->lock);
> +
> +	page = i915_vma_first_page(slpc->vma);
> +	data = kmap_atomic(page);
> +	if (overriding) {
> +		bits = data->override_params_set_bits[id >> 5];
> +		*overriding = (0 != (bits & (1 << (id % 32))));
> +	}
> +	if (value)
> +		*value = data->override_params_values[id];
> +
> +	kunmap_atomic(data);
> +}
> +
> +/**
> + * intel_guc_slpc_task_control() - Update status of SLPC task.
> + * @slpc: pointer to intel_guc_slpc.
> + *
> + * This function will update status of task in SLPC shared data.
> + * Then it invokes SLPC Host to GuC action to communicate the
> + * required task status.
> + *
> + * Return: 0 on success, non-zero error code on failure.
> + */
> +int intel_guc_slpc_task_control(struct intel_guc_slpc *slpc, u64 val,
> +				u32 enable_id, u32 disable_id)
> +{
> +	int ret = 0;
> +
> +	GEM_BUG_ON(!slpc->vma);
> +
> +	lockdep_assert_held(&slpc->lock);
> +
> +	if (val == SLPC_PARAM_TASK_DEFAULT) {
> +		/* set default */

please drop these comments

> +		slpc_unset_param(slpc, enable_id);
> +		slpc_unset_param(slpc, disable_id);
> +	} else if (val == SLPC_PARAM_TASK_ENABLED) {
> +		/* set enable */
> +		slpc_set_param(slpc, enable_id, 1);
> +		slpc_unset_param(slpc, disable_id);
> +	} else if (val == SLPC_PARAM_TASK_DISABLED) {
> +		/* set disable */
> +		slpc_set_param(slpc, disable_id, 1);
> +		slpc_unset_param(slpc, enable_id);
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	host2guc_slpc_reset(slpc);
> +
> +	return ret;
> +}
> +
> +/**
> + * intel_guc_slpc_task_status() - gets the status of SLPC task.
> + * @slpc: pointer to intel_guc_slpc.
> + *
> + * This function will read status of task from SLPC shared data.
> + * Task could be in either "enabled", "disabled", "default" or
> + * "unknown" state.
> + *
> + * Return: 0 on success, non-zero error code on failure.
> + */
> +int intel_guc_slpc_task_status(struct intel_guc_slpc *slpc, u64 *val,
> +			       u32 enable_id, u32 disable_id)
> +{
> +	int override_enable, override_disable;
> +	u32 value_enable, value_disable;
> +	int ret = 0;
> +
> +	GEM_BUG_ON(!slpc->vma);

iirc, bkm is that we should not check against null ptr

> +
> +	lockdep_assert_held(&slpc->lock);
> +
> +	if (val) {
> +		slpc_get_param(slpc, enable_id,
> +			       &override_enable, &value_enable);
> +		slpc_get_param(slpc, disable_id,
> +			       &override_disable, &value_disable);
> +
> +		/*
> +		 * Set the output value:
> +		 * 0: default
> +		 * 1: enabled
> +		 * 2: disabled
> +		 * 3: unknown (should not happen)
> +		 */
> +		if (override_disable && value_disable == 1)
> +			*val = SLPC_PARAM_TASK_DISABLED;
> +		else if (override_enable && value_enable == 1)
> +			*val = SLPC_PARAM_TASK_ENABLED;
> +		else if (!override_enable && !override_disable)
> +			*val = SLPC_PARAM_TASK_DEFAULT;
> +		else
> +			*val = SLPC_PARAM_TASK_UNKNOWN;
> +
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>  /**
>   * intel_guc_slpc_init() - Initialize the SLPC shared data structure.
>   * @slpc: pointer to intel_guc_slpc.
> diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.h  
> b/drivers/gpu/drm/i915/intel_guc_slpc.h
> index 75f0b5d..87b504d 100644
> --- a/drivers/gpu/drm/i915/intel_guc_slpc.h
> +++ b/drivers/gpu/drm/i915/intel_guc_slpc.h
> @@ -14,6 +14,11 @@ struct intel_guc_slpc {
>  	struct i915_vma *vma;
>  };
> +int intel_guc_slpc_task_control(struct intel_guc_slpc *slpc, u64 val,
> +				u32 enable_id, u32 disable_id);
> +int intel_guc_slpc_task_status(struct intel_guc_slpc *slpc, u64 *val,
> +			       u32 enable_id, u32 disable_id);
> +
>  int intel_guc_slpc_init(struct intel_guc_slpc *slpc);
>  int intel_guc_slpc_enable(struct intel_guc_slpc *slpc);
>  void intel_guc_slpc_handle_engine_reset(struct intel_guc_slpc *slpc);

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.c b/drivers/gpu/drm/i915/intel_guc_slpc.c
index bdafbaa..011e442 100644
--- a/drivers/gpu/drm/i915/intel_guc_slpc.c
+++ b/drivers/gpu/drm/i915/intel_guc_slpc.c
@@ -404,6 +404,179 @@  static void host2guc_slpc_tdr_reset(struct intel_guc_slpc *slpc)
 	slpc_send(slpc, &data, 5);
 }
 
+static void host2guc_slpc_set_param(struct intel_guc_slpc *slpc,
+				    u32 id, u32 value)
+{
+	struct slpc_event_input data = {0};
+
+	data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_SET, 2);
+	data.args[0] = id;
+	data.args[1] = value;
+
+	slpc_send(slpc, &data, 4);
+}
+
+static void host2guc_slpc_unset_param(struct intel_guc_slpc *slpc,
+				      u32 id)
+{
+	struct slpc_event_input data = {0};
+
+	data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1);
+	data.args[0] = id;
+
+	slpc_send(slpc, &data, 3);
+}
+
+static void slpc_set_param(struct intel_guc_slpc *slpc, u32 id, u32 value)
+{
+	struct slpc_shared_data *data = NULL;
+	struct page *page;
+
+	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
+	GEM_BUG_ON(!slpc->vma);
+
+	lockdep_assert_held(&slpc->lock);
+
+	page = i915_vma_first_page(slpc->vma);
+	data = kmap_atomic(page);
+	slpc_mem_set_param(data, id, value);
+	kunmap_atomic(data);
+
+	host2guc_slpc_set_param(slpc, id, value);
+}
+
+static void slpc_unset_param(struct intel_guc_slpc *slpc, u32 id)
+{
+	struct slpc_shared_data *data = NULL;
+	struct page *page;
+
+	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
+	GEM_BUG_ON(!slpc->vma);
+
+	lockdep_assert_held(&slpc->lock);
+
+	page = i915_vma_first_page(slpc->vma);
+	data = kmap_atomic(page);
+	slpc_mem_unset_param(data, id);
+	kunmap_atomic(data);
+
+	host2guc_slpc_unset_param(slpc, id);
+}
+
+static void slpc_get_param(struct intel_guc_slpc *slpc, u32 id,
+			   int *overriding, u32 *value)
+{
+	struct slpc_shared_data *data = NULL;
+	struct page *page;
+	u32 bits;
+
+	GEM_BUG_ON(id >= SLPC_MAX_PARAM);
+	GEM_BUG_ON(!slpc->vma);
+
+	lockdep_assert_held(&slpc->lock);
+
+	page = i915_vma_first_page(slpc->vma);
+	data = kmap_atomic(page);
+	if (overriding) {
+		bits = data->override_params_set_bits[id >> 5];
+		*overriding = (0 != (bits & (1 << (id % 32))));
+	}
+	if (value)
+		*value = data->override_params_values[id];
+
+	kunmap_atomic(data);
+}
+
+/**
+ * intel_guc_slpc_task_control() - Update status of SLPC task.
+ * @slpc: pointer to intel_guc_slpc.
+ *
+ * This function will update status of task in SLPC shared data.
+ * Then it invokes SLPC Host to GuC action to communicate the
+ * required task status.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int intel_guc_slpc_task_control(struct intel_guc_slpc *slpc, u64 val,
+				u32 enable_id, u32 disable_id)
+{
+	int ret = 0;
+
+	GEM_BUG_ON(!slpc->vma);
+
+	lockdep_assert_held(&slpc->lock);
+
+	if (val == SLPC_PARAM_TASK_DEFAULT) {
+		/* set default */
+		slpc_unset_param(slpc, enable_id);
+		slpc_unset_param(slpc, disable_id);
+	} else if (val == SLPC_PARAM_TASK_ENABLED) {
+		/* set enable */
+		slpc_set_param(slpc, enable_id, 1);
+		slpc_unset_param(slpc, disable_id);
+	} else if (val == SLPC_PARAM_TASK_DISABLED) {
+		/* set disable */
+		slpc_set_param(slpc, disable_id, 1);
+		slpc_unset_param(slpc, enable_id);
+	} else {
+		ret = -EINVAL;
+	}
+
+	host2guc_slpc_reset(slpc);
+
+	return ret;
+}
+
+/**
+ * intel_guc_slpc_task_status() - gets the status of SLPC task.
+ * @slpc: pointer to intel_guc_slpc.
+ *
+ * This function will read status of task from SLPC shared data.
+ * Task could be in either "enabled", "disabled", "default" or
+ * "unknown" state.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int intel_guc_slpc_task_status(struct intel_guc_slpc *slpc, u64 *val,
+			       u32 enable_id, u32 disable_id)
+{
+	int override_enable, override_disable;
+	u32 value_enable, value_disable;
+	int ret = 0;
+
+	GEM_BUG_ON(!slpc->vma);
+
+	lockdep_assert_held(&slpc->lock);
+
+	if (val) {
+		slpc_get_param(slpc, enable_id,
+			       &override_enable, &value_enable);
+		slpc_get_param(slpc, disable_id,
+			       &override_disable, &value_disable);
+
+		/*
+		 * Set the output value:
+		 * 0: default
+		 * 1: enabled
+		 * 2: disabled
+		 * 3: unknown (should not happen)
+		 */
+		if (override_disable && value_disable == 1)
+			*val = SLPC_PARAM_TASK_DISABLED;
+		else if (override_enable && value_enable == 1)
+			*val = SLPC_PARAM_TASK_ENABLED;
+		else if (!override_enable && !override_disable)
+			*val = SLPC_PARAM_TASK_DEFAULT;
+		else
+			*val = SLPC_PARAM_TASK_UNKNOWN;
+
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 /**
  * intel_guc_slpc_init() - Initialize the SLPC shared data structure.
  * @slpc: pointer to intel_guc_slpc.
diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.h b/drivers/gpu/drm/i915/intel_guc_slpc.h
index 75f0b5d..87b504d 100644
--- a/drivers/gpu/drm/i915/intel_guc_slpc.h
+++ b/drivers/gpu/drm/i915/intel_guc_slpc.h
@@ -14,6 +14,11 @@  struct intel_guc_slpc {
 	struct i915_vma *vma;
 };
 
+int intel_guc_slpc_task_control(struct intel_guc_slpc *slpc, u64 val,
+				u32 enable_id, u32 disable_id);
+int intel_guc_slpc_task_status(struct intel_guc_slpc *slpc, u64 *val,
+			       u32 enable_id, u32 disable_id);
+
 int intel_guc_slpc_init(struct intel_guc_slpc *slpc);
 int intel_guc_slpc_enable(struct intel_guc_slpc *slpc);
 void intel_guc_slpc_handle_engine_reset(struct intel_guc_slpc *slpc);