aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_ramht.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-04 02:29:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-04 02:29:23 -0400
commit612a9aab56a93533e76e3ad91642db7033e03b69 (patch)
tree8402096973f67af941f9392f7da06cca03e0b58a /drivers/gpu/drm/nouveau/nouveau_ramht.c
parent3a494318b14b1bc0f59d2d6ce84c505c74d82d2a (diff)
parent268d28371cd326be4dfcd7eba5917bf4b9d30c8f (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge (part 1) from Dave Airlie: "So first of all my tree and uapi stuff has a conflict mess, its my fault as the nouveau stuff didn't hit -next as were trying to rebase regressions out of it before we merged. Highlights: - SH mobile modesetting driver and associated helpers - some DRM core documentation - i915 modesetting rework, haswell hdmi, haswell and vlv fixes, write combined pte writing, ilk rc6 support, - nouveau: major driver rework into a hw core driver, makes features like SLI a lot saner to implement, - psb: add eDP/DP support for Cedarview - radeon: 2 layer page tables, async VM pte updates, better PLL selection for > 2 screens, better ACPI interactions The rest is general grab bag of fixes. So why part 1? well I have the exynos pull req which came in a bit late but was waiting for me to do something they shouldn't have and it looks fairly safe, and David Howells has some more header cleanups he'd like me to pull, that seem like a good idea, but I'd like to get this merge out of the way so -next dosen't get blocked." Tons of conflicts mostly due to silly include line changes, but mostly mindless. A few other small semantic conflicts too, noted from Dave's pre-merged branch. * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (447 commits) drm/nv98/crypt: fix fuc build with latest envyas drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering drm/nv41/vm: fix and enable use of "real" pciegart drm/nv44/vm: fix and enable use of "real" pciegart drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie drm/nouveau: store supported dma mask in vmmgr drm/nvc0/ibus: initial implementation of subdev drm/nouveau/therm: add support for fan-control modes drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules drm/nouveau/therm: calculate the pwm divisor on nv50+ drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster drm/nouveau/therm: move thermal-related functions to the therm subdev drm/nouveau/bios: parse the pwm divisor from the perf table drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices drm/nouveau/therm: rework thermal table parsing drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table drm/nouveau: fix pm initialization order drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it drm/nouveau: log channel debug/error messages from client object rather than drm client drm/nouveau: have drm debugging macros build on top of core macros ...
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 0ebb62f1fc80..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 <drm/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}