diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-09-01 01:24:31 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-09-24 02:20:14 -0400 |
commit | a8eaebc6c52bb0cd243b4cb421068f42d378be9c (patch) | |
tree | 12f796e5210d51f78b9fc6ddd4750cf1421373c2 /drivers/gpu/drm/nouveau/nouveau_ramht.c | |
parent | de3a6c0a3b642c0c350414d63298a1b19a009290 (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.c | 139 |
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 e5cc93c55d80..5f9d52f06305 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 | ||
64 | int | 64 | int |
65 | nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) | 65 | nouveau_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 | ||
122 | void | 132 | void |
123 | nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) | 133 | nouveau_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 | |||
174 | struct nouveau_gpuobj * | ||
175 | nouveau_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 | |||
187 | int | ||
188 | nouveau_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 | |||
206 | void | ||
207 | nouveau_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 | } |