diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvif/notify.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/notify.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c index 7c06123a559c..0898c3155292 100644 --- a/drivers/gpu/drm/nouveau/nvif/notify.c +++ b/drivers/gpu/drm/nouveau/nvif/notify.c | |||
@@ -87,12 +87,25 @@ nvif_notify_get(struct nvif_notify *notify) | |||
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | static inline int | ||
91 | nvif_notify_func(struct nvif_notify *notify, bool keep) | ||
92 | { | ||
93 | int ret = notify->func(notify); | ||
94 | if (ret == NVIF_NOTIFY_KEEP || | ||
95 | !test_and_clear_bit(NVKM_NOTIFY_USER, ¬ify->flags)) { | ||
96 | if (!keep) | ||
97 | atomic_dec(¬ify->putcnt); | ||
98 | else | ||
99 | nvif_notify_get_(notify); | ||
100 | } | ||
101 | return ret; | ||
102 | } | ||
103 | |||
90 | static void | 104 | static void |
91 | nvif_notify_work(struct work_struct *work) | 105 | nvif_notify_work(struct work_struct *work) |
92 | { | 106 | { |
93 | struct nvif_notify *notify = container_of(work, typeof(*notify), work); | 107 | struct nvif_notify *notify = container_of(work, typeof(*notify), work); |
94 | if (notify->func(notify) == NVIF_NOTIFY_KEEP) | 108 | nvif_notify_func(notify, true); |
95 | nvif_notify_get_(notify); | ||
96 | } | 109 | } |
97 | 110 | ||
98 | int | 111 | int |
@@ -113,19 +126,15 @@ nvif_notify(const void *header, u32 length, const void *data, u32 size) | |||
113 | if (!WARN_ON(notify == NULL)) { | 126 | if (!WARN_ON(notify == NULL)) { |
114 | struct nvif_client *client = nvif_client(notify->object); | 127 | struct nvif_client *client = nvif_client(notify->object); |
115 | if (!WARN_ON(notify->size != size)) { | 128 | if (!WARN_ON(notify->size != size)) { |
129 | atomic_inc(¬ify->putcnt); | ||
116 | if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { | 130 | if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { |
117 | atomic_inc(¬ify->putcnt); | ||
118 | memcpy((void *)notify->data, data, size); | 131 | memcpy((void *)notify->data, data, size); |
119 | schedule_work(¬ify->work); | 132 | schedule_work(¬ify->work); |
120 | return NVIF_NOTIFY_DROP; | 133 | return NVIF_NOTIFY_DROP; |
121 | } | 134 | } |
122 | notify->data = data; | 135 | notify->data = data; |
123 | ret = notify->func(notify); | 136 | ret = nvif_notify_func(notify, client->driver->keep); |
124 | notify->data = NULL; | 137 | notify->data = NULL; |
125 | if (ret != NVIF_NOTIFY_DROP && client->driver->keep) { | ||
126 | atomic_inc(¬ify->putcnt); | ||
127 | nvif_notify_get_(notify); | ||
128 | } | ||
129 | } | 138 | } |
130 | } | 139 | } |
131 | 140 | ||
@@ -228,8 +237,10 @@ nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *), | |||
228 | if (notify) { | 237 | if (notify) { |
229 | int ret = nvif_notify_init(object, nvif_notify_del, func, work, | 238 | int ret = nvif_notify_init(object, nvif_notify_del, func, work, |
230 | type, data, size, reply, notify); | 239 | type, data, size, reply, notify); |
231 | if (ret) | 240 | if (ret) { |
232 | kfree(notify); | 241 | kfree(notify); |
242 | notify = NULL; | ||
243 | } | ||
233 | *pnotify = notify; | 244 | *pnotify = notify; |
234 | return ret; | 245 | return ret; |
235 | } | 246 | } |