aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_ramht.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-09-01 01:24:31 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-09-24 02:20:14 -0400
commita8eaebc6c52bb0cd243b4cb421068f42d378be9c (patch)
tree12f796e5210d51f78b9fc6ddd4750cf1421373c2 /drivers/gpu/drm/nouveau/nouveau_ramht.c
parentde3a6c0a3b642c0c350414d63298a1b19a009290 (diff)
drm/nouveau: remove nouveau_gpuobj_ref completely, replace with sanity
Reviewed-by: Francisco Jerez <currojerez@riseup.net> 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.c139
1 files changed, 104 insertions, 35 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
index e5cc93c55d8..5f9d52f0630 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ramht.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c
@@ -62,48 +62,56 @@ nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
62} 62}
63 63
64int 64int
65nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) 65nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
66 struct nouveau_gpuobj *gpuobj)
66{ 67{
68 struct drm_device *dev = chan->dev;
67 struct drm_nouveau_private *dev_priv = dev->dev_private; 69 struct drm_nouveau_private *dev_priv = dev->dev_private;
68 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; 70 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
69 struct nouveau_channel *chan = ref->channel; 71 struct nouveau_ramht_entry *entry;
70 struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; 72 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
71 uint32_t ctx, co, ho; 73 uint32_t ctx, co, ho;
72 74
73 if (!ramht) { 75 if (nouveau_ramht_find(chan, handle))
74 NV_ERROR(dev, "No hash table!\n"); 76 return -EEXIST;
75 return -EINVAL; 77
76 } 78 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
79 if (!entry)
80 return -ENOMEM;
81 entry->channel = chan;
82 entry->gpuobj = NULL;
83 entry->handle = handle;
84 list_add(&entry->head, &chan->ramht->entries);
85 nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
77 86
78 if (dev_priv->card_type < NV_40) { 87 if (dev_priv->card_type < NV_40) {
79 ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | 88 ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
80 (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | 89 (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
81 (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); 90 (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
82 } else 91 } else
83 if (dev_priv->card_type < NV_50) { 92 if (dev_priv->card_type < NV_50) {
84 ctx = (ref->instance >> 4) | 93 ctx = (gpuobj->cinst >> 4) |
85 (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | 94 (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
86 (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); 95 (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
87 } else { 96 } else {
88 if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { 97 if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
89 ctx = (ref->instance << 10) | 2; 98 ctx = (gpuobj->cinst << 10) | 2;
90 } else { 99 } else {
91 ctx = (ref->instance >> 4) | 100 ctx = (gpuobj->cinst >> 4) |
92 ((ref->gpuobj->engine << 101 ((gpuobj->engine <<
93 NV40_RAMHT_CONTEXT_ENGINE_SHIFT)); 102 NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
94 } 103 }
95 } 104 }
96 105
97 co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); 106 co = ho = nouveau_ramht_hash_handle(dev, chan->id, handle);
98 do { 107 do {
99 if (!nouveau_ramht_entry_valid(dev, ramht, co)) { 108 if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
100 NV_DEBUG(dev, 109 NV_DEBUG(dev,
101 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", 110 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
102 chan->id, co, ref->handle, ctx); 111 chan->id, co, handle, ctx);
103 nv_wo32(ramht, co + 0, ref->handle); 112 nv_wo32(ramht, co + 0, handle);
104 nv_wo32(ramht, co + 4, ctx); 113 nv_wo32(ramht, co + 4, ctx);
105 114
106 list_add_tail(&ref->list, &chan->ramht_refs);
107 instmem->flush(dev); 115 instmem->flush(dev);
108 return 0; 116 return 0;
109 } 117 }
@@ -116,35 +124,40 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
116 } while (co != ho); 124 } while (co != ho);
117 125
118 NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); 126 NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
127 list_del(&entry->head);
128 kfree(entry);
119 return -ENOMEM; 129 return -ENOMEM;
120} 130}
121 131
122void 132void
123nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) 133nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
124{ 134{
135 struct drm_device *dev = chan->dev;
125 struct drm_nouveau_private *dev_priv = dev->dev_private; 136 struct drm_nouveau_private *dev_priv = dev->dev_private;
126 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; 137 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
127 struct nouveau_channel *chan = ref->channel; 138 struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
128 struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; 139 struct nouveau_ramht_entry *entry, *tmp;
129 uint32_t co, ho; 140 u32 co, ho;
130 141
131 if (!ramht) { 142 list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
132 NV_ERROR(dev, "No hash table!\n"); 143 if (entry->channel != chan || entry->handle != handle)
133 return; 144 continue;
145
146 nouveau_gpuobj_ref(NULL, &entry->gpuobj);
147 list_del(&entry->head);
148 kfree(entry);
149 break;
134 } 150 }
135 151
136 co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); 152 co = ho = nouveau_ramht_hash_handle(dev, chan->id, handle);
137 do { 153 do {
138 if (nouveau_ramht_entry_valid(dev, ramht, co) && 154 if (nouveau_ramht_entry_valid(dev, ramht, co) &&
139 (ref->handle == nv_ro32(ramht, co))) { 155 (handle == nv_ro32(ramht, co))) {
140 NV_DEBUG(dev, 156 NV_DEBUG(dev,
141 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", 157 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
142 chan->id, co, ref->handle, 158 chan->id, co, handle, nv_ro32(ramht, co + 4));
143 nv_ro32(ramht, co + 4));
144 nv_wo32(ramht, co + 0, 0x00000000); 159 nv_wo32(ramht, co + 0, 0x00000000);
145 nv_wo32(ramht, co + 4, 0x00000000); 160 nv_wo32(ramht, co + 4, 0x00000000);
146
147 list_del(&ref->list);
148 instmem->flush(dev); 161 instmem->flush(dev);
149 return; 162 return;
150 } 163 }
@@ -153,8 +166,64 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
153 if (co >= dev_priv->ramht_size) 166 if (co >= dev_priv->ramht_size)
154 co = 0; 167 co = 0;
155 } while (co != ho); 168 } while (co != ho);
156 list_del(&ref->list);
157 169
158 NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", 170 NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
159 chan->id, ref->handle); 171 chan->id, handle);
172}
173
174struct nouveau_gpuobj *
175nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
176{
177 struct nouveau_ramht_entry *entry;
178
179 list_for_each_entry(entry, &chan->ramht->entries, head) {
180 if (entry->channel == chan && entry->handle == handle)
181 return entry->gpuobj;
182 }
183
184 return NULL;
185}
186
187int
188nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
189 struct nouveau_ramht **pramht)
190{
191 struct nouveau_ramht *ramht;
192
193 ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
194 if (!ramht)
195 return -ENOMEM;
196
197 ramht->dev = dev;
198 ramht->refcount = 1;
199 INIT_LIST_HEAD(&ramht->entries);
200 nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
201
202 *pramht = ramht;
203 return 0;
204}
205
206void
207nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
208 struct nouveau_channel *chan)
209{
210 struct nouveau_ramht_entry *entry, *tmp;
211 struct nouveau_ramht *ramht;
212
213 if (ref)
214 ref->refcount++;
215
216 ramht = *ptr;
217 if (ramht) {
218 list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
219 if (entry->channel == chan)
220 nouveau_ramht_remove(chan, entry->handle);
221 }
222
223 if (--ramht->refcount == 0) {
224 nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
225 kfree(ramht);
226 }
227 }
228 *ptr = ref;
160} 229}