When using page list framebuffer, and using RGB888 format, some
pixels can cross the page boundaries, and this case was not handled,
leading to writing 1 or 2 bytes on the next virtual address.

Add a check and a specific function to handle this case.

Fixes: c9ff2808790f0 ("drm/panic: Add support to scanout buffer as array of 
pages")
Signed-off-by: Jocelyn Falempe <[email protected]>
---
 drivers/gpu/drm/drm_panic.c | 46 +++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
index bc5158683b2b..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)
-- 
2.51.0

Reply via email to