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