diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-09-01 01:24:36 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-09-24 02:23:30 -0400 |
commit | dac790080467eb12f1049ddca1c101eb0dcc9f0c (patch) | |
tree | a7779656812c37cb34cb7129c4925f8b84b65e1f | |
parent | e05c5a317efb03854950a3fcc5c9501bfefc7d68 (diff) |
drm/nouveau: add spinlock around ramht modifications
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_ramht.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_ramht.h | 3 |
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 | ||
30 | static uint32_t | 30 | static u32 |
31 | nouveau_ramht_hash_handle(struct nouveau_channel *chan, uint32_t handle) | 31 | nouveau_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 | ||
54 | static int | 54 | static int |
55 | nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht, | 55 | nouveau_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 | ||
134 | void | 139 | static void |
135 | nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) | 140 | nouveau_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 | ||
181 | void | ||
182 | nouveau_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 | |||
176 | struct nouveau_gpuobj * | 192 | struct nouveau_gpuobj * |
177 | nouveau_ramht_find(struct nouveau_channel *chan, u32 handle) | 193 | nouveau_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 | ||
189 | int | 212 | int |
@@ -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 | ||
233 | static void | ||
234 | nouveau_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 | |||
209 | void | 243 | void |
210 | nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, | 244 | nouveau_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 | ||
35 | struct nouveau_ramht { | 35 | struct 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; |