diff --git a/MAINTAINERS b/MAINTAINERS index 5b5a4e4b35cf..af7d736ef12e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9120,7 +9120,8 @@ F: drivers/gpu/drm/drm_draw.c F: drivers/gpu/drm/drm_draw_internal.h F: drivers/gpu/drm/drm_panic*.c F: drivers/gpu/drm/tests/drm_panic_test.c -F: include/drm/drm_panic* +F: include/drm/drm_panic.h +F: include/drm/drm_panic_helper.h DRM PANIC QR CODE M: Jocelyn Falempe diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index adfbffae2983..5a1b7fd3de36 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -28,6 +28,7 @@ #include #include "drm/drm_framebuffer.h" #include +#include #include #include #include @@ -2176,6 +2177,7 @@ static const struct drm_plane_funcs dm_plane_funcs = { .atomic_set_property = dm_atomic_plane_set_property, .atomic_get_property = dm_atomic_plane_get_property, #endif + DRM_PANIC_PLANE_FUNCS, }; int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index ea0ef8096aa9..08db132acae8 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 @@ -652,6 +653,7 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, DRM_GEM_SHADOW_PLANE_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; static int ast_primary_plane_init(struct ast_device *ast) diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index e54584da4c3d..cca623eb23e5 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,7 @@ static const uint32_t safe_modeset_formats[] = { static const struct drm_plane_funcs primary_plane_funcs = { DRM_PLANE_NON_ATOMIC_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; /** diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 522ea990a2e9..2bb172231dd0 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -42,32 +43,17 @@ MODULE_LICENSE("GPL"); /** * DOC: overview * - * To enable DRM panic for a driver, the primary plane must implement a - * &drm_plane_helper_funcs.get_scanout_buffer helper function. It is then - * automatically registered to the drm panic handler. - * When a panic occurs, the &drm_plane_helper_funcs.get_scanout_buffer will be - * called, and the driver can provide a framebuffer so the panic handler can - * draw the panic screen on it. Currently only linear buffer and a few color - * formats are supported. - * Optionally the driver can also provide a &drm_plane_helper_funcs.panic_flush - * callback, that will be called after that, to send additional commands to the - * hardware to make the scanout buffer visible. - */ - -/* - * This module displays a user friendly message on screen when a kernel panic - * occurs. This is conflicting with fbcon, so you can only enable it when fbcon - * is disabled. - * It's intended for end-user, so have minimal technical/debug information. + * This module displays a user friendly message on screen when a kernel + * panic occurs. It's intended for end users and therefore have minimal + * technical/debug information. * - * Implementation details: + * To enable DRM panic for a driver, the at least one primary plane must + * implement struct &drm_plane_funcs.display_panic_screen. The plane is + * then automatically registered to the drm panic handler. * - * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq, - * or attempt to sleep. It's a best effort, and it may not be able to display - * the message in all situations (like if the panic occurs in the middle of a - * modesetting). - * It will display only one static frame, so performance optimizations are low - * priority as the machine is already in an unusable state. + * When a panic occurs, the DRM panic handler calls struct + * &drm_plane_funcs.display_panic_screen. See + * drm_plane_helper_display_panic_screen() for a generic implementation. */ struct drm_panic_line { @@ -817,12 +803,6 @@ static void drm_panic_qr_init(void) {}; static void drm_panic_qr_exit(void) {}; #endif -enum drm_panic_type { - DRM_PANIC_TYPE_KMSG, - DRM_PANIC_TYPE_USER, - DRM_PANIC_TYPE_QR, -}; - static enum drm_panic_type drm_panic_type = -1; static const char *drm_panic_type_map[] = { @@ -936,21 +916,46 @@ static void drm_panic_clear_description(void) desc_line->txt = NULL; } -static void draw_panic_plane(struct drm_plane *plane, const char *description, - enum drm_panic_type panic_type, u32 fg_color, u32 bg_color, - unsigned int qr_version) +/** + * drm_plane_helper_display_panic_screen - Displays a panic screen according to the given settings + * @plane: the DRM plane to display to + * @description: error message to display + * @panic_type: type of panic screen + * @fg_color: text foreground color + * @bg_color: text background color + * @qr_version: version of the QR code, if any + * + * This helper display a panic screen on common primary planes. The panic + * screen can either display a kernel message, a user message or a QR code. + * + * The helper uses struct drm_plane_helper_funcs.get_scanout_buffer, where + * the plane can provide a scanout buffer that the panic handler can draw to. + * Currently only linear buffer and a few color formats are supported. + * + * Optionally the plane can also provide a &drm_plane_helper_funcs.panic_flush + * callback, which the DRM panic handler calls after drawing to send additional + * commands to the hardware to make the scanout buffer visible. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_plane_helper_display_panic_screen(struct drm_plane *plane, const char *description, + enum drm_panic_type panic_type, + u32 fg_color, u32 bg_color, unsigned int qr_version) { struct drm_scanout_buffer sb = { }; int ret; ret = plane->helper_private->get_scanout_buffer(plane, &sb); + if (ret) + return ret; - if (ret || !drm_panic_is_format_supported(sb.format)) - return; + if (!drm_panic_is_format_supported(sb.format)) + return -EINVAL; /* One of these should be set, or it can't draw pixels */ if (!sb.set_pixel && !sb.pages && iosys_map_is_null(&sb.map[0])) - return; + return -EINVAL; drm_panic_set_description(description); @@ -965,7 +970,10 @@ static void draw_panic_plane(struct drm_plane *plane, const char *description, } drm_panic_clear_description(); + + return ret; } +EXPORT_SYMBOL(drm_plane_helper_display_panic_screen); static void drm_panic_display_panic_screen(struct drm_plane *plane, const char *description) { @@ -988,8 +996,8 @@ static void drm_panic_display_panic_screen(struct drm_plane *plane, const char * unsigned long flags; if (drm_panic_trylock(dev, flags)) { - draw_panic_plane(plane, description, drm_panic_type, - fg_color, bg_color, qr_version); + plane->funcs->display_panic_screen(plane, description, drm_panic_type, + fg_color, bg_color, qr_version); drm_panic_unlock(dev, flags); } } @@ -1062,7 +1070,7 @@ bool drm_panic_is_enabled(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) continue; - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + if (!plane->funcs || !plane->funcs->display_panic_screen) continue; return true; } @@ -1085,7 +1093,7 @@ void drm_panic_register(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) continue; - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + if (!plane->funcs || !plane->funcs->display_panic_screen) continue; plane->kmsg_panic.dump = drm_panic; plane->kmsg_panic.max_reason = KMSG_DUMP_PANIC; @@ -1114,7 +1122,7 @@ void drm_panic_unregister(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) continue; - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + if (!plane->funcs || !plane->funcs->display_panic_screen) continue; kmsg_dump_unregister(&plane->kmsg_panic); } diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 3261e730c69d..523d1c7ea072 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -237,6 +238,7 @@ static const struct drm_plane_funcs hv_drm_plane_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, DRM_GEM_SHADOW_PLANE_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_encoder_funcs hv_drm_simple_encoder_funcs_cleanup = { diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index df6da1c6a359..0902b17d0269 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "i9xx_plane.h" @@ -887,6 +888,7 @@ static const struct drm_plane_funcs i965_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i965_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs i8xx_plane_funcs = { @@ -897,6 +899,7 @@ static const struct drm_plane_funcs i8xx_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i8xx_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static void i9xx_disable_tiling(struct intel_plane *plane) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 5cda1ab90e40..8c0f414badf3 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -2712,6 +2713,7 @@ static const struct drm_plane_funcs skl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = skl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs icl_plane_funcs = { @@ -2722,6 +2724,7 @@ static const struct drm_plane_funcs icl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = icl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs tgl_plane_funcs = { @@ -2732,6 +2735,7 @@ static const struct drm_plane_funcs tgl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = tgl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static void diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index afebd4fe4395..67e78a5ac881 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 #include