* [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-17 15:06 ` Thomas Zimmermann
2024-01-17 15:26 ` Jani Nikula
2024-01-04 16:00 ` [PATCH v7 2/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (8 subsequent siblings)
9 siblings, 2 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
This is needed for drm_panic, to draw the font, and fill
the background color, in multiple color format.
v5:
* Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
* Also add drm_fb_fill() to fill area with background color.
v6:
* fix __le32 conversion warning found by the kernel test bot
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
include/drm/drm_format_helper.h | 9 +
2 files changed, 360 insertions(+), 81 deletions(-)
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index b1be458ed4dd..8cbc2d747cff 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state)
}
EXPORT_SYMBOL(drm_format_conv_state_release);
+static inline __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
+{
+ u16 val16;
+ u32 pix;
+
+ pix = le32_to_cpu(val32);
+ val16 = ((pix & 0x00F80000) >> 8) |
+ ((pix & 0x0000FC00) >> 5) |
+ ((pix & 0x000000F8) >> 3);
+ return cpu_to_le16(val16);
+}
+
+static inline __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
+{
+ u16 val16;
+ u32 pix;
+
+ pix = le32_to_cpu(val32);
+ val16 = ((pix & 0x00f80000) >> 8) |
+ ((pix & 0x0000f800) >> 5) |
+ ((pix & 0x000000f8) >> 2) |
+ BIT(0); /* set alpha bit */
+ return cpu_to_le16(val16);
+}
+
+static inline __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
+{
+ u16 val16;
+ u32 pix;
+
+ pix = le32_to_cpu(val32);
+ val16 = ((pix & 0x00f80000) >> 9) |
+ ((pix & 0x0000f800) >> 6) |
+ ((pix & 0x000000f8) >> 3);
+ return cpu_to_le16(val16);
+}
+
+static inline __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
+{
+ u16 val16;
+ u32 pix;
+
+ pix = le32_to_cpu(val32);
+ val16 = BIT(15) | /* set alpha bit */
+ ((pix & 0x00f80000) >> 9) |
+ ((pix & 0x0000f800) >> 6) |
+ ((pix & 0x000000f8) >> 3);
+ return cpu_to_le16(val16);
+}
+
+static inline __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
+{
+ u32 val32;
+
+ val32 = le32_to_cpu(pix);
+ val32 |= GENMASK(31, 24); /* fill alpha bits */
+ return cpu_to_le32(val32);
+}
+
+static inline __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
+{
+ u32 val32;
+
+ val32 = le32_to_cpu(pix);
+ val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
+ ((val32 & 0x0000ff00) >> 8) << 8 |
+ ((val32 & 0x000000ff) >> 0) << 16 |
+ ((val32 & 0xff000000) >> 24) << 24;
+ return cpu_to_le32(val32);
+}
+
+static inline __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
+{
+ u32 val32;
+
+ val32 = le32_to_cpu(pix);
+ val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
+ ((val32 & 0x0000ff00) >> 8) << 8 |
+ ((val32 & 0x000000ff) >> 0) << 16 |
+ GENMASK(31, 24); /* fill alpha bits */
+ return cpu_to_le32(val32);
+}
+
+static inline __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
+{
+ u32 val32;
+
+ val32 = le32_to_cpu(pix);
+ val32 = ((val32 & 0x000000FF) << 2) |
+ ((val32 & 0x0000FF00) << 4) |
+ ((val32 & 0x00FF0000) << 6);
+ return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
+}
+
+static inline __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
+{
+ u32 val32;
+
+ val32 = le32_to_cpu(pix);
+ val32 = ((val32 & 0x000000FF) << 2) |
+ ((val32 & 0x0000FF00) << 4) |
+ ((val32 & 0x00FF0000) << 6);
+ val32 = GENMASK(31, 30) | /* set alpha bits */
+ val32 | ((val32 >> 8) & 0x00300c03);
+ return cpu_to_le32(val32);
+}
+
+/**
+ * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
+ * @color: input color, in xrgb8888 format
+ * @format: output format
+ *
+ * Returns:
+ * Color in the format specified, casted to u32.
+ * Or 0 if the format is unknown.
+ */
+u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
+{
+ __le32 pix = cpu_to_le32(color);
+
+ switch (format) {
+ case DRM_FORMAT_RGB565:
+ return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
+ case DRM_FORMAT_RGBA5551:
+ return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
+ case DRM_FORMAT_XRGB1555:
+ return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
+ case DRM_FORMAT_ARGB1555:
+ return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_XRGB8888:
+ return le32_to_cpu(pix);
+ case DRM_FORMAT_ARGB8888:
+ return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
+ case DRM_FORMAT_XBGR8888:
+ return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
+ case DRM_FORMAT_XRGB2101010:
+ return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
+ case DRM_FORMAT_ARGB2101010:
+ return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
+ default:
+ WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
+ return 0;
+ }
+}
+EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
+
static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
{
return clip->y1 * pitch + clip->x1 * cpp;
@@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
}
EXPORT_SYMBOL(drm_fb_swab);
+static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
+ const u8 *sbuf8, unsigned int spitch,
+ unsigned int height, unsigned int width,
+ __le16 fg16, __le16 bg16)
+{
+ unsigned int l, x;
+ __le16 val16;
+
+ for (l = 0; l < height; l++) {
+ for (x = 0; x < width; x++) {
+ val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
+ iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
+ }
+ }
+}
+
+static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
+ const u8 *sbuf8, unsigned int spitch,
+ unsigned int height, unsigned int width,
+ __le32 fg32, __le32 bg32)
+{
+ unsigned int l, x;
+ __le32 color;
+ u32 val32;
+
+ for (l = 0; l < height; l++) {
+ for (x = 0; x < width; x++) {
+ u32 off = l * dpitch + x * 3;
+
+ color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
+ val32 = le32_to_cpu(color);
+
+ /* write blue-green-red to output in little endianness */
+ iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
+ iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
+ iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
+ }
+ }
+}
+
+static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
+ const u8 *sbuf8, unsigned int spitch,
+ unsigned int height, unsigned int width,
+ __le32 fg32, __le32 bg32)
+{
+ unsigned int l, x;
+ __le32 val32;
+
+ for (l = 0; l < height; l++) {
+ for (x = 0; x < width; x++) {
+ val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
+ iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
+ }
+ }
+}
+
+/**
+ * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
+ * @dmap: destination iosys_map
+ * @dpitch: destination pitch in bytes
+ * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
+ * @spitch: source pitch in bytes
+ * @height: height of the image to copy, in pixels
+ * @width: width of the image to copy, in pixels
+ * @fg_color: foreground color, in destination format
+ * @bg_color: background color, in destination format
+ * @pixel_width: pixel width in bytes.
+ *
+ * This can be used to draw font which are monochrome images, to a framebuffer
+ * in other supported format.
+ */
+void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
+ const u8 *sbuf8, unsigned int spitch,
+ unsigned int height, unsigned int width,
+ u32 fg_color, u32 bg_color,
+ unsigned int pixel_width)
+{
+ switch (pixel_width) {
+ case 2:
+ drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
+ height, width,
+ cpu_to_le16(fg_color),
+ cpu_to_le16(bg_color));
+ break;
+ case 3:
+ drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
+ height, width,
+ cpu_to_le32(fg_color),
+ cpu_to_le32(bg_color));
+ break;
+ case 4:
+ drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
+ height, width,
+ cpu_to_le32(fg_color),
+ cpu_to_le32(bg_color));
+ break;
+ default:
+ WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
+ }
+}
+EXPORT_SYMBOL(drm_fb_blit_from_r1);
+
+static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u8 color)
+{
+ unsigned int l, x;
+
+ for (l = 0; l < height; l++)
+ for (x = 0; x < width; x++)
+ iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
+}
+
+static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u16 color)
+{
+ unsigned int l, x;
+
+ for (l = 0; l < height; l++)
+ for (x = 0; x < width; x++)
+ iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
+}
+
+static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u32 color)
+{
+ unsigned int l, x;
+
+ for (l = 0; l < height; l++) {
+ for (x = 0; x < width; x++) {
+ unsigned int off = l * dpitch + x * 3;
+
+ /* write blue-green-red to output in little endianness */
+ iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
+ iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
+ iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
+ }
+ }
+}
+
+static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u32 color)
+{
+ unsigned int l, x;
+
+ for (l = 0; l < height; l++)
+ for (x = 0; x < width; x++)
+ iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
+}
+
+/**
+ * drm_fb_fill - Fill a rectangle with a color
+ * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
+ * @dpitch: destination pitch in bytes
+ * @height: height of the rectangle, in pixels
+ * @width: width of the rectangle, in pixels
+ * @color: color to fill the rectangle.
+ * @pixel_width: pixel width in bytes
+ *
+ * Fill a rectangle with a color, in a linear framebuffer.
+ */
+void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u32 color, unsigned int pixel_width)
+{
+ switch (pixel_width) {
+ case 1:
+ drm_fb_fill8(dmap, dpitch, height, width, color);
+ break;
+ case 2:
+ drm_fb_fill16(dmap, dpitch, height, width, color);
+ break;
+ case 3:
+ drm_fb_fill24(dmap, dpitch, height, width, color);
+ break;
+ case 4:
+ drm_fb_fill32(dmap, dpitch, height, width, color);
+ break;
+ default:
+ WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
+ }
+}
+EXPORT_SYMBOL(drm_fb_fill);
+
static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
u8 *dbuf8 = dbuf;
@@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u16 val16;
- u32 pix;
for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val16 = ((pix & 0x00F80000) >> 8) |
- ((pix & 0x0000FC00) >> 5) |
- ((pix & 0x000000F8) >> 3);
- dbuf16[x] = cpu_to_le16(val16);
+ dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
}
}
@@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u16 val16;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val16 = ((pix & 0x00f80000) >> 9) |
- ((pix & 0x0000f800) >> 6) |
- ((pix & 0x000000f8) >> 3);
- dbuf16[x] = cpu_to_le16(val16);
- }
+ for (x = 0; x < pixels; x++)
+ dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
}
/**
@@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u16 val16;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val16 = BIT(15) | /* set alpha bit */
- ((pix & 0x00f80000) >> 9) |
- ((pix & 0x0000f800) >> 6) |
- ((pix & 0x000000f8) >> 3);
- dbuf16[x] = cpu_to_le16(val16);
- }
+ for (x = 0; x < pixels; x++)
+ dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
}
/**
@@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
__le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u16 val16;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val16 = ((pix & 0x00f80000) >> 8) |
- ((pix & 0x0000f800) >> 5) |
- ((pix & 0x000000f8) >> 2) |
- BIT(0); /* set alpha bit */
- dbuf16[x] = cpu_to_le16(val16);
- }
+ for (x = 0; x < pixels; x++)
+ dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
}
/**
@@ -707,13 +1012,9 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- pix |= GENMASK(31, 24); /* fill alpha bits */
- dbuf32[x] = cpu_to_le32(pix);
- }
+ for (x = 0; x < pixels; x++)
+ dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
}
/**
@@ -756,16 +1057,9 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- pix = ((pix & 0x00ff0000) >> 16) << 0 |
- ((pix & 0x0000ff00) >> 8) << 8 |
- ((pix & 0x000000ff) >> 0) << 16 |
- GENMASK(31, 24); /* fill alpha bits */
- *dbuf32++ = cpu_to_le32(pix);
- }
+ for (x = 0; x < pixels; x++)
+ *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
}
static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
@@ -787,16 +1081,9 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- pix = ((pix & 0x00ff0000) >> 16) << 0 |
- ((pix & 0x0000ff00) >> 8) << 8 |
- ((pix & 0x000000ff) >> 0) << 16 |
- ((pix & 0xff000000) >> 24) << 24;
- *dbuf32++ = cpu_to_le32(pix);
- }
+ for (x = 0; x < pixels; x++)
+ *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
}
static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
@@ -818,17 +1105,9 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u32 val32;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val32 = ((pix & 0x000000FF) << 2) |
- ((pix & 0x0000FF00) << 4) |
- ((pix & 0x00FF0000) << 6);
- pix = val32 | ((val32 >> 8) & 0x00300C03);
- *dbuf32++ = cpu_to_le32(pix);
- }
+ for (x = 0; x < pixels; x++)
+ *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
}
/**
@@ -872,18 +1151,9 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
__le32 *dbuf32 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
- u32 val32;
- u32 pix;
- for (x = 0; x < pixels; x++) {
- pix = le32_to_cpu(sbuf32[x]);
- val32 = ((pix & 0x000000ff) << 2) |
- ((pix & 0x0000ff00) << 4) |
- ((pix & 0x00ff0000) << 6);
- pix = GENMASK(31, 30) | /* set alpha bits */
- val32 | ((val32 >> 8) & 0x00300c03);
- *dbuf32++ = cpu_to_le32(pix);
- }
+ for (x = 0; x < pixels; x++)
+ *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
}
/**
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index f13b34e0b752..f416f0bef52d 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
size_t new_size, gfp_t flags);
void drm_format_conv_state_release(struct drm_format_conv_state *state);
+u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
const struct drm_rect *clip);
@@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip, bool cached,
struct drm_format_conv_state *state);
+void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
+ const u8 *sbuf8, unsigned int spitch,
+ unsigned int height, unsigned int width,
+ u32 fg_color, u32 bg_color,
+ unsigned int pixel_width);
+void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
+ unsigned int height, unsigned int width,
+ u32 color, unsigned int pixel_width);
void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
const struct iosys_map *src, const struct drm_framebuffer *fb,
const struct drm_rect *clip, struct drm_format_conv_state *state);
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-04 16:00 ` [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill Jocelyn Falempe
@ 2024-01-17 15:06 ` Thomas Zimmermann
2024-01-17 16:40 ` Jocelyn Falempe
2024-01-17 15:26 ` Jani Nikula
1 sibling, 1 reply; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:06 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 19517 bytes --]
Hi
Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> This is needed for drm_panic, to draw the font, and fill
> the background color, in multiple color format.
TBH, I don't like this patch at all. It looks like you're reimplementing
existing functionality for a single use case; specifically drm_fb_blit().
What's wrong with the existing interfaces?
Best regards
Thomas
>
> v5:
> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
> * Also add drm_fb_fill() to fill area with background color.
> v6:
> * fix __le32 conversion warning found by the kernel test bot
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
> include/drm/drm_format_helper.h | 9 +
> 2 files changed, 360 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
> index b1be458ed4dd..8cbc2d747cff 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state)
> }
> EXPORT_SYMBOL(drm_format_conv_state_release);
>
> +static inline __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00F80000) >> 8) |
> + ((pix & 0x0000FC00) >> 5) |
> + ((pix & 0x000000F8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00f80000) >> 8) |
> + ((pix & 0x0000f800) >> 5) |
> + ((pix & 0x000000f8) >> 2) |
> + BIT(0); /* set alpha bit */
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00f80000) >> 9) |
> + ((pix & 0x0000f800) >> 6) |
> + ((pix & 0x000000f8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = BIT(15) | /* set alpha bit */
> + ((pix & 0x00f80000) >> 9) |
> + ((pix & 0x0000f800) >> 6) |
> + ((pix & 0x000000f8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 |= GENMASK(31, 24); /* fill alpha bits */
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
> + ((val32 & 0x0000ff00) >> 8) << 8 |
> + ((val32 & 0x000000ff) >> 0) << 16 |
> + ((val32 & 0xff000000) >> 24) << 24;
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
> + ((val32 & 0x0000ff00) >> 8) << 8 |
> + ((val32 & 0x000000ff) >> 0) << 16 |
> + GENMASK(31, 24); /* fill alpha bits */
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x000000FF) << 2) |
> + ((val32 & 0x0000FF00) << 4) |
> + ((val32 & 0x00FF0000) << 6);
> + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x000000FF) << 2) |
> + ((val32 & 0x0000FF00) << 4) |
> + ((val32 & 0x00FF0000) << 6);
> + val32 = GENMASK(31, 30) | /* set alpha bits */
> + val32 | ((val32 >> 8) & 0x00300c03);
> + return cpu_to_le32(val32);
> +}
> +
> +/**
> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
> + * @color: input color, in xrgb8888 format
> + * @format: output format
> + *
> + * Returns:
> + * Color in the format specified, casted to u32.
> + * Or 0 if the format is unknown.
> + */
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
> +{
> + __le32 pix = cpu_to_le32(color);
> +
> + switch (format) {
> + case DRM_FORMAT_RGB565:
> + return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
> + case DRM_FORMAT_RGBA5551:
> + return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
> + case DRM_FORMAT_XRGB1555:
> + return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
> + case DRM_FORMAT_ARGB1555:
> + return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
> + case DRM_FORMAT_RGB888:
> + case DRM_FORMAT_XRGB8888:
> + return le32_to_cpu(pix);
> + case DRM_FORMAT_ARGB8888:
> + return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
> + case DRM_FORMAT_XBGR8888:
> + return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
> + case DRM_FORMAT_XRGB2101010:
> + return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
> + case DRM_FORMAT_ARGB2101010:
> + return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
> + default:
> + WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
> + return 0;
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
> +
> static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
> {
> return clip->y1 * pitch + clip->x1 * cpp;
> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
> }
> EXPORT_SYMBOL(drm_fb_swab);
>
> +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le16 fg16, __le16 bg16)
> +{
> + unsigned int l, x;
> + __le16 val16;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
> + }
> + }
> +}
> +
> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le32 fg32, __le32 bg32)
> +{
> + unsigned int l, x;
> + __le32 color;
> + u32 val32;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + u32 off = l * dpitch + x * 3;
> +
> + color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> + val32 = le32_to_cpu(color);
> +
> + /* write blue-green-red to output in little endianness */
> + iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
> + iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
> + iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
> + }
> + }
> +}
> +
> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le32 fg32, __le32 bg32)
> +{
> + unsigned int l, x;
> + __le32 val32;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
> + }
> + }
> +}
> +
> +/**
> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
> + * @dmap: destination iosys_map
> + * @dpitch: destination pitch in bytes
> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
> + * @spitch: source pitch in bytes
> + * @height: height of the image to copy, in pixels
> + * @width: width of the image to copy, in pixels
> + * @fg_color: foreground color, in destination format
> + * @bg_color: background color, in destination format
> + * @pixel_width: pixel width in bytes.
> + *
> + * This can be used to draw font which are monochrome images, to a framebuffer
> + * in other supported format.
> + */
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + u32 fg_color, u32 bg_color,
> + unsigned int pixel_width)
> +{
> + switch (pixel_width) {
> + case 2:
> + drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le16(fg_color),
> + cpu_to_le16(bg_color));
> + break;
> + case 3:
> + drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le32(fg_color),
> + cpu_to_le32(bg_color));
> + break;
> + case 4:
> + drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le32(fg_color),
> + cpu_to_le32(bg_color));
> + break;
> + default:
> + WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
> +
> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u8 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
> +}
> +
> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u16 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
> +}
> +
> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + unsigned int off = l * dpitch + x * 3;
> +
> + /* write blue-green-red to output in little endianness */
> + iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
> + iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
> + iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
> + }
> + }
> +}
> +
> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
> +}
> +
> +/**
> + * drm_fb_fill - Fill a rectangle with a color
> + * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
> + * @dpitch: destination pitch in bytes
> + * @height: height of the rectangle, in pixels
> + * @width: width of the rectangle, in pixels
> + * @color: color to fill the rectangle.
> + * @pixel_width: pixel width in bytes
> + *
> + * Fill a rectangle with a color, in a linear framebuffer.
> + */
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color, unsigned int pixel_width)
> +{
> + switch (pixel_width) {
> + case 1:
> + drm_fb_fill8(dmap, dpitch, height, width, color);
> + break;
> + case 2:
> + drm_fb_fill16(dmap, dpitch, height, width, color);
> + break;
> + case 3:
> + drm_fb_fill24(dmap, dpitch, height, width, color);
> + break;
> + case 4:
> + drm_fb_fill32(dmap, dpitch, height, width, color);
> + break;
> + default:
> + WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_fill);
> +
> static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
> {
> u8 *dbuf8 = dbuf;
> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00F80000) >> 8) |
> - ((pix & 0x0000FC00) >> 5) |
> - ((pix & 0x000000F8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> + dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
> }
> }
>
> @@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00f80000) >> 9) |
> - ((pix & 0x0000f800) >> 6) |
> - ((pix & 0x000000f8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
> }
>
> /**
> @@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = BIT(15) | /* set alpha bit */
> - ((pix & 0x00f80000) >> 9) |
> - ((pix & 0x0000f800) >> 6) |
> - ((pix & 0x000000f8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
> }
>
> /**
> @@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00f80000) >> 8) |
> - ((pix & 0x0000f800) >> 5) |
> - ((pix & 0x000000f8) >> 2) |
> - BIT(0); /* set alpha bit */
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
> }
>
> /**
> @@ -707,13 +1012,9 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix |= GENMASK(31, 24); /* fill alpha bits */
> - dbuf32[x] = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
> }
>
> /**
> @@ -756,16 +1057,9 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
> - ((pix & 0x0000ff00) >> 8) << 8 |
> - ((pix & 0x000000ff) >> 0) << 16 |
> - GENMASK(31, 24); /* fill alpha bits */
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
> }
>
> static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -787,16 +1081,9 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
> - ((pix & 0x0000ff00) >> 8) << 8 |
> - ((pix & 0x000000ff) >> 0) << 16 |
> - ((pix & 0xff000000) >> 24) << 24;
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
> }
>
> static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -818,17 +1105,9 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 val32;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val32 = ((pix & 0x000000FF) << 2) |
> - ((pix & 0x0000FF00) << 4) |
> - ((pix & 0x00FF0000) << 6);
> - pix = val32 | ((val32 >> 8) & 0x00300C03);
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
> }
>
> /**
> @@ -872,18 +1151,9 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 val32;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val32 = ((pix & 0x000000ff) << 2) |
> - ((pix & 0x0000ff00) << 4) |
> - ((pix & 0x00ff0000) << 6);
> - pix = GENMASK(31, 30) | /* set alpha bits */
> - val32 | ((val32 >> 8) & 0x00300c03);
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
> }
>
> /**
> diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
> index f13b34e0b752..f416f0bef52d 100644
> --- a/include/drm/drm_format_helper.h
> +++ b/include/drm/drm_format_helper.h
> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
> size_t new_size, gfp_t flags);
> void drm_format_conv_state_release(struct drm_format_conv_state *state);
>
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
> unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
> const struct drm_rect *clip);
>
> @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
> const struct iosys_map *src, const struct drm_framebuffer *fb,
> const struct drm_rect *clip, bool cached,
> struct drm_format_conv_state *state);
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + u32 fg_color, u32 bg_color,
> + unsigned int pixel_width);
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color, unsigned int pixel_width);
> void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
> const struct iosys_map *src, const struct drm_framebuffer *fb,
> const struct drm_rect *clip, struct drm_format_conv_state *state);
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-17 15:06 ` Thomas Zimmermann
@ 2024-01-17 16:40 ` Jocelyn Falempe
2024-01-19 10:58 ` Thomas Zimmermann
0 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-17 16:40 UTC (permalink / raw)
To: Thomas Zimmermann, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
On 17/01/2024 16:06, Thomas Zimmermann wrote:
> Hi
>
> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
>> This is needed for drm_panic, to draw the font, and fill
>> the background color, in multiple color format.
>
> TBH, I don't like this patch at all. It looks like you're reimplementing
> existing functionality for a single use case; specifically drm_fb_blit().
>
> What's wrong with the existing interfaces?
drm_fb_blit() is good to copy a framebuffer to another, but is clearly
unoptimal to draw font.
It handles xrgb8888 to any rgb format, and I need monochrome to any rgb
format.
I need to convert foreground and background color to the destination
format, but using drm_fb_blit() to convert 1 pixel is tedious.
It also requires an additional memory buffer, and do an additional
memory copy that we don't need at all.
It also has no way to fill a region with the background color.
The last thing, is if I plan to add YUV support, with this
implementation, I only need to write one function that convert one
pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line() and
drm_fb_r1_to_yuvxxxx() boilerplate.
Best regards,
--
Jocelyn
>
> Best regards
> Thomas
>
>>
>> v5:
>> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>> * Also add drm_fb_fill() to fill area with background color.
>> v6:
>> * fix __le32 conversion warning found by the kernel test bot
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>> ---
>> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
>> include/drm/drm_format_helper.h | 9 +
>> 2 files changed, 360 insertions(+), 81 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_format_helper.c
>> b/drivers/gpu/drm/drm_format_helper.c
>> index b1be458ed4dd..8cbc2d747cff 100644
>> --- a/drivers/gpu/drm/drm_format_helper.c
>> +++ b/drivers/gpu/drm/drm_format_helper.c
>> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct
>> drm_format_conv_state *state)
>> }
>> EXPORT_SYMBOL(drm_format_conv_state_release);
>> +static inline __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00F80000) >> 8) |
>> + ((pix & 0x0000FC00) >> 5) |
>> + ((pix & 0x000000F8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00f80000) >> 8) |
>> + ((pix & 0x0000f800) >> 5) |
>> + ((pix & 0x000000f8) >> 2) |
>> + BIT(0); /* set alpha bit */
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00f80000) >> 9) |
>> + ((pix & 0x0000f800) >> 6) |
>> + ((pix & 0x000000f8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = BIT(15) | /* set alpha bit */
>> + ((pix & 0x00f80000) >> 9) |
>> + ((pix & 0x0000f800) >> 6) |
>> + ((pix & 0x000000f8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 |= GENMASK(31, 24); /* fill alpha bits */
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
>> + ((val32 & 0x0000ff00) >> 8) << 8 |
>> + ((val32 & 0x000000ff) >> 0) << 16 |
>> + ((val32 & 0xff000000) >> 24) << 24;
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
>> + ((val32 & 0x0000ff00) >> 8) << 8 |
>> + ((val32 & 0x000000ff) >> 0) << 16 |
>> + GENMASK(31, 24); /* fill alpha bits */
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x000000FF) << 2) |
>> + ((val32 & 0x0000FF00) << 4) |
>> + ((val32 & 0x00FF0000) << 6);
>> + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x000000FF) << 2) |
>> + ((val32 & 0x0000FF00) << 4) |
>> + ((val32 & 0x00FF0000) << 6);
>> + val32 = GENMASK(31, 30) | /* set alpha bits */
>> + val32 | ((val32 >> 8) & 0x00300c03);
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +/**
>> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to
>> the desired format
>> + * @color: input color, in xrgb8888 format
>> + * @format: output format
>> + *
>> + * Returns:
>> + * Color in the format specified, casted to u32.
>> + * Or 0 if the format is unknown.
>> + */
>> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
>> +{
>> + __le32 pix = cpu_to_le32(color);
>> +
>> + switch (format) {
>> + case DRM_FORMAT_RGB565:
>> + return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
>> + case DRM_FORMAT_RGBA5551:
>> + return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
>> + case DRM_FORMAT_XRGB1555:
>> + return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
>> + case DRM_FORMAT_ARGB1555:
>> + return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
>> + case DRM_FORMAT_RGB888:
>> + case DRM_FORMAT_XRGB8888:
>> + return le32_to_cpu(pix);
>> + case DRM_FORMAT_ARGB8888:
>> + return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
>> + case DRM_FORMAT_XBGR8888:
>> + return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
>> + case DRM_FORMAT_XRGB2101010:
>> + return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
>> + case DRM_FORMAT_ARGB2101010:
>> + return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
>> + default:
>> + WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
>> + return 0;
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
>> +
>> static unsigned int clip_offset(const struct drm_rect *clip,
>> unsigned int pitch, unsigned int cpp)
>> {
>> return clip->y1 * pitch + clip->x1 * cpp;
>> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const
>> unsigned int *dst_pitch,
>> }
>> EXPORT_SYMBOL(drm_fb_swab);
>> +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int
>> dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le16 fg16, __le16 bg16)
>> +{
>> + unsigned int l, x;
>> + __le16 val16;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8)))
>> ? fg16 : bg16;
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16,
>> le16_to_cpu(val16));
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int
>> dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le32 fg32, __le32 bg32)
>> +{
>> + unsigned int l, x;
>> + __le32 color;
>> + u32 val32;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + u32 off = l * dpitch + x * 3;
>> +
>> + color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8)))
>> ? fg32 : bg32;
>> + val32 = le32_to_cpu(color);
>> +
>> + /* write blue-green-red to output in little endianness */
>> + iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
>> + iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
>> + iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int
>> dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le32 fg32, __le32 bg32)
>> +{
>> + unsigned int l, x;
>> + __le32 val32;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8)))
>> ? fg32 : bg32;
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32,
>> le32_to_cpu(val32));
>> + }
>> + }
>> +}
>> +
>> +/**
>> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear
>> framebuffer
>> + * @dmap: destination iosys_map
>> + * @dpitch: destination pitch in bytes
>> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
>> + * @spitch: source pitch in bytes
>> + * @height: height of the image to copy, in pixels
>> + * @width: width of the image to copy, in pixels
>> + * @fg_color: foreground color, in destination format
>> + * @bg_color: background color, in destination format
>> + * @pixel_width: pixel width in bytes.
>> + *
>> + * This can be used to draw font which are monochrome images, to a
>> framebuffer
>> + * in other supported format.
>> + */
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + u32 fg_color, u32 bg_color,
>> + unsigned int pixel_width)
>> +{
>> + switch (pixel_width) {
>> + case 2:
>> + drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le16(fg_color),
>> + cpu_to_le16(bg_color));
>> + break;
>> + case 3:
>> + drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le32(fg_color),
>> + cpu_to_le32(bg_color));
>> + break;
>> + case 4:
>> + drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le32(fg_color),
>> + cpu_to_le32(bg_color));
>> + break;
>> + default:
>> + WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
>> +
>> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u8 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
>> +}
>> +
>> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u16 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16,
>> color);
>> +}
>> +
>> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + unsigned int off = l * dpitch + x * 3;
>> +
>> + /* write blue-green-red to output in little endianness */
>> + iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
>> + iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
>> + iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32,
>> color);
>> +}
>> +
>> +/**
>> + * drm_fb_fill - Fill a rectangle with a color
>> + * @dmap: destination iosys_map, pointing to the top left corner of
>> the rectangle
>> + * @dpitch: destination pitch in bytes
>> + * @height: height of the rectangle, in pixels
>> + * @width: width of the rectangle, in pixels
>> + * @color: color to fill the rectangle.
>> + * @pixel_width: pixel width in bytes
>> + *
>> + * Fill a rectangle with a color, in a linear framebuffer.
>> + */
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color, unsigned int pixel_width)
>> +{
>> + switch (pixel_width) {
>> + case 1:
>> + drm_fb_fill8(dmap, dpitch, height, width, color);
>> + break;
>> + case 2:
>> + drm_fb_fill16(dmap, dpitch, height, width, color);
>> + break;
>> + case 3:
>> + drm_fb_fill24(dmap, dpitch, height, width, color);
>> + break;
>> + case 4:
>> + drm_fb_fill32(dmap, dpitch, height, width, color);
>> + break;
>> + default:
>> + WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_fill);
>> +
>> static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void
>> *sbuf, unsigned int pixels)
>> {
>> u8 *dbuf8 = dbuf;
>> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void
>> *dbuf, const void *sbuf, unsigne
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>> for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00F80000) >> 8) |
>> - ((pix & 0x0000FC00) >> 5) |
>> - ((pix & 0x000000F8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> + dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
>> }
>> }
>> @@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void
>> *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00f80000) >> 9) |
>> - ((pix & 0x0000f800) >> 6) |
>> - ((pix & 0x000000f8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
>> }
>> /**
>> @@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void
>> *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = BIT(15) | /* set alpha bit */
>> - ((pix & 0x00f80000) >> 9) |
>> - ((pix & 0x0000f800) >> 6) |
>> - ((pix & 0x000000f8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
>> }
>> /**
>> @@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void
>> *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00f80000) >> 8) |
>> - ((pix & 0x0000f800) >> 5) |
>> - ((pix & 0x000000f8) >> 2) |
>> - BIT(0); /* set alpha bit */
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
>> }
>> /**
>> @@ -707,13 +1012,9 @@ static void
>> drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix |= GENMASK(31, 24); /* fill alpha bits */
>> - dbuf32[x] = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
>> }
>> /**
>> @@ -756,16 +1057,9 @@ static void
>> drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
>> - ((pix & 0x0000ff00) >> 8) << 8 |
>> - ((pix & 0x000000ff) >> 0) << 16 |
>> - GENMASK(31, 24); /* fill alpha bits */
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
>> }
>> static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const
>> unsigned int *dst_pitch,
>> @@ -787,16 +1081,9 @@ static void
>> drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
>> - ((pix & 0x0000ff00) >> 8) << 8 |
>> - ((pix & 0x000000ff) >> 0) << 16 |
>> - ((pix & 0xff000000) >> 24) << 24;
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
>> }
>> static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const
>> unsigned int *dst_pitch,
>> @@ -818,17 +1105,9 @@ static void
>> drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 val32;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val32 = ((pix & 0x000000FF) << 2) |
>> - ((pix & 0x0000FF00) << 4) |
>> - ((pix & 0x00FF0000) << 6);
>> - pix = val32 | ((val32 >> 8) & 0x00300C03);
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
>> }
>> /**
>> @@ -872,18 +1151,9 @@ static void
>> drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 val32;
>> - u32 pix;
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val32 = ((pix & 0x000000ff) << 2) |
>> - ((pix & 0x0000ff00) << 4) |
>> - ((pix & 0x00ff0000) << 6);
>> - pix = GENMASK(31, 30) | /* set alpha bits */
>> - val32 | ((val32 >> 8) & 0x00300c03);
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
>> }
>> /**
>> diff --git a/include/drm/drm_format_helper.h
>> b/include/drm/drm_format_helper.h
>> index f13b34e0b752..f416f0bef52d 100644
>> --- a/include/drm/drm_format_helper.h
>> +++ b/include/drm/drm_format_helper.h
>> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct
>> drm_format_conv_state *state,
>> size_t new_size, gfp_t flags);
>> void drm_format_conv_state_release(struct drm_format_conv_state
>> *state);
>> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
>> unsigned int drm_fb_clip_offset(unsigned int pitch, const struct
>> drm_format_info *format,
>> const struct drm_rect *clip);
>> @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const
>> unsigned int *dst_pitch,
>> const struct iosys_map *src, const struct drm_framebuffer *fb,
>> const struct drm_rect *clip, bool cached,
>> struct drm_format_conv_state *state);
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + u32 fg_color, u32 bg_color,
>> + unsigned int pixel_width);
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color, unsigned int pixel_width);
>> void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned
>> int *dst_pitch,
>> const struct iosys_map *src, const struct
>> drm_framebuffer *fb,
>> const struct drm_rect *clip, struct
>> drm_format_conv_state *state);
>
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-17 16:40 ` Jocelyn Falempe
@ 2024-01-19 10:58 ` Thomas Zimmermann
2024-01-19 12:25 ` Pekka Paalanen
2024-01-23 12:56 ` Thomas Zimmermann
0 siblings, 2 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-19 10:58 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 4732 bytes --]
Hi
Am 17.01.24 um 17:40 schrieb Jocelyn Falempe:
>
>
> On 17/01/2024 16:06, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
>>> This is needed for drm_panic, to draw the font, and fill
>>> the background color, in multiple color format.
>>
>> TBH, I don't like this patch at all. It looks like you're
>> reimplementing existing functionality for a single use case;
>> specifically drm_fb_blit().
>>
>> What's wrong with the existing interfaces?
I've spend considerable time to clean up the format-helper code and get
it into shape. It's not there yet, but on its way. So I'd rather prefer
to update the existing code for new use cases. Adding a new interface
for a single use case is something like a leap backwards.
So let's see if we can work out something.
>
> drm_fb_blit() is good to copy a framebuffer to another, but is clearly
> unoptimal to draw font.
1) The framebuffer data structure is only there for historical reasons.
It should be removed from the internal implementation entirely. A first
patch should go into this in any case. It didn't happened so far, as
I've been busy with other work.
2) For the public API, I've long wanted to replace framebuffers with
something more flexible, let's call it drm_pixmap
struct drm_pixmap {
struct drm_format_info *format
unsigned int width, height
unsigned int pitches[DRM_FORMAT_MAX_PLANES]
iomap vaddr[DRM_FORMAT_MAX_PLANES]
};
It's the essence of drm_framebuffer. Let's say there's also an init
helper drm_pixmap_init_from_framebuffer(pix, fb) that sets up
everything. The implementation of drm_fb_blit() would look like this:
drm_fb_blit(...) {
drm_pixmap pix;
drm_pixmap_init_from_framebuffer(pix, fb)
__drm_fb_blit_pixmap( <like drm_fb_blit() but with a pixmap> )
}
That would require some changes to drivers, but it's only simple
refactoring.
3) When looking at your patch, there's
src = font->data + (msg->txt[i] * font->height) * src_stride;
which should be in a helper that sets up the drm_pixmap for a font
character:
drm_pixmap_init_from_char(pixmap, c, font_data)
where 'c' equals msg->txt[i]
The text drawing in the panic handler would do something like
for (msg->txt[i]) {
drm_pixmap_init_from_char(pixmap, ...)
drm_fb_blit_pixmap(...)
}
> It handles xrgb8888 to any rgb format, and I need monochrome to any rgb
> format.
4) You're free to add any conversion to drm_fb_blit(). It's supposed to
handle all available format conversion. With the pixmap-related changes
outlined above and the actual conversion code, I think that would
already put characters on the screen.
> I need to convert foreground and background color to the destination
> format, but using drm_fb_blit() to convert 1 pixel is tedious.
5) I've recently added drm_format_conv_state to the API. It is supposed
to hold state that is required for the conversion process. I
specifically had color palettes in mind. Please use the data structure.
Something like that:
struct drm_format_conv_state {
...
const drm_color_lut *palette;
}
and in the conversion code:
void r1_to_rgb() {
for (x < pixels) {
rgb = state->palette[r1]
}
}
>
> It also requires an additional memory buffer, and do an additional
> memory copy that we don't need at all.
6) That memcpy_to_io() not a big deal. You should pre-allocate that
memory buffer in the panic handler and init the drm_format_conv_state
with DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED().
>
> It also has no way to fill a region with the background color.
7) Please add a separate drm_fb_fill() implementation. If you have a
palette in struct drm_format_conf_state, you can add a helper for each
destination format that takes a drm_color_lut value as input.
This point is probably worth a separate discussion.
>
> The last thing, is if I plan to add YUV support, with this
> implementation, I only need to write one function that convert one
> pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line() and
> drm_fb_r1_to_yuvxxxx() boilerplate.
8) YUVs are multi-plane formats IIRC. So it's likely a bit more
complicated.And I'm not aware of any current use case for YUV. If the
framebuffer console doesn't support it, the panic helper probably won't
either.
Best regards
Thomas
>
> Best regards,
>
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-19 10:58 ` Thomas Zimmermann
@ 2024-01-19 12:25 ` Pekka Paalanen
2024-01-19 13:31 ` Thomas Zimmermann
2024-01-23 12:56 ` Thomas Zimmermann
1 sibling, 1 reply; 51+ messages in thread
From: Pekka Paalanen @ 2024-01-19 12:25 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, mripard, gpiccoli,
noralf, dri-devel, daniel, airlied
[-- Attachment #1: Type: text/plain, Size: 1015 bytes --]
On Fri, 19 Jan 2024 11:58:38 +0100
Thomas Zimmermann <tzimmermann@suse.de> wrote:
> Hi
>
> Am 17.01.24 um 17:40 schrieb Jocelyn Falempe:
...
> > The last thing, is if I plan to add YUV support, with this
> > implementation, I only need to write one function that convert one
> > pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line() and
> > drm_fb_r1_to_yuvxxxx() boilerplate.
>
> 8) YUVs are multi-plane formats IIRC. So it's likely a bit more
> complicated.And I'm not aware of any current use case for YUV. If the
> framebuffer console doesn't support it, the panic helper probably won't
> either.
Kernel panic during a fullscreen video playback, maybe?
That use case is likely to have an YUV FB as the only visible KMS plane
FB, either primary or overlay plane depending on which is capable of
displaying it. Sub-titles might not exist, or might be in a fairly
small RGB overlay.
I don't know if such case is important enough to handle.
Thanks,
pq
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-19 12:25 ` Pekka Paalanen
@ 2024-01-19 13:31 ` Thomas Zimmermann
0 siblings, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-19 13:31 UTC (permalink / raw)
To: Pekka Paalanen
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, mripard, gpiccoli,
noralf, dri-devel, daniel, airlied
[-- Attachment #1.1: Type: text/plain, Size: 1840 bytes --]
Hi
Am 19.01.24 um 13:25 schrieb Pekka Paalanen:
> On Fri, 19 Jan 2024 11:58:38 +0100
> Thomas Zimmermann <tzimmermann@suse.de> wrote:
>
>> Hi
>>
>> Am 17.01.24 um 17:40 schrieb Jocelyn Falempe:
>
> ...
>
>>> The last thing, is if I plan to add YUV support, with this
>>> implementation, I only need to write one function that convert one
>>> pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line() and
>>> drm_fb_r1_to_yuvxxxx() boilerplate.
>>
>> 8) YUVs are multi-plane formats IIRC. So it's likely a bit more
>> complicated.And I'm not aware of any current use case for YUV. If the
>> framebuffer console doesn't support it, the panic helper probably won't
>> either.
>
> Kernel panic during a fullscreen video playback, maybe?
>
> That use case is likely to have an YUV FB as the only visible KMS plane
> FB, either primary or overlay plane depending on which is capable of
> displaying it. Sub-titles might not exist, or might be in a fairly
> small RGB overlay.
>
> I don't know if such case is important enough to handle.
That's at least a possible use case AFAICT.
Each conversion is implemented in a helper drm_fb_<src format>_to_<dst
format>(). drm_fb_blit() is just a big switch statement to call the
correct helper. Something like drm_r1_to_yuv422() would be no different
and would integrate with the existing drm_fb_blit() nicely.
So it appears to me as if it's better to either extend the current code
for multi-plane formats, or write custom helpers
drm_fb_r1_to_yuv<whatever>().
Best regards
Thomas
>
>
> Thanks,
> pq
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-19 10:58 ` Thomas Zimmermann
2024-01-19 12:25 ` Pekka Paalanen
@ 2024-01-23 12:56 ` Thomas Zimmermann
2024-01-23 14:56 ` Jocelyn Falempe
1 sibling, 1 reply; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-23 12:56 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 5314 bytes --]
Hi,
FYI for points 1 and 2, I'm typing up a patchset that introduces
drm_pixmap for the source buffer. I'll post it when I have something ready.
Best regards
Thomas
Am 19.01.24 um 11:58 schrieb Thomas Zimmermann:
> Hi
>
> Am 17.01.24 um 17:40 schrieb Jocelyn Falempe:
>>
>>
>> On 17/01/2024 16:06, Thomas Zimmermann wrote:
>>> Hi
>>>
>>> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
>>>> This is needed for drm_panic, to draw the font, and fill
>>>> the background color, in multiple color format.
>>>
>>> TBH, I don't like this patch at all. It looks like you're
>>> reimplementing existing functionality for a single use case;
>>> specifically drm_fb_blit().
>>>
>>> What's wrong with the existing interfaces?
>
> I've spend considerable time to clean up the format-helper code and get
> it into shape. It's not there yet, but on its way. So I'd rather prefer
> to update the existing code for new use cases. Adding a new interface
> for a single use case is something like a leap backwards.
>
> So let's see if we can work out something.
>
>>
>> drm_fb_blit() is good to copy a framebuffer to another, but is clearly
>> unoptimal to draw font.
>
> 1) The framebuffer data structure is only there for historical reasons.
> It should be removed from the internal implementation entirely. A first
> patch should go into this in any case. It didn't happened so far, as
> I've been busy with other work.
>
> 2) For the public API, I've long wanted to replace framebuffers with
> something more flexible, let's call it drm_pixmap
>
> struct drm_pixmap {
> struct drm_format_info *format
> unsigned int width, height
> unsigned int pitches[DRM_FORMAT_MAX_PLANES]
> iomap vaddr[DRM_FORMAT_MAX_PLANES]
> };
>
> It's the essence of drm_framebuffer. Let's say there's also an init
> helper drm_pixmap_init_from_framebuffer(pix, fb) that sets up
> everything. The implementation of drm_fb_blit() would look like this:
>
> drm_fb_blit(...) {
>
> drm_pixmap pix;
> drm_pixmap_init_from_framebuffer(pix, fb)
> __drm_fb_blit_pixmap( <like drm_fb_blit() but with a pixmap> )
> }
>
> That would require some changes to drivers, but it's only simple
> refactoring.
>
> 3) When looking at your patch, there's
>
> src = font->data + (msg->txt[i] * font->height) * src_stride;
>
> which should be in a helper that sets up the drm_pixmap for a font
> character:
>
> drm_pixmap_init_from_char(pixmap, c, font_data)
>
> where 'c' equals msg->txt[i]
>
> The text drawing in the panic handler would do something like
>
> for (msg->txt[i]) {
> drm_pixmap_init_from_char(pixmap, ...)
> drm_fb_blit_pixmap(...)
> }
>
>
>> It handles xrgb8888 to any rgb format, and I need monochrome to any
>> rgb format.
>
> 4) You're free to add any conversion to drm_fb_blit(). It's supposed to
> handle all available format conversion. With the pixmap-related changes
> outlined above and the actual conversion code, I think that would
> already put characters on the screen.
>
>> I need to convert foreground and background color to the destination
>> format, but using drm_fb_blit() to convert 1 pixel is tedious.
>
> 5) I've recently added drm_format_conv_state to the API. It is supposed
> to hold state that is required for the conversion process. I
> specifically had color palettes in mind. Please use the data structure.
> Something like that:
>
> struct drm_format_conv_state {
> ...
> const drm_color_lut *palette;
> }
>
> and in the conversion code:
>
> void r1_to_rgb() {
> for (x < pixels) {
> rgb = state->palette[r1]
> }
> }
>
>>
>> It also requires an additional memory buffer, and do an additional
>> memory copy that we don't need at all.
>
> 6) That memcpy_to_io() not a big deal. You should pre-allocate that
> memory buffer in the panic handler and init the drm_format_conv_state
> with DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED().
>
>>
>> It also has no way to fill a region with the background color.
>
> 7) Please add a separate drm_fb_fill() implementation. If you have a
> palette in struct drm_format_conf_state, you can add a helper for each
> destination format that takes a drm_color_lut value as input.
>
> This point is probably worth a separate discussion.
>
>>
>> The last thing, is if I plan to add YUV support, with this
>> implementation, I only need to write one function that convert one
>> pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line()
>> and drm_fb_r1_to_yuvxxxx() boilerplate.
>
> 8) YUVs are multi-plane formats IIRC. So it's likely a bit more
> complicated.And I'm not aware of any current use case for YUV. If the
> framebuffer console doesn't support it, the panic helper probably won't
> either.
>
> Best regards
> Thomas
>
>>
>> Best regards,
>>
>
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-23 12:56 ` Thomas Zimmermann
@ 2024-01-23 14:56 ` Jocelyn Falempe
2024-01-30 11:20 ` Thomas Zimmermann
0 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-23 14:56 UTC (permalink / raw)
To: Thomas Zimmermann, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
On 23/01/2024 13:56, Thomas Zimmermann wrote:
> Hi,
>
> FYI for points 1 and 2, I'm typing up a patchset that introduces
> drm_pixmap for the source buffer. I'll post it when I have something ready.
Thanks, I didn't have time to look into this yet.
Best regards,
--
Jocelyn
>
> Best regards
> Thomas
>
> Am 19.01.24 um 11:58 schrieb Thomas Zimmermann:
>> Hi
>>
>> Am 17.01.24 um 17:40 schrieb Jocelyn Falempe:
>>>
>>>
>>> On 17/01/2024 16:06, Thomas Zimmermann wrote:
>>>> Hi
>>>>
>>>> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
>>>>> This is needed for drm_panic, to draw the font, and fill
>>>>> the background color, in multiple color format.
>>>>
>>>> TBH, I don't like this patch at all. It looks like you're
>>>> reimplementing existing functionality for a single use case;
>>>> specifically drm_fb_blit().
>>>>
>>>> What's wrong with the existing interfaces?
>>
>> I've spend considerable time to clean up the format-helper code and
>> get it into shape. It's not there yet, but on its way. So I'd rather
>> prefer to update the existing code for new use cases. Adding a new
>> interface for a single use case is something like a leap backwards.
>>
>> So let's see if we can work out something.
>>
>>>
>>> drm_fb_blit() is good to copy a framebuffer to another, but is
>>> clearly unoptimal to draw font.
>>
>> 1) The framebuffer data structure is only there for historical
>> reasons. It should be removed from the internal implementation
>> entirely. A first patch should go into this in any case. It didn't
>> happened so far, as I've been busy with other work.
>>
>> 2) For the public API, I've long wanted to replace framebuffers with
>> something more flexible, let's call it drm_pixmap
>>
>> struct drm_pixmap {
>> struct drm_format_info *format
>> unsigned int width, height
>> unsigned int pitches[DRM_FORMAT_MAX_PLANES]
>> iomap vaddr[DRM_FORMAT_MAX_PLANES]
>> };
>>
>> It's the essence of drm_framebuffer. Let's say there's also an init
>> helper drm_pixmap_init_from_framebuffer(pix, fb) that sets up
>> everything. The implementation of drm_fb_blit() would look like this:
>>
>> drm_fb_blit(...) {
>>
>> drm_pixmap pix;
>> drm_pixmap_init_from_framebuffer(pix, fb)
>> __drm_fb_blit_pixmap( <like drm_fb_blit() but with a pixmap> )
>> }
>>
>> That would require some changes to drivers, but it's only simple
>> refactoring.
>>
>> 3) When looking at your patch, there's
>>
>> src = font->data + (msg->txt[i] * font->height) * src_stride;
>>
>> which should be in a helper that sets up the drm_pixmap for a font
>> character:
>>
>> drm_pixmap_init_from_char(pixmap, c, font_data)
>>
>> where 'c' equals msg->txt[i]
>>
>> The text drawing in the panic handler would do something like
>>
>> for (msg->txt[i]) {
>> drm_pixmap_init_from_char(pixmap, ...)
>> drm_fb_blit_pixmap(...)
>> }
>>
>>
>>> It handles xrgb8888 to any rgb format, and I need monochrome to any
>>> rgb format.
>>
>> 4) You're free to add any conversion to drm_fb_blit(). It's supposed
>> to handle all available format conversion. With the pixmap-related
>> changes outlined above and the actual conversion code, I think that
>> would already put characters on the screen.
>>
>>> I need to convert foreground and background color to the destination
>>> format, but using drm_fb_blit() to convert 1 pixel is tedious.
>>
>> 5) I've recently added drm_format_conv_state to the API. It is
>> supposed to hold state that is required for the conversion process. I
>> specifically had color palettes in mind. Please use the data
>> structure. Something like that:
>>
>> struct drm_format_conv_state {
>> ...
>> const drm_color_lut *palette;
>> }
>>
>> and in the conversion code:
>>
>> void r1_to_rgb() {
>> for (x < pixels) {
>> rgb = state->palette[r1]
>> }
>> }
>>
>>>
>>> It also requires an additional memory buffer, and do an additional
>>> memory copy that we don't need at all.
>>
>> 6) That memcpy_to_io() not a big deal. You should pre-allocate that
>> memory buffer in the panic handler and init the drm_format_conv_state
>> with DRM_FORMAT_CONV_STATE_INIT_PREALLOCATED().
>>
>>>
>>> It also has no way to fill a region with the background color.
>>
>> 7) Please add a separate drm_fb_fill() implementation. If you have a
>> palette in struct drm_format_conf_state, you can add a helper for each
>> destination format that takes a drm_color_lut value as input.
>>
>> This point is probably worth a separate discussion.
>>
>>>
>>> The last thing, is if I plan to add YUV support, with this
>>> implementation, I only need to write one function that convert one
>>> pixel. Otherwise I would need to add the drm_fb_r1_to_yuvxxx_line()
>>> and drm_fb_r1_to_yuvxxxx() boilerplate.
>>
>> 8) YUVs are multi-plane formats IIRC. So it's likely a bit more
>> complicated.And I'm not aware of any current use case for YUV. If the
>> framebuffer console doesn't support it, the panic helper probably
>> won't either.
>>
>> Best regards
>> Thomas
>>
>>>
>>> Best regards,
>>>
>>
>
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-23 14:56 ` Jocelyn Falempe
@ 2024-01-30 11:20 ` Thomas Zimmermann
0 siblings, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-30 11:20 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 705 bytes --]
Hi
Am 23.01.24 um 15:56 schrieb Jocelyn Falempe:
>
>
> On 23/01/2024 13:56, Thomas Zimmermann wrote:
>> Hi,
>>
>> FYI for points 1 and 2, I'm typing up a patchset that introduces
>> drm_pixmap for the source buffer. I'll post it when I have something
>> ready.
>
> Thanks, I didn't have time to look into this yet.
You can find my RFC series at [1].
Best regards
Thomas
[1] https://patchwork.freedesktop.org/series/129301/
>
> Best regards,
>
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-04 16:00 ` [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill Jocelyn Falempe
2024-01-17 15:06 ` Thomas Zimmermann
@ 2024-01-17 15:26 ` Jani Nikula
2024-01-17 16:43 ` Jocelyn Falempe
1 sibling, 1 reply; 51+ messages in thread
From: Jani Nikula @ 2024-01-17 15:26 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, tzimmermann, airlied,
maarten.lankhorst, mripard, daniel, javierm, bluescreen_avenger,
noralf
Cc: gpiccoli, Jocelyn Falempe
On Thu, 04 Jan 2024, Jocelyn Falempe <jfalempe@redhat.com> wrote:
> This is needed for drm_panic, to draw the font, and fill
> the background color, in multiple color format.
>
> v5:
> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
> * Also add drm_fb_fill() to fill area with background color.
> v6:
> * fix __le32 conversion warning found by the kernel test bot
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
> include/drm/drm_format_helper.h | 9 +
> 2 files changed, 360 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
> index b1be458ed4dd..8cbc2d747cff 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state)
> }
> EXPORT_SYMBOL(drm_format_conv_state_release);
>
> +static inline __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
Please don't use inline in C files. Just let the compiler do its job.
BR,
Jani.
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00F80000) >> 8) |
> + ((pix & 0x0000FC00) >> 5) |
> + ((pix & 0x000000F8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00f80000) >> 8) |
> + ((pix & 0x0000f800) >> 5) |
> + ((pix & 0x000000f8) >> 2) |
> + BIT(0); /* set alpha bit */
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = ((pix & 0x00f80000) >> 9) |
> + ((pix & 0x0000f800) >> 6) |
> + ((pix & 0x000000f8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
> +{
> + u16 val16;
> + u32 pix;
> +
> + pix = le32_to_cpu(val32);
> + val16 = BIT(15) | /* set alpha bit */
> + ((pix & 0x00f80000) >> 9) |
> + ((pix & 0x0000f800) >> 6) |
> + ((pix & 0x000000f8) >> 3);
> + return cpu_to_le16(val16);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 |= GENMASK(31, 24); /* fill alpha bits */
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
> + ((val32 & 0x0000ff00) >> 8) << 8 |
> + ((val32 & 0x000000ff) >> 0) << 16 |
> + ((val32 & 0xff000000) >> 24) << 24;
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
> + ((val32 & 0x0000ff00) >> 8) << 8 |
> + ((val32 & 0x000000ff) >> 0) << 16 |
> + GENMASK(31, 24); /* fill alpha bits */
> + return cpu_to_le32(val32);
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x000000FF) << 2) |
> + ((val32 & 0x0000FF00) << 4) |
> + ((val32 & 0x00FF0000) << 6);
> + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
> +}
> +
> +static inline __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
> +{
> + u32 val32;
> +
> + val32 = le32_to_cpu(pix);
> + val32 = ((val32 & 0x000000FF) << 2) |
> + ((val32 & 0x0000FF00) << 4) |
> + ((val32 & 0x00FF0000) << 6);
> + val32 = GENMASK(31, 30) | /* set alpha bits */
> + val32 | ((val32 >> 8) & 0x00300c03);
> + return cpu_to_le32(val32);
> +}
> +
> +/**
> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
> + * @color: input color, in xrgb8888 format
> + * @format: output format
> + *
> + * Returns:
> + * Color in the format specified, casted to u32.
> + * Or 0 if the format is unknown.
> + */
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
> +{
> + __le32 pix = cpu_to_le32(color);
> +
> + switch (format) {
> + case DRM_FORMAT_RGB565:
> + return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
> + case DRM_FORMAT_RGBA5551:
> + return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
> + case DRM_FORMAT_XRGB1555:
> + return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
> + case DRM_FORMAT_ARGB1555:
> + return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
> + case DRM_FORMAT_RGB888:
> + case DRM_FORMAT_XRGB8888:
> + return le32_to_cpu(pix);
> + case DRM_FORMAT_ARGB8888:
> + return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
> + case DRM_FORMAT_XBGR8888:
> + return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
> + case DRM_FORMAT_XRGB2101010:
> + return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
> + case DRM_FORMAT_ARGB2101010:
> + return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
> + default:
> + WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
> + return 0;
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
> +
> static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
> {
> return clip->y1 * pitch + clip->x1 * cpp;
> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
> }
> EXPORT_SYMBOL(drm_fb_swab);
>
> +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le16 fg16, __le16 bg16)
> +{
> + unsigned int l, x;
> + __le16 val16;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
> + }
> + }
> +}
> +
> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le32 fg32, __le32 bg32)
> +{
> + unsigned int l, x;
> + __le32 color;
> + u32 val32;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + u32 off = l * dpitch + x * 3;
> +
> + color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> + val32 = le32_to_cpu(color);
> +
> + /* write blue-green-red to output in little endianness */
> + iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
> + iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
> + iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
> + }
> + }
> +}
> +
> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + __le32 fg32, __le32 bg32)
> +{
> + unsigned int l, x;
> + __le32 val32;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
> + }
> + }
> +}
> +
> +/**
> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
> + * @dmap: destination iosys_map
> + * @dpitch: destination pitch in bytes
> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
> + * @spitch: source pitch in bytes
> + * @height: height of the image to copy, in pixels
> + * @width: width of the image to copy, in pixels
> + * @fg_color: foreground color, in destination format
> + * @bg_color: background color, in destination format
> + * @pixel_width: pixel width in bytes.
> + *
> + * This can be used to draw font which are monochrome images, to a framebuffer
> + * in other supported format.
> + */
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + u32 fg_color, u32 bg_color,
> + unsigned int pixel_width)
> +{
> + switch (pixel_width) {
> + case 2:
> + drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le16(fg_color),
> + cpu_to_le16(bg_color));
> + break;
> + case 3:
> + drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le32(fg_color),
> + cpu_to_le32(bg_color));
> + break;
> + case 4:
> + drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
> + height, width,
> + cpu_to_le32(fg_color),
> + cpu_to_le32(bg_color));
> + break;
> + default:
> + WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
> +
> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u8 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
> +}
> +
> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u16 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
> +}
> +
> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++) {
> + for (x = 0; x < width; x++) {
> + unsigned int off = l * dpitch + x * 3;
> +
> + /* write blue-green-red to output in little endianness */
> + iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
> + iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
> + iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
> + }
> + }
> +}
> +
> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color)
> +{
> + unsigned int l, x;
> +
> + for (l = 0; l < height; l++)
> + for (x = 0; x < width; x++)
> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
> +}
> +
> +/**
> + * drm_fb_fill - Fill a rectangle with a color
> + * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
> + * @dpitch: destination pitch in bytes
> + * @height: height of the rectangle, in pixels
> + * @width: width of the rectangle, in pixels
> + * @color: color to fill the rectangle.
> + * @pixel_width: pixel width in bytes
> + *
> + * Fill a rectangle with a color, in a linear framebuffer.
> + */
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color, unsigned int pixel_width)
> +{
> + switch (pixel_width) {
> + case 1:
> + drm_fb_fill8(dmap, dpitch, height, width, color);
> + break;
> + case 2:
> + drm_fb_fill16(dmap, dpitch, height, width, color);
> + break;
> + case 3:
> + drm_fb_fill24(dmap, dpitch, height, width, color);
> + break;
> + case 4:
> + drm_fb_fill32(dmap, dpitch, height, width, color);
> + break;
> + default:
> + WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_fill);
> +
> static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
> {
> u8 *dbuf8 = dbuf;
> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00F80000) >> 8) |
> - ((pix & 0x0000FC00) >> 5) |
> - ((pix & 0x000000F8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> + dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
> }
> }
>
> @@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00f80000) >> 9) |
> - ((pix & 0x0000f800) >> 6) |
> - ((pix & 0x000000f8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
> }
>
> /**
> @@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = BIT(15) | /* set alpha bit */
> - ((pix & 0x00f80000) >> 9) |
> - ((pix & 0x0000f800) >> 6) |
> - ((pix & 0x000000f8) >> 3);
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
> }
>
> /**
> @@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
> __le16 *dbuf16 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u16 val16;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val16 = ((pix & 0x00f80000) >> 8) |
> - ((pix & 0x0000f800) >> 5) |
> - ((pix & 0x000000f8) >> 2) |
> - BIT(0); /* set alpha bit */
> - dbuf16[x] = cpu_to_le16(val16);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
> }
>
> /**
> @@ -707,13 +1012,9 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix |= GENMASK(31, 24); /* fill alpha bits */
> - dbuf32[x] = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
> }
>
> /**
> @@ -756,16 +1057,9 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
> - ((pix & 0x0000ff00) >> 8) << 8 |
> - ((pix & 0x000000ff) >> 0) << 16 |
> - GENMASK(31, 24); /* fill alpha bits */
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
> }
>
> static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -787,16 +1081,9 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
> - ((pix & 0x0000ff00) >> 8) << 8 |
> - ((pix & 0x000000ff) >> 0) << 16 |
> - ((pix & 0xff000000) >> 24) << 24;
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
> }
>
> static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -818,17 +1105,9 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 val32;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val32 = ((pix & 0x000000FF) << 2) |
> - ((pix & 0x0000FF00) << 4) |
> - ((pix & 0x00FF0000) << 6);
> - pix = val32 | ((val32 >> 8) & 0x00300C03);
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
> }
>
> /**
> @@ -872,18 +1151,9 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
> __le32 *dbuf32 = dbuf;
> const __le32 *sbuf32 = sbuf;
> unsigned int x;
> - u32 val32;
> - u32 pix;
>
> - for (x = 0; x < pixels; x++) {
> - pix = le32_to_cpu(sbuf32[x]);
> - val32 = ((pix & 0x000000ff) << 2) |
> - ((pix & 0x0000ff00) << 4) |
> - ((pix & 0x00ff0000) << 6);
> - pix = GENMASK(31, 30) | /* set alpha bits */
> - val32 | ((val32 >> 8) & 0x00300c03);
> - *dbuf32++ = cpu_to_le32(pix);
> - }
> + for (x = 0; x < pixels; x++)
> + *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
> }
>
> /**
> diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
> index f13b34e0b752..f416f0bef52d 100644
> --- a/include/drm/drm_format_helper.h
> +++ b/include/drm/drm_format_helper.h
> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
> size_t new_size, gfp_t flags);
> void drm_format_conv_state_release(struct drm_format_conv_state *state);
>
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
> unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
> const struct drm_rect *clip);
>
> @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
> const struct iosys_map *src, const struct drm_framebuffer *fb,
> const struct drm_rect *clip, bool cached,
> struct drm_format_conv_state *state);
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> + const u8 *sbuf8, unsigned int spitch,
> + unsigned int height, unsigned int width,
> + u32 fg_color, u32 bg_color,
> + unsigned int pixel_width);
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> + unsigned int height, unsigned int width,
> + u32 color, unsigned int pixel_width);
> void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
> const struct iosys_map *src, const struct drm_framebuffer *fb,
> const struct drm_rect *clip, struct drm_format_conv_state *state);
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
2024-01-17 15:26 ` Jani Nikula
@ 2024-01-17 16:43 ` Jocelyn Falempe
0 siblings, 0 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-17 16:43 UTC (permalink / raw)
To: Jani Nikula, dri-devel, tzimmermann, airlied, maarten.lankhorst,
mripard, daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
On 17/01/2024 16:26, Jani Nikula wrote:
> On Thu, 04 Jan 2024, Jocelyn Falempe <jfalempe@redhat.com> wrote:
>> This is needed for drm_panic, to draw the font, and fill
>> the background color, in multiple color format.
>>
>> v5:
>> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>> * Also add drm_fb_fill() to fill area with background color.
>> v6:
>> * fix __le32 conversion warning found by the kernel test bot
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>> ---
>> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
>> include/drm/drm_format_helper.h | 9 +
>> 2 files changed, 360 insertions(+), 81 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
>> index b1be458ed4dd..8cbc2d747cff 100644
>> --- a/drivers/gpu/drm/drm_format_helper.c
>> +++ b/drivers/gpu/drm/drm_format_helper.c
>> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state)
>> }
>> EXPORT_SYMBOL(drm_format_conv_state_release);
>>
>> +static inline __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
>
> Please don't use inline in C files. Just let the compiler do its job.
Sure, I will remove those inline in next version.
Thanks,
--
Jocelyn
>
> BR,
> Jani.
>
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00F80000) >> 8) |
>> + ((pix & 0x0000FC00) >> 5) |
>> + ((pix & 0x000000F8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00f80000) >> 8) |
>> + ((pix & 0x0000f800) >> 5) |
>> + ((pix & 0x000000f8) >> 2) |
>> + BIT(0); /* set alpha bit */
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = ((pix & 0x00f80000) >> 9) |
>> + ((pix & 0x0000f800) >> 6) |
>> + ((pix & 0x000000f8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
>> +{
>> + u16 val16;
>> + u32 pix;
>> +
>> + pix = le32_to_cpu(val32);
>> + val16 = BIT(15) | /* set alpha bit */
>> + ((pix & 0x00f80000) >> 9) |
>> + ((pix & 0x0000f800) >> 6) |
>> + ((pix & 0x000000f8) >> 3);
>> + return cpu_to_le16(val16);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 |= GENMASK(31, 24); /* fill alpha bits */
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
>> + ((val32 & 0x0000ff00) >> 8) << 8 |
>> + ((val32 & 0x000000ff) >> 0) << 16 |
>> + ((val32 & 0xff000000) >> 24) << 24;
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x00ff0000) >> 16) << 0 |
>> + ((val32 & 0x0000ff00) >> 8) << 8 |
>> + ((val32 & 0x000000ff) >> 0) << 16 |
>> + GENMASK(31, 24); /* fill alpha bits */
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x000000FF) << 2) |
>> + ((val32 & 0x0000FF00) << 4) |
>> + ((val32 & 0x00FF0000) << 6);
>> + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
>> +}
>> +
>> +static inline __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
>> +{
>> + u32 val32;
>> +
>> + val32 = le32_to_cpu(pix);
>> + val32 = ((val32 & 0x000000FF) << 2) |
>> + ((val32 & 0x0000FF00) << 4) |
>> + ((val32 & 0x00FF0000) << 6);
>> + val32 = GENMASK(31, 30) | /* set alpha bits */
>> + val32 | ((val32 >> 8) & 0x00300c03);
>> + return cpu_to_le32(val32);
>> +}
>> +
>> +/**
>> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
>> + * @color: input color, in xrgb8888 format
>> + * @format: output format
>> + *
>> + * Returns:
>> + * Color in the format specified, casted to u32.
>> + * Or 0 if the format is unknown.
>> + */
>> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
>> +{
>> + __le32 pix = cpu_to_le32(color);
>> +
>> + switch (format) {
>> + case DRM_FORMAT_RGB565:
>> + return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
>> + case DRM_FORMAT_RGBA5551:
>> + return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
>> + case DRM_FORMAT_XRGB1555:
>> + return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
>> + case DRM_FORMAT_ARGB1555:
>> + return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
>> + case DRM_FORMAT_RGB888:
>> + case DRM_FORMAT_XRGB8888:
>> + return le32_to_cpu(pix);
>> + case DRM_FORMAT_ARGB8888:
>> + return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
>> + case DRM_FORMAT_XBGR8888:
>> + return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
>> + case DRM_FORMAT_XRGB2101010:
>> + return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
>> + case DRM_FORMAT_ARGB2101010:
>> + return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
>> + default:
>> + WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
>> + return 0;
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
>> +
>> static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
>> {
>> return clip->y1 * pitch + clip->x1 * cpp;
>> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
>> }
>> EXPORT_SYMBOL(drm_fb_swab);
>>
>> +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le16 fg16, __le16 bg16)
>> +{
>> + unsigned int l, x;
>> + __le16 val16;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le32 fg32, __le32 bg32)
>> +{
>> + unsigned int l, x;
>> + __le32 color;
>> + u32 val32;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + u32 off = l * dpitch + x * 3;
>> +
>> + color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
>> + val32 = le32_to_cpu(color);
>> +
>> + /* write blue-green-red to output in little endianness */
>> + iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
>> + iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
>> + iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + __le32 fg32, __le32 bg32)
>> +{
>> + unsigned int l, x;
>> + __le32 val32;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
>> + }
>> + }
>> +}
>> +
>> +/**
>> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
>> + * @dmap: destination iosys_map
>> + * @dpitch: destination pitch in bytes
>> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
>> + * @spitch: source pitch in bytes
>> + * @height: height of the image to copy, in pixels
>> + * @width: width of the image to copy, in pixels
>> + * @fg_color: foreground color, in destination format
>> + * @bg_color: background color, in destination format
>> + * @pixel_width: pixel width in bytes.
>> + *
>> + * This can be used to draw font which are monochrome images, to a framebuffer
>> + * in other supported format.
>> + */
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + u32 fg_color, u32 bg_color,
>> + unsigned int pixel_width)
>> +{
>> + switch (pixel_width) {
>> + case 2:
>> + drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le16(fg_color),
>> + cpu_to_le16(bg_color));
>> + break;
>> + case 3:
>> + drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le32(fg_color),
>> + cpu_to_le32(bg_color));
>> + break;
>> + case 4:
>> + drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
>> + height, width,
>> + cpu_to_le32(fg_color),
>> + cpu_to_le32(bg_color));
>> + break;
>> + default:
>> + WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
>> +
>> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u8 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
>> +}
>> +
>> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u16 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
>> +}
>> +
>> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++) {
>> + for (x = 0; x < width; x++) {
>> + unsigned int off = l * dpitch + x * 3;
>> +
>> + /* write blue-green-red to output in little endianness */
>> + iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
>> + iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
>> + iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
>> + }
>> + }
>> +}
>> +
>> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color)
>> +{
>> + unsigned int l, x;
>> +
>> + for (l = 0; l < height; l++)
>> + for (x = 0; x < width; x++)
>> + iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
>> +}
>> +
>> +/**
>> + * drm_fb_fill - Fill a rectangle with a color
>> + * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
>> + * @dpitch: destination pitch in bytes
>> + * @height: height of the rectangle, in pixels
>> + * @width: width of the rectangle, in pixels
>> + * @color: color to fill the rectangle.
>> + * @pixel_width: pixel width in bytes
>> + *
>> + * Fill a rectangle with a color, in a linear framebuffer.
>> + */
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color, unsigned int pixel_width)
>> +{
>> + switch (pixel_width) {
>> + case 1:
>> + drm_fb_fill8(dmap, dpitch, height, width, color);
>> + break;
>> + case 2:
>> + drm_fb_fill16(dmap, dpitch, height, width, color);
>> + break;
>> + case 3:
>> + drm_fb_fill24(dmap, dpitch, height, width, color);
>> + break;
>> + case 4:
>> + drm_fb_fill32(dmap, dpitch, height, width, color);
>> + break;
>> + default:
>> + WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
>> + }
>> +}
>> +EXPORT_SYMBOL(drm_fb_fill);
>> +
>> static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
>> {
>> u8 *dbuf8 = dbuf;
>> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>>
>> for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00F80000) >> 8) |
>> - ((pix & 0x0000FC00) >> 5) |
>> - ((pix & 0x000000F8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> + dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
>> }
>> }
>>
>> @@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00f80000) >> 9) |
>> - ((pix & 0x0000f800) >> 6) |
>> - ((pix & 0x000000f8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
>> }
>>
>> /**
>> @@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = BIT(15) | /* set alpha bit */
>> - ((pix & 0x00f80000) >> 9) |
>> - ((pix & 0x0000f800) >> 6) |
>> - ((pix & 0x000000f8) >> 3);
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
>> }
>>
>> /**
>> @@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
>> __le16 *dbuf16 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u16 val16;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val16 = ((pix & 0x00f80000) >> 8) |
>> - ((pix & 0x0000f800) >> 5) |
>> - ((pix & 0x000000f8) >> 2) |
>> - BIT(0); /* set alpha bit */
>> - dbuf16[x] = cpu_to_le16(val16);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
>> }
>>
>> /**
>> @@ -707,13 +1012,9 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix |= GENMASK(31, 24); /* fill alpha bits */
>> - dbuf32[x] = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
>> }
>>
>> /**
>> @@ -756,16 +1057,9 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
>> - ((pix & 0x0000ff00) >> 8) << 8 |
>> - ((pix & 0x000000ff) >> 0) << 16 |
>> - GENMASK(31, 24); /* fill alpha bits */
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
>> }
>>
>> static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
>> @@ -787,16 +1081,9 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - pix = ((pix & 0x00ff0000) >> 16) << 0 |
>> - ((pix & 0x0000ff00) >> 8) << 8 |
>> - ((pix & 0x000000ff) >> 0) << 16 |
>> - ((pix & 0xff000000) >> 24) << 24;
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
>> }
>>
>> static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
>> @@ -818,17 +1105,9 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 val32;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val32 = ((pix & 0x000000FF) << 2) |
>> - ((pix & 0x0000FF00) << 4) |
>> - ((pix & 0x00FF0000) << 6);
>> - pix = val32 | ((val32 >> 8) & 0x00300C03);
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
>> }
>>
>> /**
>> @@ -872,18 +1151,9 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
>> __le32 *dbuf32 = dbuf;
>> const __le32 *sbuf32 = sbuf;
>> unsigned int x;
>> - u32 val32;
>> - u32 pix;
>>
>> - for (x = 0; x < pixels; x++) {
>> - pix = le32_to_cpu(sbuf32[x]);
>> - val32 = ((pix & 0x000000ff) << 2) |
>> - ((pix & 0x0000ff00) << 4) |
>> - ((pix & 0x00ff0000) << 6);
>> - pix = GENMASK(31, 30) | /* set alpha bits */
>> - val32 | ((val32 >> 8) & 0x00300c03);
>> - *dbuf32++ = cpu_to_le32(pix);
>> - }
>> + for (x = 0; x < pixels; x++)
>> + *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
>> }
>>
>> /**
>> diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
>> index f13b34e0b752..f416f0bef52d 100644
>> --- a/include/drm/drm_format_helper.h
>> +++ b/include/drm/drm_format_helper.h
>> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
>> size_t new_size, gfp_t flags);
>> void drm_format_conv_state_release(struct drm_format_conv_state *state);
>>
>> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
>> unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
>> const struct drm_rect *clip);
>>
>> @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
>> const struct iosys_map *src, const struct drm_framebuffer *fb,
>> const struct drm_rect *clip, bool cached,
>> struct drm_format_conv_state *state);
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> + const u8 *sbuf8, unsigned int spitch,
>> + unsigned int height, unsigned int width,
>> + u32 fg_color, u32 bg_color,
>> + unsigned int pixel_width);
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> + unsigned int height, unsigned int width,
>> + u32 color, unsigned int pixel_width);
>> void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
>> const struct iosys_map *src, const struct drm_framebuffer *fb,
>> const struct drm_rect *clip, struct drm_format_conv_state *state);
>
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
2024-01-04 16:00 ` [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-12 13:31 ` Daniel Vetter
` (2 more replies)
2024-01-04 16:00 ` [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro Jocelyn Falempe
` (7 subsequent siblings)
9 siblings, 3 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
This module displays a user friendly message when a kernel panic
occurs. It currently doesn't contain any debug information,
but that can be added later.
v2
* Use get_scanout_buffer() instead of the drm client API.
(Thomas Zimmermann)
* Add the panic reason to the panic message (Nerdopolis)
* Add an exclamation mark (Nerdopolis)
v3
* Rework the drawing functions, to write the pixels line by line and
to use the drm conversion helper to support other formats.
(Thomas Zimmermann)
v4
* Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
* Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
* Add foreground/background color config option
* Fix the bottom lines not painted if the framebuffer height
is not a multiple of the font height.
* Automatically register the device to drm_panic, if the function
get_scanout_buffer exists. (Thomas Zimmermann)
v5
* Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
* Also add drm_fb_fill() to fill area with background color.
* Add draw_pixel_xy() API for drivers that can't provide a linear buffer.
* Add a flush() callback for drivers that needs to synchronize the buffer.
* Add a void *private field, so drivers can pass private data to
draw_pixel_xy() and flush().
v6
* Fix sparse warning for panic_msg and logo.
v7
* Add select DRM_KMS_HELPER for the color conversion functions.
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/Kconfig | 23 +++
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/drm_drv.c | 8 +
drivers/gpu/drm/drm_panic.c | 369 ++++++++++++++++++++++++++++++++++++
include/drm/drm_drv.h | 21 ++
include/drm/drm_panic.h | 97 ++++++++++
6 files changed, 519 insertions(+)
create mode 100644 drivers/gpu/drm/drm_panic.c
create mode 100644 include/drm/drm_panic.h
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 628f90ed8a9b..a8219c98c8d6 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -103,6 +103,29 @@ config DRM_KMS_HELPER
help
CRTC helpers for KMS drivers.
+config DRM_PANIC
+ bool "Display a user-friendly message when a kernel panic occurs"
+ depends on DRM && !FRAMEBUFFER_CONSOLE
+ select DRM_KMS_HELPER
+ select FONT_SUPPORT
+ help
+ Enable a drm panic handler, which will display a user-friendly message
+ when a kernel panic occurs. It's useful when using a user-space
+ console instead of fbcon.
+ It will only work if your graphic driver supports this feature.
+ To support Hi-DPI Display, you can enable bigger fonts like
+ FONT_TER16x32
+
+config DRM_PANIC_FOREGROUND_COLOR
+ hex "Drm panic screen foreground color, in RGB"
+ depends on DRM_PANIC
+ default 0xffffff
+
+config DRM_PANIC_BACKGROUND_COLOR
+ hex "Drm panic screen background color, in RGB"
+ depends on DRM_PANIC
+ default 0x000000
+
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
bool "Enable refcount backtrace history in the DP MST helpers"
depends on STACKTRACE_SUPPORT
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8ac6f4b9546e..fdf3d3fe0c78 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -60,6 +60,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
drm_privacy_screen.o \
drm_privacy_screen_x86.o
drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
+drm-$(CONFIG_DRM_PANIC) += drm_panic.o
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 243cacb3575c..998942e6d687 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -43,6 +43,7 @@
#include <drm/drm_file.h>
#include <drm/drm_managed.h>
#include <drm/drm_mode_object.h>
+#include <drm/drm_panic.h>
#include <drm/drm_print.h>
#include <drm/drm_privacy_screen_machine.h>
@@ -944,6 +945,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
goto err_unload;
}
+ if (driver->get_scanout_buffer)
+ drm_panic_register(dev);
+
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor,
driver->patchlevel, driver->date,
@@ -987,6 +991,8 @@ void drm_dev_unregister(struct drm_device *dev)
{
dev->registered = false;
+ drm_panic_unregister(dev);
+
drm_client_dev_unregister(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -1066,6 +1072,7 @@ static void drm_core_exit(void)
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
+ drm_panic_exit();
idr_destroy(&drm_minors_idr);
drm_connector_ida_destroy();
}
@@ -1077,6 +1084,7 @@ static int __init drm_core_init(void)
drm_connector_ida_init();
idr_init(&drm_minors_idr);
drm_memcpy_init_early();
+ drm_panic_init();
ret = drm_sysfs_init();
if (ret < 0) {
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
new file mode 100644
index 000000000000..362a696ec48a
--- /dev/null
+++ b/drivers/gpu/drm/drm_panic.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/*
+ * Copyright (c) 2023 Red Hat.
+ * Author: Jocelyn Falempe <jfalempe@redhat.com>
+ * inspired by the drm_log driver from David Herrmann <dh.herrmann@gmail.com>
+ * Tux Ascii art taken from cowsay written by Tony Monroe
+ */
+
+#include <linux/font.h>
+#include <linux/iosys-map.h>
+#include <linux/kdebug.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/panic_notifier.h>
+#include <linux/types.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_panic.h>
+#include <drm/drm_print.h>
+
+
+MODULE_AUTHOR("Jocelyn Falempe");
+MODULE_DESCRIPTION("DRM panic handler");
+MODULE_LICENSE("GPL");
+
+/**
+ * DOC: DRM Panic
+ *
+ * This module displays a user friendly message on screen when a kernel panic
+ * occurs. This is conflicting with fbcon, so you can only enable it when fbcon
+ * is disabled.
+ * It's intended for end-user, so have minimal technical/debug information.
+ */
+
+/*
+ * Implementation details:
+ *
+ * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq,
+ * or attempt to sleep. It's a best effort, and it may not be able to display
+ * the message in all situations (like if the panic occurs in the middle of a
+ * modesetting).
+ * It will display only one static frame, so performance optimizations are low
+ * priority as the machine is already in an unusable state.
+ */
+
+/*
+ * List of active drm devices that can render a panic
+ */
+struct drm_panic_device {
+ struct list_head head;
+ struct drm_device *dev;
+};
+
+struct drm_panic_line {
+ u32 len;
+ const char *txt;
+};
+
+#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
+
+static struct drm_panic_line panic_msg[] = {
+ PANIC_LINE("KERNEL PANIC !"),
+ PANIC_LINE(""),
+ PANIC_LINE("Please reboot your computer."),
+ PANIC_LINE(""),
+ PANIC_LINE(""), /* overwritten with panic reason */
+};
+
+static const struct drm_panic_line logo[] = {
+ PANIC_LINE(" .--. _"),
+ PANIC_LINE(" |o_o | | |"),
+ PANIC_LINE(" |:_/ | | |"),
+ PANIC_LINE(" // \\ \\ |_|"),
+ PANIC_LINE(" (| | ) _"),
+ PANIC_LINE(" /'\\_ _/`\\ (_)"),
+ PANIC_LINE(" \\___)=(___/"),
+};
+
+static LIST_HEAD(drm_panic_devices);
+static DEFINE_MUTEX(drm_panic_lock);
+
+static void draw_empty_line_map(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
+{
+ struct iosys_map dst = sb->map;
+
+ iosys_map_incr(&dst, top * sb->pitch);
+ drm_fb_fill(&dst, sb->pitch, height, sb->width, color, sb->format->cpp[0]);
+}
+
+static void draw_txt_line_map(const struct drm_panic_line *msg, size_t left, size_t top,
+ struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
+ const struct font_desc *font)
+{
+ size_t i;
+ const u8 *src;
+ size_t src_stride = DIV_ROUND_UP(font->width, 8);
+ struct iosys_map dst = sb->map;
+ size_t end_text;
+ unsigned int px_width = sb->format->cpp[0];
+
+ iosys_map_incr(&dst, top * sb->pitch);
+ drm_fb_fill(&dst, sb->pitch, font->height, left, bg_color, px_width);
+ iosys_map_incr(&dst, left * px_width);
+ for (i = 0; i < msg->len; i++) {
+ src = font->data + (msg->txt[i] * font->height) * src_stride;
+ drm_fb_blit_from_r1(&dst, sb->pitch, src, src_stride, font->height, font->width,
+ fg_color, bg_color, px_width);
+ iosys_map_incr(&dst, font->width * px_width);
+ }
+ end_text = (msg->len * font->width) + left;
+ if (sb->width > end_text)
+ drm_fb_fill(&dst, sb->pitch, font->height, sb->width - end_text,
+ bg_color, px_width);
+}
+
+static void draw_empty_line_px(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
+{
+ unsigned int x, y;
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < sb->width; x++)
+ sb->draw_pixel_xy(x, y + top, color, sb->private);
+}
+
+static void draw_txt_line_px(const struct drm_panic_line *msg, size_t left, size_t top,
+ struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
+ const struct font_desc *font)
+{
+ unsigned int x, y, i;
+ const u8 *src;
+ u32 color;
+ size_t src_stride = DIV_ROUND_UP(font->width, 8);
+ size_t end_text = msg->len * font->width + left;
+ size_t right = sb->width > end_text ? sb->width - end_text : 0;
+
+ for (y = 0; y < font->height; y++) {
+ for (x = 0; x < left; x++)
+ sb->draw_pixel_xy(x, y + top, bg_color, sb->private);
+
+ for (i = 0; i < msg->len; i++) {
+ src = font->data + (msg->txt[i] * font->height + y) * src_stride;
+ for (x = 0; x < font->width; x++) {
+ color = (src[x / 8] & (0x80 >> (x % 8))) ? fg_color : bg_color;
+ sb->draw_pixel_xy(x + left + font->width * i, y + top, color,
+ sb->private);
+ }
+ }
+
+ for (x = 0; x < right; x++)
+ sb->draw_pixel_xy(x + end_text, y + top, bg_color, sb->private);
+ }
+}
+
+static void draw_empty_line(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
+{
+ if (sb->draw_pixel_xy)
+ draw_empty_line_px(sb, top, height, color);
+ else
+ draw_empty_line_map(sb, top, height, color);
+}
+
+static void draw_txt_line(const struct drm_panic_line *msg, size_t left, size_t top,
+ struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
+ const struct font_desc *font)
+{
+ if (sb->draw_pixel_xy)
+ draw_txt_line_px(msg, left, top, sb, fg_color, bg_color, font);
+ else
+ draw_txt_line_map(msg, left, top, sb, fg_color, bg_color, font);
+}
+
+
+static size_t panic_msg_needed_lines(size_t chars_per_line)
+{
+ size_t msg_len = ARRAY_SIZE(panic_msg);
+ size_t lines = 0;
+ size_t i;
+
+ for (i = 0; i < msg_len; i++)
+ lines += panic_msg[i].len ? DIV_ROUND_UP(panic_msg[i].len, chars_per_line) : 1;
+ return lines;
+}
+
+static bool can_draw_logo(size_t chars_per_line, size_t lines, size_t msg_lines)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(logo); i++) {
+ if (logo[i].len > chars_per_line)
+ return false;
+ }
+ if (lines < msg_lines + ARRAY_SIZE(logo))
+ return false;
+ return true;
+}
+
+static size_t get_start_line(size_t lines, size_t msg_lines, bool draw_logo)
+{
+ size_t remaining;
+ size_t logo_len = ARRAY_SIZE(logo);
+
+ if (lines < msg_lines)
+ return 0;
+ remaining = lines - msg_lines;
+ if (draw_logo && remaining / 2 <= logo_len)
+ return logo_len + (remaining - logo_len) / 4;
+ return remaining / 2;
+}
+
+/*
+ * Draw the panic message at the center of the screen
+ */
+static void draw_panic_static(struct drm_scanout_buffer *sb, const char *msg)
+{
+ size_t lines, msg_lines, l, msg_start_line, remaining, msgi;
+ size_t chars_per_line;
+ bool draw_logo;
+ struct drm_panic_line panic_line;
+ size_t msg_len = ARRAY_SIZE(panic_msg);
+ size_t logo_len = ARRAY_SIZE(logo);
+ u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR;
+ u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR;
+ const struct font_desc *font = get_default_font(sb->width, sb->height, 0x8080, 0x8080);
+
+ if (!font)
+ return;
+
+ /* Set the panic reason */
+ panic_msg[msg_len - 1].len = strlen(msg);
+ panic_msg[msg_len - 1].txt = msg;
+
+ lines = sb->height / font->height;
+ chars_per_line = sb->width / font->width;
+
+ msg_lines = panic_msg_needed_lines(chars_per_line);
+ draw_logo = can_draw_logo(chars_per_line, lines, msg_lines);
+ msg_start_line = get_start_line(lines, msg_lines, draw_logo);
+
+ fg_color = drm_fb_convert_from_xrgb8888(fg_color, sb->format->format);
+ bg_color = drm_fb_convert_from_xrgb8888(bg_color, sb->format->format);
+
+ msgi = 0;
+ panic_line.len = 0;
+ for (l = 0; l < lines; l++) {
+ if (draw_logo && l < logo_len)
+ draw_txt_line(&logo[l], 0, l * font->height, sb, fg_color, bg_color, font);
+ else if (l >= msg_start_line && msgi < msg_len) {
+ if (!panic_line.len) {
+ panic_line.txt = panic_msg[msgi].txt;
+ panic_line.len = panic_msg[msgi].len;
+ }
+ if (!panic_line.len) {
+ draw_empty_line(sb, l * font->height, font->height, bg_color);
+ msgi++;
+ } else if (panic_line.len > chars_per_line) {
+ remaining = panic_line.len - chars_per_line;
+ panic_line.len = chars_per_line;
+ draw_txt_line(&panic_line, 0, l * font->height, sb, fg_color,
+ bg_color, font);
+ panic_line.txt += chars_per_line;
+ panic_line.len = remaining;
+ } else {
+ draw_txt_line(&panic_line,
+ font->width * (chars_per_line - panic_line.len) / 2,
+ l * font->height, sb, fg_color, bg_color, font);
+ panic_line.len = 0;
+ msgi++;
+ }
+ } else {
+ draw_empty_line(sb, l * font->height, font->height, bg_color);
+ }
+ }
+ /* Fill the bottom of the screen, if sb->height is not a multiple of font->height */
+ if (sb->height % font->height)
+ draw_empty_line(sb, l * font->height, sb->height - l * font->height, bg_color);
+}
+
+static void draw_panic_device(struct drm_device *dev, const char *msg)
+{
+ struct drm_scanout_buffer sb = {0};
+
+ if (dev->driver->get_scanout_buffer(dev, &sb))
+ return;
+ draw_panic_static(&sb, msg);
+ if (sb.flush)
+ sb.flush(sb.private);
+}
+
+static int drm_panic(struct notifier_block *this, unsigned long event,
+ void *ptr)
+{
+ struct drm_panic_device *drm_panic_device;
+
+ list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
+ draw_panic_device(drm_panic_device->dev, ptr);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block drm_panic_notifier = {
+ .notifier_call = drm_panic,
+};
+
+/**
+ * drm_panic_register() - Initialize DRM panic for a device
+ * @dev: the DRM device on which the panic screen will be displayed.
+ */
+void drm_panic_register(struct drm_device *dev)
+{
+ struct drm_panic_device *new;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return;
+
+ new->dev = dev;
+ mutex_lock(&drm_panic_lock);
+ list_add_tail(&new->head, &drm_panic_devices);
+ mutex_unlock(&drm_panic_lock);
+
+ drm_info(dev, "Registered with drm panic\n");
+}
+EXPORT_SYMBOL(drm_panic_register);
+
+/**
+ * drm_panic_unregister()
+ * @dev: the DRM device previously registered.
+ */
+void drm_panic_unregister(struct drm_device *dev)
+{
+ struct drm_panic_device *drm_panic_device;
+ struct drm_panic_device *found = NULL;
+
+ mutex_lock(&drm_panic_lock);
+ list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
+ if (drm_panic_device->dev == dev)
+ found = drm_panic_device;
+ }
+ if (found) {
+ list_del(&found->head);
+ kfree(found);
+ drm_info(dev, "Unregistered with drm panic\n");
+ }
+ mutex_unlock(&drm_panic_lock);
+}
+EXPORT_SYMBOL(drm_panic_unregister);
+
+/**
+ * drm_panic_init() - Initialize drm-panic subsystem
+ *
+ * register the panic notifier
+ */
+void drm_panic_init(void)
+{
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &drm_panic_notifier);
+}
+
+/**
+ * drm_panic_exit() - Shutdown drm-panic subsystem
+ */
+void drm_panic_exit(void)
+{
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &drm_panic_notifier);
+}
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 8878260d7529..99e5bcf13975 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -43,6 +43,7 @@ struct dma_buf_attachment;
struct drm_display_mode;
struct drm_mode_create_dumb;
struct drm_printer;
+struct drm_scanout_buffer;
struct sg_table;
/**
@@ -401,6 +402,26 @@ struct drm_driver {
*/
void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f);
+ /**
+ * @get_scanout_buffer:
+ *
+ * Get the current scanout buffer, to display a panic message with drm_panic.
+ * The driver should do the minimum changes to provide a linear buffer, that
+ * can be used to display the panic screen.
+ * It is called from a panic callback, and must follow its restrictions.
+ * (no locks, no memory allocation, no sleep, no thread/workqueue, ...)
+ * It's a best effort mode, so it's expected that in some complex cases the
+ * panic screen won't be displayed.
+ * Some hardware cannot provide a linear buffer, so there is a draw_pixel_xy()
+ * callback in the struct drm_scanout_buffer that can be used in this case.
+ *
+ * Returns:
+ *
+ * Zero on success, negative errno on failure.
+ */
+ int (*get_scanout_buffer)(struct drm_device *dev,
+ struct drm_scanout_buffer *sb);
+
/** @major: driver major number */
int major;
/** @minor: driver minor number */
diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
new file mode 100644
index 000000000000..bcf392b6fa1b
--- /dev/null
+++ b/include/drm/drm_panic.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+#ifndef __DRM_PANIC_H__
+#define __DRM_PANIC_H__
+
+/*
+ * Copyright (c) 2023 Red Hat.
+ * Author: Jocelyn Falempe <jfalempe@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/iosys-map.h>
+
+struct drm_device;
+
+/**
+ * struct drm_scanout_buffer - DRM scanout buffer
+ *
+ * This structure holds the information necessary for drm_panic to draw the
+ * panic screen, and display it.
+ * If the driver can't provide a linear buffer, it must clear @map with
+ * iosys_map_clear() and provide a draw_pixel_xy() function.
+ */
+struct drm_scanout_buffer {
+ /**
+ * @format:
+ *
+ * drm format of the scanout buffer.
+ */
+ const struct drm_format_info *format;
+ /**
+ * @map:
+ *
+ * Virtual address of the scanout buffer, either in memory or iomem.
+ * The scanout buffer should be in linear format, and can be directly
+ * sent to the display hardware. Tearing is not an issue for the panic
+ * screen.
+ */
+ struct iosys_map map;
+ /**
+ * @width: Width of the scanout buffer, in pixels.
+ */
+ unsigned int width;
+ /**
+ * @height: Height of the scanout buffer, in pixels.
+ */
+ unsigned int height;
+ /**
+ * @pitch: Length in bytes between the start of two consecutive lines.
+ */
+ unsigned int pitch;
+ /**
+ * @private:
+ *
+ * In case the driver can't provide a linear buffer, this is a pointer to
+ * some private data, that will be passed when calling @draw_pixel_xy()
+ * and @flush()
+ */
+ void *private;
+ /**
+ * @draw_pixel_xy:
+ *
+ * In case the driver can't provide a linear buffer, this is a function
+ * that drm_panic will call for each pixel to draw.
+ * Color will be converted to the format specified by @format.
+ */
+ void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color, void *private);
+ /**
+ * @flush:
+ *
+ * This function is called after the panic screen is drawn, either using
+ * the iosys_map or the draw_pixel_xy path. In this function, the driver
+ * can send additional commands to the hardware, to make the buffer
+ * visible.
+ */
+ void (*flush)(void *private);
+};
+
+#ifdef CONFIG_DRM_PANIC
+
+void drm_panic_init(void);
+void drm_panic_exit(void);
+
+void drm_panic_register(struct drm_device *dev);
+void drm_panic_unregister(struct drm_device *dev);
+
+#else
+
+static inline void drm_panic_init(void) {}
+static inline void drm_panic_exit(void) {}
+
+static inline void drm_panic_register(struct drm_device *dev) {}
+static inline void drm_panic_unregister(struct drm_device *dev) {}
+
+#endif
+
+#endif /* __DRM_PANIC_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-04 16:00 ` [PATCH v7 2/9] drm/panic: Add a drm panic handler Jocelyn Falempe
@ 2024-01-12 13:31 ` Daniel Vetter
2024-01-16 10:54 ` Jocelyn Falempe
2024-01-12 13:50 ` Daniel Vetter
2024-01-17 15:49 ` Thomas Zimmermann
2 siblings, 1 reply; 51+ messages in thread
From: Daniel Vetter @ 2024-01-12 13:31 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, mripard, gpiccoli,
noralf, dri-devel, airlied
On Thu, Jan 04, 2024 at 05:00:46PM +0100, Jocelyn Falempe wrote:
> This module displays a user friendly message when a kernel panic
> occurs. It currently doesn't contain any debug information,
> but that can be added later.
>
> v2
> * Use get_scanout_buffer() instead of the drm client API.
> (Thomas Zimmermann)
> * Add the panic reason to the panic message (Nerdopolis)
> * Add an exclamation mark (Nerdopolis)
>
> v3
> * Rework the drawing functions, to write the pixels line by line and
> to use the drm conversion helper to support other formats.
> (Thomas Zimmermann)
>
> v4
> * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
> * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
> * Add foreground/background color config option
> * Fix the bottom lines not painted if the framebuffer height
> is not a multiple of the font height.
> * Automatically register the device to drm_panic, if the function
> get_scanout_buffer exists. (Thomas Zimmermann)
>
> v5
> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
> * Also add drm_fb_fill() to fill area with background color.
> * Add draw_pixel_xy() API for drivers that can't provide a linear buffer.
> * Add a flush() callback for drivers that needs to synchronize the buffer.
> * Add a void *private field, so drivers can pass private data to
> draw_pixel_xy() and flush().
>
> v6
> * Fix sparse warning for panic_msg and logo.
>
> v7
> * Add select DRM_KMS_HELPER for the color conversion functions.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
Bunch of comments on the glue, I didn't look at the drawing function in
detail assuming that that's all working :-)
-Sima
> ---
> drivers/gpu/drm/Kconfig | 23 +++
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/drm_drv.c | 8 +
> drivers/gpu/drm/drm_panic.c | 369 ++++++++++++++++++++++++++++++++++++
> include/drm/drm_drv.h | 21 ++
> include/drm/drm_panic.h | 97 ++++++++++
> 6 files changed, 519 insertions(+)
> create mode 100644 drivers/gpu/drm/drm_panic.c
> create mode 100644 include/drm/drm_panic.h
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 628f90ed8a9b..a8219c98c8d6 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -103,6 +103,29 @@ config DRM_KMS_HELPER
> help
> CRTC helpers for KMS drivers.
>
> +config DRM_PANIC
> + bool "Display a user-friendly message when a kernel panic occurs"
> + depends on DRM && !FRAMEBUFFER_CONSOLE
> + select DRM_KMS_HELPER
> + select FONT_SUPPORT
> + help
> + Enable a drm panic handler, which will display a user-friendly message
> + when a kernel panic occurs. It's useful when using a user-space
> + console instead of fbcon.
> + It will only work if your graphic driver supports this feature.
> + To support Hi-DPI Display, you can enable bigger fonts like
> + FONT_TER16x32
> +
> +config DRM_PANIC_FOREGROUND_COLOR
> + hex "Drm panic screen foreground color, in RGB"
> + depends on DRM_PANIC
> + default 0xffffff
> +
> +config DRM_PANIC_BACKGROUND_COLOR
> + hex "Drm panic screen background color, in RGB"
> + depends on DRM_PANIC
> + default 0x000000
> +
> config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> bool "Enable refcount backtrace history in the DP MST helpers"
> depends on STACKTRACE_SUPPORT
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 8ac6f4b9546e..fdf3d3fe0c78 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -60,6 +60,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
> drm_privacy_screen.o \
> drm_privacy_screen_x86.o
> drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
> +drm-$(CONFIG_DRM_PANIC) += drm_panic.o
> obj-$(CONFIG_DRM) += drm.o
>
> obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 243cacb3575c..998942e6d687 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -43,6 +43,7 @@
> #include <drm/drm_file.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_mode_object.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_print.h>
> #include <drm/drm_privacy_screen_machine.h>
>
> @@ -944,6 +945,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
> goto err_unload;
> }
>
> + if (driver->get_scanout_buffer)
> + drm_panic_register(dev);
> +
> DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
> driver->name, driver->major, driver->minor,
> driver->patchlevel, driver->date,
> @@ -987,6 +991,8 @@ void drm_dev_unregister(struct drm_device *dev)
> {
> dev->registered = false;
>
> + drm_panic_unregister(dev);
> +
> drm_client_dev_unregister(dev);
>
> if (drm_core_check_feature(dev, DRIVER_MODESET))
> @@ -1066,6 +1072,7 @@ static void drm_core_exit(void)
> unregister_chrdev(DRM_MAJOR, "drm");
> debugfs_remove(drm_debugfs_root);
> drm_sysfs_destroy();
> + drm_panic_exit();
> idr_destroy(&drm_minors_idr);
> drm_connector_ida_destroy();
> }
> @@ -1077,6 +1084,7 @@ static int __init drm_core_init(void)
> drm_connector_ida_init();
> idr_init(&drm_minors_idr);
> drm_memcpy_init_early();
> + drm_panic_init();
>
> ret = drm_sysfs_init();
> if (ret < 0) {
> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
> new file mode 100644
> index 000000000000..362a696ec48a
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_panic.c
> @@ -0,0 +1,369 @@
> +// SPDX-License-Identifier: GPL-2.0 or MIT
> +/*
> + * Copyright (c) 2023 Red Hat.
> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
> + * inspired by the drm_log driver from David Herrmann <dh.herrmann@gmail.com>
> + * Tux Ascii art taken from cowsay written by Tony Monroe
> + */
> +
> +#include <linux/font.h>
> +#include <linux/iosys-map.h>
> +#include <linux/kdebug.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/panic_notifier.h>
> +#include <linux/types.h>
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_format_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_panic.h>
> +#include <drm/drm_print.h>
> +
> +
> +MODULE_AUTHOR("Jocelyn Falempe");
> +MODULE_DESCRIPTION("DRM panic handler");
> +MODULE_LICENSE("GPL");
> +
> +/**
> + * DOC: DRM Panic
You need to tie these nice kerneldocs into the overall documentation tree,
or they're not getting built. Please then also check that all the links
and formatting works correctly.
> + *
> + * This module displays a user friendly message on screen when a kernel panic
> + * occurs. This is conflicting with fbcon, so you can only enable it when fbcon
> + * is disabled.
> + * It's intended for end-user, so have minimal technical/debug information.
> + */
> +
> +/*
> + * Implementation details:
> + *
> + * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq,
> + * or attempt to sleep. It's a best effort, and it may not be able to display
> + * the message in all situations (like if the panic occurs in the middle of a
> + * modesetting).
> + * It will display only one static frame, so performance optimizations are low
> + * priority as the machine is already in an unusable state.
> + */
> +
> +/*
> + * List of active drm devices that can render a panic
> + */
> +struct drm_panic_device {
> + struct list_head head;
> + struct drm_device *dev;
> +};
> +
> +struct drm_panic_line {
> + u32 len;
> + const char *txt;
> +};
> +
> +#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
> +
> +static struct drm_panic_line panic_msg[] = {
> + PANIC_LINE("KERNEL PANIC !"),
> + PANIC_LINE(""),
> + PANIC_LINE("Please reboot your computer."),
> + PANIC_LINE(""),
> + PANIC_LINE(""), /* overwritten with panic reason */
> +};
> +
> +static const struct drm_panic_line logo[] = {
> + PANIC_LINE(" .--. _"),
> + PANIC_LINE(" |o_o | | |"),
> + PANIC_LINE(" |:_/ | | |"),
> + PANIC_LINE(" // \\ \\ |_|"),
> + PANIC_LINE(" (| | ) _"),
> + PANIC_LINE(" /'\\_ _/`\\ (_)"),
> + PANIC_LINE(" \\___)=(___/"),
> +};
> +
> +static LIST_HEAD(drm_panic_devices);
> +static DEFINE_MUTEX(drm_panic_lock);
> +
> +static void draw_empty_line_map(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
> +{
> + struct iosys_map dst = sb->map;
> +
> + iosys_map_incr(&dst, top * sb->pitch);
> + drm_fb_fill(&dst, sb->pitch, height, sb->width, color, sb->format->cpp[0]);
> +}
> +
> +static void draw_txt_line_map(const struct drm_panic_line *msg, size_t left, size_t top,
> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
> + const struct font_desc *font)
> +{
> + size_t i;
> + const u8 *src;
> + size_t src_stride = DIV_ROUND_UP(font->width, 8);
> + struct iosys_map dst = sb->map;
> + size_t end_text;
> + unsigned int px_width = sb->format->cpp[0];
> +
> + iosys_map_incr(&dst, top * sb->pitch);
> + drm_fb_fill(&dst, sb->pitch, font->height, left, bg_color, px_width);
> + iosys_map_incr(&dst, left * px_width);
> + for (i = 0; i < msg->len; i++) {
> + src = font->data + (msg->txt[i] * font->height) * src_stride;
> + drm_fb_blit_from_r1(&dst, sb->pitch, src, src_stride, font->height, font->width,
> + fg_color, bg_color, px_width);
> + iosys_map_incr(&dst, font->width * px_width);
> + }
> + end_text = (msg->len * font->width) + left;
> + if (sb->width > end_text)
> + drm_fb_fill(&dst, sb->pitch, font->height, sb->width - end_text,
> + bg_color, px_width);
> +}
> +
> +static void draw_empty_line_px(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
> +{
> + unsigned int x, y;
> +
> + for (y = 0; y < height; y++)
> + for (x = 0; x < sb->width; x++)
> + sb->draw_pixel_xy(x, y + top, color, sb->private);
> +}
> +
> +static void draw_txt_line_px(const struct drm_panic_line *msg, size_t left, size_t top,
> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
> + const struct font_desc *font)
> +{
> + unsigned int x, y, i;
> + const u8 *src;
> + u32 color;
> + size_t src_stride = DIV_ROUND_UP(font->width, 8);
> + size_t end_text = msg->len * font->width + left;
> + size_t right = sb->width > end_text ? sb->width - end_text : 0;
> +
> + for (y = 0; y < font->height; y++) {
> + for (x = 0; x < left; x++)
> + sb->draw_pixel_xy(x, y + top, bg_color, sb->private);
> +
> + for (i = 0; i < msg->len; i++) {
> + src = font->data + (msg->txt[i] * font->height + y) * src_stride;
> + for (x = 0; x < font->width; x++) {
> + color = (src[x / 8] & (0x80 >> (x % 8))) ? fg_color : bg_color;
> + sb->draw_pixel_xy(x + left + font->width * i, y + top, color,
> + sb->private);
> + }
> + }
> +
> + for (x = 0; x < right; x++)
> + sb->draw_pixel_xy(x + end_text, y + top, bg_color, sb->private);
> + }
> +}
> +
> +static void draw_empty_line(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
> +{
> + if (sb->draw_pixel_xy)
> + draw_empty_line_px(sb, top, height, color);
> + else
> + draw_empty_line_map(sb, top, height, color);
> +}
> +
> +static void draw_txt_line(const struct drm_panic_line *msg, size_t left, size_t top,
> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
> + const struct font_desc *font)
> +{
> + if (sb->draw_pixel_xy)
> + draw_txt_line_px(msg, left, top, sb, fg_color, bg_color, font);
> + else
> + draw_txt_line_map(msg, left, top, sb, fg_color, bg_color, font);
> +}
> +
> +
> +static size_t panic_msg_needed_lines(size_t chars_per_line)
> +{
> + size_t msg_len = ARRAY_SIZE(panic_msg);
> + size_t lines = 0;
> + size_t i;
> +
> + for (i = 0; i < msg_len; i++)
> + lines += panic_msg[i].len ? DIV_ROUND_UP(panic_msg[i].len, chars_per_line) : 1;
> + return lines;
> +}
> +
> +static bool can_draw_logo(size_t chars_per_line, size_t lines, size_t msg_lines)
> +{
> + size_t i;
> +
> + for (i = 0; i < ARRAY_SIZE(logo); i++) {
> + if (logo[i].len > chars_per_line)
> + return false;
> + }
> + if (lines < msg_lines + ARRAY_SIZE(logo))
> + return false;
> + return true;
> +}
> +
> +static size_t get_start_line(size_t lines, size_t msg_lines, bool draw_logo)
> +{
> + size_t remaining;
> + size_t logo_len = ARRAY_SIZE(logo);
> +
> + if (lines < msg_lines)
> + return 0;
> + remaining = lines - msg_lines;
> + if (draw_logo && remaining / 2 <= logo_len)
> + return logo_len + (remaining - logo_len) / 4;
> + return remaining / 2;
> +}
> +
> +/*
> + * Draw the panic message at the center of the screen
> + */
> +static void draw_panic_static(struct drm_scanout_buffer *sb, const char *msg)
> +{
> + size_t lines, msg_lines, l, msg_start_line, remaining, msgi;
> + size_t chars_per_line;
> + bool draw_logo;
> + struct drm_panic_line panic_line;
> + size_t msg_len = ARRAY_SIZE(panic_msg);
> + size_t logo_len = ARRAY_SIZE(logo);
> + u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR;
> + u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR;
> + const struct font_desc *font = get_default_font(sb->width, sb->height, 0x8080, 0x8080);
> +
> + if (!font)
> + return;
> +
> + /* Set the panic reason */
> + panic_msg[msg_len - 1].len = strlen(msg);
> + panic_msg[msg_len - 1].txt = msg;
> +
> + lines = sb->height / font->height;
> + chars_per_line = sb->width / font->width;
> +
> + msg_lines = panic_msg_needed_lines(chars_per_line);
> + draw_logo = can_draw_logo(chars_per_line, lines, msg_lines);
> + msg_start_line = get_start_line(lines, msg_lines, draw_logo);
> +
> + fg_color = drm_fb_convert_from_xrgb8888(fg_color, sb->format->format);
> + bg_color = drm_fb_convert_from_xrgb8888(bg_color, sb->format->format);
> +
> + msgi = 0;
> + panic_line.len = 0;
> + for (l = 0; l < lines; l++) {
> + if (draw_logo && l < logo_len)
> + draw_txt_line(&logo[l], 0, l * font->height, sb, fg_color, bg_color, font);
> + else if (l >= msg_start_line && msgi < msg_len) {
> + if (!panic_line.len) {
> + panic_line.txt = panic_msg[msgi].txt;
> + panic_line.len = panic_msg[msgi].len;
> + }
> + if (!panic_line.len) {
> + draw_empty_line(sb, l * font->height, font->height, bg_color);
> + msgi++;
> + } else if (panic_line.len > chars_per_line) {
> + remaining = panic_line.len - chars_per_line;
> + panic_line.len = chars_per_line;
> + draw_txt_line(&panic_line, 0, l * font->height, sb, fg_color,
> + bg_color, font);
> + panic_line.txt += chars_per_line;
> + panic_line.len = remaining;
> + } else {
> + draw_txt_line(&panic_line,
> + font->width * (chars_per_line - panic_line.len) / 2,
> + l * font->height, sb, fg_color, bg_color, font);
> + panic_line.len = 0;
> + msgi++;
> + }
> + } else {
> + draw_empty_line(sb, l * font->height, font->height, bg_color);
> + }
> + }
> + /* Fill the bottom of the screen, if sb->height is not a multiple of font->height */
> + if (sb->height % font->height)
> + draw_empty_line(sb, l * font->height, sb->height - l * font->height, bg_color);
> +}
> +
> +static void draw_panic_device(struct drm_device *dev, const char *msg)
> +{
> + struct drm_scanout_buffer sb = {0};
> +
> + if (dev->driver->get_scanout_buffer(dev, &sb))
> + return;
> + draw_panic_static(&sb, msg);
> + if (sb.flush)
> + sb.flush(sb.private);
> +}
> +
> +static int drm_panic(struct notifier_block *this, unsigned long event,
> + void *ptr)
> +{
> + struct drm_panic_device *drm_panic_device;
> +
> + list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
> + draw_panic_device(drm_panic_device->dev, ptr);
The locking here is busted. Which is why the atomic notifier chain is
special and uses atomic semantics - I would just avoid this issue and
directly register each drm_panic_device instead of trying to maintain a
drm-local list and getting the locking rules wrong.
> + }
> + return NOTIFY_OK;
> +}
> +
> +static struct notifier_block drm_panic_notifier = {
> + .notifier_call = drm_panic,
> +};
> +
> +/**
> + * drm_panic_register() - Initialize DRM panic for a device
> + * @dev: the DRM device on which the panic screen will be displayed.
> + */
> +void drm_panic_register(struct drm_device *dev)
> +{
> + struct drm_panic_device *new;
> +
> + new = kzalloc(sizeof(*new), GFP_KERNEL);
> + if (!new)
> + return;
> +
> + new->dev = dev;
> + mutex_lock(&drm_panic_lock);
> + list_add_tail(&new->head, &drm_panic_devices);
> + mutex_unlock(&drm_panic_lock);
> +
> + drm_info(dev, "Registered with drm panic\n");
> +}
> +EXPORT_SYMBOL(drm_panic_register);
> +
> +/**
> + * drm_panic_unregister()
> + * @dev: the DRM device previously registered.
> + */
> +void drm_panic_unregister(struct drm_device *dev)
> +{
> + struct drm_panic_device *drm_panic_device;
> + struct drm_panic_device *found = NULL;
> +
> + mutex_lock(&drm_panic_lock);
> + list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
Can't we just store a pointer in drm_device (or embed the entire thing
outright) instead of this dance?
> + if (drm_panic_device->dev == dev)
> + found = drm_panic_device;
> + }
> + if (found) {
> + list_del(&found->head);
> + kfree(found);
> + drm_info(dev, "Unregistered with drm panic\n");
> + }
> + mutex_unlock(&drm_panic_lock);
> +}
> +EXPORT_SYMBOL(drm_panic_unregister);
> +
> +/**
> + * drm_panic_init() - Initialize drm-panic subsystem
> + *
> + * register the panic notifier
> + */
> +void drm_panic_init(void)
> +{
> + atomic_notifier_chain_register(&panic_notifier_list,
> + &drm_panic_notifier);
> +}
> +
> +/**
> + * drm_panic_exit() - Shutdown drm-panic subsystem
> + */
> +void drm_panic_exit(void)
> +{
> + atomic_notifier_chain_unregister(&panic_notifier_list,
> + &drm_panic_notifier);
> +}
> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
> index 8878260d7529..99e5bcf13975 100644
> --- a/include/drm/drm_drv.h
> +++ b/include/drm/drm_drv.h
> @@ -43,6 +43,7 @@ struct dma_buf_attachment;
> struct drm_display_mode;
> struct drm_mode_create_dumb;
> struct drm_printer;
> +struct drm_scanout_buffer;
> struct sg_table;
>
> /**
> @@ -401,6 +402,26 @@ struct drm_driver {
> */
> void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f);
>
> + /**
> + * @get_scanout_buffer:
> + *
> + * Get the current scanout buffer, to display a panic message with drm_panic.
> + * The driver should do the minimum changes to provide a linear buffer, that
> + * can be used to display the panic screen.
> + * It is called from a panic callback, and must follow its restrictions.
> + * (no locks, no memory allocation, no sleep, no thread/workqueue, ...)
> + * It's a best effort mode, so it's expected that in some complex cases the
> + * panic screen won't be displayed.
> + * Some hardware cannot provide a linear buffer, so there is a draw_pixel_xy()
> + * callback in the struct drm_scanout_buffer that can be used in this case.
I'd move this to the documentation of drm_scanout_buffer and just put a
kernel-doc hyperlink in here referencing that for further information.
> + *
> + * Returns:
> + *
> + * Zero on success, negative errno on failure.
> + */
> + int (*get_scanout_buffer)(struct drm_device *dev,
> + struct drm_scanout_buffer *sb);
Please put this hook into drm_mode_config_funcs and not into the overall
drm_driver struct. At least for kms we're trying to keep a clean design
(and I know that stuff like dumb buffers got misplaced, not a good reason
to do it again ...).
> +
> /** @major: driver major number */
> int major;
> /** @minor: driver minor number */
> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
> new file mode 100644
> index 000000000000..bcf392b6fa1b
> --- /dev/null
> +++ b/include/drm/drm_panic.h
> @@ -0,0 +1,97 @@
> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
> +#ifndef __DRM_PANIC_H__
> +#define __DRM_PANIC_H__
> +
> +/*
> + * Copyright (c) 2023 Red Hat.
> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/iosys-map.h>
> +
> +struct drm_device;
> +
> +/**
> + * struct drm_scanout_buffer - DRM scanout buffer
> + *
> + * This structure holds the information necessary for drm_panic to draw the
> + * panic screen, and display it.
> + * If the driver can't provide a linear buffer, it must clear @map with
> + * iosys_map_clear() and provide a draw_pixel_xy() function.
I think it's better to move this to the documentation of @map and
@draw_pixel_xy.
> + */
> +struct drm_scanout_buffer {
> + /**
> + * @format:
> + *
> + * drm format of the scanout buffer.
> + */
> + const struct drm_format_info *format;
> + /**
> + * @map:
> + *
> + * Virtual address of the scanout buffer, either in memory or iomem.
> + * The scanout buffer should be in linear format, and can be directly
The should here is confusing, because it's an either/or.
> + * sent to the display hardware. Tearing is not an issue for the panic
> + * screen.
> + */
> + struct iosys_map map;
I think you're a bit unclear on whether you allow non-null @map for the
case when @draw_pixel_xy is set. Current docs says it's either/or, but you
don't have any checks for iosys_map_is_null(). I'd add something like
WARN_ON(sb->draw_pixel_xy && !iosys_map_is_null(sb->map));
right after the call to ->get_scanout_buffer to lock down this rule.
> + /**
> + * @width: Width of the scanout buffer, in pixels.
> + */
> + unsigned int width;
> + /**
> + * @height: Height of the scanout buffer, in pixels.
> + */
> + unsigned int height;
> + /**
> + * @pitch: Length in bytes between the start of two consecutive lines.
> + */
> + unsigned int pitch;
> + /**
> + * @private:
> + *
> + * In case the driver can't provide a linear buffer, this is a pointer to
> + * some private data, that will be passed when calling @draw_pixel_xy()
> + * and @flush()
> + */
> + void *private;
> + /**
> + * @draw_pixel_xy:
> + *
> + * In case the driver can't provide a linear buffer, this is a function
> + * that drm_panic will call for each pixel to draw.
> + * Color will be converted to the format specified by @format.
> + */
> + void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color, void *private);
> + /**
> + * @flush:
> + *
> + * This function is called after the panic screen is drawn, either using
> + * the iosys_map or the draw_pixel_xy path. In this function, the driver
> + * can send additional commands to the hardware, to make the buffer
> + * visible.
Uh how does flush work for the @map path? I'd just pass the overall
drm_scanout_buffer struct to both of these hooks as the first parameter
and let the driver figure out what it needs.
> + */
> + void (*flush)(void *private);
> +};
> +
> +#ifdef CONFIG_DRM_PANIC
> +
> +void drm_panic_init(void);
> +void drm_panic_exit(void);
> +
> +void drm_panic_register(struct drm_device *dev);
> +void drm_panic_unregister(struct drm_device *dev);
> +
> +#else
> +
> +static inline void drm_panic_init(void) {}
> +static inline void drm_panic_exit(void) {}
> +
> +static inline void drm_panic_register(struct drm_device *dev) {}
> +static inline void drm_panic_unregister(struct drm_device *dev) {}
> +
> +#endif
> +
> +#endif /* __DRM_PANIC_H__ */
> --
> 2.43.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-12 13:31 ` Daniel Vetter
@ 2024-01-16 10:54 ` Jocelyn Falempe
2024-01-18 13:36 ` Daniel Vetter
0 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-16 10:54 UTC (permalink / raw)
To: Daniel Vetter
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
On 12/01/2024 14:31, Daniel Vetter wrote:
> On Thu, Jan 04, 2024 at 05:00:46PM +0100, Jocelyn Falempe wrote:
>> This module displays a user friendly message when a kernel panic
>> occurs. It currently doesn't contain any debug information,
>> but that can be added later.
>>
>> v2
>> * Use get_scanout_buffer() instead of the drm client API.
>> (Thomas Zimmermann)
>> * Add the panic reason to the panic message (Nerdopolis)
>> * Add an exclamation mark (Nerdopolis)
>>
>> v3
>> * Rework the drawing functions, to write the pixels line by line and
>> to use the drm conversion helper to support other formats.
>> (Thomas Zimmermann)
>>
>> v4
>> * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
>> * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
>> * Add foreground/background color config option
>> * Fix the bottom lines not painted if the framebuffer height
>> is not a multiple of the font height.
>> * Automatically register the device to drm_panic, if the function
>> get_scanout_buffer exists. (Thomas Zimmermann)
>>
>> v5
>> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>> * Also add drm_fb_fill() to fill area with background color.
>> * Add draw_pixel_xy() API for drivers that can't provide a linear buffer.
>> * Add a flush() callback for drivers that needs to synchronize the buffer.
>> * Add a void *private field, so drivers can pass private data to
>> draw_pixel_xy() and flush().
>>
>> v6
>> * Fix sparse warning for panic_msg and logo.
>>
>> v7
>> * Add select DRM_KMS_HELPER for the color conversion functions.
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>
> Bunch of comments on the glue, I didn't look at the drawing function in
> detail assuming that that's all working :-)
Thanks a lot for that detailed review.
> -Sima
>
>> ---
>> drivers/gpu/drm/Kconfig | 23 +++
>> drivers/gpu/drm/Makefile | 1 +
>> drivers/gpu/drm/drm_drv.c | 8 +
>> drivers/gpu/drm/drm_panic.c | 369 ++++++++++++++++++++++++++++++++++++
>> include/drm/drm_drv.h | 21 ++
>> include/drm/drm_panic.h | 97 ++++++++++
>> 6 files changed, 519 insertions(+)
>> create mode 100644 drivers/gpu/drm/drm_panic.c
>> create mode 100644 include/drm/drm_panic.h
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 628f90ed8a9b..a8219c98c8d6 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -103,6 +103,29 @@ config DRM_KMS_HELPER
>> help
>> CRTC helpers for KMS drivers.
>>
>> +config DRM_PANIC
>> + bool "Display a user-friendly message when a kernel panic occurs"
>> + depends on DRM && !FRAMEBUFFER_CONSOLE
>> + select DRM_KMS_HELPER
>> + select FONT_SUPPORT
>> + help
>> + Enable a drm panic handler, which will display a user-friendly message
>> + when a kernel panic occurs. It's useful when using a user-space
>> + console instead of fbcon.
>> + It will only work if your graphic driver supports this feature.
>> + To support Hi-DPI Display, you can enable bigger fonts like
>> + FONT_TER16x32
>> +
>> +config DRM_PANIC_FOREGROUND_COLOR
>> + hex "Drm panic screen foreground color, in RGB"
>> + depends on DRM_PANIC
>> + default 0xffffff
>> +
>> +config DRM_PANIC_BACKGROUND_COLOR
>> + hex "Drm panic screen background color, in RGB"
>> + depends on DRM_PANIC
>> + default 0x000000
>> +
>> config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
>> bool "Enable refcount backtrace history in the DP MST helpers"
>> depends on STACKTRACE_SUPPORT
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 8ac6f4b9546e..fdf3d3fe0c78 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -60,6 +60,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
>> drm_privacy_screen.o \
>> drm_privacy_screen_x86.o
>> drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
>> +drm-$(CONFIG_DRM_PANIC) += drm_panic.o
>> obj-$(CONFIG_DRM) += drm.o
>>
>> obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> index 243cacb3575c..998942e6d687 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -43,6 +43,7 @@
>> #include <drm/drm_file.h>
>> #include <drm/drm_managed.h>
>> #include <drm/drm_mode_object.h>
>> +#include <drm/drm_panic.h>
>> #include <drm/drm_print.h>
>> #include <drm/drm_privacy_screen_machine.h>
>>
>> @@ -944,6 +945,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
>> goto err_unload;
>> }
>>
>> + if (driver->get_scanout_buffer)
>> + drm_panic_register(dev);
>> +
>> DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
>> driver->name, driver->major, driver->minor,
>> driver->patchlevel, driver->date,
>> @@ -987,6 +991,8 @@ void drm_dev_unregister(struct drm_device *dev)
>> {
>> dev->registered = false;
>>
>> + drm_panic_unregister(dev);
>> +
>> drm_client_dev_unregister(dev);
>>
>> if (drm_core_check_feature(dev, DRIVER_MODESET))
>> @@ -1066,6 +1072,7 @@ static void drm_core_exit(void)
>> unregister_chrdev(DRM_MAJOR, "drm");
>> debugfs_remove(drm_debugfs_root);
>> drm_sysfs_destroy();
>> + drm_panic_exit();
>> idr_destroy(&drm_minors_idr);
>> drm_connector_ida_destroy();
>> }
>> @@ -1077,6 +1084,7 @@ static int __init drm_core_init(void)
>> drm_connector_ida_init();
>> idr_init(&drm_minors_idr);
>> drm_memcpy_init_early();
>> + drm_panic_init();
>>
>> ret = drm_sysfs_init();
>> if (ret < 0) {
>> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
>> new file mode 100644
>> index 000000000000..362a696ec48a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_panic.c
>> @@ -0,0 +1,369 @@
>> +// SPDX-License-Identifier: GPL-2.0 or MIT
>> +/*
>> + * Copyright (c) 2023 Red Hat.
>> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
>> + * inspired by the drm_log driver from David Herrmann <dh.herrmann@gmail.com>
>> + * Tux Ascii art taken from cowsay written by Tony Monroe
>> + */
>> +
>> +#include <linux/font.h>
>> +#include <linux/iosys-map.h>
>> +#include <linux/kdebug.h>
>> +#include <linux/list.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/panic_notifier.h>
>> +#include <linux/types.h>
>> +
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_format_helper.h>
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/drm_panic.h>
>> +#include <drm/drm_print.h>
>> +
>> +
>> +MODULE_AUTHOR("Jocelyn Falempe");
>> +MODULE_DESCRIPTION("DRM panic handler");
>> +MODULE_LICENSE("GPL");
>> +
>> +/**
>> + * DOC: DRM Panic
>
> You need to tie these nice kerneldocs into the overall documentation tree,
> or they're not getting built. Please then also check that all the links
> and formatting works correctly.
oh yes, I need to add it to the Documentation/drm/xx.rst.
I'm not sure where drm panic fits there.
If I move get_scanout_buffer() pointer to the drm_mode_config struct,
adding drm_panic docs to drm-kms.rst makes sense ?
>
>> + *
>> + * This module displays a user friendly message on screen when a kernel panic
>> + * occurs. This is conflicting with fbcon, so you can only enable it when fbcon
>> + * is disabled.
>> + * It's intended for end-user, so have minimal technical/debug information.
>> + */
>> +
>> +/*
>> + * Implementation details:
>> + *
>> + * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq,
>> + * or attempt to sleep. It's a best effort, and it may not be able to display
>> + * the message in all situations (like if the panic occurs in the middle of a
>> + * modesetting).
>> + * It will display only one static frame, so performance optimizations are low
>> + * priority as the machine is already in an unusable state.
>> + */
>> +
>> +/*
>> + * List of active drm devices that can render a panic
>> + */
>> +struct drm_panic_device {
>> + struct list_head head;
>> + struct drm_device *dev;
>> +};
>> +
>> +struct drm_panic_line {
>> + u32 len;
>> + const char *txt;
>> +};
>> +
>> +#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
>> +
>> +static struct drm_panic_line panic_msg[] = {
>> + PANIC_LINE("KERNEL PANIC !"),
>> + PANIC_LINE(""),
>> + PANIC_LINE("Please reboot your computer."),
>> + PANIC_LINE(""),
>> + PANIC_LINE(""), /* overwritten with panic reason */
>> +};
>> +
>> +static const struct drm_panic_line logo[] = {
>> + PANIC_LINE(" .--. _"),
>> + PANIC_LINE(" |o_o | | |"),
>> + PANIC_LINE(" |:_/ | | |"),
>> + PANIC_LINE(" // \\ \\ |_|"),
>> + PANIC_LINE(" (| | ) _"),
>> + PANIC_LINE(" /'\\_ _/`\\ (_)"),
>> + PANIC_LINE(" \\___)=(___/"),
>> +};
>> +
>> +static LIST_HEAD(drm_panic_devices);
>> +static DEFINE_MUTEX(drm_panic_lock);
>> +
>> +static void draw_empty_line_map(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
>> +{
>> + struct iosys_map dst = sb->map;
>> +
>> + iosys_map_incr(&dst, top * sb->pitch);
>> + drm_fb_fill(&dst, sb->pitch, height, sb->width, color, sb->format->cpp[0]);
>> +}
>> +
>> +static void draw_txt_line_map(const struct drm_panic_line *msg, size_t left, size_t top,
>> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
>> + const struct font_desc *font)
>> +{
>> + size_t i;
>> + const u8 *src;
>> + size_t src_stride = DIV_ROUND_UP(font->width, 8);
>> + struct iosys_map dst = sb->map;
>> + size_t end_text;
>> + unsigned int px_width = sb->format->cpp[0];
>> +
>> + iosys_map_incr(&dst, top * sb->pitch);
>> + drm_fb_fill(&dst, sb->pitch, font->height, left, bg_color, px_width);
>> + iosys_map_incr(&dst, left * px_width);
>> + for (i = 0; i < msg->len; i++) {
>> + src = font->data + (msg->txt[i] * font->height) * src_stride;
>> + drm_fb_blit_from_r1(&dst, sb->pitch, src, src_stride, font->height, font->width,
>> + fg_color, bg_color, px_width);
>> + iosys_map_incr(&dst, font->width * px_width);
>> + }
>> + end_text = (msg->len * font->width) + left;
>> + if (sb->width > end_text)
>> + drm_fb_fill(&dst, sb->pitch, font->height, sb->width - end_text,
>> + bg_color, px_width);
>> +}
>> +
>> +static void draw_empty_line_px(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
>> +{
>> + unsigned int x, y;
>> +
>> + for (y = 0; y < height; y++)
>> + for (x = 0; x < sb->width; x++)
>> + sb->draw_pixel_xy(x, y + top, color, sb->private);
>> +}
>> +
>> +static void draw_txt_line_px(const struct drm_panic_line *msg, size_t left, size_t top,
>> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
>> + const struct font_desc *font)
>> +{
>> + unsigned int x, y, i;
>> + const u8 *src;
>> + u32 color;
>> + size_t src_stride = DIV_ROUND_UP(font->width, 8);
>> + size_t end_text = msg->len * font->width + left;
>> + size_t right = sb->width > end_text ? sb->width - end_text : 0;
>> +
>> + for (y = 0; y < font->height; y++) {
>> + for (x = 0; x < left; x++)
>> + sb->draw_pixel_xy(x, y + top, bg_color, sb->private);
>> +
>> + for (i = 0; i < msg->len; i++) {
>> + src = font->data + (msg->txt[i] * font->height + y) * src_stride;
>> + for (x = 0; x < font->width; x++) {
>> + color = (src[x / 8] & (0x80 >> (x % 8))) ? fg_color : bg_color;
>> + sb->draw_pixel_xy(x + left + font->width * i, y + top, color,
>> + sb->private);
>> + }
>> + }
>> +
>> + for (x = 0; x < right; x++)
>> + sb->draw_pixel_xy(x + end_text, y + top, bg_color, sb->private);
>> + }
>> +}
>> +
>> +static void draw_empty_line(struct drm_scanout_buffer *sb, size_t top, size_t height, u32 color)
>> +{
>> + if (sb->draw_pixel_xy)
>> + draw_empty_line_px(sb, top, height, color);
>> + else
>> + draw_empty_line_map(sb, top, height, color);
>> +}
>> +
>> +static void draw_txt_line(const struct drm_panic_line *msg, size_t left, size_t top,
>> + struct drm_scanout_buffer *sb, u32 fg_color, u32 bg_color,
>> + const struct font_desc *font)
>> +{
>> + if (sb->draw_pixel_xy)
>> + draw_txt_line_px(msg, left, top, sb, fg_color, bg_color, font);
>> + else
>> + draw_txt_line_map(msg, left, top, sb, fg_color, bg_color, font);
>> +}
>> +
>> +
>> +static size_t panic_msg_needed_lines(size_t chars_per_line)
>> +{
>> + size_t msg_len = ARRAY_SIZE(panic_msg);
>> + size_t lines = 0;
>> + size_t i;
>> +
>> + for (i = 0; i < msg_len; i++)
>> + lines += panic_msg[i].len ? DIV_ROUND_UP(panic_msg[i].len, chars_per_line) : 1;
>> + return lines;
>> +}
>> +
>> +static bool can_draw_logo(size_t chars_per_line, size_t lines, size_t msg_lines)
>> +{
>> + size_t i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(logo); i++) {
>> + if (logo[i].len > chars_per_line)
>> + return false;
>> + }
>> + if (lines < msg_lines + ARRAY_SIZE(logo))
>> + return false;
>> + return true;
>> +}
>> +
>> +static size_t get_start_line(size_t lines, size_t msg_lines, bool draw_logo)
>> +{
>> + size_t remaining;
>> + size_t logo_len = ARRAY_SIZE(logo);
>> +
>> + if (lines < msg_lines)
>> + return 0;
>> + remaining = lines - msg_lines;
>> + if (draw_logo && remaining / 2 <= logo_len)
>> + return logo_len + (remaining - logo_len) / 4;
>> + return remaining / 2;
>> +}
>> +
>> +/*
>> + * Draw the panic message at the center of the screen
>> + */
>> +static void draw_panic_static(struct drm_scanout_buffer *sb, const char *msg)
>> +{
>> + size_t lines, msg_lines, l, msg_start_line, remaining, msgi;
>> + size_t chars_per_line;
>> + bool draw_logo;
>> + struct drm_panic_line panic_line;
>> + size_t msg_len = ARRAY_SIZE(panic_msg);
>> + size_t logo_len = ARRAY_SIZE(logo);
>> + u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR;
>> + u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR;
>> + const struct font_desc *font = get_default_font(sb->width, sb->height, 0x8080, 0x8080);
>> +
>> + if (!font)
>> + return;
>> +
>> + /* Set the panic reason */
>> + panic_msg[msg_len - 1].len = strlen(msg);
>> + panic_msg[msg_len - 1].txt = msg;
>> +
>> + lines = sb->height / font->height;
>> + chars_per_line = sb->width / font->width;
>> +
>> + msg_lines = panic_msg_needed_lines(chars_per_line);
>> + draw_logo = can_draw_logo(chars_per_line, lines, msg_lines);
>> + msg_start_line = get_start_line(lines, msg_lines, draw_logo);
>> +
>> + fg_color = drm_fb_convert_from_xrgb8888(fg_color, sb->format->format);
>> + bg_color = drm_fb_convert_from_xrgb8888(bg_color, sb->format->format);
>> +
>> + msgi = 0;
>> + panic_line.len = 0;
>> + for (l = 0; l < lines; l++) {
>> + if (draw_logo && l < logo_len)
>> + draw_txt_line(&logo[l], 0, l * font->height, sb, fg_color, bg_color, font);
>> + else if (l >= msg_start_line && msgi < msg_len) {
>> + if (!panic_line.len) {
>> + panic_line.txt = panic_msg[msgi].txt;
>> + panic_line.len = panic_msg[msgi].len;
>> + }
>> + if (!panic_line.len) {
>> + draw_empty_line(sb, l * font->height, font->height, bg_color);
>> + msgi++;
>> + } else if (panic_line.len > chars_per_line) {
>> + remaining = panic_line.len - chars_per_line;
>> + panic_line.len = chars_per_line;
>> + draw_txt_line(&panic_line, 0, l * font->height, sb, fg_color,
>> + bg_color, font);
>> + panic_line.txt += chars_per_line;
>> + panic_line.len = remaining;
>> + } else {
>> + draw_txt_line(&panic_line,
>> + font->width * (chars_per_line - panic_line.len) / 2,
>> + l * font->height, sb, fg_color, bg_color, font);
>> + panic_line.len = 0;
>> + msgi++;
>> + }
>> + } else {
>> + draw_empty_line(sb, l * font->height, font->height, bg_color);
>> + }
>> + }
>> + /* Fill the bottom of the screen, if sb->height is not a multiple of font->height */
>> + if (sb->height % font->height)
>> + draw_empty_line(sb, l * font->height, sb->height - l * font->height, bg_color);
>> +}
>> +
>> +static void draw_panic_device(struct drm_device *dev, const char *msg)
>> +{
>> + struct drm_scanout_buffer sb = {0};
>> +
>> + if (dev->driver->get_scanout_buffer(dev, &sb))
>> + return;
>> + draw_panic_static(&sb, msg);
>> + if (sb.flush)
>> + sb.flush(sb.private);
>> +}
>> +
>> +static int drm_panic(struct notifier_block *this, unsigned long event,
>> + void *ptr)
>> +{
>> + struct drm_panic_device *drm_panic_device;
>> +
>> + list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
>> + draw_panic_device(drm_panic_device->dev, ptr);
>
> The locking here is busted. Which is why the atomic notifier chain is
> special and uses atomic semantics - I would just avoid this issue and
> directly register each drm_panic_device instead of trying to maintain a
> drm-local list and getting the locking rules wrong.
It's a bit complex to get the drm_device pointer in the callback.
I think I can add a "struct notifier_block" in the struct
drm_mode_config, and use the container_of macro, to retrieve it.
This also makes it easy to unregister.
>
>> + }
>> + return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block drm_panic_notifier = {
>> + .notifier_call = drm_panic,
>> +};
>> +
>> +/**
>> + * drm_panic_register() - Initialize DRM panic for a device
>> + * @dev: the DRM device on which the panic screen will be displayed.
>> + */
>> +void drm_panic_register(struct drm_device *dev)
>> +{
>> + struct drm_panic_device *new;
>> +
>> + new = kzalloc(sizeof(*new), GFP_KERNEL);
>> + if (!new)
>> + return;
>> +
>> + new->dev = dev;
>> + mutex_lock(&drm_panic_lock);
>> + list_add_tail(&new->head, &drm_panic_devices);
>> + mutex_unlock(&drm_panic_lock);
>> +
>> + drm_info(dev, "Registered with drm panic\n");
>> +}
>> +EXPORT_SYMBOL(drm_panic_register);
>> +
>> +/**
>> + * drm_panic_unregister()
>> + * @dev: the DRM device previously registered.
>> + */
>> +void drm_panic_unregister(struct drm_device *dev)
>> +{
>> + struct drm_panic_device *drm_panic_device;
>> + struct drm_panic_device *found = NULL;
>> +
>> + mutex_lock(&drm_panic_lock);
>> + list_for_each_entry(drm_panic_device, &drm_panic_devices, head) {
>
> Can't we just store a pointer in drm_device (or embed the entire thing
> outright) instead of this dance?
If I store the struct notifier_block in the struct drm_mode_config,
then this dance is no more needed.
>
>> + if (drm_panic_device->dev == dev)
>> + found = drm_panic_device;
>> + }
>> + if (found) {
>> + list_del(&found->head);
>> + kfree(found);
>> + drm_info(dev, "Unregistered with drm panic\n");
>> + }
>> + mutex_unlock(&drm_panic_lock);
>> +}
>> +EXPORT_SYMBOL(drm_panic_unregister);
>> +
>> +/**
>> + * drm_panic_init() - Initialize drm-panic subsystem
>> + *
>> + * register the panic notifier
>> + */
>> +void drm_panic_init(void)
>> +{
>> + atomic_notifier_chain_register(&panic_notifier_list,
>> + &drm_panic_notifier);
>> +}
>> +
>> +/**
>> + * drm_panic_exit() - Shutdown drm-panic subsystem
>> + */
>> +void drm_panic_exit(void)
>> +{
>> + atomic_notifier_chain_unregister(&panic_notifier_list,
>> + &drm_panic_notifier);
>> +}
>> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
>> index 8878260d7529..99e5bcf13975 100644
>> --- a/include/drm/drm_drv.h
>> +++ b/include/drm/drm_drv.h
>> @@ -43,6 +43,7 @@ struct dma_buf_attachment;
>> struct drm_display_mode;
>> struct drm_mode_create_dumb;
>> struct drm_printer;
>> +struct drm_scanout_buffer;
>> struct sg_table;
>>
>> /**
>> @@ -401,6 +402,26 @@ struct drm_driver {
>> */
>> void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f);
>>
>> + /**
>> + * @get_scanout_buffer:
>> + *
>> + * Get the current scanout buffer, to display a panic message with drm_panic.
>> + * The driver should do the minimum changes to provide a linear buffer, that
>> + * can be used to display the panic screen.
>> + * It is called from a panic callback, and must follow its restrictions.
>> + * (no locks, no memory allocation, no sleep, no thread/workqueue, ...)
>> + * It's a best effort mode, so it's expected that in some complex cases the
>> + * panic screen won't be displayed.
>
>> + * Some hardware cannot provide a linear buffer, so there is a draw_pixel_xy()
>> + * callback in the struct drm_scanout_buffer that can be used in this case.
>
> I'd move this to the documentation of drm_scanout_buffer and just put a
> kernel-doc hyperlink in here referencing that for further information.
Agreed
>
>> + *
>> + * Returns:
>> + *
>> + * Zero on success, negative errno on failure.
>> + */
>> + int (*get_scanout_buffer)(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb);
>
> Please put this hook into drm_mode_config_funcs and not into the overall
> drm_driver struct. At least for kms we're trying to keep a clean design
> (and I know that stuff like dumb buffers got misplaced, not a good reason
> to do it again ...).
sure, I'm moving it there.
>
>> +
>> /** @major: driver major number */
>> int major;
>> /** @minor: driver minor number */
>> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
>> new file mode 100644
>> index 000000000000..bcf392b6fa1b
>> --- /dev/null
>> +++ b/include/drm/drm_panic.h
>> @@ -0,0 +1,97 @@
>> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
>> +#ifndef __DRM_PANIC_H__
>> +#define __DRM_PANIC_H__
>> +
>> +/*
>> + * Copyright (c) 2023 Red Hat.
>> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/iosys-map.h>
>> +
>> +struct drm_device;
>> +
>> +/**
>> + * struct drm_scanout_buffer - DRM scanout buffer
>> + *
>> + * This structure holds the information necessary for drm_panic to draw the
>> + * panic screen, and display it.
>
>> + * If the driver can't provide a linear buffer, it must clear @map with
>> + * iosys_map_clear() and provide a draw_pixel_xy() function.
>
> I think it's better to move this to the documentation of @map and
> @draw_pixel_xy.
ok, I will move it there.
>
>> + */
>> +struct drm_scanout_buffer {
>> + /**
>> + * @format:
>> + *
>> + * drm format of the scanout buffer.
>> + */
>> + const struct drm_format_info *format;
>> + /**
>> + * @map:
>> + *
>> + * Virtual address of the scanout buffer, either in memory or iomem.
>> + * The scanout buffer should be in linear format, and can be directly
>
> The should here is confusing, because it's an either/or.
>
>
>> + * sent to the display hardware. Tearing is not an issue for the panic
>> + * screen.
>> + */
>> + struct iosys_map map;
>
> I think you're a bit unclear on whether you allow non-null @map for the
> case when @draw_pixel_xy is set. Current docs says it's either/or, but you
> don't have any checks for iosys_map_is_null(). I'd add something like
>
> WARN_ON(sb->draw_pixel_xy && !iosys_map_is_null(sb->map));
>
> right after the call to ->get_scanout_buffer to lock down this rule.
ok, yes, I can add that check to avoid misuse of the API.
>
>> + /**
>> + * @width: Width of the scanout buffer, in pixels.
>> + */
>> + unsigned int width;
>> + /**
>> + * @height: Height of the scanout buffer, in pixels.
>> + */
>> + unsigned int height;
>> + /**
>> + * @pitch: Length in bytes between the start of two consecutive lines.
>> + */
>> + unsigned int pitch;
>> + /**
>> + * @private:
>> + *
>> + * In case the driver can't provide a linear buffer, this is a pointer to
>> + * some private data, that will be passed when calling @draw_pixel_xy()
>> + * and @flush()
>> + */
>> + void *private;
>> + /**
>> + * @draw_pixel_xy:
>> + *
>> + * In case the driver can't provide a linear buffer, this is a function
>> + * that drm_panic will call for each pixel to draw.
>> + * Color will be converted to the format specified by @format.
>> + */
>
>> + void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color, void *private);
>> + /**
>> + * @flush:
>> + *
>> + * This function is called after the panic screen is drawn, either using
>> + * the iosys_map or the draw_pixel_xy path. In this function, the driver
>> + * can send additional commands to the hardware, to make the buffer
>> + * visible.
>
> Uh how does flush work for the @map path? I'd just pass the overall
> drm_scanout_buffer struct to both of these hooks as the first parameter
> and let the driver figure out what it needs.
I can add the drm_scanout_buffer struct to both. There are probably some
drivers that will need it.
I use the flush callback for the virtio-gpu support (which I didn't send
yet), and didn't need the drm_scanout_buffer in this case, but there are
probably other drivers that will need it.
>
>> + */
>> + void (*flush)(void *private);
>> +};
>> +
>> +#ifdef CONFIG_DRM_PANIC
>> +
>> +void drm_panic_init(void);
>> +void drm_panic_exit(void);
>> +
>> +void drm_panic_register(struct drm_device *dev);
>> +void drm_panic_unregister(struct drm_device *dev);
>> +
>> +#else
>> +
>> +static inline void drm_panic_init(void) {}
>> +static inline void drm_panic_exit(void) {}
>> +
>> +static inline void drm_panic_register(struct drm_device *dev) {}
>> +static inline void drm_panic_unregister(struct drm_device *dev) {}
>> +
>> +#endif
>> +
>> +#endif /* __DRM_PANIC_H__ */
>> --
>> 2.43.0
>>
>
--
Jocelyn
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-16 10:54 ` Jocelyn Falempe
@ 2024-01-18 13:36 ` Daniel Vetter
0 siblings, 0 replies; 51+ messages in thread
From: Daniel Vetter @ 2024-01-18 13:36 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, Daniel Vetter, javierm, mripard, gpiccoli,
noralf, dri-devel, tzimmermann, airlied
On Tue, Jan 16, 2024 at 11:54:42AM +0100, Jocelyn Falempe wrote:
> On 12/01/2024 14:31, Daniel Vetter wrote:
> > You need to tie these nice kerneldocs into the overall documentation tree,
> > or they're not getting built. Please then also check that all the links
> > and formatting works correctly.
>
> oh yes, I need to add it to the Documentation/drm/xx.rst.
> I'm not sure where drm panic fits there.
> If I move get_scanout_buffer() pointer to the drm_mode_config struct, adding
> drm_panic docs to drm-kms.rst makes sense ?
Yeah I think a section in the modeset docs (not the modeset helper docs,
this is fairly core concept imo) makes the most sense.
> > The locking here is busted. Which is why the atomic notifier chain is
> > special and uses atomic semantics - I would just avoid this issue and
> > directly register each drm_panic_device instead of trying to maintain a
> > drm-local list and getting the locking rules wrong.
>
> It's a bit complex to get the drm_device pointer in the callback.
> I think I can add a "struct notifier_block" in the struct drm_mode_config,
> and use the container_of macro, to retrieve it.
> This also makes it easy to unregister.
Yeah if you register each drm_device separately you also need to embedded
the notifier chain into every single one. drm_mode_config sounds ok for
that to me.
I didn't realize that the kmsg_dumper api doesn't have some kind of void*
argument but you need to embed the notifier in the right place, in case
some of my other comments confused you.
-Sima
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-04 16:00 ` [PATCH v7 2/9] drm/panic: Add a drm panic handler Jocelyn Falempe
2024-01-12 13:31 ` Daniel Vetter
@ 2024-01-12 13:50 ` Daniel Vetter
2024-01-19 17:20 ` Jocelyn Falempe
2024-01-17 15:49 ` Thomas Zimmermann
2 siblings, 1 reply; 51+ messages in thread
From: Daniel Vetter @ 2024-01-12 13:50 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, mripard, gpiccoli,
noralf, dri-devel, airlied
On Thu, Jan 04, 2024 at 05:00:46PM +0100, Jocelyn Falempe wrote:
> +/**
> + * drm_panic_init() - Initialize drm-panic subsystem
> + *
> + * register the panic notifier
> + */
> +void drm_panic_init(void)
> +{
> + atomic_notifier_chain_register(&panic_notifier_list,
> + &drm_panic_notifier);
Ok I've found another one after checking core panic code. This is the
wrong hook, we want to be a sttruct kmsg_dumper and use
kmsg_dump_register. And again once for each drm_panic_device so that we
can rely on core locking, as I've explained in the other reply.
Also because it trashes buffers from userspace I think by default we want
to only dump on panic, so KMS_DUMP_PANIC.
-Sima
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-12 13:50 ` Daniel Vetter
@ 2024-01-19 17:20 ` Jocelyn Falempe
0 siblings, 0 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-19 17:20 UTC (permalink / raw)
To: Daniel Vetter
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
On 12/01/2024 14:50, Daniel Vetter wrote:
> On Thu, Jan 04, 2024 at 05:00:46PM +0100, Jocelyn Falempe wrote:
>> +/**
>> + * drm_panic_init() - Initialize drm-panic subsystem
>> + *
>> + * register the panic notifier
>> + */
>> +void drm_panic_init(void)
>> +{
>> + atomic_notifier_chain_register(&panic_notifier_list,
>> + &drm_panic_notifier);
>
> Ok I've found another one after checking core panic code. This is the
> wrong hook, we want to be a sttruct kmsg_dumper and use
> kmsg_dump_register. And again once for each drm_panic_device so that we
> can rely on core locking, as I've explained in the other reply.
>
> Also because it trashes buffers from userspace I think by default we want
> to only dump on panic, so KMS_DUMP_PANIC.
> -Sima
I've tested this change and I don't think kmsg_dumper is the right callback.
At least with panic_notifier, you get one line on why the panic occurs.
With kmsg_dumper you get the whole kmsg buffer, but I don't want to
throw that at the user. And it's not possible to extract just the panic
reason from the log.
I think the debug information should go in a QRCode, so you can actually
report the crash somewhere, and copy/paste the backtrace and other info
to the bug. I've a PoC for that, but I prefer to have the main drm_panic
merged before working further on this.
Anyway it's pretty easy to change from one to the other, since the API
are quite similar. So if we need the complete kmsg log someday, it
should be easy to switch.
Best regards,
--
Jocelyn
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-04 16:00 ` [PATCH v7 2/9] drm/panic: Add a drm panic handler Jocelyn Falempe
2024-01-12 13:31 ` Daniel Vetter
2024-01-12 13:50 ` Daniel Vetter
@ 2024-01-17 15:49 ` Thomas Zimmermann
2024-01-18 10:17 ` Jocelyn Falempe
2 siblings, 1 reply; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:49 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 5451 bytes --]
Hi
Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
[...]
>
> + /**
> + * @get_scanout_buffer:
> + *
> + * Get the current scanout buffer, to display a panic message with drm_panic.
> + * The driver should do the minimum changes to provide a linear buffer, that
> + * can be used to display the panic screen.
> + * It is called from a panic callback, and must follow its restrictions.
> + * (no locks, no memory allocation, no sleep, no thread/workqueue, ...)
> + * It's a best effort mode, so it's expected that in some complex cases the
> + * panic screen won't be displayed.
> + * Some hardware cannot provide a linear buffer, so there is a draw_pixel_xy()
> + * callback in the struct drm_scanout_buffer that can be used in this case.
> + *
> + * Returns:
> + *
> + * Zero on success, negative errno on failure.
> + */
> + int (*get_scanout_buffer)(struct drm_device *dev,
> + struct drm_scanout_buffer *sb);
> +
After reading through Sima's comments on (try-)locking, I'd like to
propose a different interface: instead of having the panic handler
search for the scanout buffer, let each driver explicitly set the
scanout buffer after each page flip. The algorithm for mode programming
then looks like this:
1) Maybe clear the panic handler's buffer at the beginning of
atomic_commit_tail, if necessary
2) Do the mode setting as usual
3) In the driver's atomic_flush or atomic_update, call something like
void drm_panic_set_scanout_buffer(dev, scanout_buffer)
to set the panic handler's new output.
This avoids all the locking and the second guessing about the pipeline
status.
I don't see an easy way of reliably showing a panic screen during a
modeset. But during a modeset, the old scanout buffer should
(theoretically) not disappear until the new scanout buffer is in place.
So if the panic happens, it would blit to the old address at worst.
Well, that assumption needs to be verified per driver.
Best regards
Thomas
> /** @major: driver major number */
> int major;
> /** @minor: driver minor number */
> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
> new file mode 100644
> index 000000000000..bcf392b6fa1b
> --- /dev/null
> +++ b/include/drm/drm_panic.h
> @@ -0,0 +1,97 @@
> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
> +#ifndef __DRM_PANIC_H__
> +#define __DRM_PANIC_H__
> +
> +/*
> + * Copyright (c) 2023 Red Hat.
> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/iosys-map.h>
> +
> +struct drm_device;
> +
> +/**
> + * struct drm_scanout_buffer - DRM scanout buffer
> + *
> + * This structure holds the information necessary for drm_panic to draw the
> + * panic screen, and display it.
> + * If the driver can't provide a linear buffer, it must clear @map with
> + * iosys_map_clear() and provide a draw_pixel_xy() function.
> + */
> +struct drm_scanout_buffer {
> + /**
> + * @format:
> + *
> + * drm format of the scanout buffer.
> + */
> + const struct drm_format_info *format;
> + /**
> + * @map:
> + *
> + * Virtual address of the scanout buffer, either in memory or iomem.
> + * The scanout buffer should be in linear format, and can be directly
> + * sent to the display hardware. Tearing is not an issue for the panic
> + * screen.
> + */
> + struct iosys_map map;
> + /**
> + * @width: Width of the scanout buffer, in pixels.
> + */
> + unsigned int width;
> + /**
> + * @height: Height of the scanout buffer, in pixels.
> + */
> + unsigned int height;
> + /**
> + * @pitch: Length in bytes between the start of two consecutive lines.
> + */
> + unsigned int pitch;
> + /**
> + * @private:
> + *
> + * In case the driver can't provide a linear buffer, this is a pointer to
> + * some private data, that will be passed when calling @draw_pixel_xy()
> + * and @flush()
> + */
> + void *private;
> + /**
> + * @draw_pixel_xy:
> + *
> + * In case the driver can't provide a linear buffer, this is a function
> + * that drm_panic will call for each pixel to draw.
> + * Color will be converted to the format specified by @format.
> + */
> + void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color, void *private);
> + /**
> + * @flush:
> + *
> + * This function is called after the panic screen is drawn, either using
> + * the iosys_map or the draw_pixel_xy path. In this function, the driver
> + * can send additional commands to the hardware, to make the buffer
> + * visible.
> + */
> + void (*flush)(void *private);
> +};
> +
> +#ifdef CONFIG_DRM_PANIC
> +
> +void drm_panic_init(void);
> +void drm_panic_exit(void);
> +
> +void drm_panic_register(struct drm_device *dev);
> +void drm_panic_unregister(struct drm_device *dev);
> +
> +#else
> +
> +static inline void drm_panic_init(void) {}
> +static inline void drm_panic_exit(void) {}
> +
> +static inline void drm_panic_register(struct drm_device *dev) {}
> +static inline void drm_panic_unregister(struct drm_device *dev) {}
> +
> +#endif
> +
> +#endif /* __DRM_PANIC_H__ */
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-17 15:49 ` Thomas Zimmermann
@ 2024-01-18 10:17 ` Jocelyn Falempe
2024-01-19 9:46 ` Thomas Zimmermann
0 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-18 10:17 UTC (permalink / raw)
To: Thomas Zimmermann, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
On 17/01/2024 16:49, Thomas Zimmermann wrote:
> Hi
>
> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> [...]
>> + /**
>> + * @get_scanout_buffer:
>> + *
>> + * Get the current scanout buffer, to display a panic message
>> with drm_panic.
>> + * The driver should do the minimum changes to provide a linear
>> buffer, that
>> + * can be used to display the panic screen.
>> + * It is called from a panic callback, and must follow its
>> restrictions.
>> + * (no locks, no memory allocation, no sleep, no
>> thread/workqueue, ...)
>> + * It's a best effort mode, so it's expected that in some complex
>> cases the
>> + * panic screen won't be displayed.
>> + * Some hardware cannot provide a linear buffer, so there is a
>> draw_pixel_xy()
>> + * callback in the struct drm_scanout_buffer that can be used in
>> this case.
>> + *
>> + * Returns:
>> + *
>> + * Zero on success, negative errno on failure.
>> + */
>> + int (*get_scanout_buffer)(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb);
>> +
>
> After reading through Sima's comments on (try-)locking, I'd like to
> propose a different interface: instead of having the panic handler
> search for the scanout buffer, let each driver explicitly set the
> scanout buffer after each page flip. The algorithm for mode programming
> then looks like this:
>
> 1) Maybe clear the panic handler's buffer at the beginning of
> atomic_commit_tail, if necessary
> 2) Do the mode setting as usual
> 3) In the driver's atomic_flush or atomic_update, call something like
>
> void drm_panic_set_scanout_buffer(dev, scanout_buffer)
>
> to set the panic handler's new output.
>
> This avoids all the locking and the second guessing about the pipeline
> status.
>
> I don't see an easy way of reliably showing a panic screen during a
> modeset. But during a modeset, the old scanout buffer should
> (theoretically) not disappear until the new scanout buffer is in place.
> So if the panic happens, it would blit to the old address at worst.
> Well, that assumption needs to be verified per driver.
That's an interesting approach, and I will give it a try.
I think you still need a callback in the driver, to actually send the
data to the GPU.
Also one thing that I don't handle yet, is when there are multiple
outputs, so we may want to set and update multiple scanout buffers ?
Best regards,
--
Jocelyn
>
> Best regards
> Thomas
>
>
>> /** @major: driver major number */
>> int major;
>> /** @minor: driver minor number */
>> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
>> new file mode 100644
>> index 000000000000..bcf392b6fa1b
>> --- /dev/null
>> +++ b/include/drm/drm_panic.h
>> @@ -0,0 +1,97 @@
>> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
>> +#ifndef __DRM_PANIC_H__
>> +#define __DRM_PANIC_H__
>> +
>> +/*
>> + * Copyright (c) 2023 Red Hat.
>> + * Author: Jocelyn Falempe <jfalempe@redhat.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/iosys-map.h>
>> +
>> +struct drm_device;
>> +
>> +/**
>> + * struct drm_scanout_buffer - DRM scanout buffer
>> + *
>> + * This structure holds the information necessary for drm_panic to
>> draw the
>> + * panic screen, and display it.
>> + * If the driver can't provide a linear buffer, it must clear @map with
>> + * iosys_map_clear() and provide a draw_pixel_xy() function.
>> + */
>> +struct drm_scanout_buffer {
>> + /**
>> + * @format:
>> + *
>> + * drm format of the scanout buffer.
>> + */
>> + const struct drm_format_info *format;
>> + /**
>> + * @map:
>> + *
>> + * Virtual address of the scanout buffer, either in memory or iomem.
>> + * The scanout buffer should be in linear format, and can be
>> directly
>> + * sent to the display hardware. Tearing is not an issue for the
>> panic
>> + * screen.
>> + */
>> + struct iosys_map map;
>> + /**
>> + * @width: Width of the scanout buffer, in pixels.
>> + */
>> + unsigned int width;
>> + /**
>> + * @height: Height of the scanout buffer, in pixels.
>> + */
>> + unsigned int height;
>> + /**
>> + * @pitch: Length in bytes between the start of two consecutive
>> lines.
>> + */
>> + unsigned int pitch;
>> + /**
>> + * @private:
>> + *
>> + * In case the driver can't provide a linear buffer, this is a
>> pointer to
>> + * some private data, that will be passed when calling
>> @draw_pixel_xy()
>> + * and @flush()
>> + */
>> + void *private;
>> + /**
>> + * @draw_pixel_xy:
>> + *
>> + * In case the driver can't provide a linear buffer, this is a
>> function
>> + * that drm_panic will call for each pixel to draw.
>> + * Color will be converted to the format specified by @format.
>> + */
>> + void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color,
>> void *private);
>> + /**
>> + * @flush:
>> + *
>> + * This function is called after the panic screen is drawn,
>> either using
>> + * the iosys_map or the draw_pixel_xy path. In this function, the
>> driver
>> + * can send additional commands to the hardware, to make the buffer
>> + * visible.
>> + */
>> + void (*flush)(void *private);
>> +};
>> +
>> +#ifdef CONFIG_DRM_PANIC
>> +
>> +void drm_panic_init(void);
>> +void drm_panic_exit(void);
>> +
>> +void drm_panic_register(struct drm_device *dev);
>> +void drm_panic_unregister(struct drm_device *dev);
>> +
>> +#else
>> +
>> +static inline void drm_panic_init(void) {}
>> +static inline void drm_panic_exit(void) {}
>> +
>> +static inline void drm_panic_register(struct drm_device *dev) {}
>> +static inline void drm_panic_unregister(struct drm_device *dev) {}
>> +
>> +#endif
>> +
>> +#endif /* __DRM_PANIC_H__ */
>
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
2024-01-18 10:17 ` Jocelyn Falempe
@ 2024-01-19 9:46 ` Thomas Zimmermann
0 siblings, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-19 9:46 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 3826 bytes --]
Hi
Am 18.01.24 um 11:17 schrieb Jocelyn Falempe:
>
>
> On 17/01/2024 16:49, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
>> [...]
>>> + /**
>>> + * @get_scanout_buffer:
>>> + *
>>> + * Get the current scanout buffer, to display a panic message
>>> with drm_panic.
>>> + * The driver should do the minimum changes to provide a linear
>>> buffer, that
>>> + * can be used to display the panic screen.
>>> + * It is called from a panic callback, and must follow its
>>> restrictions.
>>> + * (no locks, no memory allocation, no sleep, no
>>> thread/workqueue, ...)
>>> + * It's a best effort mode, so it's expected that in some
>>> complex cases the
>>> + * panic screen won't be displayed.
>>> + * Some hardware cannot provide a linear buffer, so there is a
>>> draw_pixel_xy()
>>> + * callback in the struct drm_scanout_buffer that can be used in
>>> this case.
>>> + *
>>> + * Returns:
>>> + *
>>> + * Zero on success, negative errno on failure.
>>> + */
>>> + int (*get_scanout_buffer)(struct drm_device *dev,
>>> + struct drm_scanout_buffer *sb);
>>> +
>>
>> After reading through Sima's comments on (try-)locking, I'd like to
>> propose a different interface: instead of having the panic handler
>> search for the scanout buffer, let each driver explicitly set the
>> scanout buffer after each page flip. The algorithm for mode
>> programming then looks like this:
>>
>> 1) Maybe clear the panic handler's buffer at the beginning of
>> atomic_commit_tail, if necessary
>> 2) Do the mode setting as usual
>> 3) In the driver's atomic_flush or atomic_update, call something like
>>
>> void drm_panic_set_scanout_buffer(dev, scanout_buffer)
>>
>> to set the panic handler's new output.
>>
>> This avoids all the locking and the second guessing about the pipeline
>> status.
>>
>> I don't see an easy way of reliably showing a panic screen during a
>> modeset. But during a modeset, the old scanout buffer should
>> (theoretically) not disappear until the new scanout buffer is in
>> place. So if the panic happens, it would blit to the old address at
>> worst. Well, that assumption needs to be verified per driver.
>
> That's an interesting approach, and I will give it a try.
> I think you still need a callback in the driver, to actually send the
> data to the GPU.
Sure, you could add this callback directly to the scanout buffer.
>
> Also one thing that I don't handle yet, is when there are multiple
> outputs, so we may want to set and update multiple scanout buffers ?
That makes me think about adding panic handling directly to the plane,
something like this
drm_plane_enable_panic_output(struct drm_plane*)
drm_plane_set_panic_output_buffer(struct drm_plane*, struct
drm_scanout_buffer*)
First time the driver calls drm_plane_enable_panic_output(), it sets up
the panic handling for the given plane and maybe for DRM as a whole.
Each instance of the DRM panic handler operates on a single plane. Then
during the pageflips, drm_plane_set_panic_output_buffer() updates the
output buffer. The necessary sync/flush callbacks can be part of the
drm_plane_funcs.
If/when the plane gets removed from the modesetting pipeline, the panic
handling would be removed automatically.
Best regards
Thomas
>
> Best regards,
>
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
2024-01-04 16:00 ` [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill Jocelyn Falempe
2024-01-04 16:00 ` [PATCH v7 2/9] drm/panic: Add a drm panic handler Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-08 10:24 ` Jocelyn Falempe
2024-01-04 16:00 ` [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported() Jocelyn Falempe
` (6 subsequent siblings)
9 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
To support drm_panic, most drivers need to find the current primary
visible plane with a framebuffer attached.
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
include/drm/drm_plane.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index c6565a6f9324..41c08a2ddf8d 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -948,6 +948,21 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+/**
+ * drm_for_each_primary_visible_plane - iterate over all primary visible planes
+ * @plane: the loop cursor
+ * @dev: the DRM device
+ *
+ * Iterate over all primary, visible plane, with a framebuffer.
+ * This is useful for drm_panic, to find the current scanout buffer.
+ */
+#define drm_for_each_primary_visible_plane(plane, dev) \
+ list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
+ for_each_if((plane)->type == DRM_PLANE_TYPE_PRIMARY && \
+ (plane)->state && \
+ (plane)->state->fb && \
+ (plane)->state->visible)
+
/**
* drm_for_each_plane - iterate over all planes
* @plane: the loop cursor
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro
2024-01-04 16:00 ` [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro Jocelyn Falempe
@ 2024-01-08 10:24 ` Jocelyn Falempe
2024-01-08 10:30 ` Joe Perches
0 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-08 10:24 UTC (permalink / raw)
To: Andy Whitcroft, Joe Perches, Dwaipayan Ray, Lukas Bulwahn
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
Hi checkpatch maintainers,
This patch gives me the following checkpatch error:
ERROR: Macros with complex values should be enclosed in parentheses
#30: FILE: include/drm/drm_plane.h:959:
+#define drm_for_each_primary_visible_plane(plane, dev) \
+ list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
+ for_each_if((plane)->type == DRM_PLANE_TYPE_PRIMARY && \
+ (plane)->state && \
+ (plane)->state->fb && \
+ (plane)->state->visible)
total: 1 errors, 0 warnings, 21 lines checked
I think this requirement cannot work when you use list_for_each kind of
macros.
Do you have any suggestion ?
Best regards,
--
Jocelyn
On 04/01/2024 17:00, Jocelyn Falempe wrote:
> To support drm_panic, most drivers need to find the current primary
> visible plane with a framebuffer attached.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> include/drm/drm_plane.h | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index c6565a6f9324..41c08a2ddf8d 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -948,6 +948,21 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
> list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
> for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
>
> +/**
> + * drm_for_each_primary_visible_plane - iterate over all primary visible planes
> + * @plane: the loop cursor
> + * @dev: the DRM device
> + *
> + * Iterate over all primary, visible plane, with a framebuffer.
> + * This is useful for drm_panic, to find the current scanout buffer.
> + */
> +#define drm_for_each_primary_visible_plane(plane, dev) \
> + list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
> + for_each_if((plane)->type == DRM_PLANE_TYPE_PRIMARY && \
> + (plane)->state && \
> + (plane)->state->fb && \
> + (plane)->state->visible)
> +
> /**
> * drm_for_each_plane - iterate over all planes
> * @plane: the loop cursor
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro
2024-01-08 10:24 ` Jocelyn Falempe
@ 2024-01-08 10:30 ` Joe Perches
0 siblings, 0 replies; 51+ messages in thread
From: Joe Perches @ 2024-01-08 10:30 UTC (permalink / raw)
To: Jocelyn Falempe, Andy Whitcroft, Dwaipayan Ray, Lukas Bulwahn
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
On Mon, 2024-01-08 at 11:24 +0100, Jocelyn Falempe wrote:
> Hi checkpatch maintainers,
>
> This patch gives me the following checkpatch error:
>
> ERROR: Macros with complex values should be enclosed in parentheses
> #30: FILE: include/drm/drm_plane.h:959:
> +#define drm_for_each_primary_visible_plane(plane, dev) \
> + list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
> + for_each_if((plane)->type == DRM_PLANE_TYPE_PRIMARY && \
> + (plane)->state && \
> + (plane)->state->fb && \
> + (plane)->state->visible)
>
> total: 1 errors, 0 warnings, 21 lines checked
>
> I think this requirement cannot work when you use list_for_each kind of
> macros.
> Do you have any suggestion ?
>
checkpatch is a brainless regex script.
Ignore it when it's stupid.
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (2 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-05 5:45 ` kernel test robot
2024-01-04 16:00 ` [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Jocelyn Falempe
` (5 subsequent siblings)
9 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
So driver knows early if drm_panic will be able to display something
on the current scanout buffer.
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/drm_panic.c | 13 +++++++++++++
include/drm/drm_panic.h | 4 ++++
2 files changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
index 362a696ec48a..c68167cd4c08 100644
--- a/drivers/gpu/drm/drm_panic.c
+++ b/drivers/gpu/drm/drm_panic.c
@@ -348,6 +348,19 @@ void drm_panic_unregister(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_panic_unregister);
+/**
+ * drm_panic_is_format_supported()
+ * @format: a fourcc color code
+ * Returns: true if supported, false otherwise.
+ *
+ * Check if drm_panic will be able to use this color format.
+ */
+bool drm_panic_is_format_supported(u32 format)
+{
+ return drm_fb_convert_from_xrgb8888(0xffffff, format) != 0;
+}
+EXPORT_SYMBOL(drm_panic_is_format_supported);
+
/**
* drm_panic_init() - Initialize drm-panic subsystem
*
diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
index bcf392b6fa1b..1549c8eb8dcc 100644
--- a/include/drm/drm_panic.h
+++ b/include/drm/drm_panic.h
@@ -84,6 +84,8 @@ void drm_panic_exit(void);
void drm_panic_register(struct drm_device *dev);
void drm_panic_unregister(struct drm_device *dev);
+bool drm_panic_is_format_supported(u32 format);
+
#else
static inline void drm_panic_init(void) {}
@@ -92,6 +94,8 @@ static inline void drm_panic_exit(void) {}
static inline void drm_panic_register(struct drm_device *dev) {}
static inline void drm_panic_unregister(struct drm_device *dev) {}
+bool drm_panic_is_format_supported(u32 format) {return false; }
+
#endif
#endif /* __DRM_PANIC_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
2024-01-04 16:00 ` [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported() Jocelyn Falempe
@ 2024-01-05 5:45 ` kernel test robot
0 siblings, 0 replies; 51+ messages in thread
From: kernel test robot @ 2024-01-05 5:45 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, tzimmermann, airlied,
maarten.lankhorst, mripard, daniel, javierm, bluescreen_avenger,
noralf
Cc: oe-kbuild-all, gpiccoli, Jocelyn Falempe
Hi Jocelyn,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 50a3c772bd927dd409c484832ddd9f6bf00b7389]
url: https://github.com/intel-lab-lkp/linux/commits/Jocelyn-Falempe/drm-format-helper-Add-drm_fb_blit_from_r1-and-drm_fb_fill/20240105-001038
base: 50a3c772bd927dd409c484832ddd9f6bf00b7389
patch link: https://lore.kernel.org/r/20240104160301.185915-5-jfalempe%40redhat.com
patch subject: [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
config: hexagon-randconfig-r071-20240105 (https://download.01.org/0day-ci/archive/20240105/202401051328.IW9dwjX4-lkp@intel.com/config)
compiler: clang version 18.0.0git (https://github.com/llvm/llvm-project 7e186d366d6c7def0543acc255931f617e76dff0)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240105/202401051328.IW9dwjX4-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401051328.IW9dwjX4-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
547 | val = __raw_readb(PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
| ^
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
| ^
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
584 | __raw_writeb(value, PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
In file included from drivers/gpu/drm/drm_drv.c:46:
>> include/drm/drm_panic.h:97:6: warning: no previous prototype for function 'drm_panic_is_format_supported' [-Wmissing-prototypes]
97 | bool drm_panic_is_format_supported(u32 format) {return false; }
| ^
include/drm/drm_panic.h:97:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
97 | bool drm_panic_is_format_supported(u32 format) {return false; }
| ^
| static
7 warnings generated.
vim +/drm_panic_is_format_supported +97 include/drm/drm_panic.h
96
> 97 bool drm_panic_is_format_supported(u32 format) {return false; }
98
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
@ 2024-01-05 5:45 ` kernel test robot
0 siblings, 0 replies; 51+ messages in thread
From: kernel test robot @ 2024-01-05 5:45 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, tzimmermann, airlied,
maarten.lankhorst, mripard, daniel, javierm, bluescreen_avenger,
noralf
Cc: gpiccoli, Jocelyn Falempe, oe-kbuild-all
Hi Jocelyn,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 50a3c772bd927dd409c484832ddd9f6bf00b7389]
url: https://github.com/intel-lab-lkp/linux/commits/Jocelyn-Falempe/drm-format-helper-Add-drm_fb_blit_from_r1-and-drm_fb_fill/20240105-001038
base: 50a3c772bd927dd409c484832ddd9f6bf00b7389
patch link: https://lore.kernel.org/r/20240104160301.185915-5-jfalempe%40redhat.com
patch subject: [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
config: hexagon-randconfig-r071-20240105 (https://download.01.org/0day-ci/archive/20240105/202401051328.IW9dwjX4-lkp@intel.com/config)
compiler: clang version 18.0.0git (https://github.com/llvm/llvm-project 7e186d366d6c7def0543acc255931f617e76dff0)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240105/202401051328.IW9dwjX4-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401051328.IW9dwjX4-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
547 | val = __raw_readb(PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
| ^
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
| ^
In file included from drivers/gpu/drm/drm_drv.c:38:
In file included from include/drm/drm_accel.h:11:
In file included from include/drm/drm_file.h:39:
In file included from include/drm/drm_prime.h:37:
In file included from include/linux/scatterlist.h:9:
In file included from arch/hexagon/include/asm/io.h:337:
include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
584 | __raw_writeb(value, PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
In file included from drivers/gpu/drm/drm_drv.c:46:
>> include/drm/drm_panic.h:97:6: warning: no previous prototype for function 'drm_panic_is_format_supported' [-Wmissing-prototypes]
97 | bool drm_panic_is_format_supported(u32 format) {return false; }
| ^
include/drm/drm_panic.h:97:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
97 | bool drm_panic_is_format_supported(u32 format) {return false; }
| ^
| static
7 warnings generated.
vim +/drm_panic_is_format_supported +97 include/drm/drm_panic.h
96
> 97 bool drm_panic_is_format_supported(u32 format) {return false; }
98
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (3 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported() Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-06 2:54 ` kernel test robot
` (2 more replies)
2024-01-04 16:00 ` [PATCH v7 6/9] drm/simpledrm: Add drm_panic support Jocelyn Falempe
` (4 subsequent siblings)
9 siblings, 3 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
This was initialy done for imx6, but should work on most drivers
using drm_fb_dma_helper.
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
include/drm/drm_fb_dma_helper.h | 4 +++
2 files changed, 59 insertions(+)
diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
index 3b535ad1b07c..caed2935df4f 100644
--- a/drivers/gpu/drm/drm_fb_dma_helper.c
+++ b/drivers/gpu/drm/drm_fb_dma_helper.c
@@ -15,6 +15,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_panic.h>
#include <drm/drm_plane.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
@@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
}
}
EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
+
+#if defined(CONFIG_DRM_PANIC)
+/**
+ * @dev: DRM device
+ * @drm_scanout_buffer: scanout buffer for the panic handler
+ * Returns: 0 or negative error code
+ *
+ * Generic get_scanout_buffer() implementation, for drivers that uses the
+ * drm_fb_dma_helper.
+ */
+int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+ struct drm_plane *plane;
+ struct drm_gem_dma_object *dma_obj;
+ struct drm_framebuffer *fb;
+
+ drm_for_each_primary_visible_plane(plane, dev) {
+ fb = plane->state->fb;
+ /* Only support linear modifier */
+ if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
+ continue;
+
+ /* Check if color format is supported */
+ if (!drm_panic_is_format_supported(fb->format->format))
+ continue;
+
+ dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
+
+ /* Buffer should be accessible from the CPU */
+ if (dma_obj->base.import_attach)
+ continue;
+
+ /* Buffer should be already mapped to CPU */
+ if (!dma_obj->vaddr)
+ continue;
+
+ iosys_map_set_vaddr(&sb->map, dma_obj->vaddr);
+ sb->format = fb->format;
+ sb->height = fb->height;
+ sb->width = fb->width;
+ sb->pitch = fb->pitches[0];
+ return 0;
+ }
+ return -ENODEV;
+}
+#else
+int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+ return 0;
+}
+#endif
+EXPORT_SYMBOL(drm_panic_gem_get_scanout_buffer);
diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h
index d5e036c57801..2ae432865079 100644
--- a/include/drm/drm_fb_dma_helper.h
+++ b/include/drm/drm_fb_dma_helper.h
@@ -7,6 +7,7 @@
struct drm_device;
struct drm_framebuffer;
struct drm_plane_state;
+struct drm_scanout_buffer;
struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb,
unsigned int plane);
@@ -19,5 +20,8 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
struct drm_plane_state *old_state,
struct drm_plane_state *state);
+int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-04 16:00 ` [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Jocelyn Falempe
@ 2024-01-06 2:54 ` kernel test robot
2024-01-08 10:20 ` Maxime Ripard
2024-01-12 13:41 ` Daniel Vetter
2 siblings, 0 replies; 51+ messages in thread
From: kernel test robot @ 2024-01-06 2:54 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, tzimmermann, airlied,
maarten.lankhorst, mripard, daniel, javierm, bluescreen_avenger,
noralf
Cc: oe-kbuild-all, gpiccoli, Jocelyn Falempe
Hi Jocelyn,
kernel test robot noticed the following build errors:
[auto build test ERROR on 50a3c772bd927dd409c484832ddd9f6bf00b7389]
url: https://github.com/intel-lab-lkp/linux/commits/Jocelyn-Falempe/drm-format-helper-Add-drm_fb_blit_from_r1-and-drm_fb_fill/20240105-001038
base: 50a3c772bd927dd409c484832ddd9f6bf00b7389
patch link: https://lore.kernel.org/r/20240104160301.185915-6-jfalempe%40redhat.com
patch subject: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
config: mips-gcw0_defconfig (https://download.01.org/0day-ci/archive/20240106/202401061003.lNwFS0D6-lkp@intel.com/config)
compiler: mipsel-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240106/202401061003.lNwFS0D6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401061003.lNwFS0D6-lkp@intel.com/
All errors (new ones prefixed by >>):
mipsel-linux-ld: drivers/gpu/drm/drm_fb_dma_helper.o: in function `drm_panic_is_format_supported':
>> drm_fb_dma_helper.c:(.text+0x2c8): multiple definition of `drm_panic_is_format_supported'; drivers/gpu/drm/drm_drv.o:drm_drv.c:(.text+0x1104): first defined here
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
@ 2024-01-06 2:54 ` kernel test robot
0 siblings, 0 replies; 51+ messages in thread
From: kernel test robot @ 2024-01-06 2:54 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, tzimmermann, airlied,
maarten.lankhorst, mripard, daniel, javierm, bluescreen_avenger,
noralf
Cc: gpiccoli, Jocelyn Falempe, oe-kbuild-all
Hi Jocelyn,
kernel test robot noticed the following build errors:
[auto build test ERROR on 50a3c772bd927dd409c484832ddd9f6bf00b7389]
url: https://github.com/intel-lab-lkp/linux/commits/Jocelyn-Falempe/drm-format-helper-Add-drm_fb_blit_from_r1-and-drm_fb_fill/20240105-001038
base: 50a3c772bd927dd409c484832ddd9f6bf00b7389
patch link: https://lore.kernel.org/r/20240104160301.185915-6-jfalempe%40redhat.com
patch subject: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
config: mips-gcw0_defconfig (https://download.01.org/0day-ci/archive/20240106/202401061003.lNwFS0D6-lkp@intel.com/config)
compiler: mipsel-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240106/202401061003.lNwFS0D6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202401061003.lNwFS0D6-lkp@intel.com/
All errors (new ones prefixed by >>):
mipsel-linux-ld: drivers/gpu/drm/drm_fb_dma_helper.o: in function `drm_panic_is_format_supported':
>> drm_fb_dma_helper.c:(.text+0x2c8): multiple definition of `drm_panic_is_format_supported'; drivers/gpu/drm/drm_drv.o:drm_drv.c:(.text+0x1104): first defined here
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-04 16:00 ` [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Jocelyn Falempe
2024-01-06 2:54 ` kernel test robot
@ 2024-01-08 10:20 ` Maxime Ripard
2024-01-12 12:29 ` Jocelyn Falempe
2024-01-12 13:41 ` Daniel Vetter
2 siblings, 1 reply; 51+ messages in thread
From: Maxime Ripard @ 2024-01-08 10:20 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, dri-devel, gpiccoli,
noralf, airlied
[-- Attachment #1: Type: text/plain, Size: 2817 bytes --]
Hi,
On Thu, Jan 04, 2024 at 05:00:49PM +0100, Jocelyn Falempe wrote:
> This was initialy done for imx6, but should work on most drivers
> using drm_fb_dma_helper.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
> include/drm/drm_fb_dma_helper.h | 4 +++
> 2 files changed, 59 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
> index 3b535ad1b07c..caed2935df4f 100644
> --- a/drivers/gpu/drm/drm_fb_dma_helper.c
> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
> @@ -15,6 +15,7 @@
> #include <drm/drm_framebuffer.h>
> #include <drm/drm_gem_dma_helper.h>
> #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_plane.h>
> #include <linux/dma-mapping.h>
> #include <linux/module.h>
> @@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
> }
> }
> EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
> +
> +#if defined(CONFIG_DRM_PANIC)
> +/**
> + * @dev: DRM device
> + * @drm_scanout_buffer: scanout buffer for the panic handler
> + * Returns: 0 or negative error code
> + *
> + * Generic get_scanout_buffer() implementation, for drivers that uses the
> + * drm_fb_dma_helper.
> + */
> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct drm_plane *plane;
> + struct drm_gem_dma_object *dma_obj;
> + struct drm_framebuffer *fb;
> +
> + drm_for_each_primary_visible_plane(plane, dev) {
> + fb = plane->state->fb;
> + /* Only support linear modifier */
> + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
> + continue;
> +
> + /* Check if color format is supported */
> + if (!drm_panic_is_format_supported(fb->format->format))
> + continue;
> +
> + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
> +
> + /* Buffer should be accessible from the CPU */
> + if (dma_obj->base.import_attach)
> + continue;
> +
> + /* Buffer should be already mapped to CPU */
> + if (!dma_obj->vaddr)
> + continue;
> +
> + iosys_map_set_vaddr(&sb->map, dma_obj->vaddr);
> + sb->format = fb->format;
> + sb->height = fb->height;
> + sb->width = fb->width;
> + sb->pitch = fb->pitches[0];
> + return 0;
> + }
> + return -ENODEV;
> +}
> +#else
> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + return 0;
> +}
> +#endif
> +EXPORT_SYMBOL(drm_panic_gem_get_scanout_buffer);
Looks much better, thanks :)
I think we should be more vocal about the failure cases too. Maybe log
it through warn/pr_crit or whatever so that at least we have an idea
what went wrong in a post mortem.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-08 10:20 ` Maxime Ripard
@ 2024-01-12 12:29 ` Jocelyn Falempe
0 siblings, 0 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-12 12:29 UTC (permalink / raw)
To: Maxime Ripard
Cc: bluescreen_avenger, tzimmermann, javierm, dri-devel, gpiccoli,
noralf, airlied
On 08/01/2024 11:20, Maxime Ripard wrote:
> Hi,
>
> On Thu, Jan 04, 2024 at 05:00:49PM +0100, Jocelyn Falempe wrote:
>> This was initialy done for imx6, but should work on most drivers
>> using drm_fb_dma_helper.
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>> ---
>> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
>> include/drm/drm_fb_dma_helper.h | 4 +++
>> 2 files changed, 59 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
>> index 3b535ad1b07c..caed2935df4f 100644
>> --- a/drivers/gpu/drm/drm_fb_dma_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
>> @@ -15,6 +15,7 @@
>> #include <drm/drm_framebuffer.h>
>> #include <drm/drm_gem_dma_helper.h>
>> #include <drm/drm_gem_framebuffer_helper.h>
>> +#include <drm/drm_panic.h>
>> #include <drm/drm_plane.h>
>> #include <linux/dma-mapping.h>
>> #include <linux/module.h>
>> @@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
>> }
>> }
>> EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
>> +
>> +#if defined(CONFIG_DRM_PANIC)
>> +/**
>> + * @dev: DRM device
>> + * @drm_scanout_buffer: scanout buffer for the panic handler
>> + * Returns: 0 or negative error code
>> + *
>> + * Generic get_scanout_buffer() implementation, for drivers that uses the
>> + * drm_fb_dma_helper.
>> + */
>> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb)
>> +{
>> + struct drm_plane *plane;
>> + struct drm_gem_dma_object *dma_obj;
>> + struct drm_framebuffer *fb;
>> +
>> + drm_for_each_primary_visible_plane(plane, dev) {
>> + fb = plane->state->fb;
>> + /* Only support linear modifier */
>> + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
>> + continue;
>> +
>> + /* Check if color format is supported */
>> + if (!drm_panic_is_format_supported(fb->format->format))
>> + continue;
>> +
>> + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
>> +
>> + /* Buffer should be accessible from the CPU */
>> + if (dma_obj->base.import_attach)
>> + continue;
>> +
>> + /* Buffer should be already mapped to CPU */
>> + if (!dma_obj->vaddr)
>> + continue;
>> +
>> + iosys_map_set_vaddr(&sb->map, dma_obj->vaddr);
>> + sb->format = fb->format;
>> + sb->height = fb->height;
>> + sb->width = fb->width;
>> + sb->pitch = fb->pitches[0];
>> + return 0;
>> + }
>> + return -ENODEV;
>> +}
>> +#else
>> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb)
>> +{
>> + return 0;
>> +}
>> +#endif
>> +EXPORT_SYMBOL(drm_panic_gem_get_scanout_buffer);
>
> Looks much better, thanks :)
>
> I think we should be more vocal about the failure cases too. Maybe log
> it through warn/pr_crit or whatever so that at least we have an idea
> what went wrong in a post mortem.
Thanks for the review.
Yes I can add an error message when it fails to find a scanout buffer.
>
> Maxime
--
Jocelyn
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-04 16:00 ` [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Jocelyn Falempe
2024-01-06 2:54 ` kernel test robot
2024-01-08 10:20 ` Maxime Ripard
@ 2024-01-12 13:41 ` Daniel Vetter
2024-01-12 13:56 ` Maxime Ripard
2024-01-17 14:28 ` Jocelyn Falempe
2 siblings, 2 replies; 51+ messages in thread
From: Daniel Vetter @ 2024-01-12 13:41 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, mripard, gpiccoli,
noralf, dri-devel, airlied
On Thu, Jan 04, 2024 at 05:00:49PM +0100, Jocelyn Falempe wrote:
> This was initialy done for imx6, but should work on most drivers
> using drm_fb_dma_helper.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
> include/drm/drm_fb_dma_helper.h | 4 +++
> 2 files changed, 59 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
> index 3b535ad1b07c..caed2935df4f 100644
> --- a/drivers/gpu/drm/drm_fb_dma_helper.c
> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
> @@ -15,6 +15,7 @@
> #include <drm/drm_framebuffer.h>
> #include <drm/drm_gem_dma_helper.h>
> #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_plane.h>
> #include <linux/dma-mapping.h>
> #include <linux/module.h>
> @@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
> }
> }
> EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
> +
> +#if defined(CONFIG_DRM_PANIC)
> +/**
> + * @dev: DRM device
> + * @drm_scanout_buffer: scanout buffer for the panic handler
> + * Returns: 0 or negative error code
> + *
> + * Generic get_scanout_buffer() implementation, for drivers that uses the
> + * drm_fb_dma_helper.
> + */
> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct drm_plane *plane;
> + struct drm_gem_dma_object *dma_obj;
> + struct drm_framebuffer *fb;
> +
> + drm_for_each_primary_visible_plane(plane, dev) {
Ok that's not enough locking by far. You can't just hope that nothing
disappears while you're in a panic handler. We've been there and ended up
reliably oopsing in the panic handler itself. So you _have_ to follow the
full set of locking rules for all drm structures, or things will just get
worse at the worst possible moment.
But also, you're not allowed to do anything else than trylock, because a
panic handler might run from nmi context, and so you cannot even acquire
irq-safe spinlocks reliably.
Which means:
- You need to be safe against concurrent drm_dev_unregister. Using the
atomic panic notifier directly for each device should take care of that
(but maybe that stuff is still not nmi safe, not sure).
- You _have_ to use all the locks. Luckily iterating over the plane list
doesn't need one, but you have to trylock the plane's modeset lock.
Which means your nice iterator macro is already toast, because that
already looks at state it's not allowed to look at without a lock. Or
well, the plane->state pointer is no-go already.
Given the locking issues I'm not sure whether the
drm_for_each_primary_visible_plane iterator is going to work, you'd need
something like iter_init/next/end we have for walking the connector list.
Plus it would be very panic specific due to the trylock, so maybe
drm_for_each_visible_plane_in_panic_handler()
or something like that.
One thing I was wondering is whether we should lift this iteration over
all planes into the shared code, and move the ->get_scanout_buffer
function to the drm_plane_funcs structure instead?
> + fb = plane->state->fb;
> + /* Only support linear modifier */
> + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
> + continue;
> +
> + /* Check if color format is supported */
> + if (!drm_panic_is_format_supported(fb->format->format))
> + continue;
> +
> + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
> +
> + /* Buffer should be accessible from the CPU */
> + if (dma_obj->base.import_attach)
This might be a bit too restrictive, since some drivers import dma-buf
including a vmap. So just checking for ->vaddr might be better. But can be
changed later on.
> + continue;
> +
> + /* Buffer should be already mapped to CPU */
I'd clarify this comment to state that vaddr is invariant over the
lifetime of the buffer and therefore needs no locking. Correct locking
that a) takes all the locks b) never ever stalls for one is absolutely
crucial for a panic handler that won't make the situation worse.
> + if (!dma_obj->vaddr)
> + continue;
> +
> + iosys_map_set_vaddr(&sb->map, dma_obj->vaddr);
> + sb->format = fb->format;
> + sb->height = fb->height;
> + sb->width = fb->width;
> + sb->pitch = fb->pitches[0];
> + return 0;
Otherwise this lgtm.
-Sima
> + }
> + return -ENODEV;
> +}
> +#else
> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + return 0;
> +}
> +#endif
> +EXPORT_SYMBOL(drm_panic_gem_get_scanout_buffer);
> diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h
> index d5e036c57801..2ae432865079 100644
> --- a/include/drm/drm_fb_dma_helper.h
> +++ b/include/drm/drm_fb_dma_helper.h
> @@ -7,6 +7,7 @@
> struct drm_device;
> struct drm_framebuffer;
> struct drm_plane_state;
> +struct drm_scanout_buffer;
>
> struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb,
> unsigned int plane);
> @@ -19,5 +20,8 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
> struct drm_plane_state *old_state,
> struct drm_plane_state *state);
>
> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb);
> +
> #endif
>
> --
> 2.43.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-12 13:41 ` Daniel Vetter
@ 2024-01-12 13:56 ` Maxime Ripard
2024-01-18 13:38 ` Daniel Vetter
2024-01-17 14:28 ` Jocelyn Falempe
1 sibling, 1 reply; 51+ messages in thread
From: Maxime Ripard @ 2024-01-12 13:56 UTC (permalink / raw)
To: Daniel Vetter
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, dri-devel, gpiccoli,
noralf, tzimmermann, airlied
[-- Attachment #1: Type: text/plain, Size: 1239 bytes --]
On Fri, Jan 12, 2024 at 02:41:53PM +0100, Daniel Vetter wrote:
> > + fb = plane->state->fb;
> > + /* Only support linear modifier */
> > + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
> > + continue;
> > +
> > + /* Check if color format is supported */
> > + if (!drm_panic_is_format_supported(fb->format->format))
> > + continue;
> > +
> > + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
> > +
> > + /* Buffer should be accessible from the CPU */
> > + if (dma_obj->base.import_attach)
>
> This might be a bit too restrictive, since some drivers import dma-buf
> including a vmap. So just checking for ->vaddr might be better. But can be
> changed later on.
>
> > + continue;
> > +
> > + /* Buffer should be already mapped to CPU */
>
> I'd clarify this comment to state that vaddr is invariant over the
> lifetime of the buffer and therefore needs no locking. Correct locking
> that a) takes all the locks b) never ever stalls for one is absolutely
> crucial for a panic handler that won't make the situation worse.
I think this comment was made to address buffers that are accessible to
the CPU but don't have a CPU mapping (ie, created with
DMA_ATTR_NO_KERNEL_MAPPING for example).
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-12 13:56 ` Maxime Ripard
@ 2024-01-18 13:38 ` Daniel Vetter
2024-01-26 12:39 ` Maxime Ripard
0 siblings, 1 reply; 51+ messages in thread
From: Daniel Vetter @ 2024-01-18 13:38 UTC (permalink / raw)
To: Maxime Ripard
Cc: Jocelyn Falempe, bluescreen_avenger, Daniel Vetter, javierm,
dri-devel, gpiccoli, noralf, tzimmermann, airlied
On Fri, Jan 12, 2024 at 02:56:17PM +0100, Maxime Ripard wrote:
> On Fri, Jan 12, 2024 at 02:41:53PM +0100, Daniel Vetter wrote:
> > > + fb = plane->state->fb;
> > > + /* Only support linear modifier */
> > > + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
> > > + continue;
> > > +
> > > + /* Check if color format is supported */
> > > + if (!drm_panic_is_format_supported(fb->format->format))
> > > + continue;
> > > +
> > > + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
> > > +
> > > + /* Buffer should be accessible from the CPU */
> > > + if (dma_obj->base.import_attach)
> >
> > This might be a bit too restrictive, since some drivers import dma-buf
> > including a vmap. So just checking for ->vaddr might be better. But can be
> > changed later on.
> >
> > > + continue;
> > > +
> > > + /* Buffer should be already mapped to CPU */
> >
> > I'd clarify this comment to state that vaddr is invariant over the
> > lifetime of the buffer and therefore needs no locking. Correct locking
> > that a) takes all the locks b) never ever stalls for one is absolutely
> > crucial for a panic handler that won't make the situation worse.
>
> I think this comment was made to address buffers that are accessible to
> the CPU but don't have a CPU mapping (ie, created with
> DMA_ATTR_NO_KERNEL_MAPPING for example).
But then the NULL value of vaddr would also be invariant ...
My emphasis is more that we need to be really careful with all the locking
rules here in the panic handler and not just assume it's going to be safe.
I've stitched some tricky design together, but need to still move it from
the whiteboard to a patch.
-Sima
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-18 13:38 ` Daniel Vetter
@ 2024-01-26 12:39 ` Maxime Ripard
0 siblings, 0 replies; 51+ messages in thread
From: Maxime Ripard @ 2024-01-26 12:39 UTC (permalink / raw)
To: Daniel Vetter
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, dri-devel, gpiccoli,
noralf, tzimmermann, airlied
[-- Attachment #1: Type: text/plain, Size: 1925 bytes --]
On Thu, Jan 18, 2024 at 02:38:53PM +0100, Daniel Vetter wrote:
> On Fri, Jan 12, 2024 at 02:56:17PM +0100, Maxime Ripard wrote:
> > On Fri, Jan 12, 2024 at 02:41:53PM +0100, Daniel Vetter wrote:
> > > > + fb = plane->state->fb;
> > > > + /* Only support linear modifier */
> > > > + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
> > > > + continue;
> > > > +
> > > > + /* Check if color format is supported */
> > > > + if (!drm_panic_is_format_supported(fb->format->format))
> > > > + continue;
> > > > +
> > > > + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
> > > > +
> > > > + /* Buffer should be accessible from the CPU */
> > > > + if (dma_obj->base.import_attach)
> > >
> > > This might be a bit too restrictive, since some drivers import dma-buf
> > > including a vmap. So just checking for ->vaddr might be better. But can be
> > > changed later on.
> > >
> > > > + continue;
> > > > +
> > > > + /* Buffer should be already mapped to CPU */
> > >
> > > I'd clarify this comment to state that vaddr is invariant over the
> > > lifetime of the buffer and therefore needs no locking. Correct locking
> > > that a) takes all the locks b) never ever stalls for one is absolutely
> > > crucial for a panic handler that won't make the situation worse.
> >
> > I think this comment was made to address buffers that are accessible to
> > the CPU but don't have a CPU mapping (ie, created with
> > DMA_ATTR_NO_KERNEL_MAPPING for example).
>
> But then the NULL value of vaddr would also be invariant ...
>
> My emphasis is more that we need to be really careful with all the locking
> rules here in the panic handler and not just assume it's going to be safe.
> I've stitched some tricky design together, but need to still move it from
> the whiteboard to a patch.
Oh, sorry.
I misinterpreted what you were going for with that review. Sorry for the noise.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-12 13:41 ` Daniel Vetter
2024-01-12 13:56 ` Maxime Ripard
@ 2024-01-17 14:28 ` Jocelyn Falempe
2024-01-18 13:51 ` Daniel Vetter
1 sibling, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-17 14:28 UTC (permalink / raw)
To: Daniel Vetter
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
On 12/01/2024 14:41, Daniel Vetter wrote:
> On Thu, Jan 04, 2024 at 05:00:49PM +0100, Jocelyn Falempe wrote:
>> This was initialy done for imx6, but should work on most drivers
>> using drm_fb_dma_helper.
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>> ---
>> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
>> include/drm/drm_fb_dma_helper.h | 4 +++
>> 2 files changed, 59 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
>> index 3b535ad1b07c..caed2935df4f 100644
>> --- a/drivers/gpu/drm/drm_fb_dma_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
>> @@ -15,6 +15,7 @@
>> #include <drm/drm_framebuffer.h>
>> #include <drm/drm_gem_dma_helper.h>
>> #include <drm/drm_gem_framebuffer_helper.h>
>> +#include <drm/drm_panic.h>
>> #include <drm/drm_plane.h>
>> #include <linux/dma-mapping.h>
>> #include <linux/module.h>
>> @@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
>> }
>> }
>> EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
>> +
>> +#if defined(CONFIG_DRM_PANIC)
>> +/**
>> + * @dev: DRM device
>> + * @drm_scanout_buffer: scanout buffer for the panic handler
>> + * Returns: 0 or negative error code
>> + *
>> + * Generic get_scanout_buffer() implementation, for drivers that uses the
>> + * drm_fb_dma_helper.
>> + */
>> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb)
>> +{
>> + struct drm_plane *plane;
>> + struct drm_gem_dma_object *dma_obj;
>> + struct drm_framebuffer *fb;
>> +
>> + drm_for_each_primary_visible_plane(plane, dev) {
>
> Ok that's not enough locking by far. You can't just hope that nothing
> disappears while you're in a panic handler. We've been there and ended up
> reliably oopsing in the panic handler itself. So you _have_ to follow the
> full set of locking rules for all drm structures, or things will just get
> worse at the worst possible moment.
>
> But also, you're not allowed to do anything else than trylock, because a
> panic handler might run from nmi context, and so you cannot even acquire
> irq-safe spinlocks reliably.
>
> Which means:
>
> - You need to be safe against concurrent drm_dev_unregister. Using the
> atomic panic notifier directly for each device should take care of that
> (but maybe that stuff is still not nmi safe, not sure).
>
> - You _have_ to use all the locks. Luckily iterating over the plane list
> doesn't need one, but you have to trylock the plane's modeset lock.
> Which means your nice iterator macro is already toast, because that
> already looks at state it's not allowed to look at without a lock. Or
> well, the plane->state pointer is no-go already.
mutex_trylock() shouldn't be called from interrupt context, and as the
panic may occurs in irq, I can't use that.
But the panic context should guarantee that only one CPU is still running:
https://elixir.bootlin.com/linux/latest/source/kernel/panic.c#L310
So I think using mutex_is_locked() should be safe:
https://elixir.bootlin.com/linux/latest/source/include/linux/mutex.h#L128
This will only check if the lock is not taken, but as it's not possible
for another task to run at the same time, I think that should be good
enough ?
The drawback, is if we want to test without crashing the kernel, then we
need to take the locks with trylock(), (and it's safe this time), but
the code path would be slightly different.
--
Jocelyn
>
> Given the locking issues I'm not sure whether the
> drm_for_each_primary_visible_plane iterator is going to work, you'd need
> something like iter_init/next/end we have for walking the connector list.
> Plus it would be very panic specific due to the trylock, so maybe
>
> drm_for_each_visible_plane_in_panic_handler()
>
> or something like that.
>
> One thing I was wondering is whether we should lift this iteration over
> all planes into the shared code, and move the ->get_scanout_buffer
> function to the drm_plane_funcs structure instead?
>
>> + fb = plane->state->fb;
>> + /* Only support linear modifier */
>> + if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
>> + continue;
>> +
>> + /* Check if color format is supported */
>> + if (!drm_panic_is_format_supported(fb->format->format))
>> + continue;
>> +
>> + dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
>> +
>> + /* Buffer should be accessible from the CPU */
>> + if (dma_obj->base.import_attach)
>
> This might be a bit too restrictive, since some drivers import dma-buf
> including a vmap. So just checking for ->vaddr might be better. But can be
> changed later on.
>
>> + continue;
>> +
>> + /* Buffer should be already mapped to CPU */
>
> I'd clarify this comment to state that vaddr is invariant over the
> lifetime of the buffer and therefore needs no locking. Correct locking
> that a) takes all the locks b) never ever stalls for one is absolutely
> crucial for a panic handler that won't make the situation worse.
>
>> + if (!dma_obj->vaddr)
>
>
>> + continue;
>> +
>> + iosys_map_set_vaddr(&sb->map, dma_obj->vaddr);
>> + sb->format = fb->format;
>> + sb->height = fb->height;
>> + sb->width = fb->width;
>> + sb->pitch = fb->pitches[0];
>> + return 0;
>
> Otherwise this lgtm.
> -Sima
>
>> + }
>> + return -ENODEV;
>> +}
>> +#else
>> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb)
>> +{
>> + return 0;
>> +}
>> +#endif
>> +EXPORT_SYMBOL(drm_panic_gem_get_scanout_buffer);
>> diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h
>> index d5e036c57801..2ae432865079 100644
>> --- a/include/drm/drm_fb_dma_helper.h
>> +++ b/include/drm/drm_fb_dma_helper.h
>> @@ -7,6 +7,7 @@
>> struct drm_device;
>> struct drm_framebuffer;
>> struct drm_plane_state;
>> +struct drm_scanout_buffer;
>>
>> struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb,
>> unsigned int plane);
>> @@ -19,5 +20,8 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
>> struct drm_plane_state *old_state,
>> struct drm_plane_state *state);
>>
>> +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb);
>> +
>> #endif
>>
>> --
>> 2.43.0
>>
>
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
2024-01-17 14:28 ` Jocelyn Falempe
@ 2024-01-18 13:51 ` Daniel Vetter
0 siblings, 0 replies; 51+ messages in thread
From: Daniel Vetter @ 2024-01-18 13:51 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, Daniel Vetter, javierm, mripard, gpiccoli,
noralf, dri-devel, tzimmermann, airlied
On Wed, Jan 17, 2024 at 03:28:09PM +0100, Jocelyn Falempe wrote:
>
>
> On 12/01/2024 14:41, Daniel Vetter wrote:
> > On Thu, Jan 04, 2024 at 05:00:49PM +0100, Jocelyn Falempe wrote:
> > > This was initialy done for imx6, but should work on most drivers
> > > using drm_fb_dma_helper.
> > >
> > > Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> > > ---
> > > drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++++++++++++++++++++++++++++
> > > include/drm/drm_fb_dma_helper.h | 4 +++
> > > 2 files changed, 59 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c
> > > index 3b535ad1b07c..caed2935df4f 100644
> > > --- a/drivers/gpu/drm/drm_fb_dma_helper.c
> > > +++ b/drivers/gpu/drm/drm_fb_dma_helper.c
> > > @@ -15,6 +15,7 @@
> > > #include <drm/drm_framebuffer.h>
> > > #include <drm/drm_gem_dma_helper.h>
> > > #include <drm/drm_gem_framebuffer_helper.h>
> > > +#include <drm/drm_panic.h>
> > > #include <drm/drm_plane.h>
> > > #include <linux/dma-mapping.h>
> > > #include <linux/module.h>
> > > @@ -148,3 +149,57 @@ void drm_fb_dma_sync_non_coherent(struct drm_device *drm,
> > > }
> > > }
> > > EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent);
> > > +
> > > +#if defined(CONFIG_DRM_PANIC)
> > > +/**
> > > + * @dev: DRM device
> > > + * @drm_scanout_buffer: scanout buffer for the panic handler
> > > + * Returns: 0 or negative error code
> > > + *
> > > + * Generic get_scanout_buffer() implementation, for drivers that uses the
> > > + * drm_fb_dma_helper.
> > > + */
> > > +int drm_panic_gem_get_scanout_buffer(struct drm_device *dev,
> > > + struct drm_scanout_buffer *sb)
> > > +{
> > > + struct drm_plane *plane;
> > > + struct drm_gem_dma_object *dma_obj;
> > > + struct drm_framebuffer *fb;
> > > +
> > > + drm_for_each_primary_visible_plane(plane, dev) {
> >
> > Ok that's not enough locking by far. You can't just hope that nothing
> > disappears while you're in a panic handler. We've been there and ended up
> > reliably oopsing in the panic handler itself. So you _have_ to follow the
> > full set of locking rules for all drm structures, or things will just get
> > worse at the worst possible moment.
> >
> > But also, you're not allowed to do anything else than trylock, because a
> > panic handler might run from nmi context, and so you cannot even acquire
> > irq-safe spinlocks reliably.
> >
> > Which means:
> >
> > - You need to be safe against concurrent drm_dev_unregister. Using the
> > atomic panic notifier directly for each device should take care of that
> > (but maybe that stuff is still not nmi safe, not sure).
> >
> > - You _have_ to use all the locks. Luckily iterating over the plane list
> > doesn't need one, but you have to trylock the plane's modeset lock.
> > Which means your nice iterator macro is already toast, because that
> > already looks at state it's not allowed to look at without a lock. Or
> > well, the plane->state pointer is no-go already.
>
> mutex_trylock() shouldn't be called from interrupt context, and as the panic
> may occurs in irq, I can't use that.
Yeah I learned that later that day too, disappointing :-/
What's worse, spin_trylock is also no-go, because on r-t kernel they're
essentially sleeping locks. And so spin_trylock can retry in a loop, and
if we interrupt another thread at /just/ the right moment where the
spinlock is in an inconsistent state, the spin_trylock in the panic
handler will loop forever.
> But the panic context should guarantee that only one CPU is still running:
> https://elixir.bootlin.com/linux/latest/source/kernel/panic.c#L310
Uh no, panics can nest so you might panic while a panic is going on and
interrupt it in the middle. So just making sure no other code is running
isn't enough unfortunately.
Also the ipi stuff that should ensure the other cpu is stopped might not
work, afaiui in nmi panic context you cannot send around ipi.
> So I think using mutex_is_locked() should be safe:
> https://elixir.bootlin.com/linux/latest/source/include/linux/mutex.h#L128
>
> This will only check if the lock is not taken, but as it's not possible for
> another task to run at the same time, I think that should be good enough ?
>
> The drawback, is if we want to test without crashing the kernel, then we
> need to take the locks with trylock(), (and it's safe this time), but the
> code path would be slightly different.
So I think this predates some of irc chat, and I haven't typed up what I
designed together with John Ogness. Haven't done the patch yet, but rought
sketch:
- we use a raw_spin_lock. That's the _only_ lock type where trylock is ok
- we protect the drm_plane->state update with that lock. That's an
extremely tiny section of code, so should be fine.
- For just that pointer update we could also use rcu, but using a spinlock
has the advantage that drivers with peek/poke mmio support (for
accessing unmapping vram or similar) could wrap these mmio access with
that spinlock, and so would be able to use peek/poke in their panic
handler. As soon as we need to protect against mmio we really need a
lock.
- Because the lock also provides a barrier there's a lot of things you can
safely assume, and so don't need additional locking for that in the
panic handler:
- Anything that's invariant over the lifetime of a drm_device (as
delineated by drm_dev_register/unregister) is safe to access, like the
plane list or plane structure
- Anything in drm_plane_state that's only computed in atomic_check and
not touched in atomic_commit code anymore is safe to access. This
means we can get at the bo and everything else without any locks, and
anything that is invariant for the lifetime of the bo like vaddr for
dma-helper bo is also fine.
- Furthermore because ->prepare_fb is called _before_ this point, and we
stall at the right places before we call ->cleanup_fb. Unfortunately
the same isn't true for ->begin/end_fb_access (by design), so we
cannot rely on everything, but we can rely on the fact that the
framebuffer is correctly pinned for drivers using dynamic buffer
managers. The kernel vmap might not be around though, I need to think
more how we best solve that issue. But that's a problem for when we
add panic support to the first such driver.
I think with this design we'd cover 95% of all cases by simply doing the
raw_spin_trylock before we call into the driver's callback.
Cheers, Sima
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (4 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-12 13:44 ` Daniel Vetter
2024-01-17 15:17 ` Thomas Zimmermann
2024-01-04 16:00 ` [PATCH v7 7/9] drm/mgag200: " Jocelyn Falempe
` (3 subsequent siblings)
9 siblings, 2 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
Add support for the drm_panic module, which displays a user-friendly
message to the screen when a kernel panic occurs.
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 7ce1c4617675..6dd2afee84d4 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -25,6 +25,7 @@
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_panic.h>
#include <drm/drm_probe_helper.h>
#define DRIVER_NAME "simpledrm"
@@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
return sdev;
}
+static int simpledrm_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+ struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+
+ sb->width = sdev->mode.hdisplay;
+ sb->height = sdev->mode.vdisplay;
+ sb->pitch = sdev->pitch;
+ sb->format = sdev->format;
+ sb->map = sdev->screen_base;
+ return 0;
+}
+
/*
* DRM driver
*/
@@ -1000,6 +1014,7 @@ static struct drm_driver simpledrm_driver = {
.minor = DRIVER_MINOR,
.driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
.fops = &simpledrm_fops,
+ .get_scanout_buffer = simpledrm_get_scanout_buffer,
};
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-04 16:00 ` [PATCH v7 6/9] drm/simpledrm: Add drm_panic support Jocelyn Falempe
@ 2024-01-12 13:44 ` Daniel Vetter
2024-01-12 13:58 ` Maxime Ripard
2024-01-17 15:17 ` Thomas Zimmermann
1 sibling, 1 reply; 51+ messages in thread
From: Daniel Vetter @ 2024-01-12 13:44 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, mripard, gpiccoli,
noralf, dri-devel, airlied
On Thu, Jan 04, 2024 at 05:00:50PM +0100, Jocelyn Falempe wrote:
> Add support for the drm_panic module, which displays a user-friendly
> message to the screen when a kernel panic occurs.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
> index 7ce1c4617675..6dd2afee84d4 100644
> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> @@ -25,6 +25,7 @@
> #include <drm/drm_gem_shmem_helper.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_probe_helper.h>
>
> #define DRIVER_NAME "simpledrm"
> @@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
> return sdev;
> }
>
> +static int simpledrm_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
So I guess simpledrm is the reason why the get_scanout_buffer hook is at
the device level and not at the plane level. Even from the few drivers you
have in your series it seems very much the exception, so I'm not sure
whether that's the best design.
I guess we'll know when we see the plane iterator code with the right
locking, whether it's ok to have that in driver hooks or it's better to
pull it out into shared code.
-Sima
> +
> + sb->width = sdev->mode.hdisplay;
> + sb->height = sdev->mode.vdisplay;
> + sb->pitch = sdev->pitch;
> + sb->format = sdev->format;
> + sb->map = sdev->screen_base;
> + return 0;
> +}
> +
> /*
> * DRM driver
> */
> @@ -1000,6 +1014,7 @@ static struct drm_driver simpledrm_driver = {
> .minor = DRIVER_MINOR,
> .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
> .fops = &simpledrm_fops,
> + .get_scanout_buffer = simpledrm_get_scanout_buffer,
> };
>
> /*
> --
> 2.43.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-12 13:44 ` Daniel Vetter
@ 2024-01-12 13:58 ` Maxime Ripard
2024-01-17 15:22 ` Thomas Zimmermann
0 siblings, 1 reply; 51+ messages in thread
From: Maxime Ripard @ 2024-01-12 13:58 UTC (permalink / raw)
To: Daniel Vetter
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, dri-devel, gpiccoli,
noralf, tzimmermann, airlied
[-- Attachment #1: Type: text/plain, Size: 1773 bytes --]
On Fri, Jan 12, 2024 at 02:44:57PM +0100, Daniel Vetter wrote:
> On Thu, Jan 04, 2024 at 05:00:50PM +0100, Jocelyn Falempe wrote:
> > Add support for the drm_panic module, which displays a user-friendly
> > message to the screen when a kernel panic occurs.
> >
> > Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> > ---
> > drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
> > 1 file changed, 15 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
> > index 7ce1c4617675..6dd2afee84d4 100644
> > --- a/drivers/gpu/drm/tiny/simpledrm.c
> > +++ b/drivers/gpu/drm/tiny/simpledrm.c
> > @@ -25,6 +25,7 @@
> > #include <drm/drm_gem_shmem_helper.h>
> > #include <drm/drm_managed.h>
> > #include <drm/drm_modeset_helper_vtables.h>
> > +#include <drm/drm_panic.h>
> > #include <drm/drm_probe_helper.h>
> >
> > #define DRIVER_NAME "simpledrm"
> > @@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
> > return sdev;
> > }
> >
> > +static int simpledrm_get_scanout_buffer(struct drm_device *dev,
> > + struct drm_scanout_buffer *sb)
> > +{
> > + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
>
> So I guess simpledrm is the reason why the get_scanout_buffer hook is at
> the device level and not at the plane level. Even from the few drivers you
> have in your series it seems very much the exception, so I'm not sure
> whether that's the best design.
>
> I guess we'll know when we see the plane iterator code with the right
> locking, whether it's ok to have that in driver hooks or it's better to
> pull it out into shared code.
Wouldn't the CRTC level be better than the planes?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-12 13:58 ` Maxime Ripard
@ 2024-01-17 15:22 ` Thomas Zimmermann
2024-01-18 10:33 ` Maxime Ripard
0 siblings, 1 reply; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:22 UTC (permalink / raw)
To: Maxime Ripard, Daniel Vetter
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, dri-devel, gpiccoli,
noralf, airlied
[-- Attachment #1.1: Type: text/plain, Size: 2396 bytes --]
Hi
Am 12.01.24 um 14:58 schrieb Maxime Ripard:
> On Fri, Jan 12, 2024 at 02:44:57PM +0100, Daniel Vetter wrote:
>> On Thu, Jan 04, 2024 at 05:00:50PM +0100, Jocelyn Falempe wrote:
>>> Add support for the drm_panic module, which displays a user-friendly
>>> message to the screen when a kernel panic occurs.
>>>
>>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>>> ---
>>> drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
>>> 1 file changed, 15 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
>>> index 7ce1c4617675..6dd2afee84d4 100644
>>> --- a/drivers/gpu/drm/tiny/simpledrm.c
>>> +++ b/drivers/gpu/drm/tiny/simpledrm.c
>>> @@ -25,6 +25,7 @@
>>> #include <drm/drm_gem_shmem_helper.h>
>>> #include <drm/drm_managed.h>
>>> #include <drm/drm_modeset_helper_vtables.h>
>>> +#include <drm/drm_panic.h>
>>> #include <drm/drm_probe_helper.h>
>>>
>>> #define DRIVER_NAME "simpledrm"
>>> @@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
>>> return sdev;
>>> }
>>>
>>> +static int simpledrm_get_scanout_buffer(struct drm_device *dev,
>>> + struct drm_scanout_buffer *sb)
>>> +{
>>> + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
>>
>> So I guess simpledrm is the reason why the get_scanout_buffer hook is at
>> the device level and not at the plane level. Even from the few drivers you
>> have in your series it seems very much the exception, so I'm not sure
>> whether that's the best design.
>>
>> I guess we'll know when we see the plane iterator code with the right
>> locking, whether it's ok to have that in driver hooks or it's better to
>> pull it out into shared code.
>
> Wouldn't the CRTC level be better than the planes?
What's in favor of the CRTC level?
I'd put a hook at the plane level and do the
drm_for_each_primary_visible_plane() in the panic handler. Simpledrm
would fit into this pattern nicely.
But it's not like I have strong feeling about this. The current
callbacks are simple enough.
Best regards
Thomas
>
> Maxime
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: Re: [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-17 15:22 ` Thomas Zimmermann
@ 2024-01-18 10:33 ` Maxime Ripard
0 siblings, 0 replies; 51+ messages in thread
From: Maxime Ripard @ 2024-01-18 10:33 UTC (permalink / raw)
To: Thomas Zimmermann
Cc: Jocelyn Falempe, bluescreen_avenger, javierm, dri-devel, gpiccoli,
noralf, Daniel Vetter, airlied
[-- Attachment #1: Type: text/plain, Size: 2775 bytes --]
On Wed, Jan 17, 2024 at 04:22:01PM +0100, Thomas Zimmermann wrote:
> Hi
>
> Am 12.01.24 um 14:58 schrieb Maxime Ripard:
> > On Fri, Jan 12, 2024 at 02:44:57PM +0100, Daniel Vetter wrote:
> > > On Thu, Jan 04, 2024 at 05:00:50PM +0100, Jocelyn Falempe wrote:
> > > > Add support for the drm_panic module, which displays a user-friendly
> > > > message to the screen when a kernel panic occurs.
> > > >
> > > > Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> > > > ---
> > > > drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
> > > > 1 file changed, 15 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
> > > > index 7ce1c4617675..6dd2afee84d4 100644
> > > > --- a/drivers/gpu/drm/tiny/simpledrm.c
> > > > +++ b/drivers/gpu/drm/tiny/simpledrm.c
> > > > @@ -25,6 +25,7 @@
> > > > #include <drm/drm_gem_shmem_helper.h>
> > > > #include <drm/drm_managed.h>
> > > > #include <drm/drm_modeset_helper_vtables.h>
> > > > +#include <drm/drm_panic.h>
> > > > #include <drm/drm_probe_helper.h>
> > > > #define DRIVER_NAME "simpledrm"
> > > > @@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
> > > > return sdev;
> > > > }
> > > > +static int simpledrm_get_scanout_buffer(struct drm_device *dev,
> > > > + struct drm_scanout_buffer *sb)
> > > > +{
> > > > + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
> > >
> > > So I guess simpledrm is the reason why the get_scanout_buffer hook is at
> > > the device level and not at the plane level. Even from the few drivers you
> > > have in your series it seems very much the exception, so I'm not sure
> > > whether that's the best design.
> > >
> > > I guess we'll know when we see the plane iterator code with the right
> > > locking, whether it's ok to have that in driver hooks or it's better to
> > > pull it out into shared code.
> >
> > Wouldn't the CRTC level be better than the planes?
>
> What's in favor of the CRTC level?
>
> I'd put a hook at the plane level and do the
> drm_for_each_primary_visible_plane() in the panic handler. Simpledrm would
> fit into this pattern nicely.
>
> But it's not like I have strong feeling about this. The current callbacks
> are simple enough.
An active CRTC is guaranteed to have an active plane, and knows what the
full blending story is. An active plane does have a CRTC too, but there
might be other planes we want to consider, and if you're doing blending
with multiple primary planes it will get quite funny very fast :)
Plus, some CRTC have internal SRAMs we could use as fallback in the case
where we won't be able to get a proper framebuffer.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* Re: [PATCH v7 6/9] drm/simpledrm: Add drm_panic support
2024-01-04 16:00 ` [PATCH v7 6/9] drm/simpledrm: Add drm_panic support Jocelyn Falempe
2024-01-12 13:44 ` Daniel Vetter
@ 2024-01-17 15:17 ` Thomas Zimmermann
1 sibling, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:17 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 1940 bytes --]
Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> Add support for the drm_panic module, which displays a user-friendly
> message to the screen when a kernel panic occurs.
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/tiny/simpledrm.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
> index 7ce1c4617675..6dd2afee84d4 100644
> --- a/drivers/gpu/drm/tiny/simpledrm.c
> +++ b/drivers/gpu/drm/tiny/simpledrm.c
> @@ -25,6 +25,7 @@
> #include <drm/drm_gem_shmem_helper.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_probe_helper.h>
>
> #define DRIVER_NAME "simpledrm"
> @@ -985,6 +986,19 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
> return sdev;
> }
>
> +static int simpledrm_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
> +
> + sb->width = sdev->mode.hdisplay;
> + sb->height = sdev->mode.vdisplay;
> + sb->pitch = sdev->pitch;
> + sb->format = sdev->format;
> + sb->map = sdev->screen_base;
> + return 0;
> +}
> +
> /*
> * DRM driver
> */
> @@ -1000,6 +1014,7 @@ static struct drm_driver simpledrm_driver = {
> .minor = DRIVER_MINOR,
> .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
> .fops = &simpledrm_fops,
> + .get_scanout_buffer = simpledrm_get_scanout_buffer,
> };
>
> /*
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 7/9] drm/mgag200: Add drm_panic support
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (5 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 6/9] drm/simpledrm: Add drm_panic support Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-17 15:15 ` Thomas Zimmermann
2024-01-04 16:00 ` [PATCH v7 8/9] drm/ast: " Jocelyn Falempe
` (2 subsequent siblings)
9 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
Add support for the drm_panic module, which displays a message to
the screen when a kernel panic occurs.
v5:
* Also check that the plane is visible and primary. (Thomas Zimmermann)
v7:
* use drm_for_each_primary_visible_plane()
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/mgag200/mgag200_drv.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index 2fb18b782b05..2bf5918eadc5 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -13,10 +13,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_framebuffer.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
#include <drm/drm_module.h>
+#include <drm/drm_panic.h>
#include <drm/drm_pciids.h>
#include "mgag200_drv.h"
@@ -84,6 +86,25 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size)
return offset - 65536;
}
+static int mgag200_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+ struct drm_plane *plane;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
+
+ /* find the primary and visible plane */
+ drm_for_each_primary_visible_plane(plane, dev) {
+ sb->format = plane->state->fb->format;
+ sb->width = plane->state->fb->width;
+ sb->height = plane->state->fb->height;
+ sb->pitch = plane->state->fb->pitches[0];
+ sb->map = map;
+ return 0;
+ }
+ return -ENODEV;
+}
+
/*
* DRM driver
*/
@@ -99,6 +120,7 @@ static const struct drm_driver mgag200_driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
+ .get_scanout_buffer = mgag200_get_scanout_buffer,
DRM_GEM_SHMEM_DRIVER_OPS,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 7/9] drm/mgag200: Add drm_panic support
2024-01-04 16:00 ` [PATCH v7 7/9] drm/mgag200: " Jocelyn Falempe
@ 2024-01-17 15:15 ` Thomas Zimmermann
0 siblings, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:15 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 2532 bytes --]
Hi
Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> Add support for the drm_panic module, which displays a message to
> the screen when a kernel panic occurs.
>
> v5:
> * Also check that the plane is visible and primary. (Thomas Zimmermann)
>
> v7:
> * use drm_for_each_primary_visible_plane()
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
> drivers/gpu/drm/mgag200/mgag200_drv.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
> index 2fb18b782b05..2bf5918eadc5 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_drv.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
> @@ -13,10 +13,12 @@
> #include <drm/drm_atomic_helper.h>
> #include <drm/drm_drv.h>
> #include <drm/drm_fbdev_generic.h>
> +#include <drm/drm_framebuffer.h>
Needs to go below drm_file.h
With that fixed:
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> #include <drm/drm_file.h>
> #include <drm/drm_ioctl.h>
> #include <drm/drm_managed.h>
> #include <drm/drm_module.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_pciids.h>
>
> #include "mgag200_drv.h"
> @@ -84,6 +86,25 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size)
> return offset - 65536;
> }
>
> +static int mgag200_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct drm_plane *plane;
> + struct mga_device *mdev = to_mga_device(dev);
> + struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
> +
> + /* find the primary and visible plane */
> + drm_for_each_primary_visible_plane(plane, dev) {
> + sb->format = plane->state->fb->format;
> + sb->width = plane->state->fb->width;
> + sb->height = plane->state->fb->height;
> + sb->pitch = plane->state->fb->pitches[0];
> + sb->map = map;
> + return 0;
> + }
> + return -ENODEV;
> +}
> +
> /*
> * DRM driver
> */
> @@ -99,6 +120,7 @@ static const struct drm_driver mgag200_driver = {
> .major = DRIVER_MAJOR,
> .minor = DRIVER_MINOR,
> .patchlevel = DRIVER_PATCHLEVEL,
> + .get_scanout_buffer = mgag200_get_scanout_buffer,
> DRM_GEM_SHMEM_DRIVER_OPS,
> };
>
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 8/9] drm/ast: Add drm_panic support
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (6 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 7/9] drm/mgag200: " Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-17 15:16 ` Thomas Zimmermann
2024-01-04 16:00 ` [PATCH v7 9/9] drm/imx: " Jocelyn Falempe
2024-01-12 14:00 ` [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Daniel Vetter
9 siblings, 1 reply; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
Add support for the drm_panic module, which displays a message to
the screen when a kernel panic occurs.
v7
* Use drm_for_each_primary_visible_plane()
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/ast/ast_drv.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 90bcb1eb9cd9..8ddce3d7fda9 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -35,6 +35,7 @@
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_module.h>
+#include <drm/drm_panic.h>
#include <drm/drm_probe_helper.h>
#include "ast_drv.h"
@@ -48,6 +49,27 @@ module_param_named(modeset, ast_modeset, int, 0400);
* DRM driver
*/
+static int ast_get_scanout_buffer(struct drm_device *dev,
+ struct drm_scanout_buffer *sb)
+{
+ struct drm_plane *plane;
+ struct ast_plane *ast_plane;
+
+ drm_for_each_primary_visible_plane(plane, dev) {
+ ast_plane = to_ast_plane(plane);
+ if (!ast_plane->vaddr)
+ continue;
+
+ sb->format = plane->state->fb->format;
+ sb->width = plane->state->fb->width;
+ sb->height = plane->state->fb->height;
+ sb->pitch = plane->state->fb->pitches[0];
+ iosys_map_set_vaddr_iomem(&sb->map, ast_plane->vaddr);
+ return 0;
+ }
+ return -ENODEV;
+}
+
DEFINE_DRM_GEM_FOPS(ast_fops);
static const struct drm_driver ast_driver = {
@@ -62,8 +84,8 @@ static const struct drm_driver ast_driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
-
- DRM_GEM_SHMEM_DRIVER_OPS
+ .get_scanout_buffer = ast_get_scanout_buffer,
+ DRM_GEM_SHMEM_DRIVER_OPS,
};
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [PATCH v7 8/9] drm/ast: Add drm_panic support
2024-01-04 16:00 ` [PATCH v7 8/9] drm/ast: " Jocelyn Falempe
@ 2024-01-17 15:16 ` Thomas Zimmermann
0 siblings, 0 replies; 51+ messages in thread
From: Thomas Zimmermann @ 2024-01-17 15:16 UTC (permalink / raw)
To: Jocelyn Falempe, dri-devel, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli
[-- Attachment #1.1: Type: text/plain, Size: 2260 bytes --]
Hi
Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> Add support for the drm_panic module, which displays a message to
> the screen when a kernel panic occurs.
>
> v7
> * Use drm_for_each_primary_visible_plane()
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
> drivers/gpu/drm/ast/ast_drv.c | 26 ++++++++++++++++++++++++--
> 1 file changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
> index 90bcb1eb9cd9..8ddce3d7fda9 100644
> --- a/drivers/gpu/drm/ast/ast_drv.c
> +++ b/drivers/gpu/drm/ast/ast_drv.c
> @@ -35,6 +35,7 @@
> #include <drm/drm_fbdev_generic.h>
> #include <drm/drm_gem_shmem_helper.h>
> #include <drm/drm_module.h>
> +#include <drm/drm_panic.h>
> #include <drm/drm_probe_helper.h>
>
> #include "ast_drv.h"
> @@ -48,6 +49,27 @@ module_param_named(modeset, ast_modeset, int, 0400);
> * DRM driver
> */
>
> +static int ast_get_scanout_buffer(struct drm_device *dev,
> + struct drm_scanout_buffer *sb)
> +{
> + struct drm_plane *plane;
> + struct ast_plane *ast_plane;
> +
> + drm_for_each_primary_visible_plane(plane, dev) {
> + ast_plane = to_ast_plane(plane);
> + if (!ast_plane->vaddr)
> + continue;
> +
> + sb->format = plane->state->fb->format;
> + sb->width = plane->state->fb->width;
> + sb->height = plane->state->fb->height;
> + sb->pitch = plane->state->fb->pitches[0];
> + iosys_map_set_vaddr_iomem(&sb->map, ast_plane->vaddr);
> + return 0;
> + }
> + return -ENODEV;
> +}
> +
> DEFINE_DRM_GEM_FOPS(ast_fops);
>
> static const struct drm_driver ast_driver = {
> @@ -62,8 +84,8 @@ static const struct drm_driver ast_driver = {
> .major = DRIVER_MAJOR,
> .minor = DRIVER_MINOR,
> .patchlevel = DRIVER_PATCHLEVEL,
> -
> - DRM_GEM_SHMEM_DRIVER_OPS
> + .get_scanout_buffer = ast_get_scanout_buffer,
> + DRM_GEM_SHMEM_DRIVER_OPS,
> };
>
> /*
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply [flat|nested] 51+ messages in thread
* [PATCH v7 9/9] drm/imx: Add drm_panic support
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (7 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 8/9] drm/ast: " Jocelyn Falempe
@ 2024-01-04 16:00 ` Jocelyn Falempe
2024-01-12 14:00 ` [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Daniel Vetter
9 siblings, 0 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-04 16:00 UTC (permalink / raw)
To: dri-devel, tzimmermann, airlied, maarten.lankhorst, mripard,
daniel, javierm, bluescreen_avenger, noralf
Cc: gpiccoli, Jocelyn Falempe
Add support for the drm_panic module, which displays a user-friendly
message to the screen when a kernel panic occurs.
v7:
* use drm_panic_gem_get_scanout_buffer() helper
Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
index 4cfabcf7375a..d202d937d4b6 100644
--- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
@@ -17,6 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
+#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
@@ -172,6 +173,7 @@ static const struct drm_driver imx_drm_driver = {
.major = 1,
.minor = 0,
.patchlevel = 0,
+ .get_scanout_buffer = drm_panic_gem_get_scanout_buffer,
};
static int compare_of(struct device *dev, void *data)
--
2.43.0
^ permalink raw reply related [flat|nested] 51+ messages in thread* Re: [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler
2024-01-04 16:00 [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Jocelyn Falempe
` (8 preceding siblings ...)
2024-01-04 16:00 ` [PATCH v7 9/9] drm/imx: " Jocelyn Falempe
@ 2024-01-12 14:00 ` Daniel Vetter
2024-01-12 14:36 ` Jocelyn Falempe
9 siblings, 1 reply; 51+ messages in thread
From: Daniel Vetter @ 2024-01-12 14:00 UTC (permalink / raw)
To: Jocelyn Falempe
Cc: bluescreen_avenger, tzimmermann, javierm, mripard, gpiccoli,
noralf, dri-devel, airlied
On Thu, Jan 04, 2024 at 05:00:44PM +0100, Jocelyn Falempe wrote:
> This introduces a new drm panic handler, which displays a message when a panic occurs.
> So when fbcon is disabled, you can still see a kernel panic.
>
> This is one of the missing feature, when disabling VT/fbcon in the kernel:
> https://www.reddit.com/r/linux/comments/10eccv9/config_vtn_in_2023/
> Fbcon can be replaced by a userspace kms console, but the panic screen must be done in the kernel.
>
> This is a proof of concept, and works with simpledrm, mgag200, ast, and imx using a new get_scanout_buffer() api
>
> To test it, make sure you're using the simpledrm driver, and trigger a panic:
> echo c > /proc/sysrq-trigger
Uh this is not great for testing in CI, we need something better. A
drm-specific solution would be a debugfs file that triggers the panic
dumping (which is the reason we should correctly unlock all locks we've
taken too).
Even better would be if the core code provides this infrastructure, so
that ideally we could exercise running from an nmi context. For the drm
testing the best we can probably do is disable local interrupts or maybe
run from a timer that immediately fires.
I think adding that test infrastructure plus an igt that exercises should
be done as part of merging the initial version. Otherwise there's just no
way we can make sure that this code doesn't immediately bitrot like all
the previous panic handlers.
Cheers, Sima
>
> v2:
> * Use get_scanout_buffer() instead of the drm client API. (Thomas Zimmermann)
> * Add the panic reason to the panic message (Nerdopolis)
> * Add an exclamation mark (Nerdopolis)
>
> v3:
> * Rework the drawing functions, to write the pixels line by line and
> to use the drm conversion helper to support other formats.
> (Thomas Zimmermann)
>
> v4:
> * Fully support all simpledrm formats using drm conversion helpers
> * Rename dpanic_* to drm_panic_*, and have more coherent function name.
> (Thomas Zimmermann)
> * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
> * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
> * Add foreground/background color config option
> * Fix the bottom lines not painted if the framebuffer height
> is not a multiple of the font height.
> * Automatically register the driver to drm_panic, if the function
> get_scanout_buffer() exists. (Thomas Zimmermann)
> * Add mgag200 support.
>
> v5:
> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
> (Thomas Zimmermann)
> * Also add drm_fb_fill() to fill area with background color.
> * Add draw_pixel_xy() API for drivers that can't provide a linear buffer.
> * Add a flush() callback for drivers that needs to synchronize the buffer.
> * Add a void *private field, so drivers can pass private data to
> draw_pixel_xy() and flush().
> * Add ast support.
> * Add experimental imx/ipuv3 support, to test on an ARM hw. (Maxime Ripard)
>
> v6:
> * Fix sparse and __le32 warnings
> * Drop the IMX/IPUV3 experiment, it was just to show that it works also on
> ARM devices.
>
> v7:
> * Add a check to see if the 4cc format is supported by drm_panic.
> * Add a drm/plane helper to loop over all visible primary buffer,
> simplifying the get_scanout_buffer implementations
> * Add a generic implementation for drivers that uses drm_fb_dma. (Maxime Ripard)
> * Add back the IMX/IPUV3 support, and use the generic implementation. (Maxime Ripard)
>
>
> Best regards,
>
> Jocelyn Falempe (9):
> drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
> drm/panic: Add a drm panic handler
> drm/plane: Add drm_for_each_primary_visible_plane macro
> drm/panic: Add drm_panic_is_format_supported()
> drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
> drm/simpledrm: Add drm_panic support
> drm/mgag200: Add drm_panic support
> drm/ast: Add drm_panic support
> drm/imx: Add drm_panic support
>
> drivers/gpu/drm/Kconfig | 23 ++
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/ast/ast_drv.c | 26 +-
> drivers/gpu/drm/drm_drv.c | 8 +
> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++
> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++-----
> drivers/gpu/drm/drm_panic.c | 382 ++++++++++++++++++++
> drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 2 +
> drivers/gpu/drm/mgag200/mgag200_drv.c | 22 ++
> drivers/gpu/drm/tiny/simpledrm.c | 15 +
> include/drm/drm_drv.h | 21 ++
> include/drm/drm_fb_dma_helper.h | 4 +
> include/drm/drm_format_helper.h | 9 +
> include/drm/drm_panic.h | 101 ++++++
> include/drm/drm_plane.h | 15 +
> 15 files changed, 1033 insertions(+), 83 deletions(-)
> create mode 100644 drivers/gpu/drm/drm_panic.c
> create mode 100644 include/drm/drm_panic.h
>
>
> base-commit: 50a3c772bd927dd409c484832ddd9f6bf00b7389
> --
> 2.43.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 51+ messages in thread* Re: [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler
2024-01-12 14:00 ` [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler Daniel Vetter
@ 2024-01-12 14:36 ` Jocelyn Falempe
0 siblings, 0 replies; 51+ messages in thread
From: Jocelyn Falempe @ 2024-01-12 14:36 UTC (permalink / raw)
To: Daniel Vetter
Cc: bluescreen_avenger, javierm, mripard, gpiccoli, noralf, dri-devel,
tzimmermann, airlied
On 12/01/2024 15:00, Daniel Vetter wrote:
> On Thu, Jan 04, 2024 at 05:00:44PM +0100, Jocelyn Falempe wrote:
>> This introduces a new drm panic handler, which displays a message when a panic occurs.
>> So when fbcon is disabled, you can still see a kernel panic.
>>
>> This is one of the missing feature, when disabling VT/fbcon in the kernel:
>> https://www.reddit.com/r/linux/comments/10eccv9/config_vtn_in_2023/
>> Fbcon can be replaced by a userspace kms console, but the panic screen must be done in the kernel.
>>
>> This is a proof of concept, and works with simpledrm, mgag200, ast, and imx using a new get_scanout_buffer() api
>>
>> To test it, make sure you're using the simpledrm driver, and trigger a panic:
>> echo c > /proc/sysrq-trigger
>
> Uh this is not great for testing in CI, we need something better. A
> drm-specific solution would be a debugfs file that triggers the panic
> dumping (which is the reason we should correctly unlock all locks we've
> taken too).
Yes, I already use a dumb file in debugfs to trigger the panic handler
for development purpose. So it's a bit easier than crashing the machine.
I didn't add it in the series, because it's a bit rough, and the panic
handler assumes there are no other thread running, and that it's the
last frame the gpu will display before rebooting.
It gives some beautiful effect (if your driver uses double buffering,
only one of them will be repainted with the panic screen, so it's
flashing a bit afterward. It's also a good way to see if your driver
uses the damage API correctly).
So I will add it in the next series.
>
> Even better would be if the core code provides this infrastructure, so
> that ideally we could exercise running from an nmi context. For the drm
> testing the best we can probably do is disable local interrupts or maybe
> run from a timer that immediately fires.
>
> I think adding that test infrastructure plus an igt that exercises should
> be done as part of merging the initial version. Otherwise there's just no
> way we can make sure that this code doesn't immediately bitrot like all
> the previous panic handlers.
ok, I will look into that. I didn't use igt yet, so I will see what I
can do.
>
> Cheers, Sima
>
>>
>> v2:
>> * Use get_scanout_buffer() instead of the drm client API. (Thomas Zimmermann)
>> * Add the panic reason to the panic message (Nerdopolis)
>> * Add an exclamation mark (Nerdopolis)
>>
>> v3:
>> * Rework the drawing functions, to write the pixels line by line and
>> to use the drm conversion helper to support other formats.
>> (Thomas Zimmermann)
>>
>> v4:
>> * Fully support all simpledrm formats using drm conversion helpers
>> * Rename dpanic_* to drm_panic_*, and have more coherent function name.
>> (Thomas Zimmermann)
>> * Use drm_fb_r1_to_32bit for fonts (Thomas Zimmermann)
>> * Remove the default y to DRM_PANIC config option (Thomas Zimmermann)
>> * Add foreground/background color config option
>> * Fix the bottom lines not painted if the framebuffer height
>> is not a multiple of the font height.
>> * Automatically register the driver to drm_panic, if the function
>> get_scanout_buffer() exists. (Thomas Zimmermann)
>> * Add mgag200 support.
>>
>> v5:
>> * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>> (Thomas Zimmermann)
>> * Also add drm_fb_fill() to fill area with background color.
>> * Add draw_pixel_xy() API for drivers that can't provide a linear buffer.
>> * Add a flush() callback for drivers that needs to synchronize the buffer.
>> * Add a void *private field, so drivers can pass private data to
>> draw_pixel_xy() and flush().
>> * Add ast support.
>> * Add experimental imx/ipuv3 support, to test on an ARM hw. (Maxime Ripard)
>>
>> v6:
>> * Fix sparse and __le32 warnings
>> * Drop the IMX/IPUV3 experiment, it was just to show that it works also on
>> ARM devices.
>>
>> v7:
>> * Add a check to see if the 4cc format is supported by drm_panic.
>> * Add a drm/plane helper to loop over all visible primary buffer,
>> simplifying the get_scanout_buffer implementations
>> * Add a generic implementation for drivers that uses drm_fb_dma. (Maxime Ripard)
>> * Add back the IMX/IPUV3 support, and use the generic implementation. (Maxime Ripard)
>>
>>
>> Best regards,
>>
>> Jocelyn Falempe (9):
>> drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
>> drm/panic: Add a drm panic handler
>> drm/plane: Add drm_for_each_primary_visible_plane macro
>> drm/panic: Add drm_panic_is_format_supported()
>> drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
>> drm/simpledrm: Add drm_panic support
>> drm/mgag200: Add drm_panic support
>> drm/ast: Add drm_panic support
>> drm/imx: Add drm_panic support
>>
>> drivers/gpu/drm/Kconfig | 23 ++
>> drivers/gpu/drm/Makefile | 1 +
>> drivers/gpu/drm/ast/ast_drv.c | 26 +-
>> drivers/gpu/drm/drm_drv.c | 8 +
>> drivers/gpu/drm/drm_fb_dma_helper.c | 55 +++
>> drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++-----
>> drivers/gpu/drm/drm_panic.c | 382 ++++++++++++++++++++
>> drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 2 +
>> drivers/gpu/drm/mgag200/mgag200_drv.c | 22 ++
>> drivers/gpu/drm/tiny/simpledrm.c | 15 +
>> include/drm/drm_drv.h | 21 ++
>> include/drm/drm_fb_dma_helper.h | 4 +
>> include/drm/drm_format_helper.h | 9 +
>> include/drm/drm_panic.h | 101 ++++++
>> include/drm/drm_plane.h | 15 +
>> 15 files changed, 1033 insertions(+), 83 deletions(-)
>> create mode 100644 drivers/gpu/drm/drm_panic.c
>> create mode 100644 include/drm/drm_panic.h
>>
>>
>> base-commit: 50a3c772bd927dd409c484832ddd9f6bf00b7389
>> --
>> 2.43.0
>>
>
^ permalink raw reply [flat|nested] 51+ messages in thread