| From: Mikulas Patocka <mpatocka@redhat.com> |
| Date: Sun, 3 Jun 2018 16:40:54 +0200 |
| Subject: drm/udl: fix display corruption of the last line |
| |
| commit 99ec9e77511dea55d81729fc80b6c63a61bfa8e0 upstream. |
| |
| The displaylink hardware has such a peculiarity that it doesn't render a |
| command until next command is received. This produces occasional |
| corruption, such as when setting 22x11 font on the console, only the first |
| line of the cursor will be blinking if the cursor is located at some |
| specific columns. |
| |
| When we end up with a repeating pixel, the driver has a bug that it leaves |
| one uninitialized byte after the command (and this byte is enough to flush |
| the command and render it - thus it fixes the screen corruption), however |
| whe we end up with a non-repeating pixel, there is no byte appended and |
| this results in temporary screen corruption. |
| |
| This patch fixes the screen corruption by always appending a byte 0xAF at |
| the end of URB. It also removes the uninitialized byte. |
| |
| Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> |
| Signed-off-by: Dave Airlie <airlied@redhat.com> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/gpu/drm/udl/udl_fb.c | 5 ++++- |
| drivers/gpu/drm/udl/udl_transfer.c | 11 +++++++---- |
| 2 files changed, 11 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/gpu/drm/udl/udl_fb.c |
| +++ b/drivers/gpu/drm/udl/udl_fb.c |
| @@ -234,7 +234,10 @@ int udl_handle_damage(struct udl_framebu |
| |
| if (cmd > (char *) urb->transfer_buffer) { |
| /* Send partial buffer remaining before exiting */ |
| - int len = cmd - (char *) urb->transfer_buffer; |
| + int len; |
| + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) |
| + *cmd++ = 0xAF; |
| + len = cmd - (char *) urb->transfer_buffer; |
| ret = udl_submit_urb(dev, urb, len); |
| bytes_sent += len; |
| } else |
| --- a/drivers/gpu/drm/udl/udl_transfer.c |
| +++ b/drivers/gpu/drm/udl/udl_transfer.c |
| @@ -149,11 +149,11 @@ static void udl_compress_hline16( |
| raw_pixels_count_byte = cmd++; /* we'll know this later */ |
| raw_pixel_start = pixel; |
| |
| - cmd_pixel_end = pixel + (min(MAX_CMD_PIXELS + 1, |
| - min((int)(pixel_end - pixel) / bpp, |
| - (int)(cmd_buffer_end - cmd) / 2))) * bpp; |
| + cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, |
| + (unsigned long)(pixel_end - pixel) / bpp, |
| + (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) * bpp; |
| |
| - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); |
| + prefetch_range((void *) pixel, cmd_pixel_end - pixel); |
| |
| while (pixel < cmd_pixel_end) { |
| const u8 *const start = pixel; |
| @@ -193,6 +193,9 @@ static void udl_compress_hline16( |
| if (pixel > raw_pixel_start) { |
| /* finalize last RAW span */ |
| *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF; |
| + } else { |
| + /* undo unused byte */ |
| + cmd--; |
| } |
| |
| *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF; |