aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/cirrus/cirrus_fbdev.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-05-02 02:45:02 -0400
committerDave Airlie <airlied@redhat.com>2013-05-01 22:46:56 -0400
commitf3b2bbdc8a87a080ccd23d27fca4b87d61340dd4 (patch)
tree34101348a8b732dcf68cc8c869938b393b1e6dae /drivers/gpu/drm/cirrus/cirrus_fbdev.c
parent306373b645d80625335b8e684fa09b14ba460cec (diff)
drm/cirrus: deal with bo reserve fail in dirty update path
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. Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/cirrus/cirrus_fbdev.c')
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index e25afccaf85b..3541b567bbd8 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -27,16 +27,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
27 int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; 27 int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
28 int ret; 28 int ret;
29 bool unmap = false; 29 bool unmap = false;
30 bool store_for_later = false;
31 int x2, y2;
32 unsigned long flags;
30 33
31 obj = afbdev->gfb.obj; 34 obj = afbdev->gfb.obj;
32 bo = gem_to_cirrus_bo(obj); 35 bo = gem_to_cirrus_bo(obj);
33 36
37 /*
38 * try and reserve the BO, if we fail with busy
39 * then the BO is being moved and we should
40 * store up the damage until later.
41 */
34 ret = cirrus_bo_reserve(bo, true); 42 ret = cirrus_bo_reserve(bo, true);
35 if (ret) { 43 if (ret) {
36 DRM_ERROR("failed to reserve fb bo\n"); 44 if (ret != -EBUSY)
45 return;
46 store_for_later = true;
47 }
48
49 x2 = x + width - 1;
50 y2 = y + height - 1;
51 spin_lock_irqsave(&afbdev->dirty_lock, flags);
52
53 if (afbdev->y1 < y)
54 y = afbdev->y1;
55 if (afbdev->y2 > y2)
56 y2 = afbdev->y2;
57 if (afbdev->x1 < x)
58 x = afbdev->x1;
59 if (afbdev->x2 > x2)
60 x2 = afbdev->x2;
61
62 if (store_for_later) {
63 afbdev->x1 = x;
64 afbdev->x2 = x2;
65 afbdev->y1 = y;
66 afbdev->y2 = y2;
67 spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
37 return; 68 return;
38 } 69 }
39 70
71 afbdev->x1 = afbdev->y1 = INT_MAX;
72 afbdev->x2 = afbdev->y2 = 0;
73 spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
74
40 if (!bo->kmap.virtual) { 75 if (!bo->kmap.virtual) {
41 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); 76 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
42 if (ret) { 77 if (ret) {
@@ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
268 303
269 cdev->mode_info.gfbdev = gfbdev; 304 cdev->mode_info.gfbdev = gfbdev;
270 gfbdev->helper.funcs = &cirrus_fb_helper_funcs; 305 gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
306 spin_lock_init(&gfbdev->dirty_lock);
271 307
272 ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, 308 ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
273 cdev->num_crtc, CIRRUSFB_CONN_LIMIT); 309 cdev->num_crtc, CIRRUSFB_CONN_LIMIT);