drivers/gpu/drm/drm_debugfs.c
drm_minor_register--->drm_debugfs_init --》drm_framebuffer_debugfs_init
static const struct drm_info_list drm_debugfs_list[] = {
{"name", drm_name_info, 0},
{"clients", drm_clients_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
};
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root)
{
struct drm_device *dev = minor->dev;
char name[64];
int ret;
INIT_LIST_HEAD(&minor->debugfs_list);
mutex_init(&minor->debugfs_lock);
sprintf(name, "%d", minor_id);
minor->debugfs_root = debugfs_create_dir(name, root);
ret = drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
if (ret) {
debugfs_remove(minor->debugfs_root);
minor->debugfs_root = NULL;
DRM_ERROR("Failed to create core drm debugfs files\n");
return ret;
}
if (drm_drv_uses_atomic_modeset(dev)) {
ret = drm_atomic_debugfs_init(minor);//atomic debugfs
if (ret) {
DRM_ERROR("Failed to create atomic debugfs files\n");
return ret;
}
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = drm_framebuffer_debugfs_init(minor);//fb
if (ret) {
DRM_ERROR("Failed to create framebuffer debugfs file\n");
return ret;
}
ret = drm_client_debugfs_init(minor);
if (ret) {
DRM_ERROR("Failed to create client debugfs file\n");
return ret;
}
}
if (dev->driver->debugfs_init) {
ret = dev->driver->debugfs_init(minor);
if (ret) {
DRM_ERROR("DRM: Driver failed to initialize "
"/sys/kernel/debug/dri.\n");
return ret;
}
}
return 0;
}
void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
const struct drm_framebuffer *fb)
{
struct drm_format_name_buf format_name;
unsigned int i;
drm_printf_indent(p, indent, "allocated by = %s\n", fb->comm);//谁分配的fb
drm_printf_indent(p, indent, "refcount=%u\n",
drm_framebuffer_read_refcount(fb));//引用计数
drm_printf_indent(p, indent, "format=%s\n",
drm_get_format_name(fb->format->format, &format_name));//fb的格式
drm_printf_indent(p, indent, "modifier=0x%llx\n", fb->modifier);
drm_printf_indent(p, indent, "size=%ux%u\n", fb->width, fb->height);//宽和高
drm_printf_indent(p, indent, "layers:\n");
for (i = 0; i < fb->format->num_planes; i++) {//打印每一个图层的信息
drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i,
drm_framebuffer_plane_width(fb->width, fb, i),
drm_framebuffer_plane_height(fb->height, fb, i));
drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]);
drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]);
drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i,
fb->obj[i] ? "" : "(null)");
if (fb->obj[i])
drm_gem_print_info(p, indent + 2, fb->obj[i]);
}
}
#ifdef CONFIG_DEBUG_FS
static int drm_framebuffer_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_printer p = drm_seq_file_printer(m);
struct drm_framebuffer *fb;
mutex_lock(&dev->mode_config.fb_lock);
drm_for_each_fb(fb, dev) {//遍历所有的fb
drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
drm_framebuffer_print_info(&p, 1, fb);
}
mutex_unlock(&dev->mode_config.fb_lock);
return 0;
}
static const struct drm_info_list drm_framebuffer_debugfs_list[] = {
{ "framebuffer", drm_framebuffer_info, 0 },
};
int drm_framebuffer_debugfs_init(struct drm_minor *minor)
{
return drm_debugfs_create_files(drm_framebuffer_debugfs_list,
ARRAY_SIZE(drm_framebuffer_debugfs_list),
minor->debugfs_root, minor);
}
drm atomic state
static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p,
bool take_locks)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
if (!drm_drv_uses_atomic_modeset(dev))
return;
list_for_each_entry(plane, &config->plane_list, head) {
if (take_locks)
drm_modeset_lock(&plane->mutex, NULL);
drm_atomic_plane_print_state(p, plane->state);//plane state
if (take_locks)
drm_modeset_unlock(&plane->mutex);
}
list_for_each_entry(crtc, &config->crtc_list, head) {
if (take_locks)
drm_modeset_lock(&crtc->mutex, NULL);
drm_atomic_crtc_print_state(p, crtc->state);//crtc
if (take_locks)
drm_modeset_unlock(&crtc->mutex);
}
drm_connector_list_iter_begin(dev, &conn_iter);
if (take_locks)
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
drm_for_each_connector_iter(connector, &conn_iter)
drm_atomic_connector_print_state(p, connector->state);//connector
if (take_locks)
drm_modeset_unlock(&dev->mode_config.connection_mutex);
drm_connector_list_iter_end(&conn_iter);
}
/**
* 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)
{
__drm_state_dump(dev, p, false);
}
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_state_dump(dev, &p, true);
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);
}