]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/ast/ast_fb.c
Merge tag 'sound-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[karo-tx-linux.git] / drivers / gpu / drm / ast / ast_fb.c
index 34931fe7d2c527ccc8ac6b7db926e1504c2aac70..fbc0823cfa18b9dbd35588d07d3c9322c58bc18d 100644 (file)
@@ -53,16 +53,52 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
        int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
        int ret;
        bool unmap = false;
+       bool store_for_later = false;
+       int x2, y2;
+       unsigned long flags;
 
        obj = afbdev->afb.obj;
        bo = gem_to_ast_bo(obj);
 
+       /*
+        * try and reserve the BO, if we fail with busy
+        * then the BO is being moved and we should
+        * store up the damage until later.
+        */
        ret = ast_bo_reserve(bo, true);
        if (ret) {
-               DRM_ERROR("failed to reserve fb bo\n");
+               if (ret != -EBUSY)
+                       return;
+
+               store_for_later = true;
+       }
+
+       x2 = x + width - 1;
+       y2 = y + height - 1;
+       spin_lock_irqsave(&afbdev->dirty_lock, flags);
+
+       if (afbdev->y1 < y)
+               y = afbdev->y1;
+       if (afbdev->y2 > y2)
+               y2 = afbdev->y2;
+       if (afbdev->x1 < x)
+               x = afbdev->x1;
+       if (afbdev->x2 > x2)
+               x2 = afbdev->x2;
+
+       if (store_for_later) {
+               afbdev->x1 = x;
+               afbdev->x2 = x2;
+               afbdev->y1 = y;
+               afbdev->y2 = y2;
+               spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
                return;
        }
 
+       afbdev->x1 = afbdev->y1 = INT_MAX;
+       afbdev->x2 = afbdev->y2 = 0;
+       spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
+
        if (!bo->kmap.virtual) {
                ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
                if (ret) {
@@ -72,10 +108,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
                }
                unmap = true;
        }
-       for (i = y; i < y + height; i++) {
+       for (i = y; i <= y2; i++) {
                /* assume equal stride for now */
                src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp);
-               memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
+               memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp);
 
        }
        if (unmap)
@@ -292,6 +328,7 @@ int ast_fbdev_init(struct drm_device *dev)
 
        ast->fbdev = afbdev;
        afbdev->helper.funcs = &ast_fb_helper_funcs;
+       spin_lock_init(&afbdev->dirty_lock);
        ret = drm_fb_helper_init(dev, &afbdev->helper,
                                 1, 1);
        if (ret) {