[PATCH v3 2/3] drm/panic: Add a drm panic handler
Jocelyn Falempe
jfalempe at redhat.com
Thu Sep 28 15:41:52 UTC 2023
On 28/09/2023 11:30, Thomas Zimmermann wrote:
>
>
> Am 27.09.23 um 19:22 schrieb Jocelyn Falempe:
>> This module displays a user friendly message when a kernel panic
>> occurs. It currently doesn't contain any debug information,
>> but that can be added later.
>>
>> v2
>> * Use get_scanout_buffer() instead of the drm client API.
>> (Thomas Zimmermann)
>> * Add the panic reason to the panic message (Nerdopolis)
>> * Add an exclamation mark (Nerdopolis)
>>
>> v3
>> * Rework the drawing functions, to write the pixels line by line and
>> to use the drm conversion helper to support other formats.
>> (Thomas Zimmermann)
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe at redhat.com>
>> ---
>> drivers/gpu/drm/Kconfig | 11 ++
>> drivers/gpu/drm/Makefile | 1 +
>> drivers/gpu/drm/drm_drv.c | 3 +
>> drivers/gpu/drm/drm_panic.c | 366 ++++++++++++++++++++++++++++++++++++
>> include/drm/drm_drv.h | 14 ++
>> include/drm/drm_panic.h | 41 ++++
>> 6 files changed, 436 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 afb3b2f5f425..98d78f865180 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -99,6 +99,17 @@ 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
>> + default y if DRM_SIMPLEDRM
>
> No 'default y' please. We sometimes do this for compatibility with
> existing configs, but that's clearly not the case here.
ok, yes it's better not enabled by default.
>
>> + 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.
>> +
>> 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 7a09a89b493b..a525dd9a2751 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -72,6 +72,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 12687dd9e1ac..0e0f1e258845 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -45,6 +45,7 @@
>> #include <drm/drm_mode_object.h>
>> #include <drm/drm_print.h>
>> #include <drm/drm_privacy_screen_machine.h>
>> +#include <drm/drm_panic.h>
>
> In alphabetical order please.
ok,
>
>> #include "drm_crtc_internal.h"
>> #include "drm_internal.h"
>> @@ -1067,6 +1068,7 @@ static void drm_core_exit(void)
>> unregister_chrdev(DRM_MAJOR, "drm");
>> debugfs_remove(drm_debugfs_root);
>> drm_sysfs_destroy();
>> + drm_panic_exit();
>> idr_destroy(&drm_minors_idr);
>> drm_connector_ida_destroy();
>> }
>> @@ -1078,6 +1080,7 @@ static int __init drm_core_init(void)
>> drm_connector_ida_init();
>> idr_init(&drm_minors_idr);
>> drm_memcpy_init_early();
>> + drm_panic_init();
>> ret = drm_sysfs_init();
>> if (ret < 0) {
>> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
>> new file mode 100644
>> index 000000000000..1d93e4dbed9a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_panic.c
>> @@ -0,0 +1,366 @@
>> +// SPDX-License-Identifier: GPL-2.0 or MIT
>> +/*
>> + * Copyright (c) 2023 Jocelyn Falempe <jfalempe at redhat.com>
>> + * inspired by the drm_log driver from David Herrmann
>> <dh.herrmann at gmail.com>
>> + * Tux Ascii art taken from cowsay written by Tony Monroe
>> + */
>> +
>> +#include <linux/font.h>
>> +#include <linux/iosys-map.h>
>> +#include <linux/kdebug.h>
>> +#include <linux/list.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/panic_notifier.h>
>> +#include <linux/types.h>
>> +
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_format_helper.h>
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/drm_panic.h>
>> +#include <drm/drm_print.h>
>> +
>> +
>> +MODULE_AUTHOR("Jocelyn Falempe");
>> +MODULE_DESCRIPTION("DRM PANIC");
>
> A better descrition please. At lease something like "DRM panic handler".
ok,
>
>> +MODULE_LICENSE("GPL");
>> +
>> +/**
>> + * DOC: DRM Panic
>> + *
>> + * This module displays a user friendly message on screen when a
>> kernel panic
>
> Drop 'user friendly' here. That message is *never* user friendly. :D
Yes, but at the same time when you look at:
https://en.wikipedia.org/wiki/Screen_of_death
If you're not a computer scientist, the Linux one is the scariest.
I added the friendly tux logo to comfort you when you may have lost your
last hour of work.
>
>> + * occurs. It's useful when using a user-space console instead of fbcon.
>> + * It's intended for end-user, so have minimal technical/debug
>> information.
>
> These two sentences miss the point. If the kernel crashes, the only
> useful message is a technical one, such as a stack trace. The panic
> handler should provide information for finding the bug.
>
My point of view is that technical/debug information should come with
kdump. Or maybe encode the stack trace in a qrcode, so you can report
the bug easily. But displaying the stack frame is useless to non-developers.
For the first version, I prefer to have only the panic reason, and then
we can add other features incrementaly.
>> + *
>> + * It will display only one static frame, so performance
>> optimizations are low
>> + * priority as the machine is already in an unusable state.
>
> An implementation detail.
>
> In these docs, I'd rather say that it display an error message if a
> kernel panic occurs on kernels without framebuffer console.
Ok, I will clarify this point.
>
> We should clarify if the message appears only if the framebuffer console
> is absent from the kernel (the current behavior), or if the console can
> be running, but not be the active DRM master.
I prefer to keep it this way, because otherwise the framebuffer console
and drm_panic might compete for the framebuffer, and I don't want to
handle this case.
>
>> + */
>> +
>> +/*
>> + * List of active drm devices that can render a panic
>> + */
>> +struct dpanic_drm_device {
>
> The naming is odd. This isn't driver code, but a DRM core feature. The
> common style for DRM core code is to start with drm_. Calling this
> structure drm_panic_device seems more appropriate. The same gos for all
> the dpanic_ names below.
Yes, I'm not good at variable naming, I will change that.
>
>> + struct list_head head;
>> + struct drm_device *dev;
>> +};
>> +
>> +struct dpanic_line {
>> + u32 len;
>> + const char *txt;
>> +};
>> +
>> +#define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
>> +
>> +struct dpanic_line panic_msg[] = {
>> + PANIC_LINE("KERNEL PANIC !"),
>> + PANIC_LINE(""),
>> + PANIC_LINE("Please reboot your computer."),
>> + PANIC_LINE(""),
>> + PANIC_LINE(""), /* overwritten with panic reason */
>> +};
>> +
>> +const struct dpanic_line logo[] = {
>> + PANIC_LINE(" .--. _"),
>> + PANIC_LINE(" |o_o | | |"),
>> + PANIC_LINE(" |:_/ | | |"),
>> + PANIC_LINE(" // \\ \\ |_|"),
>> + PANIC_LINE(" (| | ) _"),
>> + PANIC_LINE(" /'\\_ _/`\\ (_)"),
>> + PANIC_LINE(" \\___)=(___/"),
>> +};
>
> For merging this code, it should print something useful. It looks like
> stack traces can be quieried and formatted with stack_trace_save() [1]
> and stack_trace_snprint(). [2] I'd reserve a few pages for the stack
> trace and display the top-most information from the stack.
For most users, just saying to reboot the computer is the only useful
thing to print. But I know that for developpers, it would be handy to
add this later, as a config option.
>
> [1] https://elixir.bootlin.com/linux/latest/source/kernel/stacktrace.c#L259
> [2] https://elixir.bootlin.com/linux/latest/source/kernel/stacktrace.c#L37
Thanks for the pointer. I already looked at dump_stack(), but didn't
find a way to get the string.
>
>> +
>> +static LIST_HEAD(dpanic_devices);
>> +static DEFINE_MUTEX(dpanic_lock);
>> +
>> +/*
>> + * This buffer is used to convert xrgb8888 to the scanout buffer format.
>> + * It is allocated when the first client register, and freed when the
>> last client
>> + * unregisters.
>> + * There is no need for mutex, as the panic garantee that only 1 CPU
>> is still
>> + * running, and preemption is disabled.
>> + */
>> +#define DRM_PANIC_MAX_WIDTH 8096
>> +static u32 *dpanic_line_buf;
>> +static u32 fg_color = le32_to_cpu(0x00ffffff);
>> +static u32 bg_color = le32_to_cpu(0x00000000);
>> +
>> +static void dpanic_draw_line(const struct dpanic_line *msg, size_t
>> left_margin,
>> + size_t l, size_t width, const struct font_desc *font)
>> +{
>> + size_t x, i, j;
>> + const u8 *src;
>> + size_t src_stride = DIV_ROUND_UP(font->width, 8);
>> + u32 *dst = dpanic_line_buf;
>> +
>> + for (x = 0; x < left_margin * font->width; x++)
>> + *dst++ = bg_color;
>> +
>> + for (i = 0; i < msg->len; i++) {
>> + for (j = 0; j < font->width; j++) {
>> + src = font->data + (msg->txt[i] * font->height + l) *
>> src_stride;
>> + *dst++ = (src[j / 8] & (0x80 >> (j % 8))) ? fg_color :
>> bg_color;
>> + }
>> + }
>> + for (x = (left_margin + msg->len) * font->width; x < width ; x++)
>> + *dst++ = bg_color;
>> +}
>
> This helper is effectively an implementation of drm_fb_r1_to_xrgb8888().
> At some point, we should attempt to implementent it as such.
Yes, I can add this to the drm_format_helper, and call it from here.
>
> In the recent patchset for caching conversion memory, there's struct
> drm_xfrm_buf. It can later be used to store palette information and/or
> fg/bg colors.
Yes for the r1->xrgb8888 conversion, it's better to have a way to pass
fg/bg colors.
>
>> +
>> +static void dpanic_draw_txt_line(const struct dpanic_line *msg,
>> size_t left_margin, size_t y,
>> + struct drm_scanout_buffer *sb,
>> + const struct font_desc *font,
>> + void (*convert)(void *dbuf, const void *sbuf, unsigned
>> int npixels))
>> +{
>> + size_t dst_off;
>> + size_t l;
>> +
>> + for (l = 0; l < font->height; l++) {
>> + dpanic_draw_line(msg, left_margin, l, sb->width, font);
>> + if (convert)
>> + convert(dpanic_line_buf, dpanic_line_buf, sb->width);
>> +
>> + dst_off = (y * font->height + l) * sb->pitch;
>> + iosys_map_memcpy_to(&sb->map, dst_off, dpanic_line_buf,
>> + sb->width * sb->format->cpp[0]);
>> + }
>> +}
>> +
>> +static void dpanic_draw_empty_txt_line(size_t y,
>> + struct drm_scanout_buffer *sb,
>> + const struct font_desc *font,
>> + void (*convert)(void *dbuf, const void *sbuf, unsigned
>> int npixels))
>> +{
>> + size_t i, dst_off;
>> + u32 *dst = dpanic_line_buf;
>> +
>> + for (i = 0; i < sb->width; i++)
>> + *dst++ = bg_color;
>> +
>> + if (convert)
>> + convert(dpanic_line_buf, dpanic_line_buf, sb->width);
>> +
>> + for (i = 0; i < font->height; i++) {
>> + dst_off = (y * font->height + i) * sb->pitch;
>> + iosys_map_memcpy_to(&sb->map, dst_off, dpanic_line_buf,
>> + sb->width * sb->format->cpp[0]);
>> + }
>> +}
>> +
>> +static size_t dpanic_needed_lines(size_t chars_per_line)
>> +{
>> + size_t msg_len = ARRAY_SIZE(panic_msg);
>> + size_t lines = 0;
>> + size_t i;
>> +
>> + for (i = 0; i < msg_len; i++)
>> + lines += panic_msg[i].len ? DIV_ROUND_UP(panic_msg[i].len,
>> chars_per_line) : 1;
>> + return lines;
>> +}
>> +
>> +static bool dpanic_can_draw_logo(size_t chars_per_line, size_t lines,
>> size_t msg_lines)
>> +{
>> + size_t i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(logo); i++) {
>> + if (logo[i].len > chars_per_line)
>> + return false;
>> + }
>> + if (lines < msg_lines + ARRAY_SIZE(logo))
>> + return false;
>> + return true;
>> +}
>> +
>> +static size_t get_start_line(size_t lines, size_t msg_lines, bool
>> can_draw_logo)
>> +{
>> + size_t remaining;
>> + size_t logo_len = ARRAY_SIZE(logo);
>> +
>> + if (lines < msg_lines)
>> + return 0;
>> + remaining = lines - msg_lines;
>> + if (can_draw_logo && remaining / 2 <= logo_len)
>> + return logo_len + (remaining - logo_len) / 4;
>> + return remaining / 2;
>> +}
>> +
>> +/*
>> + * Return the function to convert xrgb8888 to the scanout buffer format
>> + * NULL if no conversion is needed, and ERR_PTR if format can't be
>> converted
>> + */
>> +static void (*get_convert_func(const struct drm_format_info *format))
>> + (void *, const void *, unsigned int)
>> +{
>> + switch (format->format) {
>> + case DRM_FORMAT_XRGB8888:
>> + return NULL;
>> + case DRM_FORMAT_RGB565:
>> + return drm_fb_xrgb8888_to_rgb565_line;
>> + default:
>> + return ERR_PTR(EINVAL);
>> + }
>> +}
>
> This function plus dpanic_draw_*_line() will turn into a
> reimplementation of drm_fb_blit(). We should attempt to use
> drm_fb_blit() at some point, or at least share the majority of code.
> Maybe I have to do some work in the format-helper side to make this happen.
The problem I have with using drm_fb_blit(), is that I will need to call
it for each character, which means doing the "big format switch" a lot
of times. With this approach, it's done only once for the frame.
Also that means that instead of doing one memcpy_to_io() for the whole
framebuffer line (so typically 1024~4096 pixels), that will be done only
for one character width (8 pixels).
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_format_helper.c#L122
Thanks for the review,
--
Jocelyn
>
> Best regards
> Thomas
>
>> +
>> +
>> +/*
>> + * Draw the panic message at the center of the screen
>> + */
>> +static void dpanic_static_draw(struct drm_scanout_buffer *sb, const
>> char *msg)
>> +{
>> + size_t lines, msg_lines, l, msg_start_line, msgi;
>> + size_t center, chars_per_line;
>> + bool can_draw_logo;
>> + struct dpanic_line panic_line;
>> + size_t msg_len = ARRAY_SIZE(panic_msg);
>> + size_t logo_len = ARRAY_SIZE(logo);
>> + void (*convert)(void *dbuf, const void *sbuf, unsigned int npixels);
>> + const struct font_desc *font = get_default_font(sb->width,
>> sb->height, 0x8080, 0x8080);
>> +
>> + if (!font)
>> + return;
>> +
>> + /* Set the panic reason */
>> + panic_msg[msg_len - 1].len = strlen(msg);
>> + panic_msg[msg_len - 1].txt = msg;
>> +
>> + lines = sb->height / font->height;
>> + chars_per_line = sb->width / font->width;
>> +
>> + msg_lines = dpanic_needed_lines(chars_per_line);
>> + can_draw_logo = dpanic_can_draw_logo(chars_per_line, lines,
>> msg_lines);
>> + msg_start_line = get_start_line(lines, msg_lines, can_draw_logo);
>> +
>> + convert = get_convert_func(sb->format);
>> + if (IS_ERR(convert))
>> + return;
>> +
>> + msgi = 0;
>> + panic_line.len = 0;
>> + for (l = 0; l < lines; l++) {
>> + if (can_draw_logo && l < logo_len)
>> + dpanic_draw_txt_line(&logo[l], 0, l, sb, font, convert);
>> + else if (l >= msg_start_line && msgi < msg_len) {
>> + if (!panic_line.len) {
>> + panic_line.txt = panic_msg[msgi].txt;
>> + panic_line.len = panic_msg[msgi].len;
>> + }
>> + if (!panic_line.len)
>> + dpanic_draw_empty_txt_line(l, sb, font, convert);
>> + else {
>> + center = panic_line.len > chars_per_line ?
>> + 0 : (chars_per_line - panic_line.len) / 2;
>> + dpanic_draw_txt_line(&panic_line, center, l, sb,
>> font, convert);
>> + }
>> + if (panic_line.len > chars_per_line) {
>> + panic_line.len -= chars_per_line;
>> + panic_line.txt += chars_per_line;
>> + } else {
>> + panic_line.len = 0;
>> + msgi++;
>> + }
>> + } else {
>> + dpanic_draw_empty_txt_line(l, sb, font, convert);
>> + }
>> + }
>> +}
>> +
>> +static void drm_panic_device(struct drm_device *dev, const char *msg)
>> +{
>> + struct drm_scanout_buffer sb;
>> +
>> + if (dev->driver->get_scanout_buffer(dev, &sb))
>> + return;
>> + if (!dpanic_line_buf)
>> + return;
>> +
>> + /* to avoid buffer overflow on dpanic_line_buf */
>> + if (sb.width > DRM_PANIC_MAX_WIDTH)
>> + sb.width = DRM_PANIC_MAX_WIDTH;
>> +
>> + dpanic_static_draw(&sb, msg);
>> +}
>> +
>> +static int drm_panic(struct notifier_block *this, unsigned long event,
>> + void *ptr)
>> +{
>> + struct dpanic_drm_device *dpanic_device;
>> +
>> + list_for_each_entry(dpanic_device, &dpanic_devices, head) {
>> + drm_panic_device(dpanic_device->dev, ptr);
>> + }
>> + return NOTIFY_OK;
>> +}
>> +
>> +struct notifier_block drm_panic_notifier = {
>> + .notifier_call = drm_panic,
>> +};
>> +
>> +/**
>> + * drm_panic_register() - Initialize DRM panic for a device
>> + * @dev: the DRM device on which the panic screen will be displayed.
>> + */
>> +void drm_panic_register(struct drm_device *dev)
>> +{
>> + struct dpanic_drm_device *new;
>> +
>> + new = kzalloc(sizeof(*new), GFP_KERNEL);
>> + if (!new)
>> + return;
>> +
>> + new->dev = dev;
>> + mutex_lock(&dpanic_lock);
>> + if (!dpanic_line_buf)
>> + dpanic_line_buf = kmalloc(DRM_PANIC_MAX_WIDTH * sizeof(u32),
>> GFP_KERNEL);
>> + if (!dpanic_line_buf)
>> + goto unlock;
>> + list_add_tail(&new->head, &dpanic_devices);
>> + drm_info(dev, "Registered with drm panic\n");
>> +unlock:
>> + mutex_unlock(&dpanic_lock);
>> +}
>> +EXPORT_SYMBOL(drm_panic_register);
>> +
>> +/**
>> + * drm_panic_unregister()
>> + * @dev: the DRM device previously registered.
>> + */
>> +void drm_panic_unregister(struct drm_device *dev)
>> +{
>> + struct dpanic_drm_device *dpanic_device;
>> + struct dpanic_drm_device *found = NULL;
>> +
>> + mutex_lock(&dpanic_lock);
>> + list_for_each_entry(dpanic_device, &dpanic_devices, head) {
>> + if (dpanic_device->dev == dev)
>> + found = dpanic_device;
>> + }
>> + if (found) {
>> + list_del(&found->head);
>> + kfree(found);
>> + drm_info(dev, "Unregistered with drm panic\n");
>> + }
>> + if (dpanic_line_buf && list_empty(&dpanic_devices)) {
>> + kfree(dpanic_line_buf);
>> + dpanic_line_buf = NULL;
>> + }
>> + mutex_unlock(&dpanic_lock);
>> +}
>> +EXPORT_SYMBOL(drm_panic_unregister);
>> +
>> +/**
>> + * drm_panic_init() - Initialize drm-panic subsystem
>> + *
>> + * register the panic notifier
>> + */
>> +void drm_panic_init(void)
>> +{
>> + atomic_notifier_chain_register(&panic_notifier_list,
>> + &drm_panic_notifier);
>> +}
>> +
>> +/**
>> + * drm_log_exit() - Shutdown drm-panic subsystem
>> + */
>> +void drm_panic_exit(void)
>> +{
>> + atomic_notifier_chain_unregister(&panic_notifier_list,
>> + &drm_panic_notifier);
>> +}
>> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
>> index 89e2706cac56..e538c87116d3 100644
>> --- a/include/drm/drm_drv.h
>> +++ b/include/drm/drm_drv.h
>> @@ -43,6 +43,7 @@ struct dma_buf_attachment;
>> struct drm_display_mode;
>> struct drm_mode_create_dumb;
>> struct drm_printer;
>> +struct drm_scanout_buffer;
>> struct sg_table;
>> /**
>> @@ -408,6 +409,19 @@ struct drm_driver {
>> */
>> void (*show_fdinfo)(struct drm_printer *p, struct drm_file *f);
>> + /**
>> + * @get_scanout_buffer:
>> + *
>> + * Get the current scanout buffer, to display a panic message
>> with drm_panic.
>> + * It is called from a panic callback, and must follow its
>> restrictions.
>> + *
>> + * Returns:
>> + *
>> + * Zero on success, negative errno on failure.
>> + */
>> + int (*get_scanout_buffer)(struct drm_device *dev,
>> + struct drm_scanout_buffer *sb);
>> +
>> /** @major: driver major number */
>> int major;
>> /** @minor: driver minor number */
>> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
>> new file mode 100644
>> index 000000000000..db430b8dfbb2
>> --- /dev/null
>> +++ b/include/drm/drm_panic.h
>> @@ -0,0 +1,41 @@
>> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
>> +#ifndef __DRM_PANIC_H__
>> +#define __DRM_PANIC_H__
>> +
>> +/*
>> + * Copyright (c) 2023 Jocelyn Falempe <jfalempe at redhat.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/iosys-map.h>
>> +
>> +struct drm_device;
>> +
>> +struct drm_scanout_buffer {
>> + const struct drm_format_info *format;
>> + struct iosys_map map;
>> + unsigned int pitch;
>> + unsigned int width;
>> + unsigned int height;
>> +};
>> +
>> +#ifdef CONFIG_DRM_PANIC
>> +
>> +void drm_panic_init(void);
>> +void drm_panic_exit(void);
>> +
>> +void drm_panic_register(struct drm_device *dev);
>> +void drm_panic_unregister(struct drm_device *dev);
>> +
>> +#else
>> +
>> +static inline void drm_panic_init(void) {}
>> +static inline void drm_panic_exit(void) {}
>> +
>> +static inline void drm_panic_register(struct drm_device *dev) {}
>> +static inline void drm_panic_unregister(struct drm_device *dev) {}
>> +
>> +#endif
>> +
>> +#endif /* __DRM_LOG_H__ */
>
More information about the dri-devel
mailing list