Skip to content

Commit f3b2bbd

Browse files
committed
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: [email protected] Signed-off-by: Dave Airlie <[email protected]>
1 parent 306373b commit f3b2bbd

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

drivers/gpu/drm/cirrus/cirrus_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ struct cirrus_fbdev {
154154
struct list_head fbdev_list;
155155
void *sysram;
156156
int size;
157+
int x1, y1, x2, y2; /* dirty rect */
158+
spinlock_t dirty_lock;
157159
};
158160

159161
struct cirrus_bo {

drivers/gpu/drm/cirrus/cirrus_fbdev.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
2727
int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
2828
int ret;
2929
bool unmap = false;
30+
bool store_for_later = false;
31+
int x2, y2;
32+
unsigned long flags;
3033

3134
obj = afbdev->gfb.obj;
3235
bo = gem_to_cirrus_bo(obj);
3336

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+
*/
3442
ret = cirrus_bo_reserve(bo, true);
3543
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);
3768
return;
3869
}
3970

71+
afbdev->x1 = afbdev->y1 = INT_MAX;
72+
afbdev->x2 = afbdev->y2 = 0;
73+
spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
74+
4075
if (!bo->kmap.virtual) {
4176
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
4277
if (ret) {
@@ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
268303

269304
cdev->mode_info.gfbdev = gfbdev;
270305
gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
306+
spin_lock_init(&gfbdev->dirty_lock);
271307

272308
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
273309
cdev->num_crtc, CIRRUSFB_CONN_LIMIT);

drivers/gpu/drm/cirrus/cirrus_ttm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
321321

322322
ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
323323
if (ret) {
324-
if (ret != -ERESTARTSYS)
324+
if (ret != -ERESTARTSYS && ret != -EBUSY)
325325
DRM_ERROR("reserve failed %p\n", bo);
326326
return ret;
327327
}

0 commit comments

Comments
 (0)