Commit caacfe31 authored by Imre Deak's avatar Imre Deak
Browse files

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
Loading
Loading
Loading
Loading
+32 −9
Original line number Diff line number Diff line
@@ -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);
}

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
intel_display_power_grab_async_put_ref(struct drm_i915_private *dev_priv,
				       enum intel_display_power_domain domain)
@@ -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))
		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,
				 fetch_and_zero(&power_domains->async_put_wakeref));
out_verify:
@@ -609,7 +620,8 @@ static void __intel_display_power_put(struct drm_i915_private *dev_priv,

static void
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,
@@ -618,7 +630,7 @@ queue_async_put_domains_work(struct i915_power_domains *power_domains,
	power_domains->async_put_wakeref = wakeref;
	drm_WARN_ON(&i915->drm, !queue_delayed_work(system_unbound_wq,
						    &power_domains->async_put_work,
						    msecs_to_jiffies(100)));
						    msecs_to_jiffies(delay_ms)));
}

static void
@@ -681,13 +693,15 @@ intel_display_power_put_async_work(struct work_struct *work)
		bitmap_zero(power_domains->async_put_domains[1].bits,
			    POWER_DOMAIN_NUM);
		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 {
		/*
		 * Cancel the work that got queued after this one got dequeued,
		 * 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:
@@ -706,19 +720,25 @@ intel_display_power_put_async_work(struct work_struct *work)
 * @i915: i915 device instance
 * @domain: power domain to reference
 * @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
 * intel_display_power_get*() and schedules a work to power down the
 * 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,
				     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 intel_runtime_pm *rpm = &i915->runtime_pm;
	intel_wakeref_t work_wakeref = intel_runtime_pm_get_raw(rpm);

	delay_ms = delay_ms >= 0 ? delay_ms : 100;

	mutex_lock(&power_domains->lock);

	if (power_domains->domain_use_count[domain] > 1) {
@@ -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. */
	if (power_domains->async_put_wakeref) {
		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 {
		set_bit(domain, power_domains->async_put_domains[0].bits);
		queue_async_put_domains_work(power_domains,
					     fetch_and_zero(&work_wakeref));
					     fetch_and_zero(&work_wakeref),
					     delay_ms);
	}

out_verify:
@@ -775,7 +798,7 @@ void intel_display_power_flush_work(struct drm_i915_private *i915)

	async_put_domains_mask(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:
	verify_async_put_domains_state(power_domains);
@@ -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;

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

+23 −3
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ struct i915_power_domains {
	struct delayed_work async_put_work;
	intel_wakeref_t async_put_wakeref;
	struct intel_power_domain_mask async_put_domains[2];
	int async_put_next_delay;

	struct i915_power_well *power_wells;
};
@@ -197,7 +198,8 @@ intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
				   enum intel_display_power_domain domain);
void __intel_display_power_put_async(struct drm_i915_private *i915,
				     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);
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
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,
			      enum intel_display_power_domain domain,
			      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
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,
			      enum intel_display_power_domain domain,
			      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