aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_mem.c
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-10-24 16:14:41 +0200
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 15:11:20 +1000
commita5cf68b04b2b8ea716cf6fd8499c1c54d05fdf5e (patch)
tree87f6007ef18c8d488f590523b90bcd8766537778 /drivers/gpu/drm/nouveau/nouveau_mem.c
parente419cf0954901bb3a987f8b76cbc9654ca06121c (diff)
downloadkernel_samsung_smdk4412-a5cf68b04b2b8ea716cf6fd8499c1c54d05fdf5e.zip
kernel_samsung_smdk4412-a5cf68b04b2b8ea716cf6fd8499c1c54d05fdf5e.tar.gz
kernel_samsung_smdk4412-a5cf68b04b2b8ea716cf6fd8499c1c54d05fdf5e.tar.bz2
drm/nouveau: Rework tile region handling.
The point is to share more code between the PFB/PGRAPH tile region hooks, and give the hardware specific functions a chance to allocate per-region resources. Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_mem.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c111
1 files changed, 66 insertions, 45 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index a7c3e08..549f590 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -42,83 +42,104 @@
*/
static void
-nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
- uint32_t size, uint32_t pitch)
+nv10_mem_update_tile_region(struct drm_device *dev,
+ struct nouveau_tile_reg *tile, uint32_t addr,
+ uint32_t size, uint32_t pitch, uint32_t flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+ int i = tile - dev_priv->tile.reg;
+ unsigned long save;
- tile->addr = addr;
- tile->size = size;
- tile->used = !!pitch;
nouveau_fence_unref(&tile->fence);
+ if (tile->pitch)
+ pfb->free_tile_region(dev, i);
+
+ if (pitch)
+ pfb->init_tile_region(dev, i, addr, size, pitch, flags);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, save);
pfifo->reassign(dev, false);
pfifo->cache_pull(dev, false);
nouveau_wait_for_idle(dev);
- pgraph->set_region_tiling(dev, i, addr, size, pitch);
- pfb->set_region_tiling(dev, i, addr, size, pitch);
+ pfb->set_tile_region(dev, i);
+ pgraph->set_tile_region(dev, i);
pfifo->cache_pull(dev, true);
pfifo->reassign(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, save);
}
-struct nouveau_tile_reg *
-nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
- uint32_t pitch)
+static struct nouveau_tile_reg *
+nv10_mem_get_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_tile_reg *found = NULL;
- unsigned long i, flags;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ spin_lock(&dev_priv->tile.lock);
- for (i = 0; i < pfb->num_tiles; i++) {
- struct nouveau_tile_reg *tile = &dev_priv->tile[i];
-
- if (tile->used)
- /* Tile region in use. */
- continue;
+ if (!tile->used &&
+ (!tile->fence || nouveau_fence_signalled(tile->fence)))
+ tile->used = true;
+ else
+ tile = NULL;
- if (tile->fence &&
- !nouveau_fence_signalled(tile->fence))
- /* Pending tile region. */
- continue;
+ spin_unlock(&dev_priv->tile.lock);
+ return tile;
+}
- if (max(tile->addr, addr) <
- min(tile->addr + tile->size, addr + size))
- /* Kill an intersecting tile region. */
- nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
+void
+nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile,
+ struct nouveau_fence *fence)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
- if (pitch && !found) {
- /* Free tile region. */
- nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
- found = tile;
+ if (tile) {
+ spin_lock(&dev_priv->tile.lock);
+ if (fence) {
+ /* Mark it as pending. */
+ tile->fence = fence;
+ nouveau_fence_ref(fence);
}
- }
-
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- return found;
+ tile->used = false;
+ spin_unlock(&dev_priv->tile.lock);
+ }
}
-void
-nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile,
- struct nouveau_fence *fence)
+struct nouveau_tile_reg *
+nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
+ uint32_t pitch, uint32_t flags)
{
- if (fence) {
- /* Mark it as pending. */
- tile->fence = fence;
- nouveau_fence_ref(fence);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ struct nouveau_tile_reg *tile, *found = NULL;
+ int i;
+
+ for (i = 0; i < pfb->num_tiles; i++) {
+ tile = nv10_mem_get_tile_region(dev, i);
+
+ if (pitch && !found) {
+ found = tile;
+ continue;
+
+ } else if (tile && tile->pitch) {
+ /* Kill an unused tile region. */
+ nv10_mem_update_tile_region(dev, tile, 0, 0, 0, 0);
+ }
+
+ nv10_mem_put_tile_region(dev, tile, NULL);
}
- tile->used = false;
+ if (found)
+ nv10_mem_update_tile_region(dev, found, addr, size,
+ pitch, flags);
+ return found;
}
/*