Re: [PATCH] drm/ast: Fix soft lockup
Hi, Thanks for your patch. I'm wondering how you can trigger this infinite loop ? Also this looks like a simple fix, that can be easily backported, so I'm adding stable in Cc. If Thomas has no objections, I can push it to drm-misc-fixes. Reviewed-by: Jocelyn Falempe -- Jocelyn On 25/03/2024 04:35, Jammy Huang wrote: Avoid infinite-loop in ast_dp_set_on_off(). Signed-off-by: Jammy Huang --- drivers/gpu/drm/ast/ast_dp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c index ebb6d8ebd44e..1e9259416980 100644 --- a/drivers/gpu/drm/ast/ast_dp.c +++ b/drivers/gpu/drm/ast/ast_dp.c @@ -180,6 +180,7 @@ void ast_dp_set_on_off(struct drm_device *dev, bool on) { struct ast_device *ast = to_ast_device(dev); u8 video_on_off = on; + u32 i = 0; // Video On/Off ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE3, (u8) ~AST_DP_VIDEO_ENABLE, on); @@ -192,6 +193,8 @@ void ast_dp_set_on_off(struct drm_device *dev, bool on) ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) { // wait 1 ms mdelay(1); + if (++i > 200) + break; } } } base-commit: b0546776ad3f332e215cebc0b063ba4351971cca
Re: [PATCH v5 00/13] drm/ast: Detect connector status for VGA and SIL164
Hi, Thanks for those patches, that's really a good enhancement to the ast driver, and fits well with the BMC virtual connector. I've reviewed the whole series, and it looks good to me. Reviewed-by: Jocelyn Falempe -- Jocelyn On 20/03/2024 10:34, Thomas Zimmermann wrote: Detect the status of the VGA or SIL164 conenctor by polling the DDC channel. Update the status at runtime and flip the BMC status as well. Patches 1 adds a missing include statement that will be required to make later patches compile. Patches 2 and 3 simplify the VGA and SIL164 connectors, such that no additional data structure is required. These patches have been reviewed before as part of the series at [1]. Patches 4 to 10 improve the I2C code that is used to retrieve the monitor's EDID data. It's now fully managed, it acquires the necessary lock automatically and it is called DDC, which better represents its purpose than I2C. Patches 11 to 13 finally implement polling. Patch 11 updates ast's EDID code to be up-to-date. The helper drm_connector_get_modes() reads the EDID via DDC and updates the property. No driver code is required. Patch 12 uses a similar pattern to detect the presence of the monitor and sets the connector status accordingly. As polling also needs to be cleaned up, patch 13 adds the necessary helpers to do so. Tested on AST2500 hardware and BMC output. The BMC connector now also flips its status correctly at runtime. [1] https://patchwork.freedesktop.org/series/104547/ v5: - share implementation in drm_connector_helper_detect_ctx() (Maxime) - test for DDC presence with drm_probe_ddc() (Maxime, Jani) - perform managed cleanup of poll thread Thomas Zimmermann (13): drm/ast: Include where necessary drm/ast: Fail probing if DDC channel could not be initialized drm/ast: Remove struct ast_{vga,sil165}_connector drm/ast: Allocate instance of struct ast_i2c_chan with managed helpers drm/ast: Move DDC code to ast_ddc.{c,h} drm/ast: Rename struct ast_i2c_chan to struct ast_ddc drm/ast: Pass AST device to ast_ddc_create() drm/ast: Store AST device in struct ast_ddc drm/ast: Rename struct i2c_algo_bit_data callbacks and their parameters drm/ast: Acquire I/O-register lock in DDC code drm/ast: Use drm_connector_helper_get_modes() drm/ast: Implement polling for VGA and SIL164 connectors drm/ast: Automatically clean up poll helper drivers/gpu/drm/ast/Makefile | 10 +- drivers/gpu/drm/ast/{ast_i2c.c => ast_ddc.c} | 120 +-- drivers/gpu/drm/ast/ast_ddc.h| 20 +++ drivers/gpu/drm/ast/ast_drv.c| 1 + drivers/gpu/drm/ast/ast_drv.h| 39 + drivers/gpu/drm/ast/ast_main.c | 1 + drivers/gpu/drm/ast/ast_mode.c | 147 +-- drivers/gpu/drm/drm_probe_helper.c | 56 +++ include/drm/drm_probe_helper.h | 5 + 9 files changed, 206 insertions(+), 193 deletions(-) rename drivers/gpu/drm/ast/{ast_i2c.c => ast_ddc.c} (54%) create mode 100644 drivers/gpu/drm/ast/ast_ddc.h
Re: [PATCH 12/43] drm/mgag200: Use fbdev-shmem
On 18/03/2024 08:56, Thomas Zimmermann wrote: Hi Am 13.03.24 um 15:03 schrieb Jocelyn Falempe: Hi, Thanks, it looks good to me. Reviewed-by: Jocelyn Falempe Thanks. Do you still have access to that broken realtime system? I wonder if this patch makes a difference, as there's now one large memcpy() less. Hi, Sure, I'll do some latency tests if I can get access to that server again. Best regards, Best regards Thomas
Re: [PATCH v10 1/9] drm/panic: Add drm panic locking
On 15/03/2024 16:28, John Ogness wrote: On 2024-03-15, Jocelyn Falempe wrote: +static inline int drm_panic_trylock(struct drm_device *dev, unsigned long *flags) +{ + return raw_spin_trylock_irqsave(>mode_config.panic_lock, *flags); +} [...] +static inline unsigned long drm_panic_lock(struct drm_device *dev) +{ + unsigned long flags; + + raw_spin_lock_irqsave(>mode_config.panic_lock, flags); + return flags; +} I find it a bit strange that @flags is passed as an argument in the trylock variant but returned in the lock variant. I would pass it as an argument in both variants. Just a suggestion. Or maybe I can do it as a macro instead of a static inline function, to have the same semantic as raw_spin_lock_irqsave() which modify the flags, without passing it as pointer, because it's also a macro. https://elixir.bootlin.com/linux/latest/source/include/linux/spinlock.h#L296 #define drm_panic_lock(dev, flags) \ raw_spin_lock_irqsave(>mode_config.panic_lock, flags); John Ogness -- Jocelyn
[PATCH v10 9/9] drm/ast: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/ast/ast_mode.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index a718646a66b8..49f2d8bd3377 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -700,12 +701,29 @@ static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x1, 0xdf, 0x20); } +static int ast_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct ast_plane *ast_plane = to_ast_plane(plane); + + if (plane->state && plane->state->fb && ast_plane->vaddr) { + 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(>map, ast_plane->vaddr); + return 0; + } + return -ENODEV; +} + static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .atomic_check = ast_primary_plane_helper_atomic_check, .atomic_update = ast_primary_plane_helper_atomic_update, .atomic_enable = ast_primary_plane_helper_atomic_enable, .atomic_disable = ast_primary_plane_helper_atomic_disable, + .get_scanout_buffer = ast_primary_plane_helper_get_scanout_buffer, }; static const struct drm_plane_funcs ast_primary_plane_funcs = { -- 2.44.0
[PATCH v10 4/9] drm/panic: Add debugfs entry to test without triggering panic.
Add a debugfs file, so you can test drm_panic without freezing your machine. This is unsafe, and should be enabled only for developer or tester. To display the drm_panic screen on the device 0: echo 1 > /sys/kernel/debug/dri/0/drm_panic_plane_0 v9: * Create a debugfs file for each plane in the device's debugfs directory. This allows to test for each plane of each GPU independently. Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/Kconfig | 9 drivers/gpu/drm/drm_panic.c | 43 - 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f07ca38d3f98..6e41fbd16b3d 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -125,6 +125,15 @@ config DRM_PANIC_BACKGROUND_COLOR depends on DRM_PANIC default 0x00 +config DRM_PANIC_DEBUG + bool "Add a debug fs entry to trigger drm_panic" + depends on DRM_PANIC && DEBUG_FS + help + Add dri/[device]/drm_panic_plane_x in the kernel debugfs, to force the + panic handler to write the panic message to this plane scanout buffer. + This is unsafe and should not be enabled on a production build. + If in doubt, say "N". + 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/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 2c3b2fffe659..cd2c7c2d1c59 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -493,6 +493,45 @@ static void drm_panic(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) draw_panic_plane(plane); } + +/* + * DEBUG FS, This is currently unsafe. + * Create one file per plane, so it's possible to debug one plane at a time. + */ +#ifdef CONFIG_DRM_PANIC_DEBUG +#include + +static ssize_t debugfs_trigger_write(struct file *file, const char __user *user_buf, +size_t count, loff_t *ppos) +{ + bool run; + + if (kstrtobool_from_user(user_buf, count, ) == 0 && run) { + struct drm_plane *plane = file->private_data; + + draw_panic_plane(plane); + } + return count; +} + +static const struct file_operations dbg_drm_panic_ops = { + .owner = THIS_MODULE, + .write = debugfs_trigger_write, + .open = simple_open, +}; + +static void debugfs_register_plane(struct drm_plane *plane, int index) +{ + char fname[32]; + + snprintf(fname, 32, "drm_panic_plane_%d", index); + debugfs_create_file(fname, 0200, plane->dev->debugfs_root, + plane, _drm_panic_ops); +} +#else +static void debugfs_register_plane(struct drm_plane *plane, int index) {} +#endif /* CONFIG_DRM_PANIC_DEBUG */ + /** * drm_panic_register() - Initialize DRM panic for a device * @dev: the drm device on which the panic screen will be displayed. @@ -512,8 +551,10 @@ void drm_panic_register(struct drm_device *dev) plane->kmsg_panic.max_reason = KMSG_DUMP_PANIC; if (kmsg_dump_register(>kmsg_panic)) drm_warn(dev, "Failed to register panic handler\n"); - else + else { + debugfs_register_plane(plane, registered_plane); registered_plane++; + } } if (registered_plane) drm_info(dev, "Registered %d planes with drm panic\n", registered_plane); -- 2.44.0
[PATCH v10 8/9] drm/imx: Add drm_panic support
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 v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index dade8b59feae..3e21d2a1a124 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -772,6 +772,12 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { .atomic_disable = ipu_plane_atomic_disable, .atomic_update = ipu_plane_atomic_update, }; +static const struct drm_plane_helper_funcs ipu_primary_plane_helper_funcs = { + .atomic_check = ipu_plane_atomic_check, + .atomic_disable = ipu_plane_atomic_disable, + .atomic_update = ipu_plane_atomic_update, + .get_scanout_buffer = drm_panic_gem_get_scanout_buffer, +}; bool ipu_plane_atomic_update_pending(struct drm_plane *plane) { @@ -916,7 +922,10 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - drm_plane_helper_add(_plane->base, _plane_helper_funcs); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(_plane->base, _primary_plane_helper_funcs); + else + drm_plane_helper_add(_plane->base, _plane_helper_funcs); if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) ret = drm_plane_create_zpos_property(_plane->base, zpos, 0, -- 2.44.0
[PATCH v10 6/9] drm/simpledrm: Add drm_panic support
Add support for the drm_panic module, which displays a user-friendly message to the screen when a kernel panic occurs. v8: * Replace get_scanout_buffer() with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/tiny/simpledrm.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 7ce1c4617675..f498665be8c4 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define DRIVER_NAME"simpledrm" @@ -671,11 +672,26 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan drm_dev_exit(idx); } +static int simpledrm_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, +struct drm_scanout_buffer *sb) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(plane->dev); + + sb->width = sdev->mode.hdisplay; + sb->height = sdev->mode.vdisplay; + sb->format = sdev->format; + sb->pitch = sdev->pitch; + sb->map = sdev->screen_base; + + return 0; +} + static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .atomic_check = simpledrm_primary_plane_helper_atomic_check, .atomic_update = simpledrm_primary_plane_helper_atomic_update, .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, + .get_scanout_buffer = simpledrm_primary_plane_helper_get_scanout_buffer, }; static const struct drm_plane_funcs simpledrm_primary_plane_funcs = { -- 2.44.0
[PATCH v10 7/9] drm/mgag200: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.h | 7 ++- drivers/gpu/drm/mgag200/mgag200_mode.c | 18 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 765e49fd8911..58a0e62eaf18 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -366,6 +366,7 @@ struct drm_crtc_state; struct drm_display_mode; struct drm_plane; struct drm_atomic_state; +struct drm_scanout_buffer; extern const uint32_t mgag200_primary_plane_formats[]; extern const size_t mgag200_primary_plane_formats_size; @@ -379,12 +380,16 @@ void mgag200_primary_plane_helper_atomic_enable(struct drm_plane *plane, struct drm_atomic_state *state); void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *old_state); +int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb); + #define MGAG200_PRIMARY_PLANE_HELPER_FUNCS \ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, \ .atomic_check = mgag200_primary_plane_helper_atomic_check, \ .atomic_update = mgag200_primary_plane_helper_atomic_update, \ .atomic_enable = mgag200_primary_plane_helper_atomic_enable, \ - .atomic_disable = mgag200_primary_plane_helper_atomic_disable + .atomic_disable = mgag200_primary_plane_helper_atomic_disable, \ + .get_scanout_buffer = mgag200_primary_plane_helper_get_scanout_buffer #define MGAG200_PRIMARY_PLANE_FUNCS \ .update_plane = drm_atomic_helper_update_plane, \ diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index e17cb4c5f774..8f368ecca4d4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -546,6 +547,23 @@ void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, msleep(20); } +int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct mga_device *mdev = to_mga_device(plane->dev); + struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram); + + if (plane->state && plane->state->fb) { + 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; +} + /* * CRTC */ -- 2.44.0
[PATCH v10 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * go back to get_scanout_buffer() * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_fb_dma_helper.c | 47 + include/drm/drm_fb_dma_helper.h | 4 +++ 2 files changed, 51 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 3b535ad1b07c..010327069ad4 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,3 +149,49 @@ 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) +/** + * @plane: DRM primary plane + * @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_plane *plane, +struct drm_scanout_buffer *sb) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_framebuffer *fb; + + fb = plane->state->fb; + /* Only support linear modifier */ + if (fb->modifier != DRM_FORMAT_MOD_LINEAR) + return -ENODEV; + + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + + /* Buffer should be accessible from the CPU */ + if (dma_obj->base.import_attach) + return -ENODEV; + + /* Buffer should be already mapped to CPU */ + if (!dma_obj->vaddr) + return -ENODEV; + + iosys_map_set_vaddr(>map, dma_obj->vaddr); + sb->format = fb->format; + sb->height = fb->height; + sb->width = fb->width; + sb->pitch = fb->pitches[0]; + return 0; +} +#else +int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, +struct drm_scanout_buffer *sb) +{ + return -ENODEV; +} +#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..61f24c2aba2f 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_plane *plane, +struct drm_scanout_buffer *sb); + #endif -- 2.44.0
[PATCH v10 3/9] drm/panic: Add support for color format conversion
Add support for the following formats: DRM_FORMAT_RGB565 DRM_FORMAT_RGBA5551 DRM_FORMAT_XRGB1555 DRM_FORMAT_ARGB1555 DRM_FORMAT_RGB888 DRM_FORMAT_XRGB DRM_FORMAT_ARGB DRM_FORMAT_XBGR DRM_FORMAT_XRGB2101010 DRM_FORMAT_ARGB2101010 v10: * move and simplify the functions from the drm format helper to drm_panic Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_panic.c | 272 ++-- 1 file changed, 262 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index faa64961c0f2..2c3b2fffe659 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -81,15 +81,155 @@ static const struct drm_panic_line logo[] = { PANIC_LINE(" \\___)=(___/"), }; -static void drm_panic_fill32(struct iosys_map *map, unsigned int pitch, +/* + * Color conversion + */ + +static u16 convert_xrgb_to_rgb565(u32 pix) +{ + return ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); +} + +static u16 convert_xrgb_to_rgba5551(u32 pix) +{ + return ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ +} + +static u16 convert_xrgb_to_xrgb1555(u32 pix) +{ + return ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); +} + +static u16 convert_xrgb_to_argb1555(u32 pix) +{ + return BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); +} + +static u32 convert_xrgb_to_argb(u32 pix) +{ + return pix | GENMASK(31, 24); /* fill alpha bits */ +} + +static u32 convert_xrgb_to_xbgr(u32 pix) +{ + return ((pix & 0x00ff) >> 16) << 0 | + ((pix & 0xff00) >> 8) << 8 | + ((pix & 0x00ff) >> 0) << 16 | + ((pix & 0xff00) >> 24) << 24; +} + +static u32 convert_xrgb_to_abgr(u32 pix) +{ + return ((pix & 0x00ff) >> 16) << 0 | + ((pix & 0xff00) >> 8) << 8 | + ((pix & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ +} + +static u32 convert_xrgb_to_xrgb2101010(u32 pix) +{ + pix = ((pix & 0x00FF) << 2) | + ((pix & 0xFF00) << 4) | + ((pix & 0x00FF) << 6); + return pix | ((pix >> 8) & 0x00300C03); +} + +static u32 convert_xrgb_to_argb2101010(u32 pix) +{ + pix = ((pix & 0x00FF) << 2) | + ((pix & 0xFF00) << 4) | + ((pix & 0x00FF) << 6); + return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); +} + +/* + * convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb format + * @format: output format + * + * Returns: + * Color in the format specified, casted to u32. + * Or 0 if the format is not supported. + */ +static u32 convert_from_xrgb(u32 color, u32 format) +{ + switch (format) { + case DRM_FORMAT_RGB565: + return convert_xrgb_to_rgb565(color); + case DRM_FORMAT_RGBA5551: + return convert_xrgb_to_rgba5551(color); + case DRM_FORMAT_XRGB1555: + return convert_xrgb_to_xrgb1555(color); + case DRM_FORMAT_ARGB1555: + return convert_xrgb_to_argb1555(color); + case DRM_FORMAT_RGB888: + case DRM_FORMAT_XRGB: + return color; + case DRM_FORMAT_ARGB: + return convert_xrgb_to_argb(color); + case DRM_FORMAT_XBGR: + return convert_xrgb_to_xbgr(color); + case DRM_FORMAT_ABGR: + return convert_xrgb_to_abgr(color); + case DRM_FORMAT_XRGB2101010: + return convert_xrgb_to_xrgb2101010(color); + case DRM_FORMAT_ARGB2101010: + return convert_xrgb_to_argb2101010(color); + default: + WARN_ONCE(1, "Can't convert to %p4cc\n", ); + return 0; + } +} + +/* + * Blit & Fill + */ +static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch, +const u8 *sbuf8, unsigned int spitch, unsigned int height, unsigned int width, -u32 color) +u16 fg16, u16 bg16) { unsigned int y, x; + u16 val16; -
[PATCH v10 2/9] drm/panic: Add a drm panic handler
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. v8 * Register directly each plane to the panic notifier (Sima) * Add raw_spinlock to properly handle concurrency (Sima) * Register plane instead of device, to avoid looping through plane list, and simplify code. * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) * Removed the draw_pixel_xy() API, will see later if it can be added back. v9 * Revert to using get_scanout_buffer() (Sima) * Move get_scanout_buffer() and panic_flush() to the plane helper functions (Thomas Zimmermann) * Register all planes with get_scanout_buffer() to the panic notifier * Use drm_panic_lock() to protect against race (Sima) v10 * Move blit and fill functions back in drm_panic (Thomas Zimmermann). * Simplify the text drawing functions. * Use kmsg_dumper instead of panic_notifier (Sima). Signed-off-by: Jocelyn Falempe --- Documentation/gpu/drm-kms.rst| 12 + drivers/gpu/drm/Kconfig | 23 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_drv.c| 4 + drivers/gpu/drm/drm_panic.c | 288 +++ drivers/gpu/drm/drm_plane.c | 1 + include/drm/drm_modeset_helper_vtables.h | 37 +++ include/drm/drm_panic.h | 52 include/drm/drm_plane.h | 6 + 9 files changed, 424 insertions(+) create mode 100644 drivers/gpu/drm/drm_panic.c diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 13d3627d8bc0..b64334661aeb 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -398,6 +398,18 @@ Plane Damage Tracking Functions Reference .. kernel-doc:: include/drm/drm_damage_helper.h :internal: +Plane Panic Feature +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :doc: overview + +Plane Panic Functions Reference +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :export: + Display Modes Function Reference diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 16029435b750..f07ca38d3f98 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -102,6 +102,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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 a73c04d2d7a3..f9ca4f8fa6c5 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -88,6 +88,7 @@ drm-$(CONFIG_DRM_P
[PATCH v10 1/9] drm/panic: Add drm panic locking
From: Daniel Vetter Rough sketch for the locking of drm panic printing code. The upshot of this approach is that we can pretty much entirely rely on the atomic commit flow, with the pair of raw_spin_lock/unlock providing any barriers we need, without having to create really big critical sections in code. This also avoids the need that drivers must explicitly update the panic handler state, which they might forget to do, or not do consistently, and then we blow up in the worst possible times. It is somewhat racy against a concurrent atomic update, and we might write into a buffer which the hardware will never display. But there's fundamentally no way to avoid that - if we do the panic state update explicitly after writing to the hardware, we might instead write to an old buffer that the user will barely ever see. Note that an rcu protected deference of plane->state would give us the the same guarantees, but it has the downside that we then need to protect the plane state freeing functions with call_rcu too. Which would very widely impact a lot of code and therefore doesn't seem worth the complexity compared to a raw spinlock with very tiny critical sections. Plus rcu cannot be used to protect access to peek/poke registers anyway, so we'd still need it for those cases. Peek/poke registers for vram access (or a gart pte reserved just for panic code) are also the reason I've gone with a per-device and not per-plane spinlock, since usually these things are global for the entire display. Going with per-plane locks would mean drivers for such hardware would need additional locks, which we don't want, since it deviates from the per-console takeoverlocks design. Longer term it might be useful if the panic notifiers grow a bit more structure than just the absolute bare EXPORT_SYMBOL(panic_notifier_list) - somewhat aside, why is that not EXPORT_SYMBOL_GPL ... If panic notifiers would be more like console drivers with proper register/unregister interfaces we could perhaps reuse the very fancy console lock with all it's check and takeover semantics that John Ogness is developing to fix the console_lock mess. But for the initial cut of a drm panic printing support I don't think we need that, because the critical sections are extremely small and only happen once per display refresh. So generally just 60 tiny locked sections per second, which is nothing compared to a serial console running a 115kbaud doing really slow mmio writes for each byte. So for now the raw spintrylock in drm panic notifier callback should be good enough. Another benefit of making panic notifiers more like full blown consoles (that are used in panics only) would be that we get the two stage design, where first all the safe outputs are used. And then the dangerous takeover tricks are deployed (where for display drivers we also might try to intercept any in-flight display buffer flips, which if we race and misprogram fifos and watermarks can hang the memory controller on some hw). For context the actual implementation on the drm side is by Jocelyn and this patch is meant to be combined with the overall approach in v7 (v8 is a bit less flexible, which I think is the wrong direction): https://lore.kernel.org/dri-devel/20240104160301.185915-1-jfale...@redhat.com/ Note that the locking is very much not correct there, hence this separate rfc. v2: - fix authorship, this was all my typing - some typo oopsies - link to the drm panic work by Jocelyn for context v10: - Use spinlock_irqsave/restore (John Ogness) Signed-off-by: Daniel Vetter Cc: Jocelyn Falempe Cc: Andrew Morton Cc: "Peter Zijlstra (Intel)" Cc: Lukas Wunner Cc: Petr Mladek Cc: Steven Rostedt Cc: John Ogness Cc: Sergey Senozhatsky Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_atomic_helper.c | 4 ++ drivers/gpu/drm/drm_drv.c | 1 + include/drm/drm_mode_config.h | 10 +++ include/drm/drm_panic.h | 107 4 files changed, 122 insertions(+) create mode 100644 include/drm/drm_panic.h diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 39ef0a6addeb..89dbf0ab1ba8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -3016,6 +3017,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, bool stall) { int i, ret; + unsigned long flags; struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; struct drm_crtc *crtc; @@ -3099,6 +3101,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, } } + flags = drm_panic_lock(state->dev); for_each_oldne
[PATCH v10 0/9] drm/panic: Add a drm panic handler
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. To test it, make sure you're using one of the supported driver, and trigger a panic: echo c > /proc/sysrq-trigger or you can enable CONFIG_DRM_PANIC_DEBUG and echo 1 > /sys/kernel/debug/dri/0/drm_panic_plane_0 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) v8: * Directly register each plane to the panic notifier (Sima) * Replace get_scanout_buffer() with set_scanout_buffer() to simplify the locking. (Thomas Zimmermann) * Add a debugfs entry, to trigger the drm_panic without a real panic (Sima) * Fix the drm_panic Documentation, and include it in drm-kms.rst v9: * Revert to using get_scanout_buffer() (Sima) * Move get_scanout_buffer() and panic_flush() to the plane helper functions (Thomas Zimmermann) * Register all planes with get_scanout_buffer() to the panic notifier * Use drm_panic_lock() to protect against race (Sima) * Create a debugfs file for each plane in the device's debugfs directory. This allows to test for each plane of each GPU independently. v10: * Move blit and fill functions back in drm_panic (Thomas Zimmermann). * Simplify the text drawing functions. * Use kmsg_dumper instead of panic_notifier (Sima). * Use spinlock_irqsave/restore (John Ogness) Daniel Vetter (1): drm/panic: Add drm panic locking Jocelyn Falempe (8): drm/panic: Add a drm panic handler drm/panic: Add support for color format conversion drm/panic: Add debugfs entry to test without triggering panic. drm/fb_dma: Add generic get_scanout_buffer() for drm_panic drm/simpledrm: Add drm_panic support drm/mgag200: Add drm_panic support drm/imx: Add drm_panic support drm/ast: Add drm_panic support Documentation/gpu/drm-kms.rst| 12 + drivers/gpu/drm/Kconfig | 32 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ast/ast_mode.c | 18 + drivers/gpu/drm/drm_atomic_helper.c | 4 + drivers/gpu/drm/drm_drv.c| 5 + drivers/gpu/drm/drm_fb_dma_helper.c | 47 ++ drivers/gpu/drm/drm_panic.c | 581 +++ drivers/gpu/drm/drm_plane.c | 1 + drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 11 +- drivers/gpu/drm/mgag200/mgag200_drv.h| 7 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 18 + drivers/gpu/drm/tiny/simpledrm.c | 16 + include/drm/drm_fb_dma_helper.h | 4 + include/drm/drm_mode_config.h| 10 + include/drm/drm_modeset_helper_vtables.h | 37 ++ include/drm/drm_panic.h | 159 +++ include/drm/drm_plane.h | 6 + 18 files changed, 967 insertions(+), 2 del
Re: [PATCH] vmwgfx: Create debugfs ttm_resource_manager entry only if needed
On 13/03/2024 18:57, Zack Rusin wrote: On Tue, Mar 12, 2024 at 5:36 AM Jocelyn Falempe wrote: [...] Thanks! That looks great. I can push it through drm-misc-fixes. Thanks, I think I only forget the "drm/" in the commit title, but yes you can push it with this small correction. Reviewed-by: Zack Rusin z Best regards, -- Jocelyn
Re: [PATCH 12/43] drm/mgag200: Use fbdev-shmem
Hi, Thanks, it looks good to me. Reviewed-by: Jocelyn Falempe -- Jocelyn On 12/03/2024 16:45, Thomas Zimmermann wrote: Implement fbdev emulation with fbdev-shmem. Avoids the overhead of fbdev-generic's additional shadow buffering. No functional changes. Signed-off-by: Thomas Zimmermann Cc: Dave Airlie Cc: Thomas Zimmermann Cc: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 573dbe256aa8b..65f2ed18b31c5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -285,7 +285,7 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * FIXME: A 24-bit color depth does not work with 24 bpp on * G200ER. Force 32 bpp. */ - drm_fbdev_generic_setup(dev, 32); + drm_fbdev_shmem_setup(dev, 32); return 0; }
Re: [PATCH 09/43] drm/ast: Use fbdev-shmem
Hi, Thanks, it looks good to me. Reviewed-by: Jocelyn Falempe -- Jocelyn On 12/03/2024 16:45, Thomas Zimmermann wrote: Implement fbdev emulation with fbdev-shmem. Avoids the overhead of fbdev-generic's additional shadow buffering. No functional changes. Signed-off-by: Thomas Zimmermann Cc: Dave Airlie Cc: Thomas Zimmermann Cc: Jocelyn Falempe --- drivers/gpu/drm/ast/ast_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 90bcb1eb9cd94..4fcab4304e176 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -359,7 +359,7 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - drm_fbdev_generic_setup(drm, 32); + drm_fbdev_shmem_setup(drm, 32); return 0; }
Re: [v9,5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
On 12/03/2024 17:44, Sui Jingfeng wrote: Hi, I'm get attracted by your patch, so I want to comment. Please correct or ignore me if I say something wrong. On 2024/3/7 17:14, Jocelyn Falempe wrote: This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * go back to get_scanout_buffer() * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_fb_dma_helper.c | 47 + include/drm/drm_fb_dma_helper.h | 4 +++ 2 files changed, 51 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 3b535ad1b07c..010327069ad4 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,3 +149,49 @@ 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) +/** + * @plane: DRM primary plane + * @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_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_framebuffer *fb; + + fb = plane->state->fb; + /* Only support linear modifier */ + if (fb->modifier != DRM_FORMAT_MOD_LINEAR) + return -ENODEV; I think, the framebuffer format check clause here should be moved to the core layer. For example, move this check into thedrm_panic_is_format_supported() function. And update the drm_panic_is_format_supported() function to make it take 'struct drm_framebuffer *fb' as argument. Because this check is needed for all implement, not driver specific or implement specific. I'm unsure about this. I think for some drivers it might be easier to give a memory buffer different from the plane's drm_framebuffer, and do their own specific things to display it. So forcing the use of a drm_framebuffer will remove some flexibility. I know that some display controller support TILE format, but then you can try to trigger modeset to let the display controller using linear format to display. Or, you can also convert local linear buffer(with content pained) to the device specific TILED framebuffer, then feed TILED framebuffer to the display controller to scanout. This is something like reverse the process of resolve, but the convert program is running on the CPU. As panic is not performance critical, so it's possible. This maybe a bit more difficult, but the idea behind this is that the goal of this drm_panic_gem_get_scanout_buffer() function is just to get a buffer scanout-able. Other things beyond that (like format checking) can be moved to upper level(the caller of it). So you don't need to modify(update) the specific implement if one day you have some fancy idea implemented. Correct me if I'm wrong, but the tiled format are mostly hardware dependent, and I don't think we can have a generic implementation, that can cover multiple hardware. I want to add support for multi-planar format like YUV for drm_panic later, but for tiled buffer, I think it should be easier to deactivate tiling on the hardware itself. + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + + /* Buffer should be accessible from the CPU */ + if (dma_obj->base.import_attach) + return -ENODEV; + + /* Buffer should be already mapped to CPU */ + if (!dma_obj->vaddr) + return -ENODEV; How about to call drm_gem_vmap_unlocked(dma_obj, >map); ? It is not safe to call it from panic context, because it takes locks: https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_gem.c#L1212 It may lockup the panic handler, and prevent other panic routine to run (like kdump). So it's better to call drm_gem_vmap_unlocked() when the driver prepares the buffer for the primary plane, than doing it from the panic handler. Best regards, -- Jocelyn + iosys_map_set_vaddr(>map, dma_obj->vaddr); + sb->format = fb->format; + sb->height = fb->height; + sb->width = fb->width; + sb->pitch = fb->pitches[0]; + return 0; +} +#else +int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + return -ENODEV; +} +#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..61f24c2aba2f 100644 --- a/include/drm/drm_fb_dma_helper.h +++ b/include/drm/drm_fb_dma_helper
Re: [PATCH v9 0/9] drm/panic: Add a drm panic handler
On 12/03/2024 16:16, Sui Jingfeng wrote: Hi, On 2024/3/7 17:14, 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. To test it, make sure you're using one of the supported driver, and trigger a panic: echo c > /proc/sysrq-trigger or you can enable CONFIG_DRM_PANIC_DEBUG and echo 1 > /sys/kernel/debug/dri/0/drm_panic_plane_0 Yes, the whole series works for me! I have tested with drm/loongson, Are you willing to add a implement for drm/loongson driver? If you do please add the fallowing code snippet info drm/loongson/lsdc_plane.c. Thanks you. Thanks for testing, and for enabling drm_panic on loongson. My plan is to have a first version of drm_panic merged before adding more drivers. You will be able to send this patch when drm_panic is merged in drm-misc-next, and I will review it. Best regards, -- Jocelyn static int lsdc_primary_plane_get_scanout_buffer(struct drm_plane *plane, struct drm_scanout_buffer *scanout) { struct drm_framebuffer *fb; if (!plane->state || !plane->state->fb) return -ENODEV; fb = plane->state->fb; if (fb->modifier != DRM_FORMAT_MOD_LINEAR) return -ENODEV; scanout->format = fb->format; scanout->width = fb->width; scanout->height = fb->height; scanout->pitch = fb->pitches[0]; return drm_gem_vmap_unlocked(fb->obj[0], >map); } hook this lsdc_primary_plane_get_scanout_buffer() up to the .get_scanout_buffer member of lsdc_primary_helper_funcs, and include the #include Thanks you in advance!
Re: [v9,3/9] drm/panic: Add a drm panic handler
On 12/03/2024 14:18, Sui Jingfeng wrote: Hi, [...] While applying you patch, there is new blank line at EOF reported, see below. This is not an issue, but I want to report this to you. Hi, Thanks, I will remove it for the next version. -- Jocelyn git am ../drm-panic-Add-a-drm-panic-handler.mbox Applying: drm/panic: Add drm panic locking Applying: drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill Applying: drm/panic: Add a drm panic handler .git/rebase-apply/patch:439: new blank line at EOF. + warning: 1 line adds whitespace errors. Applying: drm/panic: Add debugfs entry to test without triggering panic. Applying: drm/fb_dma: Add generic get_scanout_buffer() for drm_panic Applying: drm/simpledrm: Add drm_panic support Applying: drm/mgag200: Add drm_panic support Applying: drm/imx: Add drm_panic support Applying: drm/ast: Add drm_panic support
Re: [v2] drm/mgag200: Add a workaround for low-latency
On 12/03/2024 13:56, Sui Jingfeng wrote: Hi, Interesting patch! I know this patch already merged. While study this patch, I have a few questions. On 2024/2/8 17:51, Jocelyn Falempe wrote: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) The regression has been bisected to 2 commits: commit 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") commit 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. I don't know why it need to do a cache flush, where is the code. I'm asking because I want to study this technique. Generally speaking, X86-64 platform's default page caching is cached. And I think the cached mapping is fastest for software rendering. And the platform guaranteed the coherency for us, right? Because X86-64 platform(or CPU)'s write buffer is implemented on the top of cache? I'm means that for ARM(or other) CPU, when using Write-combine the data will has nothing to do with cache. Both regressions are fixed by this commit, which restore WC mapping for the framebuffer in system memory, and add a cache flush. So switch back to WC probably will decrease overall performance, I think. And the cache flush operation should not have a impact. Except X86-64's Write-Combine is different other platform's Write-Combine? Yes this patch is a bit weird. Usually you want your VRAM mapping to be Write-Combine. Here it also set the system memory framebuffer as Write-Combine. On most x86-64, Write Combine uses its own hardware buffer that is not in L1/L2/L3. So when it copies the framebuffer from WC system memory to VRAM, it doesn't involve the cache, and have less impact on latency for other tasks running on other CPU. Also I think the cache flush is important to flush those WC buffers, so when the next frame comes, it won't have to wait for the buffers to be copied to the slow VRAM. When running the latency tests, it's obvious that both are needed. This is how I understand it, but I may be wrong. -- Jocelyn This is only needed on x86_64, for low-latency workload, so the new kconfig DRM_MGAG200_IOBURST_WORKAROUND depends on PREEMPT_RT and X86. For more context, the whole thread can be found here [1] Signed-off-by: Jocelyn Falempe Link: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ # 1 Acked-by: Thomas Zimmermann
[PATCH] vmwgfx: Create debugfs ttm_resource_manager entry only if needed
The driver creates /sys/kernel/debug/dri/0/mob_ttm even when the corresponding ttm_resource_manager is not allocated. This leads to a crash when trying to read from this file. Add a check to create mob_ttm, system_mob_ttm, and gmr_ttm debug file only when the corresponding ttm_resource_manager is allocated. crash> bt PID: 3133409 TASK: 8fe4834a5000 CPU: 3COMMAND: "grep" #0 [b954506b3b20] machine_kexec at b2a6bec3 #1 [b954506b3b78] __crash_kexec at b2bb598a #2 [b954506b3c38] crash_kexec at b2bb68c1 #3 [b954506b3c50] oops_end at b2a2a9b1 #4 [b954506b3c70] no_context at b2a7e913 #5 [b954506b3cc8] __bad_area_nosemaphore at b2a7ec8c #6 [b954506b3d10] do_page_fault at b2a7f887 #7 [b954506b3d40] page_fault at b360116e [exception RIP: ttm_resource_manager_debug+0x11] RIP: c04afd11 RSP: b954506b3df0 RFLAGS: 00010246 RAX: 8fe41a6d1200 RBX: RCX: 0940 RDX: RSI: c04b4338 RDI: RBP: b954506b3e08 R8: 8fee3ffad000 R9: R10: 8fe41a76a000 R11: 0001 R12: R13: 0001 R14: 8fe5bb6f3900 R15: 8fe41a6d1200 ORIG_RAX: CS: 0010 SS: 0018 #8 [b954506b3e00] ttm_resource_manager_show at c04afde7 [ttm] #9 [b954506b3e30] seq_read at b2d8f9f3 RIP: 7f4c4eda8985 RSP: 7ffdbba9e9f8 RFLAGS: 0246 RAX: ffda RBX: 0037e000 RCX: 7f4c4eda8985 RDX: 0037e000 RSI: 7f4c41573000 RDI: 0003 RBP: 0037e000 R8: R9: 0037fe30 R10: R11: 0246 R12: 7f4c41573000 R13: 0003 R14: 7f4c41572010 R15: 0003 ORIG_RAX: CS: 0033 SS: 002b Signed-off-by: Jocelyn Falempe Fixes: af4a25bbe5e7 ("drm/vmwgfx: Add debugfs entries for various ttm resource managers") Cc: --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 15 +-- 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index d3e308fdfd5b..c7d90f96d16a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1444,12 +1444,15 @@ static void vmw_debugfs_resource_managers_init(struct vmw_private *vmw) root, "system_ttm"); ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, TTM_PL_VRAM), root, "vram_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_GMR), - root, "gmr_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_MOB), - root, "mob_ttm"); - ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_SYSTEM), - root, "system_mob_ttm"); + if (vmw->has_gmr) + ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_GMR), + root, "gmr_ttm"); + if (vmw->has_mob) { + ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_MOB), + root, "mob_ttm"); + ttm_resource_manager_create_debugfs(ttm_manager_type(>bdev, VMW_PL_SYSTEM), + root, "system_mob_ttm"); + } } static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, base-commit: b33651a5c98dbd5a919219d8c129d0674ef74299 -- 2.44.0
Re: [PATCH v9 1/9] drm/panic: Add drm panic locking
On 07/03/2024 11:27, John Ogness wrote: On 2024-03-07, Jocelyn Falempe wrote: diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 39ef0a6addeb..c0bb91312fb2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -3099,6 +3100,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, } } + drm_panic_lock(state->dev); for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { WARN_ON(plane->state != old_plane_state); @@ -3108,6 +3110,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, state->planes[i].state = old_plane_state; plane->state = new_plane_state; } + drm_panic_unlock(state->dev); Is there a reason irqsave/irqrestore variants are not used? Maybe this code path is too hot? This lock will be taken for each page flip, so typically at 60Hz (or maybe 144Hz for gamers). I don't know what are the performance impacts of the irqsave/irqrestore variant. By leaving interrupts enabled, there is the risk that a panic from within any interrupt handler may block the drm panic handler. The current design is that the panic handler will just use try_lock(), and if it can't take it, the panic screen will not be seen. The goal is to make sure drm_panic won't crash the machine and prevent kdump or other panic handler to run. So there is a very small race chance that the panic screen won't be seen, but that's ok. So I think in this case the drm panic handler shouldn't be blocked, as it only use try_lock(). Best regards, -- Jocelyn John Ogness
Re: [RFC] How to test panic handlers, without crashing the kernel
On 05/03/2024 18:50, Guilherme G. Piccoli wrote: On 05/03/2024 13:52, Jocelyn Falempe wrote: [...] Or maybe have two lists of panic notifiers, the safe and the destructive list. So in case of fake panic, we can only call the safe notifiers. I tried something like that: https://lore.kernel.org/lkml/20220427224924.592546-1-gpicc...@igalia.com/ There were many suggestions, a completely refactor of the idea (panic lists are not really seen as reliable things). Thanks for sharing this, so it's much more complex than what I though. Given that, I'm not really sure splitting in lists gonna fly; maybe restricting the test infrastructure to drm_panic plus some paths of panic would be enough for this debugfs interface, in principle? I mean, to unblock your work on the drm panic stuff. For drm_panic, I changed the way the debugfs is calling the drm_panic functions in the last version: https://patchwork.freedesktop.org/patch/581845/?series=122244=9 It doesn't use the panic notifier list, but create a file for each plane of each device directly. It allows to test the panic handler, not in a real panic condition, but that's still better than nothing. Cheers, Guilherme Best regards, -- Jocelyn
Re: [PATCH v9 2/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
Hi, On 07/03/2024 16:41, Thomas Zimmermann wrote: Am 07.03.24 um 15:08 schrieb Thomas Zimmermann: Hi Am 07.03.24 um 10:14 schrieb Jocelyn Falempe: This is needed for drm_panic, to draw the font, and fill the background color, in multiple color format. As you know, I'm not happy about this patch and the the changes do not reflect my easier s/easier/earlier review. These format helpers are supposed to serve all of DRM and not just the panic handler. I know that the current code isn't perfect, but the R1 support is a step backwards IMHO. I suggest to the drawing routines entirely within the panic-handler code and maybe try to sort out things later. IIRC that's how it was in earlier revisions of the patchset. Sorry I didn't change this patch in v8 and v9, I was focusing on locking and the overall design. I agree to move this back to drm_panic.c, so we can merge a first version of drm_panic. And when a generic format converter will be ready, I will do the patch to use it. 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 --- 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..2d9646cefc4f 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 __le16 drm_format_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le32 drm_format_xrgb_to_argb(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 |= GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format
[PATCH v9 9/9] drm/ast: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/ast/ast_mode.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index a718646a66b8..49f2d8bd3377 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -700,12 +701,29 @@ static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x1, 0xdf, 0x20); } +static int ast_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct ast_plane *ast_plane = to_ast_plane(plane); + + if (plane->state && plane->state->fb && ast_plane->vaddr) { + 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(>map, ast_plane->vaddr); + return 0; + } + return -ENODEV; +} + static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .atomic_check = ast_primary_plane_helper_atomic_check, .atomic_update = ast_primary_plane_helper_atomic_update, .atomic_enable = ast_primary_plane_helper_atomic_enable, .atomic_disable = ast_primary_plane_helper_atomic_disable, + .get_scanout_buffer = ast_primary_plane_helper_get_scanout_buffer, }; static const struct drm_plane_funcs ast_primary_plane_funcs = { -- 2.43.2
[PATCH v9 7/9] drm/mgag200: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.h | 7 ++- drivers/gpu/drm/mgag200/mgag200_mode.c | 18 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 765e49fd8911..58a0e62eaf18 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -366,6 +366,7 @@ struct drm_crtc_state; struct drm_display_mode; struct drm_plane; struct drm_atomic_state; +struct drm_scanout_buffer; extern const uint32_t mgag200_primary_plane_formats[]; extern const size_t mgag200_primary_plane_formats_size; @@ -379,12 +380,16 @@ void mgag200_primary_plane_helper_atomic_enable(struct drm_plane *plane, struct drm_atomic_state *state); void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *old_state); +int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb); + #define MGAG200_PRIMARY_PLANE_HELPER_FUNCS \ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, \ .atomic_check = mgag200_primary_plane_helper_atomic_check, \ .atomic_update = mgag200_primary_plane_helper_atomic_update, \ .atomic_enable = mgag200_primary_plane_helper_atomic_enable, \ - .atomic_disable = mgag200_primary_plane_helper_atomic_disable + .atomic_disable = mgag200_primary_plane_helper_atomic_disable, \ + .get_scanout_buffer = mgag200_primary_plane_helper_get_scanout_buffer #define MGAG200_PRIMARY_PLANE_FUNCS \ .update_plane = drm_atomic_helper_update_plane, \ diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index e17cb4c5f774..8f368ecca4d4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -546,6 +547,23 @@ void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, msleep(20); } +int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct mga_device *mdev = to_mga_device(plane->dev); + struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram); + + if (plane->state && plane->state->fb) { + 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; +} + /* * CRTC */ -- 2.43.2
[PATCH v9 8/9] drm/imx: Add drm_panic support
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 v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index dade8b59feae..3e21d2a1a124 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -772,6 +772,12 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { .atomic_disable = ipu_plane_atomic_disable, .atomic_update = ipu_plane_atomic_update, }; +static const struct drm_plane_helper_funcs ipu_primary_plane_helper_funcs = { + .atomic_check = ipu_plane_atomic_check, + .atomic_disable = ipu_plane_atomic_disable, + .atomic_update = ipu_plane_atomic_update, + .get_scanout_buffer = drm_panic_gem_get_scanout_buffer, +}; bool ipu_plane_atomic_update_pending(struct drm_plane *plane) { @@ -916,7 +922,10 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - drm_plane_helper_add(_plane->base, _plane_helper_funcs); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(_plane->base, _primary_plane_helper_funcs); + else + drm_plane_helper_add(_plane->base, _plane_helper_funcs); if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) ret = drm_plane_create_zpos_property(_plane->base, zpos, 0, -- 2.43.2
[PATCH v9 6/9] drm/simpledrm: Add drm_panic support
Add support for the drm_panic module, which displays a user-friendly message to the screen when a kernel panic occurs. v8: * Replace get_scanout_buffer() with drm_panic_set_buffer() (Thomas Zimmermann) v9: * Revert to using get_scanout_buffer() (Sima) * move get_scanout_buffer() to plane helper functions (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/tiny/simpledrm.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 7ce1c4617675..f498665be8c4 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define DRIVER_NAME"simpledrm" @@ -671,11 +672,26 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan drm_dev_exit(idx); } +static int simpledrm_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, +struct drm_scanout_buffer *sb) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(plane->dev); + + sb->width = sdev->mode.hdisplay; + sb->height = sdev->mode.vdisplay; + sb->format = sdev->format; + sb->pitch = sdev->pitch; + sb->map = sdev->screen_base; + + return 0; +} + static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .atomic_check = simpledrm_primary_plane_helper_atomic_check, .atomic_update = simpledrm_primary_plane_helper_atomic_update, .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, + .get_scanout_buffer = simpledrm_primary_plane_helper_get_scanout_buffer, }; static const struct drm_plane_funcs simpledrm_primary_plane_funcs = { -- 2.43.2
[PATCH v9 3/9] drm/panic: Add a drm panic handler
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. v8 * Register directly each plane to the panic notifier (Sima) * Add raw_spinlock to properly handle concurrency (Sima) * Register plane instead of device, to avoid looping through plane list, and simplify code. * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) * Removed the draw_pixel_xy() API, will see later if it can be added back. v9 * Revert to using get_scanout_buffer() (Sima) * Move get_scanout_buffer() and panic_flush() to the plane helper functions (Thomas Zimmermann) * Register all planes with get_scanout_buffer() to the panic notifier * Use drm_panic_lock() to protect against race (Sima) Signed-off-by: Jocelyn Falempe --- Documentation/gpu/drm-kms.rst| 12 + drivers/gpu/drm/Kconfig | 23 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_drv.c| 4 + drivers/gpu/drm/drm_panic.c | 322 +++ drivers/gpu/drm/drm_plane.c | 1 + include/drm/drm_modeset_helper_vtables.h | 37 +++ include/drm/drm_panic.h | 52 include/drm/drm_plane.h | 5 + 9 files changed, 457 insertions(+) create mode 100644 drivers/gpu/drm/drm_panic.c diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 13d3627d8bc0..b64334661aeb 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -398,6 +398,18 @@ Plane Damage Tracking Functions Reference .. kernel-doc:: include/drm/drm_damage_helper.h :internal: +Plane Panic Feature +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :doc: overview + +Plane Panic Functions Reference +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :export: + Display Modes Function Reference diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 16029435b750..f07ca38d3f98 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -102,6 +102,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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 a73c04d2d7a3..f9ca4f8fa6c5 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -88,6 +88,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
[PATCH v9 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) v9: * go back to get_scanout_buffer() * move get_scanout_buffer() to plane helper functions Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_fb_dma_helper.c | 47 + include/drm/drm_fb_dma_helper.h | 4 +++ 2 files changed, 51 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 3b535ad1b07c..010327069ad4 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,3 +149,49 @@ 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) +/** + * @plane: DRM primary plane + * @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_plane *plane, +struct drm_scanout_buffer *sb) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_framebuffer *fb; + + fb = plane->state->fb; + /* Only support linear modifier */ + if (fb->modifier != DRM_FORMAT_MOD_LINEAR) + return -ENODEV; + + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + + /* Buffer should be accessible from the CPU */ + if (dma_obj->base.import_attach) + return -ENODEV; + + /* Buffer should be already mapped to CPU */ + if (!dma_obj->vaddr) + return -ENODEV; + + iosys_map_set_vaddr(>map, dma_obj->vaddr); + sb->format = fb->format; + sb->height = fb->height; + sb->width = fb->width; + sb->pitch = fb->pitches[0]; + return 0; +} +#else +int drm_panic_gem_get_scanout_buffer(struct drm_plane *plane, +struct drm_scanout_buffer *sb) +{ + return -ENODEV; +} +#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..61f24c2aba2f 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_plane *plane, +struct drm_scanout_buffer *sb); + #endif -- 2.43.2
[PATCH v9 4/9] drm/panic: Add debugfs entry to test without triggering panic.
Add a debugfs file, so you can test drm_panic without freezing your machine. This is unsafe, and should be enabled only for developer or tester. To display the drm_panic screen on the device 0: echo 1 > /sys/kernel/debug/dri/0/drm_panic_plane_0 v9: * Create a debugfs file for each plane in the device's debugfs directory. This allows to test for each plane of each GPU independently. Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/Kconfig | 9 + drivers/gpu/drm/drm_panic.c | 38 + 2 files changed, 47 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f07ca38d3f98..6e41fbd16b3d 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -125,6 +125,15 @@ config DRM_PANIC_BACKGROUND_COLOR depends on DRM_PANIC default 0x00 +config DRM_PANIC_DEBUG + bool "Add a debug fs entry to trigger drm_panic" + depends on DRM_PANIC && DEBUG_FS + help + Add dri/[device]/drm_panic_plane_x in the kernel debugfs, to force the + panic handler to write the panic message to this plane scanout buffer. + This is unsafe and should not be enabled on a production build. + If in doubt, say "N". + 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/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 2e2a033d1267..24dc1f1a388f 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -270,6 +270,43 @@ static int drm_panic(struct notifier_block *this, unsigned long event, return NOTIFY_OK; } + +/* + * DEBUG FS, This is currently unsafe. + * Create one file per plane, so it's possible to debug one plane at a time. + */ +#ifdef CONFIG_DRM_PANIC_DEBUG +#include + +static ssize_t debugfs_trigger_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + bool run; + + if (kstrtobool_from_user(user_buf, count, ) == 0 && run) { + struct drm_plane *plane = file->private_data; + + draw_panic_plane(plane, "Test from debugfs"); + } + return count; +} + +static const struct file_operations dbg_drm_panic_ops = { + .owner = THIS_MODULE, + .write = debugfs_trigger_write, + .open = simple_open, +}; + +static void debugfs_register_plane(struct drm_plane *plane, int index) +{ + char fname[32]; + + snprintf(fname, 32, "drm_panic_plane_%d", index); + debugfs_create_file(fname, 0200, plane->dev->debugfs_root, + plane, _drm_panic_ops); +} +#endif /* CONFIG_DRM_PANIC_DEBUG */ + /** * drm_panic_register() - Initialize DRM panic for a device * @dev: the drm device on which the panic screen will be displayed. @@ -291,6 +328,7 @@ void drm_panic_register(struct drm_device *dev) >panic_notifier)) { drm_warn(dev, "Failed to register panic handler\n"); } else { + debugfs_register_plane(plane, registered_plane); registered_plane++; } } -- 2.43.2
[PATCH v9 2/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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 --- 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..2d9646cefc4f 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 __le16 drm_format_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le32 drm_format_xrgb_to_argb(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 |= GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb 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_xrgb(u32 color, u32 format) +{ + __le32 pix = cpu_to_le32(color); + + switch (format) { + case DRM_FORMAT_RGB565: + return le16_to_cpu(drm_format_xrgb_to_rgb565(pix)); + case DRM_FORMAT_RGBA5551: + return le16_to_cpu(drm_format_xrgb_to_rgba5551(pix)); + case DRM_FORMAT_XRGB1555: + return le16_to_cpu(drm_format_xrgb_to_xrgb1555(pix)); + case DRM_FORMAT_ARGB1555: + return le16_to_cpu(drm_format
[PATCH v9 1/9] drm/panic: Add drm panic locking
From: Daniel Vetter Rough sketch for the locking of drm panic printing code. The upshot of this approach is that we can pretty much entirely rely on the atomic commit flow, with the pair of raw_spin_lock/unlock providing any barriers we need, without having to create really big critical sections in code. This also avoids the need that drivers must explicitly update the panic handler state, which they might forget to do, or not do consistently, and then we blow up in the worst possible times. It is somewhat racy against a concurrent atomic update, and we might write into a buffer which the hardware will never display. But there's fundamentally no way to avoid that - if we do the panic state update explicitly after writing to the hardware, we might instead write to an old buffer that the user will barely ever see. Note that an rcu protected deference of plane->state would give us the the same guarantees, but it has the downside that we then need to protect the plane state freeing functions with call_rcu too. Which would very widely impact a lot of code and therefore doesn't seem worth the complexity compared to a raw spinlock with very tiny critical sections. Plus rcu cannot be used to protect access to peek/poke registers anyway, so we'd still need it for those cases. Peek/poke registers for vram access (or a gart pte reserved just for panic code) are also the reason I've gone with a per-device and not per-plane spinlock, since usually these things are global for the entire display. Going with per-plane locks would mean drivers for such hardware would need additional locks, which we don't want, since it deviates from the per-console takeoverlocks design. Longer term it might be useful if the panic notifiers grow a bit more structure than just the absolute bare EXPORT_SYMBOL(panic_notifier_list) - somewhat aside, why is that not EXPORT_SYMBOL_GPL ... If panic notifiers would be more like console drivers with proper register/unregister interfaces we could perhaps reuse the very fancy console lock with all it's check and takeover semantics that John Ogness is developing to fix the console_lock mess. But for the initial cut of a drm panic printing support I don't think we need that, because the critical sections are extremely small and only happen once per display refresh. So generally just 60 tiny locked sections per second, which is nothing compared to a serial console running a 115kbaud doing really slow mmio writes for each byte. So for now the raw spintrylock in drm panic notifier callback should be good enough. Another benefit of making panic notifiers more like full blown consoles (that are used in panics only) would be that we get the two stage design, where first all the safe outputs are used. And then the dangerous takeover tricks are deployed (where for display drivers we also might try to intercept any in-flight display buffer flips, which if we race and misprogram fifos and watermarks can hang the memory controller on some hw). For context the actual implementation on the drm side is by Jocelyn and this patch is meant to be combined with the overall approach in v7 (v8 is a bit less flexible, which I think is the wrong direction): https://lore.kernel.org/dri-devel/20240104160301.185915-1-jfale...@redhat.com/ Note that the locking is very much not correct there, hence this separate rfc. v2: - fix authorship, this was all my typing - some typo oopsies - link to the drm panic work by Jocelyn for context Signed-off-by: Daniel Vetter Cc: Jocelyn Falempe Cc: Andrew Morton Cc: "Peter Zijlstra (Intel)" Cc: Lukas Wunner Cc: Petr Mladek Cc: Steven Rostedt Cc: John Ogness Cc: Sergey Senozhatsky Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 3 + drivers/gpu/drm/drm_drv.c | 1 + include/drm/drm_mode_config.h | 10 +++ include/drm/drm_panic.h | 99 + 4 files changed, 113 insertions(+) create mode 100644 include/drm/drm_panic.h diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 39ef0a6addeb..c0bb91312fb2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -3099,6 +3100,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, } } + drm_panic_lock(state->dev); for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { WARN_ON(plane->state != old_plane_state); @@ -3108,6 +3110,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, state->planes[i].state = old_plane_state; plane->state = new_plane_state; } + drm_panic_unlock(state->dev); for_each_oldnew_pri
[PATCH v9 0/9] drm/panic: Add a drm panic handler
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. To test it, make sure you're using one of the supported driver, and trigger a panic: echo c > /proc/sysrq-trigger or you can enable CONFIG_DRM_PANIC_DEBUG and echo 1 > /sys/kernel/debug/dri/0/drm_panic_plane_0 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) v8: * Directly register each plane to the panic notifier (Sima) * Replace get_scanout_buffer() with set_scanout_buffer() to simplify the locking. (Thomas Zimmermann) * Add a debugfs entry, to trigger the drm_panic without a real panic (Sima) * Fix the drm_panic Documentation, and include it in drm-kms.rst v9: * Revert to using get_scanout_buffer() (Sima) * Move get_scanout_buffer() and panic_flush() to the plane helper functions (Thomas Zimmermann) * Register all planes with get_scanout_buffer() to the panic notifier * Use drm_panic_lock() to protect against race (Sima) * Create a debugfs file for each plane in the device's debugfs directory. This allows to test for each plane of each GPU independently. Daniel Vetter (1): drm/panic: Add drm panic locking Jocelyn Falempe (8): drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill drm/panic: Add a drm panic handler drm/panic: Add debugfs entry to test without triggering panic. drm/fb_dma: Add generic get_scanout_buffer() for drm_panic drm/simpledrm: Add drm_panic support drm/mgag200: Add drm_panic support drm/imx: Add drm_panic support drm/ast: Add drm_panic support Documentation/gpu/drm-kms.rst| 12 + drivers/gpu/drm/Kconfig | 32 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ast/ast_mode.c | 18 + drivers/gpu/drm/drm_atomic_helper.c | 3 + drivers/gpu/drm/drm_drv.c| 5 + drivers/gpu/drm/drm_fb_dma_helper.c | 47 +++ drivers/gpu/drm/drm_format_helper.c | 432 ++- drivers/gpu/drm/drm_panic.c | 360 +++ drivers/gpu/drm/drm_plane.c | 1 + drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 11 +- drivers/gpu/drm/mgag200/mgag200_drv.h| 7 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 18 + drivers/gpu/drm/tiny/simpledrm.c | 16 + include/drm/drm_fb_dma_helper.h | 4 + include/drm/drm_format_helper.h | 9 + include/drm/drm_mode_config.h| 10 + include/drm/drm_modeset_helper_vtables.h | 37 ++ include/drm/drm_panic.h | 151 include/drm/drm_plane.h | 5 + 20 files changed, 1096 insertions(+), 83 deletions(-) create mode 100644 drivers/gpu/drm/drm_panic.c create mode 100644 inclu
Re: [RFC] How to test panic handlers, without crashing the kernel
On 05/03/2024 17:23, Michael Kelley wrote: From: Guilherme G. Piccoli Sent: Monday, March 4, 2024 1:43 PM On 04/03/2024 18:12, John Ogness wrote: [...] The second question is how to simulate a panic context in a non-destructive way, so we can test the panic notifiers in CI, without crashing the machine. I'm wondering if a "fake panic" can be implemented that quiesces all the other CPUs via NMI (similar to kdb) and then calls the panic notifiers. And finally releases everything back to normal. That might produce a fairly realistic panic situation and should be fairly non-destructive (depending on what the notifiers do and how long they take). Hi Jocelyn / John, one concern here is that the panic notifiers are kind of a no man's land, so we can have very simple / safe ones, while others are destructive in nature. An example of a good behaving notifier that is destructive is the Hyper-V one, that destroys an essential host-guest interface (called "vmbus connection"). What happens if we trigger this one just for testing purposes in a debugfs interface? Likely the guest would die... [+CCing Michael Kelley here since he seems interested in panic and is also expert in Hyper-V, just in case my example is bogus.] The Hyper-V example is valid. After hv_panic_vmbus_unload() is called, the VM won't be able to do any disk, network, or graphics frame buffer I/O. There's no recovery short of restarting the VM. Thanks for the confirmation. Michael [I have retired from Microsoft. I'm still occasionally contributing to Linux kernel work with email mhkli...@outlook.com.] So, maybe the problem could be split in 2: the non-notifiers portion of the panic path, and the the notifiers; maybe restricting the notifiers you'd run is a way to circumvent the risks, like if you could pass a list of the specific notifiers you aim to test, this could be interesting. Let's see what the others think and thanks for your work in the DRM panic notifier =) Or maybe have two lists of panic notifiers, the safe and the destructive list. So in case of fake panic, we can only call the safe notifiers. Cheers, Guilherme
Re: [RFC] How to test panic handlers, without crashing the kernel
On 04/03/2024 22:12, John Ogness wrote: [Added printk maintainer and kdb folks] Hi Jocelyn, On 2024-03-01, Jocelyn Falempe wrote: While writing a panic handler for drm devices [1], I needed a way to test it without crashing the machine. So from debugfs, I called atomic_notifier_call_chain(_notifier_list, ...), but it has the side effect of calling all other panic notifiers registered. So Sima suggested to move that to the generic panic code, and test all panic notifiers with a dedicated debugfs interface. I can move that code to kernel/, but before doing that, I would like to know if you think that's the right way to test the panic code. One major event that happens before the panic notifiers is panic_other_cpus_shutdown(). This can cause special situations because CPUs can be stopped while holding resources (such as raw spin locks). And these are the situations that make it so tricky to have safe and reliable notifiers. If triggered from debugfs, these situations will never occur. My concern is that the tests via debugfs will always succeed, but in the real world panic notifiers are failing/hanging/exploding. IMHO useful panic testing requires real panic'ing. Yes, but for the drm panic, it's still useful to check that the output is working (ie: make sure the color format and the framebuffer address are good). Also I've reworked the debugfs patch, so I don't have to call all panic notifiers. It's now per device, so your can trigger the drm_panic handler on a specific GPU. For my printk panic tests I trigger unknown NMIs while booting with "unknown_nmi_panic". Particularly with Qemu this is quite easy and amazingly effective at catching problems. In fact, a recent printk series [0] fixed seven issues that were found through this method of panic testing. Thanks for this tip, I used to test with "echo c > /proc/sysrq-trigger" in the guest, but that's more permissive. I'm now testing with virsh inject-nmi, and drm_panic is still working. The second question is how to simulate a panic context in a non-destructive way, so we can test the panic notifiers in CI, without crashing the machine. I'm wondering if a "fake panic" can be implemented that quiesces all the other CPUs via NMI (similar to kdb) and then calls the panic notifiers. And finally releases everything back to normal. That might produce a fairly realistic panic situation and should be fairly non-destructive (depending on what the notifiers do and how long they take). The worst case for a panic notifier, is when the panic occurs in NMI context, but I don't know how to simulate that. The goal would be to find early if a panic notifier tries to sleep, or do other things that are not allowed in a panic context. Maybe with a new boot argument "unknown_nmi_fake_panic" that triggers the fake panic instead? John Ogness [0] https://lore.kernel.org/lkml/20240207134103.1357162-1-john.ogn...@linutronix.de Best regards, -- Jocelyn
Re: [RFC] drm/panic: Add drm panic locking
Thanks for the patch. I think it misses to initialize the lock, so we need to add a raw_spin_lock_init() in the drm device initialization. Also I'm wondering if it make sense to put that under the CONFIG_DRM_PANIC flag, so that if you don't enable it, panic_lock() and panic_unlock() would be no-op. But that may not work if the driver uses this lock to protect some register access. Best regards, -- Jocelyn On 01/03/2024 11:39, Daniel Vetter wrote: Rough sketch for the locking of drm panic printing code. The upshot of this approach is that we can pretty much entirely rely on the atomic commit flow, with the pair of raw_spin_lock/unlock providing any barriers we need, without having to create really big critical sections in code. This also avoids the need that drivers must explicitly update the panic handler state, which they might forget to do, or not do consistently, and then we blow up in the worst possible times. It is somewhat racy against a concurrent atomic update, and we might write into a buffer which the hardware will never display. But there's fundamentally no way to avoid that - if we do the panic state update explicitly after writing to the hardware, we might instead write to an old buffer that the user will barely ever see. Note that an rcu protected deference of plane->state would give us the the same guarantees, but it has the downside that we then need to protect the plane state freeing functions with call_rcu too. Which would very widely impact a lot of code and therefore doesn't seem worth the complexity compared to a raw spinlock with very tiny critical sections. Plus rcu cannot be used to protect access to peek/poke registers anyway, so we'd still need it for those cases. Peek/poke registers for vram access (or a gart pte reserved just for panic code) are also the reason I've gone with a per-device and not per-plane spinlock, since usually these things are global for the entire display. Going with per-plane locks would mean drivers for such hardware would need additional locks, which we don't want, since it deviates from the per-console takeoverlocks design. Longer term it might be useful if the panic notifiers grow a bit more structure than just the absolute bare EXPORT_SYMBOL(panic_notifier_list) - somewhat aside, why is that not EXPORT_SYMBOL_GPL ... If panic notifiers would be more like console drivers with proper register/unregister interfaces we could perhaps reuse the very fancy console lock with all it's check and takeover semantics that John Ogness is developing to fix the console_lock mess. But for the initial cut of a drm panic printing support I don't think we need that, because the critical sections are extremely small and only happen once per display refresh. So generally just 60 tiny locked sections per second, which is nothing compared to a serial console running a 115kbaud doing really slow mmio writes for each byte. So for now the raw spintrylock in drm panic notifier callback should be good enough. Another benefit of making panic notifiers more like full blown consoles (that are used in panics only) would be that we get the two stage design, where first all the safe outputs are used. And then the dangerous takeover tricks are deployed (where for display drivers we also might try to intercept any in-flight display buffer flips, which if we race and misprogram fifos and watermarks can hang the memory controller on some hw). For context the actual implementation on the drm side is by Jocelyn and this patch is meant to be combined with the overall approach in v7 (v8 is a bit less flexible, which I think is the wrong direction): https://lore.kernel.org/dri-devel/20240104160301.185915-1-jfale...@redhat.com/ Note that the locking is very much not correct there, hence this separate rfc. v2: - fix authorship, this was all my typing - some typo oopsies - link to the drm panic work by Jocelyn for context Signed-off-by: Daniel Vetter Cc: Jocelyn Falempe Cc: Andrew Morton Cc: "Peter Zijlstra (Intel)" Cc: Lukas Wunner Cc: Petr Mladek Cc: Steven Rostedt Cc: John Ogness Cc: Sergey Senozhatsky Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 3 + include/drm/drm_mode_config.h | 10 +++ include/drm/drm_panic.h | 99 + 3 files changed, 112 insertions(+) create mode 100644 include/drm/drm_panic.h diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 40c2bd3e62e8..5a908c186037 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -3086,6 +3087,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state, } } + drm_panic_lock(state->dev); for_each_oldnew_plane_in_st
[RFC] How to test panic handlers, without crashing the kernel
Hi, While writing a panic handler for drm devices [1], I needed a way to test it without crashing the machine. So from debugfs, I called atomic_notifier_call_chain(_notifier_list, ...), but it has the side effect of calling all other panic notifiers registered. So Sima suggested to move that to the generic panic code, and test all panic notifiers with a dedicated debugfs interface. I can move that code to kernel/, but before doing that, I would like to know if you think that's the right way to test the panic code. The second question is how to simulate a panic context in a non-destructive way, so we can test the panic notifiers in CI, without crashing the machine. The worst case for a panic notifier, is when the panic occurs in NMI context, but I don't know how to simulate that. The goal would be to find early if a panic notifier tries to sleep, or do other things that are not allowed in a panic context. Best regards, -- Jocelyn [1] https://patchwork.freedesktop.org/patch/580183/?series=122244=8
Re: [PATCH v8 5/8] drm/simpledrm: Add drm_panic support
On 29/02/2024 12:17, Daniel Vetter wrote: On Tue, Feb 27, 2024 at 11:04:16AM +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. v8: * Replace get_scanout_buffer() with drm_panic_set_buffer() (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/tiny/simpledrm.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 7ce1c4617675..a2190995354a 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define DRIVER_NAME "simpledrm" @@ -735,6 +736,20 @@ static const struct drm_connector_funcs simpledrm_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; +static void simpledrm_init_panic_buffer(struct drm_plane *plane) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(plane->dev); + struct drm_framebuffer fb; + + /* Fake framebuffer struct for drm_panic_set_buffer */ + fb.width = sdev->mode.hdisplay; + fb.height = sdev->mode.vdisplay; + fb.format = sdev->format; + fb.pitches[0] = sdev->pitch; + + drm_panic_set_buffer(plane->panic_scanout, , >screen_base); +} + static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { .fb_create = drm_gem_fb_create_with_dirty, .atomic_check = drm_atomic_helper_check, @@ -945,6 +960,8 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, return ERR_PTR(ret); drm_plane_helper_add(primary_plane, _primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); Just a quick comment on this: This does not work, the driver is not ready to handle panic calls at this stage. Instead we need to automatically register all planes that support panic handling in drm_dev_register(), and we need to remove them all again in drm_dev_unregister(). Outside of these functions it is not safe to call into driver code. If you register the primary plane and didn't call drm_panic_set_buffer() yet, the panic handler will not do anything, so it should be safe. But if we revert to using the get_scanout_buffer(), this makes sense. At that point it might be simpler to only register one panic notifier per drm_device, and push the loop into the panic handler again. Cheers, Sima + simpledrm_init_panic_buffer(primary_plane); /* CRTC */ -- 2.43.0
Re: [PATCH v8 3/8] drm/panic: Add debugfs entry to test without triggering panic.
On 29/02/2024 12:21, Daniel Vetter wrote: On Tue, Feb 27, 2024 at 11:04:14AM +0100, Jocelyn Falempe wrote: Add a debugfs file, so you can test drm_panic without freezing your machine. This is unsafe, and should be enabled only for developer or tester. to display the drm_panic screen, just run: echo 1 > /sys/kernel/debug/drm_panic/trigger Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/Kconfig | 9 +++ drivers/gpu/drm/drm_panic.c | 47 + 2 files changed, 56 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c17d8a8f6877..8dcea29f595c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -125,6 +125,15 @@ config DRM_PANIC_BACKGROUND_COLOR depends on DRM_PANIC default 0x00 +config DRM_PANIC_DEBUG + bool "Add a debug fs entry to trigger drm_panic" + depends on DRM_PANIC && DEBUG_FS + help + Add drm_panic/trigger in the kernel debugfs, to force the panic + handler to write the panic message to the scanout buffer. This is + unsafe and should not be enabled on a production build. + If in doubt, say "N". + 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/drm_panic.c b/drivers/gpu/drm/drm_panic.c index c9f386476ef9..c5d3f725c5f5 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -398,3 +398,50 @@ void drm_panic_unregister(struct drm_plane *plane) } EXPORT_SYMBOL(drm_panic_unregister); + +/* + * DEBUG, This is currently unsafe. + * Also it will call all panic_notifier, since there is no way to filter and + * only call the drm_panic notifier. + */ +#ifdef CONFIG_DRM_PANIC_DEBUG +#include + +static struct dentry *debug_dir; +static struct dentry *debug_trigger; + +static ssize_t dbgfs_trigger_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + bool run; + + if (kstrtobool_from_user(user_buf, count, ) == 0 && run) + atomic_notifier_call_chain(_notifier_list, 0, "Test drm panic from debugfs"); Since this is just the general panic notifier it feels very misplaced in the drm subsystem. I think moving that code into the core panic code makes a lot more sense, then we'd also have all the right people on Cc: to figure out how we can best recreate the correct calling context (like nmi context or whatever) for best case simulation of panic code. John Ogness definitely needs to see this and ack, wherever we put it. I'm not sure it makes sense to test all panic notifiers at once. So maybe I can write an atomic_notifier_call_chain_with_filter(), and filter on the callback address, so it will only call the drm_panic handlers ? -- Jocelyn -Sima + return count; +} + +static const struct file_operations dbg_drm_panic_ops = { + .owner = THIS_MODULE, + .write = dbgfs_trigger_write, +}; + +static int __init debugfs_start(void) +{ + debug_dir = debugfs_create_dir("drm_panic", NULL); + + if (IS_ERR(debug_dir)) + return PTR_ERR(debug_dir); + debug_trigger = debugfs_create_file("trigger", 0200, debug_dir, + NULL, _drm_panic_ops); + return 0; +} + +static void __exit debugfs_end(void) +{ + debugfs_remove_recursive(debug_dir); +} + +module_init(debugfs_start); +module_exit(debugfs_end); + +#endif -- 2.43.0
[PATCH v8 4/8] drm/fb_dma: Add generic set_scanout_buffer() for drm_panic
This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_fb_dma_helper.c | 37 + include/drm/drm_fb_dma_helper.h | 4 2 files changed, 41 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 3b535ad1b07c..31ba71644e2b 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,3 +149,39 @@ 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) +/** + * drm_panic_gem_set_scanout_buffer - helper around drm_panic_set_buffer() + * + * @plane: primary plane registered to drm_panic + * @fb: framebuffer attached to the plane state + * + * Update plane->panic_scanout with the new framebuffer. + */ +void drm_panic_gem_set_scanout_buffer(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct drm_gem_dma_object *dma_obj; + struct iosys_map map; + + if (!plane->panic_scanout) + return; + + if (fb->modifier == DRM_FORMAT_MOD_LINEAR) { + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + if (dma_obj && dma_obj->vaddr) { + iosys_map_set_vaddr(, dma_obj->vaddr); + drm_panic_set_buffer(plane->panic_scanout, fb, ); + return; + } + } + drm_panic_unset_buffer(plane->panic_scanout); +} +#else +void drm_panic_gem_set_scanout_buffer(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ +} +#endif +EXPORT_SYMBOL(drm_panic_gem_set_scanout_buffer); diff --git a/include/drm/drm_fb_dma_helper.h b/include/drm/drm_fb_dma_helper.h index d5e036c57801..9f9ec11343cd 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); +void drm_panic_gem_set_scanout_buffer(struct drm_plane *plane, +struct drm_framebuffer *fb); + #endif -- 2.43.0
[PATCH v8 3/8] drm/panic: Add debugfs entry to test without triggering panic.
Add a debugfs file, so you can test drm_panic without freezing your machine. This is unsafe, and should be enabled only for developer or tester. to display the drm_panic screen, just run: echo 1 > /sys/kernel/debug/drm_panic/trigger Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/Kconfig | 9 +++ drivers/gpu/drm/drm_panic.c | 47 + 2 files changed, 56 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c17d8a8f6877..8dcea29f595c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -125,6 +125,15 @@ config DRM_PANIC_BACKGROUND_COLOR depends on DRM_PANIC default 0x00 +config DRM_PANIC_DEBUG + bool "Add a debug fs entry to trigger drm_panic" + depends on DRM_PANIC && DEBUG_FS + help + Add drm_panic/trigger in the kernel debugfs, to force the panic + handler to write the panic message to the scanout buffer. This is + unsafe and should not be enabled on a production build. + If in doubt, say "N". + 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/drm_panic.c b/drivers/gpu/drm/drm_panic.c index c9f386476ef9..c5d3f725c5f5 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -398,3 +398,50 @@ void drm_panic_unregister(struct drm_plane *plane) } EXPORT_SYMBOL(drm_panic_unregister); + +/* + * DEBUG, This is currently unsafe. + * Also it will call all panic_notifier, since there is no way to filter and + * only call the drm_panic notifier. + */ +#ifdef CONFIG_DRM_PANIC_DEBUG +#include + +static struct dentry *debug_dir; +static struct dentry *debug_trigger; + +static ssize_t dbgfs_trigger_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + bool run; + + if (kstrtobool_from_user(user_buf, count, ) == 0 && run) + atomic_notifier_call_chain(_notifier_list, 0, "Test drm panic from debugfs"); + return count; +} + +static const struct file_operations dbg_drm_panic_ops = { + .owner = THIS_MODULE, + .write = dbgfs_trigger_write, +}; + +static int __init debugfs_start(void) +{ + debug_dir = debugfs_create_dir("drm_panic", NULL); + + if (IS_ERR(debug_dir)) + return PTR_ERR(debug_dir); + debug_trigger = debugfs_create_file("trigger", 0200, debug_dir, + NULL, _drm_panic_ops); + return 0; +} + +static void __exit debugfs_end(void) +{ + debugfs_remove_recursive(debug_dir); +} + +module_init(debugfs_start); +module_exit(debugfs_end); + +#endif -- 2.43.0
[PATCH v8 8/8] drm/ast: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/ast/ast_mode.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index a718646a66b8..3d6d4c71bc34 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -656,9 +657,13 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); struct ast_vbios_mode_info *vbios_mode_info = _crtc_state->vbios_mode_info; + struct iosys_map map; ast_set_color_reg(ast, fb->format); ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info); + + iosys_map_set_vaddr_iomem(, ast_plane->vaddr); + drm_panic_set_buffer(plane->panic_scanout, fb, ); } drm_atomic_helper_damage_iter_init(, old_plane_state, plane_state); @@ -736,6 +741,7 @@ static int ast_primary_plane_init(struct ast_device *ast) } drm_plane_helper_add(primary_plane, _primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); return 0; } -- 2.43.0
[PATCH v8 5/8] drm/simpledrm: Add drm_panic support
Add support for the drm_panic module, which displays a user-friendly message to the screen when a kernel panic occurs. v8: * Replace get_scanout_buffer() with drm_panic_set_buffer() (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/tiny/simpledrm.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 7ce1c4617675..a2190995354a 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define DRIVER_NAME"simpledrm" @@ -735,6 +736,20 @@ static const struct drm_connector_funcs simpledrm_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; +static void simpledrm_init_panic_buffer(struct drm_plane *plane) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(plane->dev); + struct drm_framebuffer fb; + + /* Fake framebuffer struct for drm_panic_set_buffer */ + fb.width = sdev->mode.hdisplay; + fb.height = sdev->mode.vdisplay; + fb.format = sdev->format; + fb.pitches[0] = sdev->pitch; + + drm_panic_set_buffer(plane->panic_scanout, , >screen_base); +} + static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { .fb_create = drm_gem_fb_create_with_dirty, .atomic_check = drm_atomic_helper_check, @@ -945,6 +960,8 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, return ERR_PTR(ret); drm_plane_helper_add(primary_plane, _primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); + simpledrm_init_panic_buffer(primary_plane); /* CRTC */ -- 2.43.0
[PATCH v8 7/8] drm/imx: Add drm_panic support
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 v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index dade8b59feae..e820858732ec 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -765,6 +766,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts); ipu_plane_enable(ipu_plane); + + drm_panic_gem_set_scanout_buffer(plane, fb); } static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { @@ -942,6 +945,8 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, zpos ? "overlay" : "primary", ); return ERR_PTR(ret); } + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_panic_register(_plane->base); return ipu_plane; } -- 2.43.0
[PATCH v8 6/8] drm/mgag200: Add drm_panic support
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() v8: * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_g200.c| 2 ++ drivers/gpu/drm/mgag200/mgag200_g200eh.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200se.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200wb.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_mode.c| 7 +++ 9 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index bf5d7fe525a3..1af71785733a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -217,6 +218,7 @@ static int mgag200_g200_pipeline_init(struct mga_device *mdev) } drm_plane_helper_add(primary_plane, _g200_primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, _g200_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index fad62453a91d..759cff8480f7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -216,6 +217,7 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev) } drm_plane_helper_add(primary_plane, _g200eh_primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, _g200eh_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 0f7d8112cd49..753b3292a384 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -120,6 +121,7 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev) } drm_plane_helper_add(primary_plane, _g200eh3_primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, _g200eh3_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 8d4538b71047..3dd6120bf9bb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -259,6 +260,7 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev) } drm_plane_helper_add(primary_plane, _g200er_primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, _g200er_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 56e6f986bff3..28476a93c9ba 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "mgag200_drv.h" @@ -260,6 +261,7 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev) } drm_plane_helper_add(primary_plane, _g200ev_primary_plane_helper_funcs); drm_plane_enable_fb_damage_clips(primary_plane); + drm_panic_register(primary_plane); ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, _g200ev_crtc_funcs, NULL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 170934414d7d..f7c17bc52afc 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "mgag200_drv.h"
[PATCH v8 2/8] drm/panic: Add a drm panic handler
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. v8 * Register directly each plane to the panic notifier (Sima) * Add raw_spinlock to properly handle concurrency (Sima) * Register plane instead of device, to avoid looping through plane list, and simplify code. * Replace get_scanout_buffer() logic with drm_panic_set_buffer() (Thomas Zimmermann) * Removed the draw_pixel_xy() API, will see later if it can be added back. Signed-off-by: Jocelyn Falempe --- Documentation/gpu/drm-kms.rst| 12 + drivers/gpu/drm/Kconfig | 23 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_panic.c | 400 +++ drivers/gpu/drm/drm_plane.c | 3 + include/drm/drm_modeset_helper_vtables.h | 11 + include/drm/drm_panic.h | 37 +++ include/drm/drm_plane.h | 17 + 8 files changed, 504 insertions(+) create mode 100644 drivers/gpu/drm/drm_panic.c create mode 100644 include/drm/drm_panic.h diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 13d3627d8bc0..b64334661aeb 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -398,6 +398,18 @@ Plane Damage Tracking Functions Reference .. kernel-doc:: include/drm/drm_damage_helper.h :internal: +Plane Panic Feature +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :doc: overview + +Plane Panic Functions Reference +--- + +.. kernel-doc:: drivers/gpu/drm/drm_panic.c + :export: + Display Modes Function Reference diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 872edb47bb53..c17d8a8f6877 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -102,6 +102,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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 104b42df2e95..49905b7e333f 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_panic.c b/drivers/gpu/drm/drm_panic.c new file mode 100644 index ..c9f386476ef9 --- /dev/null +++ b/drivers/gpu/drm/drm_panic.c @@ -0,0 +1,40
[PATCH v8 1/8] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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 --- 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..2d9646cefc4f 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 __le16 drm_format_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static __le32 drm_format_xrgb_to_argb(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 |= GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb 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_xrgb(u32 color, u32 format) +{ + __le32 pix = cpu_to_le32(color); + + switch (format) { + case DRM_FORMAT_RGB565: + return le16_to_cpu(drm_format_xrgb_to_rgb565(pix)); + case DRM_FORMAT_RGBA5551: + return le16_to_cpu(drm_format_xrgb_to_rgba5551(pix)); + case DRM_FORMAT_XRGB1555: + return le16_to_cpu(drm_format_xrgb_to_xrgb1555(pix)); + case DRM_FORMAT_ARGB1555: + return le16_to_cpu(drm_format
[RFC][PATCH v8 0/8] drm/panic: Add a drm panic handler
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. To test it, make sure you're using one of the supported driver, and trigger a panic: echo c > /proc/sysrq-trigger or you can enable CONFIG_DRM_PANIC_DEBUG and echo 1 > /sys/kernel/debug/drm_panic/trigger 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) v8: * Directly register each plane to the panic notifier (Sima) * Replace get_scanout_buffer() with set_scanout_buffer() to simplify the locking. (Thomas Zimmermann) * Add a debugfs entry, to trigger the drm_panic without a real panic (Sima) * Fix the drm_panic Documentation, and include it in drm-kms.rst Best regards, Jocelyn Falempe (8): drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill drm/panic: Add a drm panic handler drm/panic: Add debugfs entry to test without triggering panic. drm/fb_dma: Add generic set_scanout_buffer() for drm_panic drm/simpledrm: Add drm_panic support drm/mgag200: Add drm_panic support drm/imx: Add drm_panic support drm/ast: Add drm_panic support Documentation/gpu/drm-kms.rst | 12 + drivers/gpu/drm/Kconfig | 32 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ast/ast_mode.c| 6 + drivers/gpu/drm/drm_fb_dma_helper.c | 37 ++ drivers/gpu/drm/drm_format_helper.c | 432 + drivers/gpu/drm/drm_panic.c | 447 ++ drivers/gpu/drm/drm_plane.c | 3 + drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 5 + drivers/gpu/drm/mgag200/mgag200_g200.c| 2 + drivers/gpu/drm/mgag200/mgag200_g200eh.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200se.c | 2 + drivers/gpu/drm/mgag200/mgag200_g200wb.c | 2 + drivers/gpu/drm/mgag200/mgag200_mode.c| 7 + drivers/gpu/drm/tiny/simpledrm.c | 17 + include/drm/drm_fb_dma_helper.h | 4 + include/drm/drm_format_helper.h | 9 + include/drm/drm_modeset_helper_vtables.h | 11 + include/drm/drm_panic.h | 37 ++ include/drm/drm_plane.h | 17 + 24 files changed, 1012 insertions(+), 81 deletions(-) create mode 100644 drivers/gpu/drm/drm_panic.c create mode 100644 include/drm/drm_panic.h base-commit: bfa4437fd3938ae2e186e7664b2db65bb8775670 -- 2.43.0
Re: [PATCH v2] drm/mgag200: Add a workaround for low-latency
On 08/02/2024 12:49, Thomas Zimmermann wrote: Am 08.02.24 um 10:51 schrieb Jocelyn Falempe: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) The regression has been bisected to 2 commits: commit 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") commit 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by this commit, which restore WC mapping for the framebuffer in system memory, and add a cache flush. This is only needed on x86_64, for low-latency workload, so the new kconfig DRM_MGAG200_IOBURST_WORKAROUND depends on PREEMPT_RT and X86. For more context, the whole thread can be found here [1] Signed-off-by: Jocelyn Falempe Link: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ # 1 Acked-by: Thomas Zimmermann Applied to drm-misc-next. Thanks, -- Jocelyn
[PATCH v2] drm/mgag200: Add a workaround for low-latency
We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) The regression has been bisected to 2 commits: commit 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") commit 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by this commit, which restore WC mapping for the framebuffer in system memory, and add a cache flush. This is only needed on x86_64, for low-latency workload, so the new kconfig DRM_MGAG200_IOBURST_WORKAROUND depends on PREEMPT_RT and X86. For more context, the whole thread can be found here [1] Signed-off-by: Jocelyn Falempe Link: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ # 1 --- drivers/gpu/drm/mgag200/Kconfig| 12 drivers/gpu/drm/mgag200/mgag200_drv.c | 17 + drivers/gpu/drm/mgag200/mgag200_mode.c | 8 3 files changed, 37 insertions(+) diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index b28c5e4828f4..5e4d48df4854 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -11,3 +11,15 @@ config DRM_MGAG200 MGA G200 desktop chips and the server variants. It requires 0.3.0 of the modesetting userspace driver, and a version of mga driver that will fail on KMS enabled devices. + +config DRM_MGAG200_IOBURST_WORKAROUND + bool "Disable buffer caching" + depends on DRM_MGAG200 && PREEMPT_RT && X86 + help + Enable a workaround to avoid I/O bursts within the mgag200 driver at + the expense of overall display performance. + It restores the map_wc = true; + return >base; +} +#endif + /* * DRM driver */ @@ -99,6 +113,9 @@ static const struct drm_driver mgag200_driver = { .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, +#if defined(CONFIG_DRM_MGAG200_IOBURST_WORKAROUND) + .gem_create_object = mgag200_create_object, +#endif DRM_GEM_SHMEM_DRIVER_OPS, }; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0eb769dd76ce..e17cb4c5f774 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -436,6 +437,13 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma iosys_map_incr(, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); drm_fb_memcpy(, fb->pitches, vmap, fb, clip); + + /* Flushing the cache greatly improves latency on x86_64 */ +#if defined(CONFIG_DRM_MGAG200_IOBURST_WORKAROUND) + if (!vmap->is_iomem) + drm_clflush_virt_range(vmap->vaddr + clip->y1 * fb->pitches[0], + drm_rect_height(clip) * fb->pitches[0]); +#endif } /* base-commit: 1f36d634670d8001a45fe2f2dcae546819f9c7d8 -- 2.43.0
Re: [PATCH] drm/mgag200: Add a workaround for low-latency
On 07/02/2024 10:47, Thomas Zimmermann wrote: Hi Am 06.02.24 um 23:21 schrieb Jocelyn Falempe: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) The regression has been bisected to 2 commits: commit 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") commit 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by this commit, which restore WC mapping for the framebuffer in system memory, and add a cache flush. This is only needed on x86_64, for low-latency workload, so the new kconfig DRM_MGAG200_LATENCY_WORKAROUND depends on PREEMPT_RT and X86. For more context, the whole thread can be found here: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ This URL should be in a Link tag below the SoB line, like this: Link: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ # 1 You can refer to it from within the text with [1]. ok Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/Kconfig | 10 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 17 + drivers/gpu/drm/mgag200/mgag200_mode.c | 8 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index b28c5e4828f4..73e4feba743a 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -11,3 +11,13 @@ config DRM_MGAG200 MGA G200 desktop chips and the server variants. It requires 0.3.0 of the modesetting userspace driver, and a version of mga driver that will fail on KMS enabled devices. + +config DRM_MGAG200_LATENCY_WORKAROUND Can we call this DRM_MGAG200_IOBURST_WORKAROUND? I know what you mean by latency, but that's not what is happening in the driver. The latency you refer to is the deterministic response time of your process, but the response time of the driver actually goes up (because of the disabled caching). + bool "Enable workaround for low latency server" This is a 'low-latency server'. But I'd just say "Disabled buffer caching", so that users know what they are getting into. + depends on DRM_MGAG200 && PREEMPT_RT && X86 + help + Enable a workaround to have better latency with mgag200 driver. Here I'd say "Enable a workaround to avoid I/O bursts within the mgag200 driver at the expense of overall display performance." + It restores the system + RAM as Write-Combining, and flushing the cache after each write. + This is only needed on x86_64 and if you want low-latency. Maybe "This is only useful on x86_64 if you want to run processes with deterministic latency." The code itself looks good to me. Thanks, I will send a v2 with all these changes. -- Jocelyn Best regards Thomas + If unsure, say N. diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 54fce00e2136..3fdef8b580cc 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -84,6 +84,20 @@ resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size) return offset - 65536; } +#if defined(CONFIG_DRM_MGAG200_LATENCY_WORKAROUND) +static struct drm_gem_object *mgag200_create_object(struct drm_device *dev, size_t size) +{ + struct drm_gem_shmem_object *shmem; + + shmem = kzalloc(sizeof(*shmem), GFP_KERNEL); + if (!shmem) + return NULL; + + shmem->map_wc = true; + return >base; +} +#endif + /* * DRM driver */ @@ -99,6 +113,9 @@ static const struct drm_driver mgag200_driver = { .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, +#if defined(CONFIG_DRM_MGAG200_LATENCY_WORKAROUND) + .gem_create_object = mgag200_create_object, +#endif DRM_GEM_SHMEM_DRIVER_OPS, }; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0eb769dd76ce..34ef9fb6e96c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -436,6 +437,13 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma iosys_map_incr(, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); drm_fb_memcpy(, fb->pitches,
[PATCH] drm/mgag200: Add a workaround for low-latency
We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) The regression has been bisected to 2 commits: commit 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") commit 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by this commit, which restore WC mapping for the framebuffer in system memory, and add a cache flush. This is only needed on x86_64, for low-latency workload, so the new kconfig DRM_MGAG200_LATENCY_WORKAROUND depends on PREEMPT_RT and X86. For more context, the whole thread can be found here: https://lore.kernel.org/dri-devel/20231019135655.313759-1-jfale...@redhat.com/ Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/Kconfig| 10 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 17 + drivers/gpu/drm/mgag200/mgag200_mode.c | 8 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index b28c5e4828f4..73e4feba743a 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -11,3 +11,13 @@ config DRM_MGAG200 MGA G200 desktop chips and the server variants. It requires 0.3.0 of the modesetting userspace driver, and a version of mga driver that will fail on KMS enabled devices. + +config DRM_MGAG200_LATENCY_WORKAROUND + bool "Enable workaround for low latency server" + depends on DRM_MGAG200 && PREEMPT_RT && X86 + help + Enable a workaround to have better latency with mgag200 driver. + It restores the map_wc = true; + return >base; +} +#endif + /* * DRM driver */ @@ -99,6 +113,9 @@ static const struct drm_driver mgag200_driver = { .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, +#if defined(CONFIG_DRM_MGAG200_LATENCY_WORKAROUND) + .gem_create_object = mgag200_create_object, +#endif DRM_GEM_SHMEM_DRIVER_OPS, }; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0eb769dd76ce..34ef9fb6e96c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -436,6 +437,13 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma iosys_map_incr(, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); drm_fb_memcpy(, fb->pitches, vmap, fb, clip); + + /* Flushing the cache greatly improves latency on x86_64 */ +#if defined(CONFIG_DRM_MGAG200_LATENCY_WORKAROUND) + if (!vmap->is_iomem) + drm_clflush_virt_range(vmap->vaddr + clip->y1 * fb->pitches[0], + drm_rect_height(clip) * fb->pitches[0]); +#endif } /* base-commit: 1f36d634670d8001a45fe2f2dcae546819f9c7d8 -- 2.43.0
Re: [PATCH] drm/mgag200: Flush the cache to improve latency
On 06/02/2024 14:33, Daniel Vetter wrote: On Mon, Dec 11, 2023 at 10:31:28AM +0100, Jocelyn Falempe wrote: On 06/11/2023 11:46, Jocelyn Falempe wrote: On 23/10/2023 10:30, Jocelyn Falempe wrote: On 20/10/2023 14:06, Thomas Zimmermann wrote: (cc'ing lkml for feedback) Hi Jocelyn Am 19.10.23 um 15:55 schrieb Jocelyn Falempe: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) I'd like to hear the opinion of the RT-devs on this patch. Because AFAIK we never did such a workaround in other drivers. And AFAIK printk is a PITA anyway. Most other drivers uses DMA, which means this workaround can't apply to them. IMHO if that RT system cannot handle differences in framebuffer caching, it's under-powered. It's just a matter of time until something else changes and the problem returns. And (honest question) as it's an x86-64, how do they handle System Management Mode? I think it's not a big news, that the Matrox G200 from 1999 is under-powered. I was also a bit surprised that flushing the cache would have such effect on latency. The tests we are doing can run 24h with the workaround, without any interrupt taking more than 10us. Without the workaround, every ~30s the interrupt failed its 10us target. The regression has been bisected to 2 commits: 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by the following patch, which forces a cache flush after each frame, reverting to almost v5.9 behavior. With that second commit, we essentially never unmap an active framebuffer console. But with commit 359c6649cd9a ("drm/gem: Implement shadow-plane {begin, end}_fb_access with vmap") we now again unmap the console framebuffer after the pageflip happened. So how does the latest kernel behave wrt to the problem? The regression was found when upgrading the server from v5.4 to v5.14, so we didn't test with later kernels. We will test with v6.3 (which should have 359c6649cd9a ) and see what it gives. I don't have a clear explanation, but testing with v6.3, and forcing the Write Combine, doesn't fix the latency issue. So forcing the cache flush is still needed. Also, on some systems, they use "isolated cpu" to handle RT task, but with a standard kernel (so without the CONFIG_PREEMPT_RT). So I'm wondering if we can use a kernel module parameter for this, so that users that wants to achieve low latency, can opt-in ? something like mgag200.force_cache_flush=1 or mgag200.low_latency=1 ? Hi, I have now access to a server that reproduce the issue, and I was able to test different workarounds. So it is definitely related to the "Write Combine" mode of the mga internal RAM. If I comment the two lines to enable wc: https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/mgag200/mgag200_drv.c#L150, then the latency is <10us (but the performances are worse, from 20ms to 87ms to draw a full frame). Ok this is very strange, but at least it starts to make sense. Apparently if we stream a _lot_ of writes from wb to wc memory on a cpu that results in high latencies on other cpus. And the only way to fix that is by artificially making the wb source suffer from cache misses by flushing them out. I also tried to flush the vram using: drm_clflush_virt_range(mdev->vram + clip->y1 * fb->pitches[0], drm_rect_height(clip) * fb->pitches[0]); And that lower the latency to ~20us, but it's not enough. I tried "sfence" which I though would flush the WC buffers of the CPU, but that has no effect in practice. I think I can send a new patch, to not map the VRAM as Write Combine, either if CONFIG_PREEMPT_RT is set or if a module parameter is set. What do you think is the best approach ? I think an mgag200 module option like Dave suggested is best. Plus the entire above debug story in the commit message, especially the things you've figured out in your latest testing (apologies for missing your mail from Dec, pls ping again if things get dropped like that) kinda explains what's going on. Still doesn't make much sense that a cpu doing a lot of wb->wc transfers can hurt other cores like this, but at least that seems technically plausible. Also please link to this thread for all the details on test setup, I think the above is enough as a summary for the commit message. But if you want you can include all the details below too. Thanks, Let me send a new pa
Re: [PATCH 00/23] [RFC] drm/format-helper: Introduce drm_pixmap, font support and filling
Hi Thomas, Thanks for taking the time to write this series. I find the drm_pixmap is a nice improvement, and simplifies a bit the code. Regarding the font blit, I'm not convinced by this approach. I don't see the benefit of using the same function between fonts and framebuffer copy, as it's unlikely to have 16bit or 32bit fonts in the kernel, or to have monochrome buffer from userspace. And the big format switch will dispatch to different functions, so there is almost no code sharing between both paths. Also for each format supported, you now need 2 functions for xrgb_to_y blit, 2 functions for c1_to_y blit, and 2 functions for fill_yy. That doesn't scale well, and there is a lot of duplication between those functions. I prefer the way Noralf Thronnes has done it in [1] and only consider the pixel width. [1] https://lore.kernel.org/dri-devel/20190311174218.51899-2-nor...@tronnes.org/ Best regards, -- Jocelyn On 30/01/2024 10:53, Thomas Zimmermann wrote: This RFC patchset implements various features required for DRM panic handling [1] and should (for now) be seen in that context. Most of all, the patchset replaces struct drm_framebuffer with struct drm_pixmap in the format-conversion helpers. DRM pixmap represents a source of pixel data for the blitting operations. Patches 1 to 19 update the interface, implementation and all of the callers. These patches could be useful even without DRM panic handling. With struct drm_pixmap in place, patches 20 to 22 implement rudimentary support for blitting font data. The pixmap refers to a character's glyph, which the blit routines write to the destination memory. An example on blitting strings is given in patch 20's commit description. Patch 23 adds rudimentary support for fill operations. The design is based on blitting, but blits the same color into each pixel. [1] https://patchwork.freedesktop.org/series/122244/ Thomas Zimmermann (23): drm/format-helper: Add struct drm_pixmap drm/format-helper: Use struct drm_pixmap for drm_fb_memcpy() drm/format-helper: Streamline drm_fb_xfrm() implementations drm/format-helper: Use struct drm_pixmap internally drm/format-helper: Use struct drm_pixmap for drm_fb_swab() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_rgb332() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_rgb565() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_xrgb1555() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_argb1555() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_rgba5551() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_rgb888() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_argb() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_abgr() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_xbgr() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_xrgb2101010() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_argb2101010() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_gray8() drm/format-helper: Use struct drm_pixmap for drm_fb_xrgb_to_mono() drm/format-helper: Use struct drm_pixmap for drm_fb_blit() [DO NOT MERGE] drm/format-helper: Add font-support for DRM pixmap [DO NOT MERGE] drm/format-helper: Add color palette [DO NOT MERGE] drm/format-helper: Support blitting from C1 to XRGB [DO NOT MERGE] drm/format-helper: Add drm_fb_fill() to fill screen with color drivers/gpu/drm/ast/ast_mode.c| 4 +- drivers/gpu/drm/drm_format_helper.c | 678 -- drivers/gpu/drm/drm_mipi_dbi.c| 9 +- drivers/gpu/drm/gud/gud_pipe.c| 24 +- drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 4 +- drivers/gpu/drm/mgag200/mgag200_mode.c| 4 +- drivers/gpu/drm/solomon/ssd130x.c | 12 +- .../gpu/drm/tests/drm_format_helper_test.c| 106 ++- drivers/gpu/drm/tiny/cirrus.c | 6 +- drivers/gpu/drm/tiny/ofdrm.c | 6 +- drivers/gpu/drm/tiny/repaper.c| 4 +- drivers/gpu/drm/tiny/simpledrm.c | 6 +- drivers/gpu/drm/tiny/st7586.c | 4 +- include/drm/drm_format_helper.h | 116 ++- 14 files changed, 678 insertions(+), 305 deletions(-)
Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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( ) } 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 xrgb 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_yuv() 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,
[PATCH 2/2] drm/vmwgfx: Keep a gem reference to user bos in surfaces
From: Zack Rusin commit 91398b413d03660fd5828f7b4abc64e884b98069 upstream Surfaces can be backed (i.e. stored in) memory objects (mob's) which are created and managed by the userspace as GEM buffers. Surfaces grab only a ttm reference which means that the gem object can be deleted underneath us, especially in cases where prime buffer export is used. Make sure that all userspace surfaces which are backed by gem objects hold a gem reference to make sure they're not deleted before vmw surfaces are done with them, which fixes: [ cut here ] refcount_t: underflow; use-after-free. WARNING: CPU: 2 PID: 2632 at lib/refcount.c:28 refcount_warn_saturate+0xfb/0x150 Modules linked in: overlay vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vsock snd_ens1371 snd_ac97_codec ac97_bus snd_pcm gameport> CPU: 2 PID: 2632 Comm: vmw_ref_count Not tainted 6.5.0-rc2-vmwgfx #1 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:refcount_warn_saturate+0xfb/0x150 Code: eb 9e 0f b6 1d 8b 5b a6 01 80 fb 01 0f 87 ba e4 80 00 83 e3 01 75 89 48 c7 c7 c0 3c f9 a3 c6 05 6f 5b a6 01 01 e8 15 81 98 ff <0f> 0b e9 6f ff ff ff 0f b> RSP: 0018:bdc34344bba0 EFLAGS: 00010286 RAX: RBX: RCX: 0027 RDX: 960475ea1548 RSI: 0001 RDI: 960475ea1540 RBP: bdc34344bba8 R08: 0003 R09: 65646e75203a745f R10: a5b32b20 R11: 72657466612d6573 R12: 96037d6a6400 R13: 9603484805b0 R14: 000b R15: 9603bed06060 FS: 7f5fd8520c40() GS:960475e8() knlGS: CS: 0010 DS: ES: CR0: 80050033 CR2: 7f5fda755000 CR3: 00010d012005 CR4: 003706e0 Call Trace: ? show_regs+0x6e/0x80 ? refcount_warn_saturate+0xfb/0x150 ? __warn+0x91/0x150 ? refcount_warn_saturate+0xfb/0x150 ? report_bug+0x19d/0x1b0 ? handle_bug+0x46/0x80 ? exc_invalid_op+0x1d/0x80 ? asm_exc_invalid_op+0x1f/0x30 ? refcount_warn_saturate+0xfb/0x150 drm_gem_object_handle_put_unlocked+0xba/0x110 [drm] drm_gem_object_release_handle+0x6e/0x80 [drm] drm_gem_handle_delete+0x6a/0xc0 [drm] ? __pfx_vmw_bo_unref_ioctl+0x10/0x10 [vmwgfx] vmw_bo_unref_ioctl+0x33/0x40 [vmwgfx] drm_ioctl_kernel+0xbc/0x160 [drm] drm_ioctl+0x2d2/0x580 [drm] ? __pfx_vmw_bo_unref_ioctl+0x10/0x10 [vmwgfx] ? do_vmi_munmap+0xee/0x180 vmw_generic_ioctl+0xbd/0x180 [vmwgfx] vmw_unlocked_ioctl+0x19/0x20 [vmwgfx] __x64_sys_ioctl+0x99/0xd0 do_syscall_64+0x5d/0x90 ? syscall_exit_to_user_mode+0x2a/0x50 ? do_syscall_64+0x6d/0x90 ? handle_mm_fault+0x16e/0x2f0 ? exit_to_user_mode_prepare+0x34/0x170 ? irqentry_exit_to_user_mode+0xd/0x20 ? irqentry_exit+0x3f/0x50 ? exc_page_fault+0x8e/0x190 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 RIP: 0033:0x7f5fda51aaff Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 7> RSP: 002b:7ffd536a4d30 EFLAGS: 0246 ORIG_RAX: 0010 RAX: ffda RBX: 7ffd536a4de0 RCX: 7f5fda51aaff RDX: 7ffd536a4de0 RSI: 40086442 RDI: 0003 RBP: 40086442 R08: 55fa603ada50 R09: R10: 0001 R11: 0246 R12: 7ffd536a51b8 R13: 0003 R14: 55fa5ebb4c80 R15: 7f5fda90f040 ---[ end trace ]--- A lot of the analyis on the bug was done by Murray McAllister and Ian Forbes. Reported-by: Murray McAllister Cc: Ian Forbes Signed-off-by: Zack Rusin Fixes: a950b989ea29 ("drm/vmwgfx: Do not drop the reference to the handle too soon") Cc: # v6.2+ Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20230928041355.737635-1-z...@kde.org Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 5 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 8 +++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 22 ++- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 10 + drivers/gpu/drm/vmwgfx/vmwgfx_gem.c | 24 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 18 drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 27 +++- 10 files changed, 71 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 5ac5efea1d60..c46f380d9149 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -595,7 +595,7 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp, if (!(flags & drm_vmw_synccpu_allow_cs)) { atomic_dec(_bo->cpu_writers); } -
[PATCH 1/2] drm/vmwgfx: Fix possible invalid drm gem put calls
From: Zack Rusin commit f9e96bf1905479f18e83a3a4c314a8dfa56ede2c upstream vmw_bo_unreference sets the input buffer to null on exit, resulting in null ptr deref's on the subsequent drm gem put calls. This went unnoticed because only very old userspace would be exercising those paths but it wouldn't be hard to hit on old distros with brand new kernels. Introduce a new function that abstracts unrefing of user bo's to make the code cleaner and more explicit. Signed-off-by: Zack Rusin Reported-by: Ian Forbes Fixes: 9ef8d83e8e25 ("drm/vmwgfx: Do not drop the reference to the handle too soon") Cc: # v6.4+ Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20230818041301.407636-1-z...@kde.org Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 6 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 8 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 6 ++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 ++ drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 3 +-- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 3 +-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index ae01d22b8f84..5ac5efea1d60 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -595,10 +595,9 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp, if (!(flags & drm_vmw_synccpu_allow_cs)) { atomic_dec(_bo->cpu_writers); } - ttm_bo_put(_bo->base); + vmw_user_bo_unref(vmw_bo); } - drm_gem_object_put(_bo->base.base); return ret; } @@ -638,8 +637,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, return ret; ret = vmw_user_bo_synccpu_grab(vbo, arg->flags); - vmw_bo_unreference(); - drm_gem_object_put(>base.base); + vmw_user_bo_unref(vbo); if (unlikely(ret != 0)) { if (ret == -ERESTARTSYS || ret == -EBUSY) return -EBUSY; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 8459fab9d979..5be15732fbc5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1600,6 +1600,14 @@ vmw_bo_reference(struct vmw_buffer_object *buf) return buf; } +static inline void vmw_user_bo_unref(struct vmw_buffer_object *vbo) +{ + if (vbo) { + ttm_bo_put(>base); + drm_gem_object_put(>base.base); + } +} + static inline void vmw_fifo_resource_inc(struct vmw_private *dev_priv) { atomic_inc(_priv->num_fifo_resources); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 7e59469e1cb9..5a8b187619d3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1159,8 +1159,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, return PTR_ERR(vmw_bo); } ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false); - ttm_bo_put(_bo->base); - drm_gem_object_put(_bo->base.base); + vmw_user_bo_unref(vmw_bo); if (unlikely(ret != 0)) return ret; @@ -1214,8 +1213,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, return PTR_ERR(vmw_bo); } ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false); - ttm_bo_put(_bo->base); - drm_gem_object_put(_bo->base.base); + vmw_user_bo_unref(vmw_bo); if (unlikely(ret != 0)) return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index aab6389cb4aa..e4b2d11f2c8b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1599,10 +1599,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ - if (bo) { - vmw_bo_unreference(); - drm_gem_object_put(>base.base); - } + if (bo) + vmw_user_bo_unref(bo); if (surface) vmw_surface_unreference(); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index b5b311f2a91a..327330055ae5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -457,8 +457,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); - vmw_bo_unreference(); - drm_gem_object_put(>base.base); + vmw_user_bo_unref(buf); out_unlock:
[PATCH 0/2] drm/vmwgfx backport two fixes to v6.1.x branch
Hi, I've backported this two commits: f9e96bf19054 drm/vmwgfx: Fix possible invalid drm gem put calls 91398b413d03 drm/vmwgfx: Keep a gem reference to user bos in surfaces They both fixes a950b989ea29 ("drm/vmwgfx: Do not drop the reference to the handle too soon") which has been backported to v6.1.x branch as 0a127ac97240 There was a lot of conflicts, and as I'm not familiar with the vmwgfx driver, it's better to review and test them. I've run a short test, and it worked, but that's certainly not enough. Thanks, Zack Rusin (2): drm/vmwgfx: Fix possible invalid drm gem put calls drm/vmwgfx: Keep a gem reference to user bos in surfaces drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 7 ++ drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 8 +++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 20 ++ drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 12 +-- drivers/gpu/drm/vmwgfx/vmwgfx_gem.c | 24 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 10 - drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 3 +-- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 18 drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 5 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 27 +++- 10 files changed, 75 insertions(+), 59 deletions(-) base-commit: fec3b1451d5febbc9e04250f879c10f8952e6bed -- 2.43.0
Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
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(_notifier_list, + _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
Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
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 ..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 + */ + +#include +#include +#include + +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
Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
On 17/01/2024 16:26, Jani Nikula wrote: On Thu, 04 Jan 2024, Jocelyn Falempe 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 --- 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_xrgb_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 & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le32 drm_format_xrgb_to_argb(__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_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static inline __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb 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_xrgb(u32 color, u32 format) +{ + __le32 pix = cpu_to_le32(color); + + switch (format) { + case DRM_FORMAT_RGB565: + return le16_to_cpu(drm_forma
Re: [PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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 xrgb 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_yuv() 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 --- 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_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le32 drm_format_xrgb_to_argb(__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_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static inline __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val3
Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
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 --- 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 #include #include +#include #include #include #include @@ -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(>map, dma_obj-&g
Re: [PATCH v7 2/9] drm/panic: Add a drm panic handler
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 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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 #include #include +#include #include #include @@ -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_MAJ
Re: [RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler
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 |
Re: [PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
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 --- 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 #include #include +#include #include #include #include @@ -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(>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
Re: [PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro
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 --- 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
Re: [PATCH] drm/mgag200: Fix caching setup for remapped video memory
Hi, On 05/01/2024 09:25, Thomas Zimmermann wrote: I/O video memory for the framebuffer supports write-combine caching mode. Simplify the driver's code that sets up the caching mode. * Map video memory with ioremap_wc(), which automatically sets up the PAT entry with write-combine caching. * Remove the now obsolete call to devm_arch_io_reserve_memtype_wc(). It is only required to mmap the video memory to user space, which the driver doesn't do. * According to the PAT documentation, arch_phys_wc_add() is best called after remapping I/O memory, so move it after ioremap. Thanks a lot for taking some time to look at the latency issue. This looks good to me. Reviewed-by: Jocelyn Falempe -- Jocelyn
[PATCH v7 9/9] drm/imx: Add drm_panic support
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 --- 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 #include #include +#include #include #include #include @@ -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
[PATCH v7 8/9] drm/ast: Add drm_panic support
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 --- 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 #include #include +#include #include #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(>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
[PATCH v7 3/9] drm/plane: Add drm_for_each_primary_visible_plane macro
To support drm_panic, most drivers need to find the current primary visible plane with a framebuffer attached. Signed-off-by: Jocelyn Falempe --- 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
[PATCH v7 7/9] drm/mgag200: Add drm_panic support
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 --- 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 #include #include +#include #include #include #include #include +#include #include #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
[PATCH v7 6/9] drm/simpledrm: Add drm_panic support
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 --- 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 #include #include +#include #include #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 = _fops, + .get_scanout_buffer = simpledrm_get_scanout_buffer, }; /* -- 2.43.0
[PATCH v7 1/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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 --- 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_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le32 drm_format_xrgb_to_argb(__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_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static inline __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb 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_xrgb(u32 color, u32 format) +{ + __le32 pix = cpu_to_le32(color); + + switch (format) { + case DRM_FORMAT_RGB565: + return le16_to_cpu(drm_format_xrgb_to_rgb565(pix)); + case DRM_FORMAT_RGBA5551: + return le16_to_cpu(drm_format_xrgb_to_rgba5551(pix)); + case DRM_FORMAT_XRGB1555: + return le16_to_cpu(drm_format_xrgb_to_xrgb1555(pix)); + case DRM_FORMAT
[PATCH v7 4/9] drm/panic: Add drm_panic_is_format_supported()
So driver knows early if drm_panic will be able to display something on the current scanout buffer. Signed-off-by: Jocelyn Falempe --- 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_xrgb(0xff, 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
[PATCH v7 5/9] drm/fb_dma: Add generic get_scanout_buffer() for drm_panic
This was initialy done for imx6, but should work on most drivers using drm_fb_dma_helper. Signed-off-by: Jocelyn Falempe --- 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 #include #include +#include #include #include #include @@ -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(>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
[PATCH v7 2/9] drm/panic: Add a drm panic handler
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 --- 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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 #include #include +#include #include #include @@ -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(_minors_idr); drm_connector_ida_destroy(); } @@ -1077,6 +1084,7 @@ static int __init drm_core_init(void) drm_connector_ida_init(); idr_init(_minors_idr);
[RFC][PATCH v7 0/9] drm/panic: Add a drm panic handler
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 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
Re: [PATCH v3 4/4] drm/ssd130x: Add support for the SSD133x OLED controller family
On 19/12/2023 21:34, Javier Martinez Canillas wrote: The Solomon SSD133x controllers (such as the SSD1331) are used by RGB dot matrix OLED panels, add a modesetting pipeline to support the chip family. The SSD133x controllers support 256 (8-bit) and 65k (16-bit) color depths but only the former is implemented for now. This is because the 256 color depth format matches a fourcc code already present in DRM (RGB8), but the 65k pixel format does not match the existing RG16 fourcc code format. Instead of a R:G:B 5:6:5, the controller expects the 16-bit pixels to be R:G:B 6:5:6, and so a new fourcc needs to be added to support this format. small typo here, R:G:B 6:5:6 => that's 17 bits other than that, it looks good to me, feel free to add: Reviewed-by: Jocelyn Falempe Signed-off-by: Javier Martinez Canillas --- (no changes since v1) drivers/gpu/drm/solomon/ssd130x-i2c.c | 5 + drivers/gpu/drm/solomon/ssd130x-spi.c | 7 + drivers/gpu/drm/solomon/ssd130x.c | 370 ++ drivers/gpu/drm/solomon/ssd130x.h | 5 +- 4 files changed, 386 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/solomon/ssd130x-i2c.c b/drivers/gpu/drm/solomon/ssd130x-i2c.c index f2ccab9c06d9..a047dbec4e48 100644 --- a/drivers/gpu/drm/solomon/ssd130x-i2c.c +++ b/drivers/gpu/drm/solomon/ssd130x-i2c.c @@ -105,6 +105,11 @@ static const struct of_device_id ssd130x_of_match[] = { .compatible = "solomon,ssd1327", .data = _variants[SSD1327_ID], }, + /* ssd133x family */ + { + .compatible = "solomon,ssd1331", + .data = _variants[SSD1331_ID], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ssd130x_of_match); diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 84e035a7ab3f..84bfde31d172 100644 --- a/drivers/gpu/drm/solomon/ssd130x-spi.c +++ b/drivers/gpu/drm/solomon/ssd130x-spi.c @@ -142,6 +142,11 @@ static const struct of_device_id ssd130x_of_match[] = { .compatible = "solomon,ssd1327", .data = _variants[SSD1327_ID], }, + /* ssd133x family */ + { + .compatible = "solomon,ssd1331", + .data = _variants[SSD1331_ID], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ssd130x_of_match); @@ -166,6 +171,8 @@ static const struct spi_device_id ssd130x_spi_table[] = { { "ssd1322", SSD1322_ID }, { "ssd1325", SSD1325_ID }, { "ssd1327", SSD1327_ID }, + /* ssd133x family */ + { "ssd1331", SSD1331_ID }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, ssd130x_spi_table); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index bef293922b98..447d0c7c88c6 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -119,6 +119,26 @@ #define SSD130X_SET_VCOMH_VOLTAGE 0xbe #define SSD132X_SET_FUNCTION_SELECT_B 0xd5 +/* ssd133x commands */ +#define SSD133X_SET_COL_RANGE 0x15 +#define SSD133X_SET_ROW_RANGE 0x75 +#define SSD133X_CONTRAST_A 0x81 +#define SSD133X_CONTRAST_B 0x82 +#define SSD133X_CONTRAST_C 0x83 +#define SSD133X_SET_MASTER_CURRENT 0x87 +#define SSD132X_SET_PRECHARGE_A0x8a +#define SSD132X_SET_PRECHARGE_B0x8b +#define SSD132X_SET_PRECHARGE_C0x8c +#define SSD133X_SET_DISPLAY_START 0xa1 +#define SSD133X_SET_DISPLAY_OFFSET 0xa2 +#define SSD133X_SET_DISPLAY_NORMAL 0xa4 +#define SSD133X_SET_MASTER_CONFIG 0xad +#define SSD133X_POWER_SAVE_MODE0xb0 +#define SSD133X_PHASES_PERIOD 0xb1 +#define SSD133X_SET_CLOCK_FREQ 0xb3 +#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb +#define SSD133X_SET_VCOMH_VOLTAGE 0xbe + #define MAX_CONTRAST 255 const struct ssd130x_deviceinfo ssd130x_variants[] = { @@ -180,6 +200,12 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = { .default_width = 128, .default_height = 128, .family_id = SSD132X_FAMILY, + }, + /* ssd133x family */ + [SSD1331_ID] = { + .default_width = 96, + .default_height = 64, + .family_id = SSD133X_FAMILY, } }; EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X); @@ -589,6 +615,117 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) return 0; } +static int ssd133x_init(struct ssd130x_device *ssd130x) +{ + int ret; + + /* Set color A contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91); + if (re
Re: [PATCH] drm/mgag200: Fix gamma lut not initialized for G200ER, G200EV, G200SE
I just merged it to drm-misc-fixes: https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes=11f9eb899ecc8c02b769cf8d2532ba12786a7af7 Thanks, -- Jocelyn
Re: [PATCH] drm/mgag200: Fix gamma lut not initialized for G200ER, G200EV, G200SE
On 18/12/2023 12:31, Thomas Zimmermann wrote: Hi Am 14.12.23 um 17:38 schrieb Jocelyn Falempe: When mgag200 switched from simple KMS to regular atomic helpers, the initialization of the gamma settings was lost. This leads to a black screen, if the bios/uefi doesn't use the same pixel color depth. This has been fixed with commit ad81e23426a6 ("drm/mgag200: Fix gamma lut not initialized.") for most G200, but G200ER, G200EV, G200SE use their own version of crtc_helper_atomic_enable() and need to be fixed too. Fixes: 1baf9127c482 ("drm/mgag200: Replace simple-KMS with regular atomic helpers") Cc: #v6.1+ Reported-by: Roger Sewell Suggested-by: Roger Sewell Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.h | 4 drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200se.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_mode.c | 26 ++-- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 57c7edcab602..ed90a92b5fcd 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -392,6 +392,10 @@ void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, .destroy = drm_plane_cleanup, \ DRM_GEM_SHADOW_PLANE_FUNCS +void mgag200_crtc_set_gamma(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_property_blob *gamma_lut); + enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode); int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index bce267e0f7de..38815cb94c61 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -202,6 +202,8 @@ static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200er_reset_tagfifo(mdev); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index ac957f42abe1..e698a3a499bf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -203,6 +203,8 @@ static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200ev_set_hiprilvl(mdev); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index bd6e573c9a1a..7e4ea0046a6b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -334,6 +334,8 @@ static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af3ce5a6a636..d2a04b317232 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -65,9 +65,9 @@ static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, } } -static void mgag200_crtc_set_gamma(struct mga_device *mdev, - const struct drm_format_info *format, - struct drm_color_lut *lut) +static void mgag200_crtc_set_gamma_table(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_color_lut *lut) { int i; @@ -103,6 +103,16 @@ static void mgag200_crtc_set_gamma(struct mga_device *mdev, } } +void mgag200_crtc_set_gamma(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_property_blob *gamma_lut) +{ + if (gamma_lut) + mgag200_crtc_set_gamma_table(mdev, format, gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, format); +} Please keep this open-coded its callers. With that changed Reviewed-by: Thomas Zimmermann Thanks for the review, yes I will change that. If no other comments, I will push it to drm-misc-fixes tomorrow. -- Jocelyn + static inline void mga_wait_vsync(struct mga_device *mdev) { unsigned long timeout = jiffies + HZ/10; @@ -616,10 +626,7 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s if (crtc_state-
[PATCH] drm/mgag200: Fix gamma lut not initialized for G200ER, G200EV, G200SE
When mgag200 switched from simple KMS to regular atomic helpers, the initialization of the gamma settings was lost. This leads to a black screen, if the bios/uefi doesn't use the same pixel color depth. This has been fixed with commit ad81e23426a6 ("drm/mgag200: Fix gamma lut not initialized.") for most G200, but G200ER, G200EV, G200SE use their own version of crtc_helper_atomic_enable() and need to be fixed too. Fixes: 1baf9127c482 ("drm/mgag200: Replace simple-KMS with regular atomic helpers") Cc: #v6.1+ Reported-by: Roger Sewell Suggested-by: Roger Sewell Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.h| 4 drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_g200se.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_mode.c | 26 ++-- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 57c7edcab602..ed90a92b5fcd 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -392,6 +392,10 @@ void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, .destroy = drm_plane_cleanup, \ DRM_GEM_SHADOW_PLANE_FUNCS +void mgag200_crtc_set_gamma(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_property_blob *gamma_lut); + enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode); int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index bce267e0f7de..38815cb94c61 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -202,6 +202,8 @@ static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200er_reset_tagfifo(mdev); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index ac957f42abe1..e698a3a499bf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -203,6 +203,8 @@ static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200ev_set_hiprilvl(mdev); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index bd6e573c9a1a..7e4ea0046a6b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -334,6 +334,8 @@ static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc, mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format); + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af3ce5a6a636..d2a04b317232 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -65,9 +65,9 @@ static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, } } -static void mgag200_crtc_set_gamma(struct mga_device *mdev, - const struct drm_format_info *format, - struct drm_color_lut *lut) +static void mgag200_crtc_set_gamma_table(struct mga_device *mdev, +const struct drm_format_info *format, +struct drm_color_lut *lut) { int i; @@ -103,6 +103,16 @@ static void mgag200_crtc_set_gamma(struct mga_device *mdev, } } +void mgag200_crtc_set_gamma(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_property_blob *gamma_lut) +{ + if (gamma_lut) + mgag200_crtc_set_gamma_table(mdev, format, gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, format); +} + static inline void mga_wait_vsync(struct mga_device *mdev) { unsigned long timeout = jiffies + HZ/10; @@ -616,10 +626,7 @@ void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_s if (crtc_state->enable && crtc_state->color_mgmt_changed) { const struct drm_format_info *format = mgag200_crtc_sta
Re: [PATCH v5 6/6] drm/imx: Add drm_panic support
On 14/12/2023 14:48, Maxime Ripard wrote: Hi, On Fri, Nov 03, 2023 at 03:53:30PM +0100, Jocelyn Falempe wrote: Proof of concept to add drm_panic support on an arm based GPU. I've tested it with X11/llvmpipe, because I wasn't able to have 3d rendering with etnaviv on my imx6 board. Signed-off-by: Jocelyn Falempe Like I said in the v6, this shouldn't be dropped because it also kind of documents and shows what we are expecting from a "real" driver. Ok, I can bring it back in v7. --- drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 30 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c index 4a866ac60fff..db24b4976c61 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -17,9 +18,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -160,6 +164,31 @@ static int imx_drm_dumb_create(struct drm_file *file_priv, return ret; } +static int imx_drm_get_scanout_buffer(struct drm_device *dev, + struct drm_scanout_buffer *sb) +{ + struct drm_plane *plane; + struct drm_gem_dma_object *dma_obj; + + drm_for_each_plane(plane, dev) { + if (!plane->state || !plane->state->fb || !plane->state->visible || + plane->type != DRM_PLANE_TYPE_PRIMARY) + continue; + + dma_obj = drm_fb_dma_get_gem_obj(plane->state->fb, 0); + if (!dma_obj->vaddr) + continue; + + iosys_map_set_vaddr(>map, dma_obj->vaddr); + sb->format = plane->state->fb->format; Planes can be using a framebuffer in one of the numerous YUV format the driver advertises. + sb->height = plane->state->fb->height; + sb->width = plane->state->fb->width; + sb->pitch = plane->state->fb->pitches[0]; And your code assumes that the buffer will be large enough for an RGB buffer, which probably isn't the case for a single-planar YUV format, and certainly not the case for a multi-planar one. Yes, this code is a bit hacky, and on my test setup the framebuffer was in RGB, so I didn't handle other formats. Also it should be possible to add YUV format later, but I would like to have a minimal drm_panic merged, before adding more features. When the driver gives back its current framebuffer, the code should check: * If the buffer backed by an actual buffer (and not a dma-buf handle) Regarding the struct drm_framebuffer, I'm not sure how do you differentiate an actual buffer from a dma-buf handle ? * If the buffer is mappable by the CPU If "dma_obj->vaddr" is not null, then it's already mapped by the CPU right ? * If the buffer is in a format that the panic code can handle * If the buffer uses a linear modifier Yes, that must be checked too. Failing that, your code cannot work at the moment. We need to be clear about that and "gracefully" handle things instead of going forward and writing pixels to places we might not be able to write to. Which kind of makes me think, why do we need to involve the driver at all there? If in the panic code, we're going over all enabled CRTCs, finding the primary plane currently setup for them and getting the drm_framebuffer assigned to them, it should be enough to get us all the informations we need, right? Yes, I think I can do a generic implementation for the drivers using the drm_gem_dma helper like imx6. But for simpledrm, ast, or mgag200, I need to retrieve the VRAM address, because it's not in the drm_framebuffer struct, so they won't be able to use this generic implementation. Maxime Thanks for the review, -- Jocelyn
Re: [PATCH] drm/mgag200: Flush the cache to improve latency
On 06/11/2023 11:46, Jocelyn Falempe wrote: On 23/10/2023 10:30, Jocelyn Falempe wrote: On 20/10/2023 14:06, Thomas Zimmermann wrote: (cc'ing lkml for feedback) Hi Jocelyn Am 19.10.23 um 15:55 schrieb Jocelyn Falempe: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) I'd like to hear the opinion of the RT-devs on this patch. Because AFAIK we never did such a workaround in other drivers. And AFAIK printk is a PITA anyway. Most other drivers uses DMA, which means this workaround can't apply to them. IMHO if that RT system cannot handle differences in framebuffer caching, it's under-powered. It's just a matter of time until something else changes and the problem returns. And (honest question) as it's an x86-64, how do they handle System Management Mode? I think it's not a big news, that the Matrox G200 from 1999 is under-powered. I was also a bit surprised that flushing the cache would have such effect on latency. The tests we are doing can run 24h with the workaround, without any interrupt taking more than 10us. Without the workaround, every ~30s the interrupt failed its 10us target. The regression has been bisected to 2 commits: 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by the following patch, which forces a cache flush after each frame, reverting to almost v5.9 behavior. With that second commit, we essentially never unmap an active framebuffer console. But with commit 359c6649cd9a ("drm/gem: Implement shadow-plane {begin, end}_fb_access with vmap") we now again unmap the console framebuffer after the pageflip happened. So how does the latest kernel behave wrt to the problem? The regression was found when upgrading the server from v5.4 to v5.14, so we didn't test with later kernels. We will test with v6.3 (which should have 359c6649cd9a ) and see what it gives. I don't have a clear explanation, but testing with v6.3, and forcing the Write Combine, doesn't fix the latency issue. So forcing the cache flush is still needed. Also, on some systems, they use "isolated cpu" to handle RT task, but with a standard kernel (so without the CONFIG_PREEMPT_RT). So I'm wondering if we can use a kernel module parameter for this, so that users that wants to achieve low latency, can opt-in ? something like mgag200.force_cache_flush=1 or mgag200.low_latency=1 ? Hi, I have now access to a server that reproduce the issue, and I was able to test different workarounds. So it is definitely related to the "Write Combine" mode of the mga internal RAM. If I comment the two lines to enable wc: https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/mgag200/mgag200_drv.c#L150, then the latency is <10us (but the performances are worse, from 20ms to 87ms to draw a full frame). I also tried to flush the vram using: drm_clflush_virt_range(mdev->vram + clip->y1 * fb->pitches[0], drm_rect_height(clip) * fb->pitches[0]); And that lower the latency to ~20us, but it's not enough. I tried "sfence" which I though would flush the WC buffers of the CPU, but that has no effect in practice. I think I can send a new patch, to not map the VRAM as Write Combine, either if CONFIG_PREEMPT_RT is set or if a module parameter is set. What do you think is the best approach ? My tests setup: I either flood the console with "cat /dev/urandom | base64" from the BMC, or write to fb0 with "while true; do dd if=/dev/urandom of=/dev/fb0 ; done" then I run: cd /sys/kernel/debug/tracing echo 0 > tracing_on echo 95 > hwlat_detector/width echo hwlat > current_tracer echo 10 > tracing_thresh echo 1 > tracing_on sleep 300 cat trace echo 0 > tracing_on echo nop > current_tracer Test Results: V6.6 (~40us latency) # tracer: hwlat # # entries-in-buffer/entries-written: 6/6 #P:56 # #_-=> irqs-off/BH-disabled # / _=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / _-=> migrate-disable # / delay # TASK-PID CPU# | TIMESTAMP FUNCTION # | | | | | | <...>-8795[001] dn... 613
[PATCH v6 3/5] drm/simpledrm: Add drm_panic support
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 --- 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 34bbbd7b53dd..41eea078294b 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -986,6 +987,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 */ @@ -1001,6 +1015,7 @@ static struct drm_driver simpledrm_driver = { .minor = DRIVER_MINOR, .driver_features= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, .fops = _fops, + .get_scanout_buffer = simpledrm_get_scanout_buffer, }; /* -- 2.42.0
[PATCH v6 4/5] drm/mgag200: Add drm_panic support
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) Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_drv.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 2fb18b782b05..c79f3d9ee39a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -13,10 +13,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "mgag200_drv.h" @@ -84,6 +86,28 @@ 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_plane(plane, dev) { + if (!plane->state || !plane->state->visible || !plane->state->fb || + plane->type != DRM_PLANE_TYPE_PRIMARY) + 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]; + sb->map = map; + return 0; + } + return -ENODEV; +} + /* * DRM driver */ @@ -99,6 +123,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.42.0
[PATCH v6 5/5] drm/ast: Add drm_panic support
Add support for the drm_panic module, which displays a message to the screen when a kernel panic occurs. Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/ast/ast_drv.c | 29 +++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 90bcb1eb9cd9..bb49e89dbd3c 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "ast_drv.h" @@ -48,6 +49,30 @@ 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_plane(plane, dev) { + if (!plane->state || !plane->state->visible || !plane->state->fb || + plane->type != DRM_PLANE_TYPE_PRIMARY) + continue; + 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(>map, ast_plane->vaddr); + return 0; + } + return -ENODEV; +} + DEFINE_DRM_GEM_FOPS(ast_fops); static const struct drm_driver ast_driver = { @@ -62,8 +87,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.42.0
[PATCH v6 2/5] drm/panic: Add a drm panic handler
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 Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/Kconfig | 22 +++ drivers/gpu/drm/Makefile| 1 + drivers/gpu/drm/drm_drv.c | 8 + drivers/gpu/drm/drm_panic.c | 368 include/drm/drm_drv.h | 21 ++ include/drm/drm_panic.h | 96 ++ 6 files changed, 516 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 b7abd436455f..6bf7a5b2f288 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -103,6 +103,28 @@ 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 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 0xff + +config DRM_PANIC_BACKGROUND_COLOR + hex "Drm panic screen background color, in RGB" + depends on DRM_PANIC + default 0x00 + 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 b4cb0835620a..100e7cfad3b9 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -73,6 +73,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \ drm_privacy_screen_x86.o drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o obj-$(CONFIG_DRM) += drm.o +drm-$(CONFIG_DRM_PANIC) += drm_panic.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 3c835c99daad..897146fbda25 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -955,6 +956,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, @@ -1001,6 +1005,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)) @@ -1083,6 +1089,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(_minors_idr); drm_connector_ida_destroy(); } @@ -1094,6 +1101,7 @@ static int __init drm_core_init(void) drm_connector_ida_init(); idr_init(_minors_idr); drm_memcpy_init_early(); + drm_panic_init(); ret = drm_sysfs_init(); if (ret < 0) { diff --git a/drive
[PATCH v6 1/5] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill
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 --- drivers/gpu/drm/drm_format_helper.c | 431 ++-- include/drm/drm_format_helper.h | 9 + 2 files changed, 359 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index b1be458ed4dd..38a3c38f5d84 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -111,6 +111,152 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state) } EXPORT_SYMBOL(drm_format_conv_state_release); +static inline __le16 drm_format_xrgb_to_rgb565(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00F8) >> 8) | + ((pix & 0xFC00) >> 5) | + ((pix & 0x00F8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_rgba5551(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 8) | + ((pix & 0xf800) >> 5) | + ((pix & 0x00f8) >> 2) | + BIT(0); /* set alpha bit */ + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_xrgb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le16 drm_format_xrgb_to_argb1555(__le32 val32) +{ + u16 val16; + u32 pix; + + pix = le32_to_cpu(val32); + val16 = BIT(15) | /* set alpha bit */ + ((pix & 0x00f8) >> 9) | + ((pix & 0xf800) >> 6) | + ((pix & 0x00f8) >> 3); + return cpu_to_le16(val16); +} + +static inline __le32 drm_format_xrgb_to_argb(__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_xrgb_to_xbgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + ((val32 & 0xff00) >> 24) << 24; + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_abgr(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00ff) >> 16) << 0 | + ((val32 & 0xff00) >> 8) << 8 | + ((val32 & 0x00ff) >> 0) << 16 | + GENMASK(31, 24); /* fill alpha bits */ + return cpu_to_le32(val32); +} + +static inline __le32 drm_format_xrgb_to_xrgb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03)); +} + +static inline __le32 drm_format_xrgb_to_argb2101010(__le32 pix) +{ + u32 val32; + + val32 = le32_to_cpu(pix); + val32 = ((val32 & 0x00FF) << 2) | + ((val32 & 0xFF00) << 4) | + ((val32 & 0x00FF) << 6); + val32 = GENMASK(31, 30) | /* set alpha bits */ + val32 | ((val32 >> 8) & 0x00300c03); + return cpu_to_le32(val32); +} + +/** + * drm_fb_convert_from_xrgb - convert one pixel from xrgb to the desired format + * @color: input color, in xrgb format + * @format: output format + * + * Returns: + * Color in the format specified, casted to u32. + */ +u32 drm_fb_convert_from_xrgb(u32 color, u32 format) +{ + __le32 pix = cpu_to_le32(color); + + switch (format) { + case DRM_FORMAT_RGB565: + return le16_to_cpu(drm_format_xrgb_to_rgb565(pix)); + case DRM_FORMAT_RGBA5551: + return le16_to_cpu(drm_format_xrgb_to_rgba5551(pix)); + case DRM_FORMAT_XRGB1555: + return le16_to_cpu(drm_format_xrgb_to_xrgb1555(pix)); + case DRM_FORMAT_ARGB1555: +
[RFC][PATCH v6 0/5] drm/panic: Add a drm panic handler
drm/panic: Add a drm panic handler 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 and mgag200, 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 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. With mgag200 support, I was able to test that the xrgb to rgb565 conversion is working. IMX/IPUV3 support is not complete, I wasn't able to have etnaviv working on my board. But it shows that it can still work on ARM with DMA buffer in this case. Best regards, Jocelyn Falempe (5): drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill drm/panic: Add a drm panic handler drm/simpledrm: Add drm_panic support drm/mgag200: Add drm_panic support drm/ast: Add drm_panic support drivers/gpu/drm/Kconfig | 22 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/ast/ast_drv.c | 29 +- drivers/gpu/drm/drm_drv.c | 8 + drivers/gpu/drm/drm_format_helper.c | 431 +- drivers/gpu/drm/drm_panic.c | 368 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 25 ++ drivers/gpu/drm/tiny/simpledrm.c | 15 + include/drm/drm_drv.h | 21 ++ include/drm/drm_format_helper.h | 9 + include/drm/drm_panic.h | 96 ++ 11 files changed, 942 insertions(+), 83 deletions(-) create mode 100644 drivers/gpu/drm/drm_panic.c create mode 100644 include/drm/drm_panic.h base-commit: d0b3c318e04cc6c4e2a3c30ee0f6f619aa8d0db5 -- 2.42.0
Re: [PATCH] drm/ast: Disconnect BMC if physical connector is connected
On 16/11/2023 14:02, Thomas Zimmermann wrote: Many user-space compositors fail with mode setting if a CRTC has more than one connected connector. This is the case with the BMC on Aspeed systems. Work around this problem by setting the BMC's connector status to disconnected when the physical connector has a display attached. This way compositors will only see one connected connector at a time; either the physical one or the BMC. Thanks for the patch. I can't test it because I don't have physical access to a machine with aspeed GPU, but it looks good to me. Reviewed-by: Jocelyn Falempe -- Jocelyn
Re: Incomplete stable drm/ast backport - screen freeze on boot
On 13/11/2023 17:37, Sasha Levin wrote: On Mon, Nov 13, 2023 at 10:49:01AM +0100, Thomas Zimmermann wrote: (cc: gregkh) Hi Jocelyn Am 13.11.23 um 10:36 schrieb Jocelyn Falempe: On 13/11/2023 09:34, Keno Fischer wrote: Greetings, When connected to a remote machine via the BMC KVM functionality, I am experiencing screen freezes on boot when using 6.5 stable, but not master. The BMC on the machine in question is an ASpeed AST2600. A quick bisect shows the problematic commit to be 2fb9667 ("drm/ast: report connection status on Display Port."). This is commit f81bb0ac upstream. I believe the problem is that the previous commit in the series e329cb5 ("drm/ast: Add BMC virtual connector") was not backported to the stable branch. As a consequence, it appears that the more accurate DP state detection is causing the kernel to believe that no display is connected, even when the BMC's virtual display is in fact in use. A cherry-pick of e329cb5 onto the stable branch resolves the issue. Yes, you're right this two patches must be backported together. I'm sorry I didn't pay enough attention, that only one of the two was picked up for the stable branch. Is it possible to backport e329cb5 to the stable branch, or should I push it to drm-misc-fixes ? I think stable, which is in cc, will pick up commit e329cb5 semi-automatically now. Otherwise, maybe ping gregkh in a few days about it. I thikn it would be more appropriate to revert 2fb9667, as e329cb5 doesn't look like -stable material. I'll go ahead and do that. Ok, that's the best thing to do, as Thomas also found that userspace can be confused by the new BMC virtual connector, so it's safer to revert. Thanks, -- Jocelyn
Re: [PATCH 00/10] drm/ast: Detect device type before init
On 13/11/2023 09:50, Thomas Zimmermann wrote: Detecting the ast device's chipset type and configuration mode involves several registers, DT properties and possibly POSTing parts of the chip. It is preferable to do this before initializing the DRM driver, so that that each chip type can have an individual setup code. The patchset addresses the problem by moving all early detection code before the allocation of the ast device. Patch one gets a lock out of the way. The lock is only relevant for mode setting. Move it there. Patches 2 and 3 rework the detection of the correct I/O memory ranges. It is now self-contained, more readable and works without an instance of struct ast_device. Patches 4 to 7 rework the setup of various registers that are required for detection. Access helpers for I/O can now operate without an instance of struct ast_device. The setup functions operate on the I/O ranges that have been made available with patch 3, but again without struct ast_device. With the detection's internals done, patches 8 and 9 rework the chip's and config-mode's detection code to operate without struct ast_device as well. Finally, patch 10 moves the detection code into the PCI probe function. it runs before any of the DRM device code. The fucntion for creating an ast device, ast_device_create(), receives the detected I/O memory ranges, chip type and configuration mode. This cleans up the detection code. There is more chip-specific code in other parts of the driver. In a later patch, the ast device setup can be split up so that each chip type gets its own code path that does not interfere with other chips. Tested on AST1100 and AST2100. Thomas Zimmermann (10): drm/ast: Turn ioregs_lock to modeset_lock drm/ast: Rework I/O register setup drm/ast: Retrieve I/O-memory ranges without ast device drm/ast: Add I/O helpers without ast device drm/ast: Enable VGA without ast device instance drm/ast: Enable MMIO without ast device instance drm/ast: Partially implement POST without ast device instance drm/ast: Add enum ast_config_mode drm/ast: Detect ast device type and config mode without ast device drm/ast: Move detection code into PCI probe helper drivers/gpu/drm/ast/ast_drv.c | 261 - drivers/gpu/drm/ast/ast_drv.h | 101 + drivers/gpu/drm/ast/ast_main.c | 244 ++ drivers/gpu/drm/ast/ast_mode.c | 26 ++-- drivers/gpu/drm/ast/ast_post.c | 73 + drivers/gpu/drm/ast/ast_reg.h | 12 +- 6 files changed, 411 insertions(+), 306 deletions(-) base-commit: b7816c393496dc4497c1327310821407f7171d8b prerequisite-patch-id: 0aa359f6144c4015c140c8a6750be19099c676fb prerequisite-patch-id: c67e5d886a47b7d0266d81100837557fda34cb24 prerequisite-patch-id: cbc453ee02fae02af22fbfdce56ab732c7a88c36 I've reviewed the whole series, and I have only a minor comment on patch 9. That's a good thing to move the chip detection to its own functions, and will allow further refactoring later. For the whole series: Reviewed-by: Jocelyn Falempe -- Jocelyn
Re: [PATCH 09/10] drm/ast: Detect ast device type and config mode without ast device
On 13/11/2023 09:50, Thomas Zimmermann wrote: Return the ast chip and config in the detection function's parameters instead of storing them directly in the ast device instance. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/ast/ast_main.c | 104 ++--- 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f100df8d74f71..331a9a861153b 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -76,25 +76,27 @@ static void ast_open_key(void __iomem *ioregs) __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); } -static int ast_device_config_init(struct ast_device *ast) +static int ast_detect_chip(struct pci_dev *pdev, + void __iomem *regs, void __iomem *ioregs, + enum ast_chip *chip_out, + enum ast_config_mode *config_mode_out) { - struct drm_device *dev = >base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - struct device_node *np = dev->dev->of_node; + struct device *dev = >dev; + struct device_node *np = dev->of_node; + enum ast_config_mode config_mode = ast_use_defaults; uint32_t scu_rev = 0x; + enum ast_chip chip; u32 data; - u8 jregd0, jregd1; + u8 vgacrd0, vgacrd1; /* * Find configuration mode and read SCU revision */ - ast->config_mode = ast_use_defaults; - /* Check if we have device-tree properties */ if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", )) { /* We do, disable P2A access */ - ast->config_mode = ast_use_dt; + config_mode = ast_use_dt; scu_rev = data; } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge /* @@ -102,9 +104,9 @@ static int ast_device_config_init(struct ast_device *ast) * is disabled. We force using P2A if VGA only mode bit * is set D[7] */ - jregd0 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); - jregd1 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff); - if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { + vgacrd0 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd0); + vgacrd1 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd1); + if (!(vgacrd0 & 0x80) || !(vgacrd1 & 0x10)) { /* * We have a P2A bridge and it is enabled. @@ -112,32 +114,32 @@ static int ast_device_config_init(struct ast_device *ast) /* Patch AST2500/AST2510 */ if ((pdev->revision & 0xf0) == 0x40) { - if (!(jregd0 & AST_VRAM_INIT_STATUS_MASK)) - ast_patch_ahb_2500(ast->regs); + if (!(vgacrd0 & AST_VRAM_INIT_STATUS_MASK)) + ast_patch_ahb_2500(regs); } /* Double check that it's actually working */ - data = ast_read32(ast, 0xf004); + data = __ast_read32(regs, 0xf004); if ((data != 0x) && (data != 0x00)) { - ast->config_mode = ast_use_p2a; + config_mode = ast_use_p2a; /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e); - ast_write32(ast, 0xf000, 0x1); - scu_rev = ast_read32(ast, 0x1207c); + __ast_write32(regs, 0xf004, 0x1e6e); + __ast_write32(regs, 0xf000, 0x1); + scu_rev = __ast_read32(regs, 0x1207c); } } } - switch (ast->config_mode) { + switch (config_mode) { case ast_use_defaults: - drm_info(dev, "Using default configuration\n"); + dev_info(dev, "Using default configuration\n"); break; case ast_use_dt: - drm_info(dev, "Using device-tree for configuration\n"); + dev_info(dev, "Using device-tree for configuration\n"); break; case ast_use_p2a: - drm_info(dev, "Using P2A bridge for configuration\n"); + dev_info(dev, "Using P2A bridge for configuration\n"); break; } @@ -146,63 +148,66 @@ static int ast_device_config_init(struct ast_device *ast) */ if (pdev->revision >= 0x50) { - ast->chip = AST2600; - drm_info(dev, "AST 2600 detected\n"); + chip = AST2600; + dev_info(dev, "AST 2600 detected\n"); Adding a
Re: Incomplete stable drm/ast backport - screen freeze on boot
On 13/11/2023 09:34, Keno Fischer wrote: Greetings, When connected to a remote machine via the BMC KVM functionality, I am experiencing screen freezes on boot when using 6.5 stable, but not master. The BMC on the machine in question is an ASpeed AST2600. A quick bisect shows the problematic commit to be 2fb9667 ("drm/ast: report connection status on Display Port."). This is commit f81bb0ac upstream. I believe the problem is that the previous commit in the series e329cb5 ("drm/ast: Add BMC virtual connector") was not backported to the stable branch. As a consequence, it appears that the more accurate DP state detection is causing the kernel to believe that no display is connected, even when the BMC's virtual display is in fact in use. A cherry-pick of e329cb5 onto the stable branch resolves the issue. Yes, you're right this two patches must be backported together. I'm sorry I didn't pay enough attention, that only one of the two was picked up for the stable branch. Is it possible to backport e329cb5 to the stable branch, or should I push it to drm-misc-fixes ? Best regards, -- Jocelyn Cheers, Keno
Re: BUG in drm_kms_helper_poll_enable() fixed by reverting "drm/ast: report connection status on Display Port."
e/drivers/gpu/drm/drm_probe_helper.c#L908 So I'm not sure why it fails in this case. If I revert commit f81bb0ac7872893241319ea82504956676ef02fd ("drm/ast: report connection status on Display Port."), the splat goes away: [ 60.603837] input: OpenBMC virtual_input as /devices/pci:00/:00:07.1/:02:00.4/usb3/3-2/3-2.6/3-2.6:1.0/0003:1D6B:0104.0002/input/input4 [ 60.651733] ast :c2:00.0: vgaarb: deactivate vga console [ 60.659978] 4k 16711104 large 0 gb 0 x 1303[88897000-8880a7ffe000] miss 383488 [ 60.669321] ok. [ 60.670497] ast :c2:00.0: [drm] Using default configuration [ 60.677894] ast :c2:00.0: [drm] AST 2600 detected [ 60.683545] ast :c2:00.0: [drm] Using ASPEED DisplayPort transmitter [ 60.685381] hid-generic 0003:1D6B:0104.0002: input,hidraw0: USB HID v1.01 Keyboard [OpenBMC virtual_input] on usb-:02:00.4-2.6/input0 [ 60.691032] ast :c2:00.0: [drm] dram MCLK=396 Mhz type=1 bus_width=16 [ 60.697172] [drm] Initialized ast 0.1.0 20120228 for :c2:00.0 on minor 0 [ 60.729565] fbcon: astdrmfb (fb0) is primary device [ 60.729570] fbcon: Deferring console take-over [ 60.741322] ast :c2:00.0: [drm] fb0: astdrmfb frame buffer device [ 60.928226] ast :c2:00.0: vgaarb: deactivate vga console [ 60.940376] input: OpenBMC virtual_input as /devices/pci:00/:00:07.1/:02:00.4/usb3/3-2/3-2.6/3-2.6:1.0/0003:1D6B:0104.0002/input/input5 [ 60.965436] ast :c2:00.0: [drm] Using default configuration [ 60.972051] ast :c2:00.0: [drm] AST 2600 detected [ 60.977698] ast :c2:00.0: [drm] Using ASPEED DisplayPort transmitter [ 60.985181] ast :c2:00.0: [drm] dram MCLK=396 Mhz type=1 bus_width=16 [ 61.56] [drm] Initialized ast 0.1.0 20120228 for :c2:00.0 on minor 0 [ 61.013486] fbcon: Deferring console take-over [ 61.016918] hid-generic 0003:1D6B:0104.0002: input,hidraw0: USB HID v1.01 Keyboard [OpenBMC virtual_input] on usb-:02:00.4-2.6/input0 [ 61.018454] ast :c2:00.0: [drm] fb0: astdrmfb frame buffer device [ 61.040853] input: OpenBMC virtual_input as /devices/pci:00/:00:07.1/:02:00.4/usb3/3-2/3-2.6/3-2.6:1.1/0003:1D6B:0104.0004/input/input6 [ 61.059112] hid-generic 0003:1D6B:0104.0004: input,hidraw1: USB HID v1.01 Mouse [OpenBMC virtual_input] on usb-:02:00.4-2.6/input1 [ 61.358397] input: OpenBMC virtual_input as /devices/pci:00/:00:07.1/:02:00.4/usb3/3-2/3-2.6/3-2.6:1.1/0003:1D6B:0104.0004/input/input7 [ 61.376885] hid-generic 0003:1D6B:0104.0004: input,hidraw1: USB HID v1.01 Mouse [OpenBMC virtual_input] on usb-:02:00.4-2.6/input1 This has happened before when drm_kms_helper_poll_init() was added to an ast connector_init(), see: The crash was in the detect() callback for that previous case. This time it crashes when setting the timer, but they still look very similar, thanks for pointing this. commit 595cb5e0b832a3e100cbbdefef797b0c27bf725a Author: Kim Phillips Date: Thu Oct 21 10:30:06 2021 -0500 Revert "drm/ast: Add detect function support" I'm willing to test any proposed changes, esp. if it means not reverting this commit, too, because that will only likely lead to yet another BUG instance if/when another poll_init() gets added in the future. Should the FIXME described in reschedule_output_poll_work() be addressed? This fixme just change the timer interval from 10s to 1s, so it shouldn't explain this crash. Can you test with the attached patch ? I want to see if the detect callback is called, and also make sure the delayed_work struct is properly initialized. Thanks, Kim Best regards, -- Jocelyn From 0a9f2d81af1087ab3648206dfce160639385a6b6 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Thu, 9 Nov 2023 14:39:22 +0100 Subject: [PATCH] drm/probe-helper: Add debug for AST poll bug Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/drm_probe_helper.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3f479483d7d8..9aa95791891a 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -753,6 +753,8 @@ static void output_poll_execute(struct work_struct *work) bool repoll = false, changed; u64 old_epoch_counter; + pr_info("ASTDEBUG poll execute delayed_work %p, drm_dev %p\n", delayed_work, dev); + if (!dev->mode_config.poll_enabled) return; @@ -910,6 +912,8 @@ void drm_kms_helper_poll_init(struct drm_device *dev) INIT_DELAYED_WORK(>mode_config.output_poll_work, output_poll_execute); dev->mode_config.poll_enabled = true; + pr_info("ASTDEBUG poll init delayed work %p timer %p drm_dev %p timer flag 0x%0x\n", >mode_config.output_poll_work, >mode_config.output_poll_work.timer, dev, dev->mode_config.output_poll_work.timer.flags); + drm_kms_helper_poll_enable(dev); } EXPORT_SYMBOL(drm_kms_helper_poll_init); -- 2.41.0
Re: [PATCH] drm/mgag200: Flush the cache to improve latency
On 23/10/2023 10:30, Jocelyn Falempe wrote: On 20/10/2023 14:06, Thomas Zimmermann wrote: (cc'ing lkml for feedback) Hi Jocelyn Am 19.10.23 um 15:55 schrieb Jocelyn Falempe: We found a regression in v5.10 on real-time server, using the rt-kernel and the mgag200 driver. It's some really specialized workload, with <10us latency expectation on isolated core. After the v5.10, the real time tasks missed their <10us latency when something prints on the screen (fbcon or printk) I'd like to hear the opinion of the RT-devs on this patch. Because AFAIK we never did such a workaround in other drivers. And AFAIK printk is a PITA anyway. Most other drivers uses DMA, which means this workaround can't apply to them. IMHO if that RT system cannot handle differences in framebuffer caching, it's under-powered. It's just a matter of time until something else changes and the problem returns. And (honest question) as it's an x86-64, how do they handle System Management Mode? I think it's not a big news, that the Matrox G200 from 1999 is under-powered. I was also a bit surprised that flushing the cache would have such effect on latency. The tests we are doing can run 24h with the workaround, without any interrupt taking more than 10us. Without the workaround, every ~30s the interrupt failed its 10us target. The regression has been bisected to 2 commits: 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") The first one changed the system memory framebuffer from Write-Combine to the default caching. Before the second commit, the mgag200 driver used to unmap the framebuffer after each frame, which implicitly does a cache flush. Both regressions are fixed by the following patch, which forces a cache flush after each frame, reverting to almost v5.9 behavior. With that second commit, we essentially never unmap an active framebuffer console. But with commit 359c6649cd9a ("drm/gem: Implement shadow-plane {begin, end}_fb_access with vmap") we now again unmap the console framebuffer after the pageflip happened. So how does the latest kernel behave wrt to the problem? The regression was found when upgrading the server from v5.4 to v5.14, so we didn't test with later kernels. We will test with v6.3 (which should have 359c6649cd9a ) and see what it gives. I don't have a clear explanation, but testing with v6.3, and forcing the Write Combine, doesn't fix the latency issue. So forcing the cache flush is still needed. Also, on some systems, they use "isolated cpu" to handle RT task, but with a standard kernel (so without the CONFIG_PREEMPT_RT). So I'm wondering if we can use a kernel module parameter for this, so that users that wants to achieve low latency, can opt-in ? something like mgag200.force_cache_flush=1 or mgag200.low_latency=1 ? Best regards, -- Jocelyn This is necessary only if you have strong realtime constraints, so I put the cache flush under the CONFIG_PREEMPT_RT config flag. Also clflush is only availabe on x86, (and this issue has only been reproduced on x86_64) so it's also under the CONFIG_X86 config flag. Fixes: 0b34d58b6c32 ("drm/mgag200: Enable caching for SHMEM pages") Fixes: 4862ffaec523 ("drm/mgag200: Move vmap out of commit tail") Signed-off-by: Jocelyn Falempe --- drivers/gpu/drm/mgag200/mgag200_mode.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index af3ce5a6a636..11660cd29cea 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -436,6 +437,10 @@ static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_ma iosys_map_incr(, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); drm_fb_memcpy(, fb->pitches, vmap, fb, clip); + /* On RT systems, flushing the cache reduces the latency for other RT tasks */ +#if defined(CONFIG_X86) && defined(CONFIG_PREEMPT_RT) + drm_clflush_virt_range(vmap, fb->height * fb->pitches[0]); +#endif Your second commit is part of a larger patchset that updates several drivers. They might all be affected. So if anything, the patch should go here before the unmap call: https://elixir.bootlin.com/linux/v6.5/source/drivers/gpu/drm/drm_gem_atomic_helper.c#L377 The regression was found only with G200 currently, so I don't want to apply it blindly on other drivers. Thanks for your help, Best regards,
Re: [PATCH] drm/ast: use managed devres functions
On 30/10/2023 10:50, Philipp Stanner wrote: Currently, tha ast-driver just maps the PCI-dev's regions with pcim_iomap(). It does not actually reserve the regions exclusively with, e.g., pci_request_regions(). Replace the calls to pcim_iomap() with ones to pcim_iomap_regions() to reserve and map the regions simultaneously. Suggested-by: Thomas Zimmermann Signed-off-by: Philipp Stanner --- ¡Hola! I picked up the memory-region-request-task from the DRM-TODO-List [1] and began with this driver. Please have a first look. I wasn't entirely sure about -ENOMEM... for example, as far as my understanding goes, it should not be able to fail anyways in the second call. Yes, you can remove these checks, other drivers don't do it: https://elixir.bootlin.com/linux/latest/source/arch/x86/platform/intel-mid/pwr.c#L372 I don't have the server-hardware, thus, can't test it on a physical machine. I've done a quick check on an AST2600, and it works. Please tell me what you think. That's a good patch, thanks for your contribution. I'll wait for Thomas review, and with the checks removed, I can help push it to drm-misc-next. P. [1] https://dri.freedesktop.org/docs/drm/gpu/todo.html#request-memory-regions-in-all-drivers --- drivers/gpu/drm/ast/ast_main.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index dae365ed3969..1004c6628938 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -444,9 +444,13 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (ret) return ERR_PTR(ret); - ast->regs = pcim_iomap(pdev, 1, 0); + ret = pcim_iomap_regions(pdev, BIT(1), 0); + if (ret) + return ERR_PTR(ret); + + ast->regs = pcim_iomap_table(pdev)[1]; if (!ast->regs) - return ERR_PTR(-EIO); + return ERR_PTR(-ENOMEM); You can remove this check. /* * After AST2500, MMIO is enabled by default, and it should be adopted @@ -461,9 +465,12 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, /* "map" IO regs if the above hasn't done so already */ if (!ast->ioregs) { - ast->ioregs = pcim_iomap(pdev, 2, 0); + ret = pcim_iomap_regions(pdev, BIT(2), 0); + if (ret) + return ERR_PTR(ret); + ast->ioregs = pcim_iomap_table(pdev)[2]; if (!ast->ioregs) - return ERR_PTR(-EIO); + return ERR_PTR(-ENOMEM); you can remove this check too. } if (!ast_is_vga_enabled(dev)) { -- Jocelyn