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: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: Jani Nikula <jani.nikula@intel.com>
Acked-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190213152109.16997-1-chris@chris-wilson.co.uk
This commit is contained in:
Chris Wilson 2019-02-13 15:21:09 +00:00
Родитель 290248c27c
Коммит d31c85fc86
4 изменённых файлов: 32 добавлений и 18 удалений

Просмотреть файл

@ -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),
POWER_DOMAIN_AUDIO);
intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO, cookie);
}
static void i915_audio_component_codec_wake_override(struct device *kdev,
bool enable)
{
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
unsigned long cookie;
u32 tmp;
if (!IS_GEN(dev_priv, 9))
return;
i915_audio_component_get_power(kdev);
cookie = i915_audio_component_get_power(kdev);
/*
* Enable/disable generating the codec wake signal, overriding the
@ -779,7 +783,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev,
usleep_range(1000, 1500);
}
i915_audio_component_put_power(kdev);
i915_audio_component_put_power(kdev, cookie);
}
/* Get CDCLK in kHz */
@ -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 intel_encoder *encoder;
struct intel_crtc *crtc;
unsigned long cookie;
int err = 0;
if (!HAS_DDI(dev_priv))
return 0;
i915_audio_component_get_power(kdev);
cookie = i915_audio_component_get_power(kdev);
mutex_lock(&dev_priv->av_mutex);
/* 1. get the pipe */
@ -875,7 +880,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
unlock:
mutex_unlock(&dev_priv->av_mutex);
i915_audio_component_put_power(kdev);
i915_audio_component_put_power(kdev, cookie);
return err;
}

Просмотреть файл

@ -18,14 +18,17 @@ struct drm_audio_component_ops {
* @get_power: get the POWER_DOMAIN_AUDIO power well
*
* 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
*
* 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
*/

Просмотреть файл

@ -367,7 +367,7 @@ struct hdac_bus {
/* DRM component interface */
struct drm_audio_component *audio_component;
long display_power_status;
bool display_power_active;
unsigned long display_power_active;
/* parameters required for enhanced capabilities */
int num_streams;

Просмотреть файл

@ -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_active) {
unsigned long cookie = -1;
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, false);
bus->display_power_active = true;
bus->display_power_active = cookie;
}
} else {
if (bus->display_power_active) {
unsigned long cookie = bus->display_power_active;
if (acomp->ops->put_power)
acomp->ops->put_power(acomp->dev);
bus->display_power_active = false;
acomp->ops->put_power(acomp->dev, cookie);
bus->display_power_active = 0;
}
}
}
@ -325,9 +331,9 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
return 0;
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;
component_master_del(dev, &hdac_component_master_ops);