[PATCH v7 2/9] drm/panic: Add a drm panic handler

Jocelyn Falempe jfalempe at redhat.com
Thu Jan 18 10:17:12 UTC 2024



On 17/01/2024 16:49, Thomas Zimmermann wrote:
> Hi
> 
> Am 04.01.24 um 17:00 schrieb Jocelyn Falempe:
> [...]
>> +    /**
>> +     * @get_scanout_buffer:
>> +     *
>> +     * Get the current scanout buffer, to display a panic message 
>> with drm_panic.
>> +     * The driver should do the minimum changes to provide a linear 
>> buffer, that
>> +     * can be used to display the panic screen.
>> +     * It is called from a panic callback, and must follow its 
>> restrictions.
>> +     * (no locks, no memory allocation, no sleep, no 
>> thread/workqueue, ...)
>> +     * It's a best effort mode, so it's expected that in some complex 
>> cases the
>> +     * panic screen won't be displayed.
>> +     * Some hardware cannot provide a linear buffer, so there is a 
>> draw_pixel_xy()
>> +     * callback in the struct drm_scanout_buffer that can be used in 
>> this case.
>> +     *
>> +     * Returns:
>> +     *
>> +     * Zero on success, negative errno on failure.
>> +     */
>> +    int (*get_scanout_buffer)(struct drm_device *dev,
>> +                  struct drm_scanout_buffer *sb);
>> +
> 
> After reading through Sima's comments on (try-)locking, I'd like to 
> propose a different interface: instead of having the panic handler 
> search for the scanout buffer, let each driver explicitly set the 
> scanout buffer after each page flip. The algorithm for mode programming 
> then looks like this:
> 
>   1) Maybe clear the panic handler's buffer at the beginning of 
> atomic_commit_tail, if necessary
>   2) Do the mode setting as usual
>   3) In the driver's atomic_flush or atomic_update, call something like
> 
>      void drm_panic_set_scanout_buffer(dev, scanout_buffer)
> 
> to set the panic handler's new output.
> 
> This avoids all the locking and the second guessing about the pipeline 
> status.
> 
> I don't see an easy way of reliably showing a panic screen during a 
> modeset. But during a modeset, the old scanout buffer should 
> (theoretically) not disappear until the new scanout buffer is in place. 
> So if the panic happens, it would blit to the old address at worst. 
> Well, that assumption needs to be verified per driver.

That's an interesting approach, and I will give it a try.
I think you still need a callback in the driver, to actually send the 
data to the GPU.

Also one thing that I don't handle yet, is when there are multiple 
outputs, so we may want to set and update multiple scanout buffers ?

Best regards,

-- 

Jocelyn


> 
> Best regards
> Thomas
> 
> 
>>       /** @major: driver major number */
>>       int major;
>>       /** @minor: driver minor number */
>> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h
>> new file mode 100644
>> index 000000000000..bcf392b6fa1b
>> --- /dev/null
>> +++ b/include/drm/drm_panic.h
>> @@ -0,0 +1,97 @@
>> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
>> +#ifndef __DRM_PANIC_H__
>> +#define __DRM_PANIC_H__
>> +
>> +/*
>> + * Copyright (c) 2023 Red Hat.
>> + * Author: Jocelyn Falempe <jfalempe at redhat.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/iosys-map.h>
>> +
>> +struct drm_device;
>> +
>> +/**
>> + * struct drm_scanout_buffer - DRM scanout buffer
>> + *
>> + * This structure holds the information necessary for drm_panic to 
>> draw the
>> + * panic screen, and display it.
>> + * If the driver can't provide a linear buffer, it must clear @map with
>> + * iosys_map_clear() and provide a draw_pixel_xy() function.
>> + */
>> +struct drm_scanout_buffer {
>> +    /**
>> +     * @format:
>> +     *
>> +     * drm format of the scanout buffer.
>> +     */
>> +    const struct drm_format_info *format;
>> +    /**
>> +     * @map:
>> +     *
>> +     * Virtual address of the scanout buffer, either in memory or iomem.
>> +     * The scanout buffer should be in linear format, and can be 
>> directly
>> +     * sent to the display hardware. Tearing is not an issue for the 
>> panic
>> +     * screen.
>> +     */
>> +    struct iosys_map map;
>> +    /**
>> +     * @width: Width of the scanout buffer, in pixels.
>> +     */
>> +    unsigned int width;
>> +    /**
>> +     * @height: Height of the scanout buffer, in pixels.
>> +     */
>> +    unsigned int height;
>> +    /**
>> +     * @pitch: Length in bytes between the start of two consecutive 
>> lines.
>> +     */
>> +    unsigned int pitch;
>> +    /**
>> +     * @private:
>> +     *
>> +     * In case the driver can't provide a linear buffer, this is a 
>> pointer to
>> +     * some private data, that will be passed when calling 
>> @draw_pixel_xy()
>> +     * and @flush()
>> +     */
>> +    void *private;
>> +    /**
>> +     * @draw_pixel_xy:
>> +     *
>> +     * In case the driver can't provide a linear buffer, this is a 
>> function
>> +     * that drm_panic will call for each pixel to draw.
>> +     * Color will be converted to the format specified by @format.
>> +     */
>> +    void (*draw_pixel_xy)(unsigned int x, unsigned int y, u32 color, 
>> void *private);
>> +    /**
>> +     * @flush:
>> +     *
>> +     * This function is called after the panic screen is drawn, 
>> either using
>> +     * the iosys_map or the draw_pixel_xy path. In this function, the 
>> driver
>> +     * can send additional commands to the hardware, to make the buffer
>> +     * visible.
>> +     */
>> +    void (*flush)(void *private);
>> +};
>> +
>> +#ifdef CONFIG_DRM_PANIC
>> +
>> +void drm_panic_init(void);
>> +void drm_panic_exit(void);
>> +
>> +void drm_panic_register(struct drm_device *dev);
>> +void drm_panic_unregister(struct drm_device *dev);
>> +
>> +#else
>> +
>> +static inline void drm_panic_init(void) {}
>> +static inline void drm_panic_exit(void) {}
>> +
>> +static inline void drm_panic_register(struct drm_device *dev) {}
>> +static inline void drm_panic_unregister(struct drm_device *dev) {}
>> +
>> +#endif
>> +
>> +#endif /* __DRM_PANIC_H__ */
> 



More information about the dri-devel mailing list