Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nouveau_fence.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Ben Skeggs.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include <drm/drmP.h>
28 
29 #include <linux/ktime.h>
30 #include <linux/hrtimer.h>
31 
32 #include "nouveau_drm.h"
33 #include "nouveau_dma.h"
34 #include "nouveau_fence.h"
35 
36 void
38 {
39  struct nouveau_fence *fence, *fnext;
40  spin_lock(&fctx->lock);
41  list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
42  if (fence->work)
43  fence->work(fence->priv, false);
44  fence->channel = NULL;
45  list_del(&fence->head);
46  nouveau_fence_unref(&fence);
47  }
48  spin_unlock(&fctx->lock);
49 }
50 
51 void
53 {
54  INIT_LIST_HEAD(&fctx->flip);
55  INIT_LIST_HEAD(&fctx->pending);
56  spin_lock_init(&fctx->lock);
57 }
58 
59 static void
60 nouveau_fence_update(struct nouveau_channel *chan)
61 {
62  struct nouveau_fence_priv *priv = chan->drm->fence;
63  struct nouveau_fence_chan *fctx = chan->fence;
64  struct nouveau_fence *fence, *fnext;
65 
66  spin_lock(&fctx->lock);
67  list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
68  if (priv->read(chan) < fence->sequence)
69  break;
70 
71  if (fence->work)
72  fence->work(fence->priv, true);
73  fence->channel = NULL;
74  list_del(&fence->head);
75  nouveau_fence_unref(&fence);
76  }
77  spin_unlock(&fctx->lock);
78 }
79 
80 int
81 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
82 {
83  struct nouveau_fence_priv *priv = chan->drm->fence;
84  struct nouveau_fence_chan *fctx = chan->fence;
85  int ret;
86 
87  fence->channel = chan;
88  fence->timeout = jiffies + (3 * DRM_HZ);
89  fence->sequence = ++fctx->sequence;
90 
91  ret = priv->emit(fence);
92  if (!ret) {
93  kref_get(&fence->kref);
94  spin_lock(&fctx->lock);
95  list_add_tail(&fence->head, &fctx->pending);
96  spin_unlock(&fctx->lock);
97  }
98 
99  return ret;
100 }
101 
102 bool
104 {
105  if (fence->channel)
106  nouveau_fence_update(fence->channel);
107  return !fence->channel;
108 }
109 
110 int
111 nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
112 {
113  unsigned long sleep_time = NSEC_PER_MSEC / 1000;
114  ktime_t t;
115  int ret = 0;
116 
117  while (!nouveau_fence_done(fence)) {
118  if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
119  ret = -EBUSY;
120  break;
121  }
122 
125  if (lazy) {
126  t = ktime_set(0, sleep_time);
128  sleep_time *= 2;
129  if (sleep_time > NSEC_PER_MSEC)
130  sleep_time = NSEC_PER_MSEC;
131  }
132 
133  if (intr && signal_pending(current)) {
134  ret = -ERESTARTSYS;
135  break;
136  }
137  }
138 
140  return ret;
141 }
142 
143 int
145 {
146  struct nouveau_fence_priv *priv = chan->drm->fence;
147  struct nouveau_channel *prev;
148  int ret = 0;
149 
150  prev = fence ? fence->channel : NULL;
151  if (prev) {
152  if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
153  ret = priv->sync(fence, prev, chan);
154  if (unlikely(ret))
155  ret = nouveau_fence_wait(fence, true, false);
156  }
157  }
158 
159  return ret;
160 }
161 
162 static void
163 nouveau_fence_del(struct kref *kref)
164 {
165  struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
166  kfree(fence);
167 }
168 
169 void
171 {
172  if (*pfence)
173  kref_put(&(*pfence)->kref, nouveau_fence_del);
174  *pfence = NULL;
175 }
176 
177 struct nouveau_fence *
179 {
180  kref_get(&fence->kref);
181  return fence;
182 }
183 
184 int
185 nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence)
186 {
187  struct nouveau_fence *fence;
188  int ret = 0;
189 
190  if (unlikely(!chan->fence))
191  return -ENODEV;
192 
193  fence = kzalloc(sizeof(*fence), GFP_KERNEL);
194  if (!fence)
195  return -ENOMEM;
196  kref_init(&fence->kref);
197 
198  if (chan) {
199  ret = nouveau_fence_emit(fence, chan);
200  if (ret)
201  nouveau_fence_unref(&fence);
202  }
203 
204  *pfence = fence;
205  return ret;
206 }