[Intel-gfx] [PATCH 20/31] drm/i915/slpc: Add parameter set/unset/get, task control/status functions

Michal Wajdeczko michal.wajdeczko at intel.com
Thu Sep 21 13:47:03 UTC 2017


On Tue, 19 Sep 2017 19:41:56 +0200, Sagar Arun Kamble  
<sagar.a.kamble at 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 parameters. SLPC has
> various tasks for controlling different controls. This patch
> adds functions to control and query the task status.
>
> 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 definition 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.
>
> Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
> Signed-off-by: Tom O'Rourke <Tom.O'Rourke at intel.com>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble at intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc.c  |  21 ++++-
>  drivers/gpu/drm/i915/intel_guc.h  |   2 +
>  drivers/gpu/drm/i915/intel_slpc.c | 185  
> ++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_slpc.h |   8 ++
>  4 files changed, 215 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_guc.c  
> b/drivers/gpu/drm/i915/intel_guc.c
> index a92c7e8..656bae9 100644
> --- a/drivers/gpu/drm/i915/intel_guc.c
> +++ b/drivers/gpu/drm/i915/intel_guc.c
> @@ -67,9 +67,11 @@ void intel_guc_init_send_regs(struct intel_guc *guc)
>  /*
>   * This function implements the MMIO based host to GuC interface.
>   */
> -int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32  
> len)
> +int __intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32  
> len,
> +			  u32 *output)
>  {
>  	struct drm_i915_private *dev_priv = guc_to_i915(guc);
> +	union slpc_event_output_header header;

Don't pollute generic send function with slpc specific code.


>  	u32 status;
>  	int i;
>  	int ret;
> @@ -115,12 +117,29 @@ int intel_guc_send_mmio(struct intel_guc *guc,  
> const u32 *action, u32 len)
>  			 action[0], ret, status, I915_READ(SOFT_SCRATCH(15)));
>  	}
> +	/*
> +	 * Output data from Host to GuC SLPC actions is populated in scratch
> +	 * registers SOFT_SCRATCH(1) to SOFT_SCRATCH(14) based on event.

Note that receiving more data over MMIO will be handled by these pending  
patches
	https://patchwork.freedesktop.org/patch/170667/
	https://patchwork.freedesktop.org/patch/170669/

The same series will also add support for responses over CT so stay tuned!

> +	 * 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.
> +	 */
> +	if (output && !ret) {
> +		output[0] = header.value = I915_READ(SOFT_SCRATCH(1));
> +		ret = header.status;
> +	}
> +
>  	intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains);
>  	mutex_unlock(&guc->send_mutex);
> 	return ret;
>  }
> +int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32  
> len)
> +{
> +	return __intel_guc_send_mmio(guc, action, len, NULL);
> +}
> +
>  int intel_guc_sample_forcewake(struct intel_guc *guc)
>  {
>  	struct drm_i915_private *dev_priv = guc_to_i915(guc);
> diff --git a/drivers/gpu/drm/i915/intel_guc.h  
> b/drivers/gpu/drm/i915/intel_guc.h
> index b835d30..c27d2dd 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -132,6 +132,8 @@ struct intel_guc {
>  int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32  
> len);
>  void gen8_guc_raise_irq(struct intel_guc *guc);
>  void intel_guc_init_send_regs(struct intel_guc *guc);
> +int __intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32  
> len,
> +			  u32 *output);
>  int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32  
> len);
>  int intel_guc_sample_forcewake(struct intel_guc *guc);
>  int intel_guc_runtime_suspend(struct intel_guc *guc);
> diff --git a/drivers/gpu/drm/i915/intel_slpc.c  
> b/drivers/gpu/drm/i915/intel_slpc.c
> index 73e7bf5..f47d81e 100644
> --- a/drivers/gpu/drm/i915/intel_slpc.c
> +++ b/drivers/gpu/drm/i915/intel_slpc.c
> @@ -132,6 +132,191 @@ int slpc_mem_task_control(struct slpc_shared_data  
> *data, u64 val,
>  	return ret;
>  }
> +static void host2guc_slpc(struct intel_slpc *slpc,
> +			  struct slpc_event_input *input, u32 len)
> +{
> +	struct intel_guc *guc = slpc_to_guc(slpc);
> +	u32 *data;
> +	u32 output[SLPC_EVENT_MAX_OUTPUT_ARGS];
> +	int ret = 0;
> +
> +	/*
> +	 * We have only 15 scratch registers for communication.
> +	 * the first we will use for the event ID in input and
> +	 * output data. Event processing status will be present
> +	 * in SOFT_SCRATCH(1) register.
> +	 */
> +	BUILD_BUG_ON(SLPC_EVENT_MAX_INPUT_ARGS > 14);
> +	BUILD_BUG_ON(SLPC_EVENT_MAX_OUTPUT_ARGS < 1);
> +	BUILD_BUG_ON(SLPC_EVENT_MAX_OUTPUT_ARGS > 14);
> +
> +	data = (u32 *) input;
> +	data[0] = INTEL_GUC_ACTION_SLPC_REQUEST;
> +	ret = __intel_guc_send_mmio(guc, data, len, output);
> +
> +	if (ret)
> +		DRM_ERROR("event 0x%x status %d\n",
> +			  ((output[0] & 0xFF00) >> 8), ret);
> +}
> +
> +static void host2guc_slpc_set_param(struct intel_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;
> +
> +	host2guc_slpc(slpc, &data, 4);
> +}
> +
> +static void host2guc_slpc_unset_param(struct intel_slpc *slpc,
> +				      u32 id)
> +{
> +	struct slpc_event_input data = {0};
> +
> +	data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1);
> +	data.args[0] = id;
> +
> +	host2guc_slpc(slpc, &data, 3);
> +}
> +
> +void intel_slpc_set_param(struct intel_slpc *slpc,
> +			  u32 id,
> +			  u32 value)
> +{
> +	struct page *page;
> +	struct slpc_shared_data *data = NULL;
> +
> +	WARN_ON(id >= SLPC_MAX_PARAM);
> +
> +	if (!slpc->vma)
> +		return;
> +
> +	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);
> +}
> +
> +void intel_slpc_unset_param(struct intel_slpc *slpc,
> +			    u32 id)
> +{
> +	struct page *page;
> +	struct slpc_shared_data *data = NULL;
> +
> +	WARN_ON(id >= SLPC_MAX_PARAM);
> +
> +	if (!slpc->vma)
> +		return;
> +
> +	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);
> +}
> +
> +void intel_slpc_get_param(struct intel_slpc *slpc,
> +			  u32 id,
> +			  int *overriding, u32 *value)
> +{
> +	struct page *page;
> +	struct slpc_shared_data *data = NULL;
> +	u32 bits;
> +
> +	WARN_ON(id >= SLPC_MAX_PARAM);
> +
> +	if (!slpc->vma)
> +		return;
> +
> +	page = i915_vma_first_page(slpc->vma);
> +	data = kmap_atomic(page);
> +	if (overriding) {
> +		bits = data->override_parameters_set_bits[id >> 5];
> +		*overriding = (0 != (bits & (1 << (id % 32))));
> +	}
> +	if (value)
> +		*value = data->override_parameters_values[id];
> +
> +	kunmap_atomic(data);
> +}
> +
> +int intel_slpc_task_control(struct intel_slpc *slpc, u64 val,
> +			    u32 enable_id, u32 disable_id)
> +{
> +	struct drm_i915_private *dev_priv = slpc_to_i915(slpc);
> +	int ret = 0;
> +
> +	if (!slpc->active)
> +		return -ENODEV;
> +
> +	intel_runtime_pm_get(dev_priv);
> +
> +	if (val == SLPC_PARAM_TASK_DEFAULT) {
> +		/* set default */
> +		intel_slpc_unset_param(slpc, enable_id);
> +		intel_slpc_unset_param(slpc, disable_id);
> +	} else if (val == SLPC_PARAM_TASK_ENABLED) {
> +		/* set enable */
> +		intel_slpc_set_param(slpc, enable_id, 1);
> +		intel_slpc_unset_param(slpc, disable_id);
> +	} else if (val == SLPC_PARAM_TASK_DISABLED) {
> +		/* set disable */
> +		intel_slpc_set_param(slpc, disable_id, 1);
> +		intel_slpc_unset_param(slpc, enable_id);
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	intel_slpc_enable(slpc);
> +	intel_runtime_pm_put(dev_priv);
> +
> +	return ret;
> +}
> +
> +int intel_slpc_task_status(struct intel_slpc *slpc, u64 *val,
> +			   u32 enable_id, u32 disable_id)
> +{
> +	int override_enable, override_disable;
> +	u32 value_enable, value_disable;
> +	int ret = 0;
> +
> +	if (!slpc->active) {
> +		ret = -ENODEV;
> +	} else if (val) {
> +		intel_slpc_get_param(slpc, enable_id, &override_enable,
> +				     &value_enable);
> +		intel_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;
> +}
> +
>  static void slpc_shared_data_init(struct intel_slpc *slpc)
>  {
>  	struct drm_i915_private *dev_priv = slpc_to_i915(slpc);
> diff --git a/drivers/gpu/drm/i915/intel_slpc.h  
> b/drivers/gpu/drm/i915/intel_slpc.h
> index 9312b2f..0ff17f0 100644
> --- a/drivers/gpu/drm/i915/intel_slpc.h
> +++ b/drivers/gpu/drm/i915/intel_slpc.h
> @@ -247,6 +247,14 @@ struct slpc_param {
>  #define SLPC_PARAM_TASK_UNKNOWN  3
> /* intel_slpc.c */
> +void intel_slpc_set_param(struct intel_slpc *slpc, u32 id, u32 value);
> +void intel_slpc_unset_param(struct intel_slpc *slpc, u32 id);
> +void intel_slpc_get_param(struct intel_slpc *slpc, u32 id,
> +			  int *overriding, u32 *value);
> +int intel_slpc_task_control(struct intel_slpc *slpc, u64 val,
> +			    u32 enable_id, u32 disable_id);
> +int intel_slpc_task_status(struct intel_slpc *slpc, u64 *val,
> +			   u32 enable_id, u32 disable_id);
>  void intel_slpc_init(struct intel_slpc *slpc);
>  void intel_slpc_cleanup(struct intel_slpc *slpc);
>  void intel_slpc_enable(struct intel_slpc *slpc);


More information about the Intel-gfx mailing list