aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.c76
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ramht.h3
2 files changed, 58 insertions, 21 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
index ccbc8d69ea68..de34b6bb059f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c
@@ -27,13 +27,13 @@
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_ramht.h" 28#include "nouveau_ramht.h"
29 29
30static uint32_t 30static u32
31nouveau_ramht_hash_handle(struct nouveau_channel *chan, uint32_t handle) 31nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
32{ 32{
33 struct drm_device *dev = chan->dev; 33 struct drm_device *dev = chan->dev;
34 struct drm_nouveau_private *dev_priv = dev->dev_private; 34 struct drm_nouveau_private *dev_priv = dev->dev_private;
35 struct nouveau_ramht *ramht = chan->ramht; 35 struct nouveau_ramht *ramht = chan->ramht;
36 uint32_t hash = 0; 36 u32 hash = 0;
37 int i; 37 int i;
38 38
39 NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle); 39 NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
@@ -53,10 +53,10 @@ nouveau_ramht_hash_handle(struct nouveau_channel *chan, uint32_t handle)
53 53
54static int 54static int
55nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, 55nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
56 uint32_t offset) 56 u32 offset)
57{ 57{
58 struct drm_nouveau_private *dev_priv = dev->dev_private; 58 struct drm_nouveau_private *dev_priv = dev->dev_private;
59 uint32_t ctx = nv_ro32(ramht, offset + 4); 59 u32 ctx = nv_ro32(ramht, offset + 4);
60 60
61 if (dev_priv->card_type < NV_40) 61 if (dev_priv->card_type < NV_40)
62 return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); 62 return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
@@ -72,7 +72,8 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
72 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; 72 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
73 struct nouveau_ramht_entry *entry; 73 struct nouveau_ramht_entry *entry;
74 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; 74 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
75 uint32_t ctx, co, ho; 75 unsigned long flags;
76 u32 ctx, co, ho;
76 77
77 if (nouveau_ramht_find(chan, handle)) 78 if (nouveau_ramht_find(chan, handle))
78 return -EEXIST; 79 return -EEXIST;
@@ -83,7 +84,6 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
83 entry->channel = chan; 84 entry->channel = chan;
84 entry->gpuobj = NULL; 85 entry->gpuobj = NULL;
85 entry->handle = handle; 86 entry->handle = handle;
86 list_add(&entry->head, &chan->ramht->entries);
87 nouveau_gpuobj_ref(gpuobj, &entry->gpuobj); 87 nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
88 88
89 if (dev_priv->card_type < NV_40) { 89 if (dev_priv->card_type < NV_40) {
@@ -105,6 +105,9 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
105 } 105 }
106 } 106 }
107 107
108 spin_lock_irqsave(&chan->ramht->lock, flags);
109 list_add(&entry->head, &chan->ramht->entries);
110
108 co = ho = nouveau_ramht_hash_handle(chan, handle); 111 co = ho = nouveau_ramht_hash_handle(chan, handle);
109 do { 112 do {
110 if (!nouveau_ramht_entry_valid(dev, ramht, co)) { 113 if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
@@ -114,6 +117,7 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
114 nv_wo32(ramht, co + 0, handle); 117 nv_wo32(ramht, co + 0, handle);
115 nv_wo32(ramht, co + 4, ctx); 118 nv_wo32(ramht, co + 4, ctx);
116 119
120 spin_unlock_irqrestore(&chan->ramht->lock, flags);
117 instmem->flush(dev); 121 instmem->flush(dev);
118 return 0; 122 return 0;
119 } 123 }
@@ -127,12 +131,13 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
127 131
128 NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); 132 NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
129 list_del(&entry->head); 133 list_del(&entry->head);
134 spin_unlock_irqrestore(&chan->ramht->lock, flags);
130 kfree(entry); 135 kfree(entry);
131 return -ENOMEM; 136 return -ENOMEM;
132} 137}
133 138
134void 139static void
135nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) 140nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
136{ 141{
137 struct drm_device *dev = chan->dev; 142 struct drm_device *dev = chan->dev;
138 struct drm_nouveau_private *dev_priv = dev->dev_private; 143 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -173,17 +178,35 @@ nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
173 chan->id, handle); 178 chan->id, handle);
174} 179}
175 180
181void
182nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
183{
184 struct nouveau_ramht *ramht = chan->ramht;
185 unsigned long flags;
186
187 spin_lock_irqsave(&ramht->lock, flags);
188 nouveau_ramht_remove_locked(chan, handle);
189 spin_unlock_irqrestore(&ramht->lock, flags);
190}
191
176struct nouveau_gpuobj * 192struct nouveau_gpuobj *
177nouveau_ramht_find(struct nouveau_channel *chan, u32 handle) 193nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
178{ 194{
195 struct nouveau_ramht *ramht = chan->ramht;
179 struct nouveau_ramht_entry *entry; 196 struct nouveau_ramht_entry *entry;
197 struct nouveau_gpuobj *gpuobj = NULL;
198 unsigned long flags;
180 199
200 spin_lock_irqsave(&ramht->lock, flags);
181 list_for_each_entry(entry, &chan->ramht->entries, head) { 201 list_for_each_entry(entry, &chan->ramht->entries, head) {
182 if (entry->channel == chan && entry->handle == handle) 202 if (entry->channel == chan && entry->handle == handle) {
183 return entry->gpuobj; 203 gpuobj = entry->gpuobj;
204 break;
205 }
184 } 206 }
207 spin_unlock_irqrestore(&ramht->lock, flags);
185 208
186 return NULL; 209 return gpuobj;
187} 210}
188 211
189int 212int
@@ -197,36 +220,49 @@ nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
197 return -ENOMEM; 220 return -ENOMEM;
198 221
199 ramht->dev = dev; 222 ramht->dev = dev;
200 ramht->refcount = 1; 223 kref_init(&ramht->refcount);
201 ramht->bits = drm_order(gpuobj->size / 8); 224 ramht->bits = drm_order(gpuobj->size / 8);
202 INIT_LIST_HEAD(&ramht->entries); 225 INIT_LIST_HEAD(&ramht->entries);
226 spin_lock_init(&ramht->lock);
203 nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj); 227 nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
204 228
205 *pramht = ramht; 229 *pramht = ramht;
206 return 0; 230 return 0;
207} 231}
208 232
233static void
234nouveau_ramht_del(struct kref *ref)
235{
236 struct nouveau_ramht *ramht =
237 container_of(ref, struct nouveau_ramht, refcount);
238
239 nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
240 kfree(ramht);
241}
242
209void 243void
210nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, 244nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
211 struct nouveau_channel *chan) 245 struct nouveau_channel *chan)
212{ 246{
213 struct nouveau_ramht_entry *entry, *tmp; 247 struct nouveau_ramht_entry *entry, *tmp;
214 struct nouveau_ramht *ramht; 248 struct nouveau_ramht *ramht;
249 unsigned long flags;
215 250
216 if (ref) 251 if (ref)
217 ref->refcount++; 252 kref_get(&ref->refcount);
218 253
219 ramht = *ptr; 254 ramht = *ptr;
220 if (ramht) { 255 if (ramht) {
256 spin_lock_irqsave(&ramht->lock, flags);
221 list_for_each_entry_safe(entry, tmp, &ramht->entries, head) { 257 list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
222 if (entry->channel == chan) 258 if (entry->channel != chan)
223 nouveau_ramht_remove(chan, entry->handle); 259 continue;
224 }
225 260
226 if (--ramht->refcount == 0) { 261 nouveau_ramht_remove_locked(chan, entry->handle);
227 nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
228 kfree(ramht);
229 } 262 }
263 spin_unlock_irqrestore(&ramht->lock, flags);
264
265 kref_put(&ramht->refcount, nouveau_ramht_del);
230 } 266 }
231 *ptr = ref; 267 *ptr = ref;
232} 268}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h
index f37737a93642..b79cb5e1a8f1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.h
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h
@@ -34,7 +34,8 @@ struct nouveau_ramht_entry {
34 34
35struct nouveau_ramht { 35struct nouveau_ramht {
36 struct drm_device *dev; 36 struct drm_device *dev;
37 int refcount; 37 struct kref refcount;
38 spinlock_t lock;
38 struct nouveau_gpuobj *gpuobj; 39 struct nouveau_gpuobj *gpuobj;
39 struct list_head entries; 40 struct list_head entries;
40 int bits; 41 int bits;