diff mbox

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

Message ID 1505842927-13327-21-git-send-email-sagar.a.kamble@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

sagar.a.kamble@intel.com Sept. 19, 2017, 5:41 p.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 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@intel.com>
Signed-off-by: Tom O'Rourke <Tom.O'Rourke@intel.com>
Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@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(-)

Comments

Michal Wajdeczko Sept. 21, 2017, 1:47 p.m. UTC | #1
On Tue, 19 Sep 2017 19:41:56 +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 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@intel.com>
> Signed-off-by: Tom O'Rourke <Tom.O'Rourke@intel.com>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@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);
sagar.a.kamble@intel.com Sept. 28, 2017, 9:55 a.m. UTC | #2
On 9/21/2017 7:17 PM, Michal Wajdeczko wrote:
> On Tue, 19 Sep 2017 19:41:56 +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 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@intel.com>
>> Signed-off-by: Tom O'Rourke <Tom.O'Rourke@intel.com>
>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@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.
Ok. Will prepare new SLPC specific send function built on top of GUC CT 
based send.
>
>
>>      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!
Yes. Will base SLPC changes on top of these.
>
>> +     * 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);
diff mbox

Patch

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;
 	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.
+	 * 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);