Commit d31c85fc authored by Chris Wilson's avatar Chris Wilson

snd/hda, drm/i915: Track the display_power_status using a cookie

drm/i915 is tracking all wakeref owners with a cookie in order to
identify leaks. To that end, each rpm acquisition ops->get_power is
assigned a cookie which should be passed to ops->put_power to signify
its release (and removal from the list of wakeref owners). As snd/hda is
already using a bool to track current status of display_power extending
that to an unsigned long to hold the boolean cookie is a trivial
extension, and will quell all doubt that snd/hda is the cause of the
device runtime pm leaks.

v2: Keep using the power abstraction for local wakeref tracking.
v3: BUILD_BUG_ON impedance mismatch
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: Jani Nikula <jani.nikula@intel.com>
Acked-by: default avatarTakashi Iwai <tiwai@suse.de>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190213152109.16997-1-chris@chris-wilson.co.uk
parent 290248c2
...@@ -741,27 +741,31 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv) ...@@ -741,27 +741,31 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv)
} }
} }
static void i915_audio_component_get_power(struct device *kdev) static unsigned long i915_audio_component_get_power(struct device *kdev)
{ {
intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO); /* Catch potential impedance mismatches before they occur! */
BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long));
return intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
} }
static void i915_audio_component_put_power(struct device *kdev) static void i915_audio_component_put_power(struct device *kdev,
unsigned long cookie)
{ {
intel_display_power_put_unchecked(kdev_to_i915(kdev), intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO, cookie);
POWER_DOMAIN_AUDIO);
} }
static void i915_audio_component_codec_wake_override(struct device *kdev, static void i915_audio_component_codec_wake_override(struct device *kdev,
bool enable) bool enable)
{ {
struct drm_i915_private *dev_priv = kdev_to_i915(kdev); struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
unsigned long cookie;
u32 tmp; u32 tmp;
if (!IS_GEN(dev_priv, 9)) if (!IS_GEN(dev_priv, 9))
return; return;
i915_audio_component_get_power(kdev); cookie = i915_audio_component_get_power(kdev);
/* /*
* Enable/disable generating the codec wake signal, overriding the * Enable/disable generating the codec wake signal, overriding the
...@@ -779,7 +783,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, ...@@ -779,7 +783,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev,
usleep_range(1000, 1500); usleep_range(1000, 1500);
} }
i915_audio_component_put_power(kdev); i915_audio_component_put_power(kdev, cookie);
} }
/* Get CDCLK in kHz */ /* Get CDCLK in kHz */
...@@ -850,12 +854,13 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port, ...@@ -850,12 +854,13 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
struct i915_audio_component *acomp = dev_priv->audio_component; struct i915_audio_component *acomp = dev_priv->audio_component;
struct intel_encoder *encoder; struct intel_encoder *encoder;
struct intel_crtc *crtc; struct intel_crtc *crtc;
unsigned long cookie;
int err = 0; int err = 0;
if (!HAS_DDI(dev_priv)) if (!HAS_DDI(dev_priv))
return 0; return 0;
i915_audio_component_get_power(kdev); cookie = i915_audio_component_get_power(kdev);
mutex_lock(&dev_priv->av_mutex); mutex_lock(&dev_priv->av_mutex);
/* 1. get the pipe */ /* 1. get the pipe */
...@@ -875,7 +880,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port, ...@@ -875,7 +880,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
unlock: unlock:
mutex_unlock(&dev_priv->av_mutex); mutex_unlock(&dev_priv->av_mutex);
i915_audio_component_put_power(kdev); i915_audio_component_put_power(kdev, cookie);
return err; return err;
} }
......
...@@ -18,14 +18,17 @@ struct drm_audio_component_ops { ...@@ -18,14 +18,17 @@ struct drm_audio_component_ops {
* @get_power: get the POWER_DOMAIN_AUDIO power well * @get_power: get the POWER_DOMAIN_AUDIO power well
* *
* Request the power well to be turned on. * Request the power well to be turned on.
*
* Returns a wakeref cookie to be passed back to the corresponding
* call to @put_power.
*/ */
void (*get_power)(struct device *); unsigned long (*get_power)(struct device *);
/** /**
* @put_power: put the POWER_DOMAIN_AUDIO power well * @put_power: put the POWER_DOMAIN_AUDIO power well
* *
* Allow the power well to be turned off. * Allow the power well to be turned off.
*/ */
void (*put_power)(struct device *); void (*put_power)(struct device *, unsigned long);
/** /**
* @codec_wake_override: Enable/disable codec wake signal * @codec_wake_override: Enable/disable codec wake signal
*/ */
......
...@@ -367,7 +367,7 @@ struct hdac_bus { ...@@ -367,7 +367,7 @@ struct hdac_bus {
/* DRM component interface */ /* DRM component interface */
struct drm_audio_component *audio_component; struct drm_audio_component *audio_component;
long display_power_status; long display_power_status;
bool display_power_active; unsigned long display_power_active;
/* parameters required for enhanced capabilities */ /* parameters required for enhanced capabilities */
int num_streams; int num_streams;
......
...@@ -79,17 +79,23 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) ...@@ -79,17 +79,23 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
if (bus->display_power_status) { if (bus->display_power_status) {
if (!bus->display_power_active) { if (!bus->display_power_active) {
unsigned long cookie = -1;
if (acomp->ops->get_power) if (acomp->ops->get_power)
acomp->ops->get_power(acomp->dev); cookie = acomp->ops->get_power(acomp->dev);
snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false); snd_hdac_set_codec_wakeup(bus, false);
bus->display_power_active = true; bus->display_power_active = cookie;
} }
} else { } else {
if (bus->display_power_active) { if (bus->display_power_active) {
unsigned long cookie = bus->display_power_active;
if (acomp->ops->put_power) if (acomp->ops->put_power)
acomp->ops->put_power(acomp->dev); acomp->ops->put_power(acomp->dev, cookie);
bus->display_power_active = false;
bus->display_power_active = 0;
} }
} }
} }
...@@ -325,9 +331,9 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) ...@@ -325,9 +331,9 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
return 0; return 0;
if (WARN_ON(bus->display_power_active) && acomp->ops) if (WARN_ON(bus->display_power_active) && acomp->ops)
acomp->ops->put_power(acomp->dev); acomp->ops->put_power(acomp->dev, bus->display_power_active);
bus->display_power_active = false; bus->display_power_active = 0;
bus->display_power_status = 0; bus->display_power_status = 0;
component_master_del(dev, &hdac_component_master_ops); component_master_del(dev, &hdac_component_master_ops);
......
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