summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2019-04-01 17:46:57 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-05-25 18:16:34 +0200
commit15f4d39ae4db2ba2ae261849836bc1e939a7b6bc (patch)
tree8efd2322cd03641e196c3d957df8b4276b443bbf
parentd6763d4f7ceb1ffdd073be74fef6d7574bcf5f31 (diff)
udlfb: introduce a rendering mutex
commit babc250e278eac7b0e671bdaedf833759b43bb78 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: Mikulas 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: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/video/fbdev/udlfb.c41
-rw-r--r--include/video/udlfb.h1
2 files changed, 31 insertions, 11 deletions
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index ce30fa710244..5a0d6fb02bbc 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -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)
{
- int i;
+ int i, ret;
char *cmd;
cycles_t start_cycles, end_cycles;
int bytes_sent = 0;
@@ -606,21 +606,29 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, int width, i
start_cycles = get_cycles();
+ mutex_lock(&dlfb->render_mutex);
+
aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
x = aligned_x;
if ((width <= 0) ||
(x + width > dlfb->info->var.xres) ||
- (y + height > dlfb->info->var.yres))
- return -EINVAL;
+ (y + height > dlfb->info->var.yres)) {
+ ret = -EINVAL;
+ goto unlock_ret;
+ }
- if (!atomic_read(&dlfb->usb_active))
- return 0;
+ if (!atomic_read(&dlfb->usb_active)) {
+ ret = 0;
+ goto unlock_ret;
+ }
urb = dlfb_get_urb(dlfb);
- if (!urb)
- return 0;
+ if (!urb) {
+ ret = 0;
+ goto unlock_ret;
+ }
cmd = urb->transfer_buffer;
for (i = y; i < y + height ; i++) {
@@ -654,7 +662,11 @@ error:
>> 10)), /* Kcycles */
&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)
@@ -782,17 +794,19 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
int bytes_identical = 0;
int bytes_rendered = 0;
+ mutex_lock(&dlfb->render_mutex);
+
if (!fb_defio)
- return;
+ goto unlock_ret;
if (!atomic_read(&dlfb->usb_active))
- return;
+ goto unlock_ret;
start_cycles = get_cycles();
urb = dlfb_get_urb(dlfb);
if (!urb)
- return;
+ goto unlock_ret;
cmd = urb->transfer_buffer;
@@ -825,6 +839,8 @@ error:
atomic_add(((unsigned int) ((end_cycles - start_cycles)
>> 10)), /* Kcycles */
&dlfb->cpu_kcycles_used);
+unlock_ret:
+ mutex_unlock(&dlfb->render_mutex);
}
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)
cancel_work_sync(&dlfb->damage_work);
+ mutex_destroy(&dlfb->render_mutex);
+
if (info->cmap.len != 0)
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
@@ -1682,6 +1700,7 @@ static int dlfb_usb_probe(struct usb_interface *intf,
dlfb->ops = dlfb_ops;
info->fbops = &dlfb->ops;
+ mutex_init(&dlfb->render_mutex);
dlfb_init_damage(dlfb);
spin_lock_init(&dlfb->damage_lock);
INIT_WORK(&dlfb->damage_work, dlfb_damage_work);
diff --git a/include/video/udlfb.h b/include/video/udlfb.h
index a3724f1fca1c..58fb5732831a 100644
--- a/include/video/udlfb.h
+++ b/include/video/udlfb.h
@@ -48,6 +48,7 @@ struct dlfb_data {
int base8;
u32 pseudo_palette[256];
int blank_mode; /*one of FB_BLANK_ */
+ struct mutex render_mutex;
int damage_x;
int damage_y;
int damage_x2;