Message ID | 1505842927-13327-21-git-send-email-sagar.a.kamble@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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);
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 --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);