Commit caacfe31 authored by Imre Deak's avatar Imre Deak

drm/i915: Add way to specify the power-off delay of a display power domain

Add support for specifying a delay different than the current 100 ms
default for powering off a display power domain. This is needed by the
next patch which delays re-enabling DC states during modesets to avoid
the off->on->off toggling overhead of the DC_off power well, but does
this using a < 100 ms delay for a better utilization of DC power saving
states.
Reviewed-by: default avatarJouni Högander <jouni.hogander@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230616185104.2502003-3-imre.deak@intel.com
parent cb787464
...@@ -458,6 +458,17 @@ async_put_domains_clear_domain(struct i915_power_domains *power_domains, ...@@ -458,6 +458,17 @@ async_put_domains_clear_domain(struct i915_power_domains *power_domains,
clear_bit(domain, power_domains->async_put_domains[1].bits); clear_bit(domain, power_domains->async_put_domains[1].bits);
} }
static void
cancel_async_put_work(struct i915_power_domains *power_domains, bool sync)
{
if (sync)
cancel_delayed_work_sync(&power_domains->async_put_work);
else
cancel_delayed_work(&power_domains->async_put_work);
power_domains->async_put_next_delay = 0;
}
static bool static bool
intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv, intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain) enum intel_display_power_domain domain)
...@@ -478,7 +489,7 @@ intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv, ...@@ -478,7 +489,7 @@ intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv,
if (!bitmap_empty(async_put_mask.bits, POWER_DOMAIN_NUM)) if (!bitmap_empty(async_put_mask.bits, POWER_DOMAIN_NUM))
goto out_verify; goto out_verify;
cancel_delayed_work(&power_domains->async_put_work); cancel_async_put_work(power_domains, false);
intel_runtime_pm_put_raw(&dev_priv->runtime_pm, intel_runtime_pm_put_raw(&dev_priv->runtime_pm,
fetch_and_zero(&power_domains->async_put_wakeref)); fetch_and_zero(&power_domains->async_put_wakeref));
out_verify: out_verify:
...@@ -609,7 +620,8 @@ static void __intel_display_power_put(struct drm_i915_private *dev_priv, ...@@ -609,7 +620,8 @@ static void __intel_display_power_put(struct drm_i915_private *dev_priv,
static void static void
queue_async_put_domains_work(struct i915_power_domains *power_domains, queue_async_put_domains_work(struct i915_power_domains *power_domains,
intel_wakeref_t wakeref) intel_wakeref_t wakeref,
int delay_ms)
{ {
struct drm_i915_private *i915 = container_of(power_domains, struct drm_i915_private *i915 = container_of(power_domains,
struct drm_i915_private, struct drm_i915_private,
...@@ -618,7 +630,7 @@ queue_async_put_domains_work(struct i915_power_domains *power_domains, ...@@ -618,7 +630,7 @@ queue_async_put_domains_work(struct i915_power_domains *power_domains,
power_domains->async_put_wakeref = wakeref; power_domains->async_put_wakeref = wakeref;
drm_WARN_ON(&i915->drm, !queue_delayed_work(system_unbound_wq, drm_WARN_ON(&i915->drm, !queue_delayed_work(system_unbound_wq,
&power_domains->async_put_work, &power_domains->async_put_work,
msecs_to_jiffies(100))); msecs_to_jiffies(delay_ms)));
} }
static void static void
...@@ -681,13 +693,15 @@ intel_display_power_put_async_work(struct work_struct *work) ...@@ -681,13 +693,15 @@ intel_display_power_put_async_work(struct work_struct *work)
bitmap_zero(power_domains->async_put_domains[1].bits, bitmap_zero(power_domains->async_put_domains[1].bits,
POWER_DOMAIN_NUM); POWER_DOMAIN_NUM);
queue_async_put_domains_work(power_domains, queue_async_put_domains_work(power_domains,
fetch_and_zero(&new_work_wakeref)); fetch_and_zero(&new_work_wakeref),
power_domains->async_put_next_delay);
power_domains->async_put_next_delay = 0;
} else { } else {
/* /*
* Cancel the work that got queued after this one got dequeued, * Cancel the work that got queued after this one got dequeued,
* since here we released the corresponding async-put reference. * since here we released the corresponding async-put reference.
*/ */
cancel_delayed_work(&power_domains->async_put_work); cancel_async_put_work(power_domains, false);
} }
out_verify: out_verify:
...@@ -706,19 +720,25 @@ intel_display_power_put_async_work(struct work_struct *work) ...@@ -706,19 +720,25 @@ intel_display_power_put_async_work(struct work_struct *work)
* @i915: i915 device instance * @i915: i915 device instance
* @domain: power domain to reference * @domain: power domain to reference
* @wakeref: wakeref acquired for the reference that is being released * @wakeref: wakeref acquired for the reference that is being released
* @delay_ms: delay of powering down the power domain
* *
* This function drops the power domain reference obtained by * This function drops the power domain reference obtained by
* intel_display_power_get*() and schedules a work to power down the * intel_display_power_get*() and schedules a work to power down the
* corresponding hardware block if this is the last reference. * corresponding hardware block if this is the last reference.
* The power down is delayed by @delay_ms if this is >= 0, or by a default
* 100 ms otherwise.
*/ */
void __intel_display_power_put_async(struct drm_i915_private *i915, void __intel_display_power_put_async(struct drm_i915_private *i915,
enum intel_display_power_domain domain, enum intel_display_power_domain domain,
intel_wakeref_t wakeref) intel_wakeref_t wakeref,
int delay_ms)
{ {
struct i915_power_domains *power_domains = &i915->display.power.domains; struct i915_power_domains *power_domains = &i915->display.power.domains;
struct intel_runtime_pm *rpm = &i915->runtime_pm; struct intel_runtime_pm *rpm = &i915->runtime_pm;
intel_wakeref_t work_wakeref = intel_runtime_pm_get_raw(rpm); intel_wakeref_t work_wakeref = intel_runtime_pm_get_raw(rpm);
delay_ms = delay_ms >= 0 ? delay_ms : 100;
mutex_lock(&power_domains->lock); mutex_lock(&power_domains->lock);
if (power_domains->domain_use_count[domain] > 1) { if (power_domains->domain_use_count[domain] > 1) {
...@@ -732,10 +752,13 @@ void __intel_display_power_put_async(struct drm_i915_private *i915, ...@@ -732,10 +752,13 @@ void __intel_display_power_put_async(struct drm_i915_private *i915,
/* Let a pending work requeue itself or queue a new one. */ /* Let a pending work requeue itself or queue a new one. */
if (power_domains->async_put_wakeref) { if (power_domains->async_put_wakeref) {
set_bit(domain, power_domains->async_put_domains[1].bits); set_bit(domain, power_domains->async_put_domains[1].bits);
power_domains->async_put_next_delay = max(power_domains->async_put_next_delay,
delay_ms);
} else { } else {
set_bit(domain, power_domains->async_put_domains[0].bits); set_bit(domain, power_domains->async_put_domains[0].bits);
queue_async_put_domains_work(power_domains, queue_async_put_domains_work(power_domains,
fetch_and_zero(&work_wakeref)); fetch_and_zero(&work_wakeref),
delay_ms);
} }
out_verify: out_verify:
...@@ -775,7 +798,7 @@ void intel_display_power_flush_work(struct drm_i915_private *i915) ...@@ -775,7 +798,7 @@ void intel_display_power_flush_work(struct drm_i915_private *i915)
async_put_domains_mask(power_domains, &async_put_mask); async_put_domains_mask(power_domains, &async_put_mask);
release_async_put_domains(power_domains, &async_put_mask); release_async_put_domains(power_domains, &async_put_mask);
cancel_delayed_work(&power_domains->async_put_work); cancel_async_put_work(power_domains, false);
out_verify: out_verify:
verify_async_put_domains_state(power_domains); verify_async_put_domains_state(power_domains);
...@@ -799,7 +822,7 @@ intel_display_power_flush_work_sync(struct drm_i915_private *i915) ...@@ -799,7 +822,7 @@ intel_display_power_flush_work_sync(struct drm_i915_private *i915)
struct i915_power_domains *power_domains = &i915->display.power.domains; struct i915_power_domains *power_domains = &i915->display.power.domains;
intel_display_power_flush_work(i915); intel_display_power_flush_work(i915);
cancel_delayed_work_sync(&power_domains->async_put_work); cancel_async_put_work(power_domains, true);
verify_async_put_domains_state(power_domains); verify_async_put_domains_state(power_domains);
......
...@@ -151,6 +151,7 @@ struct i915_power_domains { ...@@ -151,6 +151,7 @@ struct i915_power_domains {
struct delayed_work async_put_work; struct delayed_work async_put_work;
intel_wakeref_t async_put_wakeref; intel_wakeref_t async_put_wakeref;
struct intel_power_domain_mask async_put_domains[2]; struct intel_power_domain_mask async_put_domains[2];
int async_put_next_delay;
struct i915_power_well *power_wells; struct i915_power_well *power_wells;
}; };
...@@ -197,7 +198,8 @@ intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv, ...@@ -197,7 +198,8 @@ intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); enum intel_display_power_domain domain);
void __intel_display_power_put_async(struct drm_i915_private *i915, void __intel_display_power_put_async(struct drm_i915_private *i915,
enum intel_display_power_domain domain, enum intel_display_power_domain domain,
intel_wakeref_t wakeref); intel_wakeref_t wakeref,
int delay_ms);
void intel_display_power_flush_work(struct drm_i915_private *i915); void intel_display_power_flush_work(struct drm_i915_private *i915);
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
void intel_display_power_put(struct drm_i915_private *dev_priv, void intel_display_power_put(struct drm_i915_private *dev_priv,
...@@ -208,7 +210,16 @@ intel_display_power_put_async(struct drm_i915_private *i915, ...@@ -208,7 +210,16 @@ intel_display_power_put_async(struct drm_i915_private *i915,
enum intel_display_power_domain domain, enum intel_display_power_domain domain,
intel_wakeref_t wakeref) intel_wakeref_t wakeref)
{ {
__intel_display_power_put_async(i915, domain, wakeref); __intel_display_power_put_async(i915, domain, wakeref, -1);
}
static inline void
intel_display_power_put_async_delay(struct drm_i915_private *i915,
enum intel_display_power_domain domain,
intel_wakeref_t wakeref,
int delay_ms)
{
__intel_display_power_put_async(i915, domain, wakeref, delay_ms);
} }
#else #else
void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv, void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv,
...@@ -227,7 +238,16 @@ intel_display_power_put_async(struct drm_i915_private *i915, ...@@ -227,7 +238,16 @@ intel_display_power_put_async(struct drm_i915_private *i915,
enum intel_display_power_domain domain, enum intel_display_power_domain domain,
intel_wakeref_t wakeref) intel_wakeref_t wakeref)
{ {
__intel_display_power_put_async(i915, domain, -1); __intel_display_power_put_async(i915, domain, -1, -1);
}
static inline void
intel_display_power_put_async_delay(struct drm_i915_private *i915,
enum intel_display_power_domain domain,
intel_wakeref_t wakeref,
int delay_ms)
{
__intel_display_power_put_async(i915, domain, -1, delay_ms);
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment