aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_ramht.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-07-04 09:44:54 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-10-02 23:12:43 -0400
commit02a841d434513c7b3620250271c372fabce56de5 (patch)
tree464e7651bc65e8b100ad9eb949729da3d491591a /drivers/gpu/drm/nouveau/nouveau_ramht.c
parent3a92d37e4099054fe187b485a9d27c439c10eca7 (diff)
drm/nouveau: restructure source tree, split core from drm implementation
Future work will be headed in the way of separating the policy supplied by the nouveau drm module from the mechanisms provided by the driver core. There will be a couple of major classes (subdev, engine) of driver modules that have clearly defined tasks, and the further directory structure change is to reflect this. No code changes here whatsoever, aside from fixing up a couple of include file pathnames. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_ramht.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.c309
1 files changed, 0 insertions, 309 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
deleted file mode 100644
index a24a81f5a89e..000000000000
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.c
+++ /dev/null
@@ -1,309 +0,0 @@
1/*
2 * Copyright 2010 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#include "drmP.h"
26
27#include "nouveau_drv.h"
28#include "nouveau_ramht.h"
29
30static u32
31nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
32{
33 struct drm_device *dev = chan->dev;
34 struct drm_nouveau_private *dev_priv = dev->dev_private;
35 struct nouveau_ramht *ramht = chan->ramht;
36 u32 hash = 0;
37 int i;
38
39 NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
40
41 for (i = 32; i > 0; i -= ramht->bits) {
42 hash ^= (handle & ((1 << ramht->bits) - 1));
43 handle >>= ramht->bits;
44 }
45
46 if (dev_priv->card_type < NV_50)
47 hash ^= chan->id << (ramht->bits - 4);
48 hash <<= 3;
49
50 NV_DEBUG(dev, "hash=0x%08x\n", hash);
51 return hash;
52}
53
54static int
55nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
56 u32 offset)
57{
58 struct drm_nouveau_private *dev_priv = dev->dev_private;
59 u32 ctx = nv_ro32(ramht, offset + 4);
60
61 if (dev_priv->card_type < NV_40)
62 return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
63 return (ctx != 0);
64}
65
66static int
67nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
68 struct nouveau_gpuobj *ramht, u32 offset)
69{
70 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
71 u32 ctx = nv_ro32(ramht, offset + 4);
72
73 if (dev_priv->card_type >= NV_50)
74 return true;
75 else if (dev_priv->card_type >= NV_40)
76 return chan->id ==
77 ((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
78 else
79 return chan->id ==
80 ((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
81}
82
83int
84nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
85 struct nouveau_gpuobj *gpuobj)
86{
87 struct drm_device *dev = chan->dev;
88 struct drm_nouveau_private *dev_priv = dev->dev_private;
89 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
90 struct nouveau_ramht_entry *entry;
91 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
92 unsigned long flags;
93 u32 ctx, co, ho;
94
95 if (nouveau_ramht_find(chan, handle))
96 return -EEXIST;
97
98 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
99 if (!entry)
100 return -ENOMEM;
101 entry->channel = chan;
102 entry->gpuobj = NULL;
103 entry->handle = handle;
104 nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
105
106 if (dev_priv->card_type < NV_40) {
107 ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->pinst >> 4) |
108 (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
109 (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
110 } else
111 if (dev_priv->card_type < NV_50) {
112 ctx = (gpuobj->pinst >> 4) |
113 (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
114 (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
115 } else {
116 if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
117 ctx = (gpuobj->cinst << 10) |
118 (chan->id << 28) |
119 chan->id; /* HASH_TAG */
120 } else {
121 ctx = (gpuobj->cinst >> 4) |
122 ((gpuobj->engine <<
123 NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
124 }
125 }
126
127 spin_lock_irqsave(&chan->ramht->lock, flags);
128 list_add(&entry->head, &chan->ramht->entries);
129
130 co = ho = nouveau_ramht_hash_handle(chan, handle);
131 do {
132 if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
133 NV_DEBUG(dev,
134 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
135 chan->id, co, handle, ctx);
136 nv_wo32(ramht, co + 0, handle);
137 nv_wo32(ramht, co + 4, ctx);
138
139 spin_unlock_irqrestore(&chan->ramht->lock, flags);
140 instmem->flush(dev);
141 return 0;
142 }
143 NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
144 chan->id, co, nv_ro32(ramht, co));
145
146 co += 8;
147 if (co >= ramht->size)
148 co = 0;
149 } while (co != ho);
150
151 NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
152 list_del(&entry->head);
153 spin_unlock_irqrestore(&chan->ramht->lock, flags);
154 kfree(entry);
155 return -ENOMEM;
156}
157
158static struct nouveau_ramht_entry *
159nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
160{
161 struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
162 struct nouveau_ramht_entry *entry;
163 unsigned long flags;
164
165 if (!ramht)
166 return NULL;
167
168 spin_lock_irqsave(&ramht->lock, flags);
169 list_for_each_entry(entry, &ramht->entries, head) {
170 if (entry->channel == chan &&
171 (!handle || entry->handle == handle)) {
172 list_del(&entry->head);
173 spin_unlock_irqrestore(&ramht->lock, flags);
174
175 return entry;
176 }
177 }
178 spin_unlock_irqrestore(&ramht->lock, flags);
179
180 return NULL;
181}
182
183static void
184nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
185{
186 struct drm_device *dev = chan->dev;
187 struct drm_nouveau_private *dev_priv = dev->dev_private;
188 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
189 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
190 unsigned long flags;
191 u32 co, ho;
192
193 spin_lock_irqsave(&chan->ramht->lock, flags);
194 co = ho = nouveau_ramht_hash_handle(chan, handle);
195 do {
196 if (nouveau_ramht_entry_valid(dev, ramht, co) &&
197 nouveau_ramht_entry_same_channel(chan, ramht, co) &&
198 (handle == nv_ro32(ramht, co))) {
199 NV_DEBUG(dev,
200 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
201 chan->id, co, handle, nv_ro32(ramht, co + 4));
202 nv_wo32(ramht, co + 0, 0x00000000);
203 nv_wo32(ramht, co + 4, 0x00000000);
204 instmem->flush(dev);
205 goto out;
206 }
207
208 co += 8;
209 if (co >= ramht->size)
210 co = 0;
211 } while (co != ho);
212
213 NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
214 chan->id, handle);
215out:
216 spin_unlock_irqrestore(&chan->ramht->lock, flags);
217}
218
219int
220nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
221{
222 struct nouveau_ramht_entry *entry;
223
224 entry = nouveau_ramht_remove_entry(chan, handle);
225 if (!entry)
226 return -ENOENT;
227
228 nouveau_ramht_remove_hash(chan, entry->handle);
229 nouveau_gpuobj_ref(NULL, &entry->gpuobj);
230 kfree(entry);
231 return 0;
232}
233
234struct nouveau_gpuobj *
235nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
236{
237 struct nouveau_ramht *ramht = chan->ramht;
238 struct nouveau_ramht_entry *entry;
239 struct nouveau_gpuobj *gpuobj = NULL;
240 unsigned long flags;
241
242 if (unlikely(!chan->ramht))
243 return NULL;
244
245 spin_lock_irqsave(&ramht->lock, flags);
246 list_for_each_entry(entry, &chan->ramht->entries, head) {
247 if (entry->channel == chan && entry->handle == handle) {
248 gpuobj = entry->gpuobj;
249 break;
250 }
251 }
252 spin_unlock_irqrestore(&ramht->lock, flags);
253
254 return gpuobj;
255}
256
257int
258nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
259 struct nouveau_ramht **pramht)
260{
261 struct nouveau_ramht *ramht;
262
263 ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
264 if (!ramht)
265 return -ENOMEM;
266
267 ramht->dev = dev;
268 kref_init(&ramht->refcount);
269 ramht->bits = drm_order(gpuobj->size / 8);
270 INIT_LIST_HEAD(&ramht->entries);
271 spin_lock_init(&ramht->lock);
272 nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
273
274 *pramht = ramht;
275 return 0;
276}
277
278static void
279nouveau_ramht_del(struct kref *ref)
280{
281 struct nouveau_ramht *ramht =
282 container_of(ref, struct nouveau_ramht, refcount);
283
284 nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
285 kfree(ramht);
286}
287
288void
289nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
290 struct nouveau_channel *chan)
291{
292 struct nouveau_ramht_entry *entry;
293 struct nouveau_ramht *ramht;
294
295 if (ref)
296 kref_get(&ref->refcount);
297
298 ramht = *ptr;
299 if (ramht) {
300 while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
301 nouveau_ramht_remove_hash(chan, entry->handle);
302 nouveau_gpuobj_ref(NULL, &entry->gpuobj);
303 kfree(entry);
304 }
305
306 kref_put(&ramht->refcount, nouveau_ramht_del);
307 }
308 *ptr = ref;
309}