#include "intel_wakeref.h"
#include "i915_drv.h"
-static void rpm_get(struct intel_wakeref *wf)
-{
- wf->wakeref = intel_runtime_pm_get(&wf->i915->runtime_pm);
-}
-
-static void rpm_put(struct intel_wakeref *wf)
-{
- intel_wakeref_t wakeref = fetch_and_zero(&wf->wakeref);
-
- intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref);
- INTEL_WAKEREF_BUG_ON(!wakeref);
-}
-
int __intel_wakeref_get_first(struct intel_wakeref *wf)
{
+ intel_wakeref_t wakeref;
+ int ret = 0;
+
+ wakeref = intel_runtime_pm_get(&wf->i915->runtime_pm);
/*
* Treat get/put as different subclasses, as we may need to run
* the put callback from under the shrinker and do not want to
* upon acquiring the wakeref.
*/
mutex_lock_nested(&wf->mutex, SINGLE_DEPTH_NESTING);
- if (!atomic_read(&wf->count)) {
- int err;
-
- rpm_get(wf);
- err = wf->ops->get(wf);
- if (unlikely(err)) {
- rpm_put(wf);
- mutex_unlock(&wf->mutex);
- return err;
+ if (!atomic_read(&wf->count)) {
+ INTEL_WAKEREF_BUG_ON(wf->wakeref);
+ wf->wakeref = wakeref;
+ wakeref = 0;
+
+ ret = wf->ops->get(wf);
+ if (ret) {
+ wakeref = xchg(&wf->wakeref, 0);
+ wake_up_var(&wf->wakeref);
+ goto unlock;
}
smp_mb__before_atomic(); /* release wf->count */
}
+
atomic_inc(&wf->count);
+ INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
+
+unlock:
mutex_unlock(&wf->mutex);
+ if (unlikely(wakeref))
+ intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref);
- INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
- return 0;
+ return ret;
}
static void ____intel_wakeref_put_last(struct intel_wakeref *wf)
{
+ intel_wakeref_t wakeref = 0;
+
INTEL_WAKEREF_BUG_ON(atomic_read(&wf->count) <= 0);
if (unlikely(!atomic_dec_and_test(&wf->count)))
goto unlock;
/* ops->put() must reschedule its own release on error/deferral */
if (likely(!wf->ops->put(wf))) {
- rpm_put(wf);
+ INTEL_WAKEREF_BUG_ON(!wf->wakeref);
+ wakeref = xchg(&wf->wakeref, 0);
wake_up_var(&wf->wakeref);
}
unlock:
mutex_unlock(&wf->mutex);
+ if (wakeref)
+ intel_runtime_pm_put(&wf->i915->runtime_pm, wakeref);
}
void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags)