aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie2013-05-02 01:45:02 -0500
committerGreg Kroah-Hartman2013-05-11 15:53:59 -0500
commit52af8300d2a3478a621791f122bd9c4e3eb5840a (patch)
tree68d5e17263b0f5daf6ae03d92ff608e0aac4d608
parent5770e6e6d30ab6776797ff4328c73a6f55870447 (diff)
downloadkernel-omap-52af8300d2a3478a621791f122bd9c4e3eb5840a.tar.gz
kernel-omap-52af8300d2a3478a621791f122bd9c4e3eb5840a.tar.xz
kernel-omap-52af8300d2a3478a621791f122bd9c4e3eb5840a.zip
drm/cirrus: deal with bo reserve fail in dirty update path
commit f3b2bbdc8a87a080ccd23d27fca4b87d61340dd4 upstream. Port over the mgag200 fix to cirrus as it suffers the same issue. On F19 testing, it was noticed we get a lot of errors in dmesg about being unable to reserve the buffer when plymouth starts, this is due to the buffer being in the process of migrating, so it makes sense we can't reserve it. In order to deal with it, this adds delayed updates for the dirty updates, when the bo is unreservable, in the normal console case this shouldn't ever happen, its just when plymouth or X is pushing the console bo to system memory. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c38
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c2
3 files changed, 40 insertions, 2 deletions
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 6e0cc724e5a2..7ca059596887 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -154,6 +154,8 @@ struct cirrus_fbdev {
154 struct list_head fbdev_list; 154 struct list_head fbdev_list;
155 void *sysram; 155 void *sysram;
156 int size; 156 int size;
157 int x1, y1, x2, y2; /* dirty rect */
158 spinlock_t dirty_lock;
157}; 159};
158 160
159struct cirrus_bo { 161struct cirrus_bo {
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 6c6b4c87d309..1e64d6f067b7 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -26,16 +26,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
26 int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; 26 int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
27 int ret; 27 int ret;
28 bool unmap = false; 28 bool unmap = false;
29 bool store_for_later = false;
30 int x2, y2;
31 unsigned long flags;
29 32
30 obj = afbdev->gfb.obj; 33 obj = afbdev->gfb.obj;
31 bo = gem_to_cirrus_bo(obj); 34 bo = gem_to_cirrus_bo(obj);
32 35
36 /*
37 * try and reserve the BO, if we fail with busy
38 * then the BO is being moved and we should
39 * store up the damage until later.
40 */
33 ret = cirrus_bo_reserve(bo, true); 41 ret = cirrus_bo_reserve(bo, true);
34 if (ret) { 42 if (ret) {
35 DRM_ERROR("failed to reserve fb bo\n"); 43 if (ret != -EBUSY)
44 return;
45 store_for_later = true;
46 }
47
48 x2 = x + width - 1;
49 y2 = y + height - 1;
50 spin_lock_irqsave(&afbdev->dirty_lock, flags);
51
52 if (afbdev->y1 < y)
53 y = afbdev->y1;
54 if (afbdev->y2 > y2)
55 y2 = afbdev->y2;
56 if (afbdev->x1 < x)
57 x = afbdev->x1;
58 if (afbdev->x2 > x2)
59 x2 = afbdev->x2;
60
61 if (store_for_later) {
62 afbdev->x1 = x;
63 afbdev->x2 = x2;
64 afbdev->y1 = y;
65 afbdev->y2 = y2;
66 spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
36 return; 67 return;
37 } 68 }
38 69
70 afbdev->x1 = afbdev->y1 = INT_MAX;
71 afbdev->x2 = afbdev->y2 = 0;
72 spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
73
39 if (!bo->kmap.virtual) { 74 if (!bo->kmap.virtual) {
40 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); 75 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
41 if (ret) { 76 if (ret) {
@@ -282,6 +317,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
282 317
283 cdev->mode_info.gfbdev = gfbdev; 318 cdev->mode_info.gfbdev = gfbdev;
284 gfbdev->helper.funcs = &cirrus_fb_helper_funcs; 319 gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
320 spin_lock_init(&gfbdev->dirty_lock);
285 321
286 ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, 322 ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
287 cdev->num_crtc, CIRRUSFB_CONN_LIMIT); 323 cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index 1413a26e4905..2ed8cfc740c9 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
321 321
322 ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); 322 ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
323 if (ret) { 323 if (ret) {
324 if (ret != -ERESTARTSYS) 324 if (ret != -ERESTARTSYS && ret != -EBUSY)
325 DRM_ERROR("reserve failed %p\n", bo); 325 DRM_ERROR("reserve failed %p\n", bo);
326 return ret; 326 return ret;
327 } 327 }