diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_mem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5158a12f7844..fb9bdd6edf1f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -192,6 +192,92 @@ void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap) | |||
192 | } | 192 | } |
193 | 193 | ||
194 | /* | 194 | /* |
195 | * NV10-NV40 tiling helpers | ||
196 | */ | ||
197 | |||
198 | static void | ||
199 | nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, | ||
200 | uint32_t size, uint32_t pitch) | ||
201 | { | ||
202 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
203 | struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; | ||
204 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | ||
205 | struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; | ||
206 | struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; | ||
207 | |||
208 | tile->addr = addr; | ||
209 | tile->size = size; | ||
210 | tile->used = !!pitch; | ||
211 | nouveau_fence_unref((void **)&tile->fence); | ||
212 | |||
213 | if (!pfifo->cache_flush(dev)) | ||
214 | return; | ||
215 | |||
216 | pfifo->reassign(dev, false); | ||
217 | pfifo->cache_flush(dev); | ||
218 | pfifo->cache_pull(dev, false); | ||
219 | |||
220 | nouveau_wait_for_idle(dev); | ||
221 | |||
222 | pgraph->set_region_tiling(dev, i, addr, size, pitch); | ||
223 | pfb->set_region_tiling(dev, i, addr, size, pitch); | ||
224 | |||
225 | pfifo->cache_pull(dev, true); | ||
226 | pfifo->reassign(dev, true); | ||
227 | } | ||
228 | |||
229 | struct nouveau_tile_reg * | ||
230 | nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, | ||
231 | uint32_t pitch) | ||
232 | { | ||
233 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
234 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | ||
235 | struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL; | ||
236 | int i; | ||
237 | |||
238 | spin_lock(&dev_priv->tile.lock); | ||
239 | |||
240 | for (i = 0; i < pfb->num_tiles; i++) { | ||
241 | if (tile[i].used) | ||
242 | /* Tile region in use. */ | ||
243 | continue; | ||
244 | |||
245 | if (tile[i].fence && | ||
246 | !nouveau_fence_signalled(tile[i].fence, NULL)) | ||
247 | /* Pending tile region. */ | ||
248 | continue; | ||
249 | |||
250 | if (max(tile[i].addr, addr) < | ||
251 | min(tile[i].addr + tile[i].size, addr + size)) | ||
252 | /* Kill an intersecting tile region. */ | ||
253 | nv10_mem_set_region_tiling(dev, i, 0, 0, 0); | ||
254 | |||
255 | if (pitch && !found) { | ||
256 | /* Free tile region. */ | ||
257 | nv10_mem_set_region_tiling(dev, i, addr, size, pitch); | ||
258 | found = &tile[i]; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | spin_unlock(&dev_priv->tile.lock); | ||
263 | |||
264 | return found; | ||
265 | } | ||
266 | |||
267 | void | ||
268 | nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile, | ||
269 | struct nouveau_fence *fence) | ||
270 | { | ||
271 | if (fence) { | ||
272 | /* Mark it as pending. */ | ||
273 | tile->fence = fence; | ||
274 | nouveau_fence_ref(fence); | ||
275 | } | ||
276 | |||
277 | tile->used = false; | ||
278 | } | ||
279 | |||
280 | /* | ||
195 | * NV50 VM helpers | 281 | * NV50 VM helpers |
196 | */ | 282 | */ |
197 | int | 283 | int |
@@ -513,6 +599,7 @@ nouveau_mem_init(struct drm_device *dev) | |||
513 | 599 | ||
514 | INIT_LIST_HEAD(&dev_priv->ttm.bo_list); | 600 | INIT_LIST_HEAD(&dev_priv->ttm.bo_list); |
515 | spin_lock_init(&dev_priv->ttm.bo_list_lock); | 601 | spin_lock_init(&dev_priv->ttm.bo_list_lock); |
602 | spin_lock_init(&dev_priv->tile.lock); | ||
516 | 603 | ||
517 | dev_priv->fb_available_size = nouveau_mem_fb_amount(dev); | 604 | dev_priv->fb_available_size = nouveau_mem_fb_amount(dev); |
518 | 605 | ||