drm/i915: Make sure we have enough memory bandwidth on ICL
[linux-block.git] / drivers / gpu / drm / i915 / intel_wakeref.c
CommitLineData
d91e6578
CW
1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright © 2019 Intel Corporation
5 */
6
7#include "intel_drv.h"
8#include "intel_wakeref.h"
9
7ee280a7
CW
10static void rpm_get(struct drm_i915_private *i915, struct intel_wakeref *wf)
11{
12 wf->wakeref = intel_runtime_pm_get(i915);
13}
14
15static void rpm_put(struct drm_i915_private *i915, struct intel_wakeref *wf)
16{
17 intel_wakeref_t wakeref = fetch_and_zero(&wf->wakeref);
18
19 intel_runtime_pm_put(i915, wakeref);
20 GEM_BUG_ON(!wakeref);
21}
22
d91e6578
CW
23int __intel_wakeref_get_first(struct drm_i915_private *i915,
24 struct intel_wakeref *wf,
25 int (*fn)(struct intel_wakeref *wf))
26{
27 /*
28 * Treat get/put as different subclasses, as we may need to run
29 * the put callback from under the shrinker and do not want to
30 * cross-contanimate that callback with any extra work performed
31 * upon acquiring the wakeref.
32 */
33 mutex_lock_nested(&wf->mutex, SINGLE_DEPTH_NESTING);
34 if (!atomic_read(&wf->count)) {
35 int err;
36
7ee280a7 37 rpm_get(i915, wf);
d91e6578
CW
38
39 err = fn(wf);
40 if (unlikely(err)) {
7ee280a7 41 rpm_put(i915, wf);
d91e6578
CW
42 mutex_unlock(&wf->mutex);
43 return err;
44 }
45
46 smp_mb__before_atomic(); /* release wf->count */
47 }
48 atomic_inc(&wf->count);
49 mutex_unlock(&wf->mutex);
50
51 return 0;
52}
53
54int __intel_wakeref_put_last(struct drm_i915_private *i915,
55 struct intel_wakeref *wf,
56 int (*fn)(struct intel_wakeref *wf))
57{
58 int err;
59
60 err = fn(wf);
61 if (likely(!err))
7ee280a7 62 rpm_put(i915, wf);
d91e6578
CW
63 else
64 atomic_inc(&wf->count);
65 mutex_unlock(&wf->mutex);
66
67 return err;
68}
69
70void __intel_wakeref_init(struct intel_wakeref *wf, struct lock_class_key *key)
71{
72 __mutex_init(&wf->mutex, "wakeref", key);
73 atomic_set(&wf->count, 0);
7ee280a7 74 wf->wakeref = 0;
d91e6578 75}