diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_ramht.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_ramht.c | 309 |
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 | |||
30 | static u32 | ||
31 | nouveau_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 | |||
54 | static int | ||
55 | nouveau_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 | |||
66 | static int | ||
67 | nouveau_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 | |||
83 | int | ||
84 | nouveau_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 | |||
158 | static struct nouveau_ramht_entry * | ||
159 | nouveau_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 | |||
183 | static void | ||
184 | nouveau_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); | ||
215 | out: | ||
216 | spin_unlock_irqrestore(&chan->ramht->lock, flags); | ||
217 | } | ||
218 | |||
219 | int | ||
220 | nouveau_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 | |||
234 | struct nouveau_gpuobj * | ||
235 | nouveau_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 | |||
257 | int | ||
258 | nouveau_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 | |||
278 | static void | ||
279 | nouveau_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 | |||
288 | void | ||
289 | nouveau_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 | } | ||