diff options
Diffstat (limited to 'drivers/gpu/drm/drm_panic.c')
| -rw-r--r-- | drivers/gpu/drm/drm_panic.c | 60 | 
1 files changed, 54 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 1d6312fa1429..d4b6ea42db0f 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -174,6 +174,33 @@ static void drm_panic_write_pixel24(void *vaddr, unsigned int offset, u32 color)  	*p = color & 0xff;  } +/* + * Special case if the pixel crosses page boundaries + */ +static void drm_panic_write_pixel24_xpage(void *vaddr, struct page *next_page, +					  unsigned int offset, u32 color) +{ +	u8 *vaddr2; +	u8 *p = vaddr + offset; + +	vaddr2 = kmap_local_page_try_from_panic(next_page); + +	*p++ = color & 0xff; +	color >>= 8; + +	if (offset == PAGE_SIZE - 1) +		p = vaddr2; + +	*p++ = color & 0xff; +	color >>= 8; + +	if (offset == PAGE_SIZE - 2) +		p = vaddr2; + +	*p = color & 0xff; +	kunmap_local(vaddr2); +} +  static void drm_panic_write_pixel32(void *vaddr, unsigned int offset, u32 color)  {  	u32 *p = vaddr + offset; @@ -231,7 +258,14 @@ static void drm_panic_blit_page(struct page **pages, unsigned int dpitch,  					page = new_page;  					vaddr = kmap_local_page_try_from_panic(pages[page]);  				} -				if (vaddr) +				if (!vaddr) +					continue; + +				// Special case for 24bit, as a pixel might cross page boundaries +				if (cpp == 3 && offset + 3 > PAGE_SIZE) +					drm_panic_write_pixel24_xpage(vaddr, pages[page + 1], +								      offset, fg32); +				else  					drm_panic_write_pixel(vaddr, offset, fg32, cpp);  			}  		} @@ -321,7 +355,15 @@ static void drm_panic_fill_page(struct page **pages, unsigned int dpitch,  				page = new_page;  				vaddr = kmap_local_page_try_from_panic(pages[page]);  			} -			drm_panic_write_pixel(vaddr, offset, color, cpp); +			if (!vaddr) +				continue; + +			// Special case for 24bit, as a pixel might cross page boundaries +			if (cpp == 3 && offset + 3 > PAGE_SIZE) +				drm_panic_write_pixel24_xpage(vaddr, pages[page + 1], +							      offset, color); +			else +				drm_panic_write_pixel(vaddr, offset, color, cpp);  		}  	}  	if (vaddr) @@ -429,6 +471,9 @@ static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *f  static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect,  				const struct font_desc *font, u32 fg_color)  { +	if (rect->x2 > sb->width || rect->y2 > sb->height) +		return; +  	if (logo_mono)  		drm_panic_blit(sb, rect, logo_mono->data,  			       DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color); @@ -477,7 +522,7 @@ static int draw_line_with_wrap(struct drm_scanout_buffer *sb, const struct font_  			       struct drm_panic_line *line, int yoffset, u32 fg_color)  {  	int chars_per_row = sb->width / font->width; -	struct drm_rect r_txt = DRM_RECT_INIT(0, yoffset, sb->width, sb->height); +	struct drm_rect r_txt = DRM_RECT_INIT(0, yoffset, sb->width, font->height);  	struct drm_panic_line line_wrap;  	if (line->len > chars_per_row) { @@ -520,7 +565,7 @@ static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb)  	struct drm_panic_line line;  	int yoffset; -	if (!font) +	if (!font || font->width > sb->width)  		return;  	yoffset = sb->height - font->height - (sb->height % font->height) / 2; @@ -733,7 +778,10 @@ static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb)  	pr_debug("QR width %d and scale %d\n", qr_width, scale);  	r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale); -	v_margin = (sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg)) / 5; +	v_margin = sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg); +	if (v_margin < 0) +		return -ENOSPC; +	v_margin /= 5;  	drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin);  	r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale, @@ -746,7 +794,7 @@ static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb)  	/* Fill with the background color, and draw text on top */  	drm_panic_fill(sb, &r_screen, bg_color); -	if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr)) +	if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr_canvas))  		drm_panic_logo_draw(sb, &r_logo, font, fg_color);  	draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);  | 
