Commit 15f4d39a authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Greg Kroah-Hartman

udlfb: introduce a rendering mutex

commit babc250e upstream.

Rendering calls may be done simultaneously from the workqueue,
dlfb_ops_write, dlfb_ops_ioctl, dlfb_ops_set_par and dlfb_dpy_deferred_io.
The code is robust enough so that it won't crash on concurrent rendering.

However, concurrent rendering may cause display corruption if the same
pixel is simultaneously being rendered. In order to avoid this corruption,
this patch adds a mutex around the rendering calls.
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Cc: Bernie Thompson <bernie@plugable.com>
Cc: Ladislav Michl <ladis@linux-mips.org>
Cc: <stable@vger.kernel.org>
[b.zolnierkie: replace "dlfb:" with "uldfb:" in the patch summary]
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d6763d4f
...@@ -596,7 +596,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, ...@@ -596,7 +596,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height) static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, int height)
{ {
int i; int i, ret;
char *cmd; char *cmd;
cycles_t start_cycles, end_cycles; cycles_t start_cycles, end_cycles;
int bytes_sent = 0; int bytes_sent = 0;
...@@ -606,21 +606,29 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, i ...@@ -606,21 +606,29 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, i
start_cycles = get_cycles(); start_cycles = get_cycles();
mutex_lock(&dlfb->render_mutex);
aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
x = aligned_x; x = aligned_x;
if ((width <= 0) || if ((width <= 0) ||
(x + width > dlfb->info->var.xres) || (x + width > dlfb->info->var.xres) ||
(y + height > dlfb->info->var.yres)) (y + height > dlfb->info->var.yres)) {
return -EINVAL; ret = -EINVAL;
goto unlock_ret;
}
if (!atomic_read(&dlfb->usb_active)) if (!atomic_read(&dlfb->usb_active)) {
return 0; ret = 0;
goto unlock_ret;
}
urb = dlfb_get_urb(dlfb); urb = dlfb_get_urb(dlfb);
if (!urb) if (!urb) {
return 0; ret = 0;
goto unlock_ret;
}
cmd = urb->transfer_buffer; cmd = urb->transfer_buffer;
for (i = y; i < y + height ; i++) { for (i = y; i < y + height ; i++) {
...@@ -654,7 +662,11 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, i ...@@ -654,7 +662,11 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, i
>> 10)), /* Kcycles */ >> 10)), /* Kcycles */
&dlfb->cpu_kcycles_used); &dlfb->cpu_kcycles_used);
return 0; ret = 0;
unlock_ret:
mutex_unlock(&dlfb->render_mutex);
return ret;
} }
static void dlfb_init_damage(struct dlfb_data *dlfb) static void dlfb_init_damage(struct dlfb_data *dlfb)
...@@ -782,17 +794,19 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, ...@@ -782,17 +794,19 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
int bytes_identical = 0; int bytes_identical = 0;
int bytes_rendered = 0; int bytes_rendered = 0;
mutex_lock(&dlfb->render_mutex);
if (!fb_defio) if (!fb_defio)
return; goto unlock_ret;
if (!atomic_read(&dlfb->usb_active)) if (!atomic_read(&dlfb->usb_active))
return; goto unlock_ret;
start_cycles = get_cycles(); start_cycles = get_cycles();
urb = dlfb_get_urb(dlfb); urb = dlfb_get_urb(dlfb);
if (!urb) if (!urb)
return; goto unlock_ret;
cmd = urb->transfer_buffer; cmd = urb->transfer_buffer;
...@@ -825,6 +839,8 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, ...@@ -825,6 +839,8 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
atomic_add(((unsigned int) ((end_cycles - start_cycles) atomic_add(((unsigned int) ((end_cycles - start_cycles)
>> 10)), /* Kcycles */ >> 10)), /* Kcycles */
&dlfb->cpu_kcycles_used); &dlfb->cpu_kcycles_used);
unlock_ret:
mutex_unlock(&dlfb->render_mutex);
} }
static int dlfb_get_edid(struct dlfb_data *dlfb, char *edid, int len) static int dlfb_get_edid(struct dlfb_data *dlfb, char *edid, int len)
...@@ -986,6 +1002,8 @@ static void dlfb_ops_destroy(struct fb_info *info) ...@@ -986,6 +1002,8 @@ static void dlfb_ops_destroy(struct fb_info *info)
cancel_work_sync(&dlfb->damage_work); cancel_work_sync(&dlfb->damage_work);
mutex_destroy(&dlfb->render_mutex);
if (info->cmap.len != 0) if (info->cmap.len != 0)
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb) if (info->monspecs.modedb)
...@@ -1682,6 +1700,7 @@ static int dlfb_usb_probe(struct usb_interface *intf, ...@@ -1682,6 +1700,7 @@ static int dlfb_usb_probe(struct usb_interface *intf,
dlfb->ops = dlfb_ops; dlfb->ops = dlfb_ops;
info->fbops = &dlfb->ops; info->fbops = &dlfb->ops;
mutex_init(&dlfb->render_mutex);
dlfb_init_damage(dlfb); dlfb_init_damage(dlfb);
spin_lock_init(&dlfb->damage_lock); spin_lock_init(&dlfb->damage_lock);
INIT_WORK(&dlfb->damage_work, dlfb_damage_work); INIT_WORK(&dlfb->damage_work, dlfb_damage_work);
......
...@@ -48,6 +48,7 @@ struct dlfb_data { ...@@ -48,6 +48,7 @@ struct dlfb_data {
int base8; int base8;
u32 pseudo_palette[256]; u32 pseudo_palette[256];
int blank_mode; /*one of FB_BLANK_ */ int blank_mode; /*one of FB_BLANK_ */
struct mutex render_mutex;
int damage_x; int damage_x;
int damage_y; int damage_y;
int damage_x2; int damage_x2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment