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

Sagar Arun Kamble
2017-09-28T09:55:36Z

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);