drm/atomic: add debugfs file to dump out atomic state

Useful to dump current state from debugfs, if turning on the drm.debug
bit is too much overhead.

The drm_state_dump() can also be used by drivers, for example to
implement a module param that dumps state on error irqs.

Signed-off-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1478358492-30738-6-git-send-email-robdclark@gmail.com
This commit is contained in:
Rob Clark 2016-11-05 11:08:10 -04:00 committed by Sean Paul
parent fceffb325b
commit 6559c901cb
3 changed files with 79 additions and 0 deletions

View File

@ -1577,6 +1577,69 @@ static void drm_atomic_print_state(const struct drm_atomic_state *state)
drm_atomic_connector_print_state(&p, connector_state);
}
/**
* drm_state_dump - dump entire device atomic state
* @dev: the drm device
* @p: where to print the state to
*
* Just for debugging. Drivers might want an option to dump state
* to dmesg in case of error irq's. (Hint, you probably want to
* ratelimit this!)
*
* The caller must drm_modeset_lock_all(), or if this is called
* from error irq handler, it should not be enabled by default.
* (Ie. if you are debugging errors you might not care that this
* is racey. But calling this without all modeset locks held is
* not inherently safe.)
*/
void drm_state_dump(struct drm_device *dev, struct drm_printer *p)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_connector *connector;
if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
return;
list_for_each_entry(plane, &config->plane_list, head)
drm_atomic_plane_print_state(p, plane->state);
list_for_each_entry(crtc, &config->crtc_list, head)
drm_atomic_crtc_print_state(p, crtc->state);
list_for_each_entry(connector, &config->connector_list, head)
drm_atomic_connector_print_state(p, connector->state);
}
EXPORT_SYMBOL(drm_state_dump);
#ifdef CONFIG_DEBUG_FS
static int drm_state_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_printer p = drm_seq_file_printer(m);
drm_modeset_lock_all(dev);
drm_state_dump(dev, &p);
drm_modeset_unlock_all(dev);
return 0;
}
/* any use in debugfs files to dump individual planes/crtc/etc? */
static const struct drm_info_list drm_atomic_debugfs_list[] = {
{"state", drm_state_info, 0},
};
int drm_atomic_debugfs_init(struct drm_minor *minor)
{
return drm_debugfs_create_files(drm_atomic_debugfs_list,
ARRAY_SIZE(drm_atomic_debugfs_list),
minor->debugfs_root, minor);
}
#endif
/*
* The big monstor ioctl
*/

View File

@ -36,6 +36,7 @@
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include <drm/drm_atomic.h>
#include "drm_internal.h"
#if defined(CONFIG_DEBUG_FS)
@ -163,6 +164,14 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
return ret;
}
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
ret = drm_atomic_debugfs_init(minor);
if (ret) {
DRM_ERROR("Failed to create atomic debugfs files\n");
return ret;
}
}
if (dev->driver->debugfs_init) {
ret = dev->driver->debugfs_init(minor);
if (ret) {

View File

@ -366,6 +366,13 @@ int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
int __must_check drm_atomic_commit(struct drm_atomic_state *state);
int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state);
void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
#ifdef CONFIG_DEBUG_FS
struct drm_minor;
int drm_atomic_debugfs_init(struct drm_minor *minor);
#endif
#define for_each_connector_in_state(__state, connector, connector_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_connector && \