root/drivers/gpu/drm/drm_debugfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_name_info
  2. drm_clients_info
  3. drm_gem_one_name_info
  4. drm_gem_name_info
  5. drm_debugfs_open
  6. drm_debugfs_create_files
  7. drm_debugfs_init
  8. drm_debugfs_remove_files
  9. drm_debugfs_remove_all_files
  10. drm_debugfs_cleanup
  11. connector_show
  12. connector_open
  13. connector_write
  14. edid_show
  15. edid_open
  16. edid_write
  17. drm_debugfs_connector_add
  18. drm_debugfs_connector_remove
  19. drm_debugfs_crtc_add
  20. drm_debugfs_crtc_remove

   1 /*
   2  * Created: Sun Dec 21 13:08:50 2008 by bgamari@gmail.com
   3  *
   4  * Copyright 2008 Ben Gamari <bgamari@gmail.com>
   5  *
   6  * Permission is hereby granted, free of charge, to any person obtaining a
   7  * copy of this software and associated documentation files (the "Software"),
   8  * to deal in the Software without restriction, including without limitation
   9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10  * and/or sell copies of the Software, and to permit persons to whom the
  11  * Software is furnished to do so, subject to the following conditions:
  12  *
  13  * The above copyright notice and this permission notice (including the next
  14  * paragraph) shall be included in all copies or substantial portions of the
  15  * Software.
  16  *
  17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23  * OTHER DEALINGS IN THE SOFTWARE.
  24  */
  25 
  26 #include <linux/debugfs.h>
  27 #include <linux/export.h>
  28 #include <linux/seq_file.h>
  29 #include <linux/slab.h>
  30 #include <linux/uaccess.h>
  31 
  32 #include <drm/drm_atomic.h>
  33 #include <drm/drm_auth.h>
  34 #include <drm/drm_client.h>
  35 #include <drm/drm_debugfs.h>
  36 #include <drm/drm_device.h>
  37 #include <drm/drm_drv.h>
  38 #include <drm/drm_edid.h>
  39 #include <drm/drm_file.h>
  40 #include <drm/drm_gem.h>
  41 
  42 #include "drm_crtc_internal.h"
  43 #include "drm_internal.h"
  44 
  45 #if defined(CONFIG_DEBUG_FS)
  46 
  47 /***************************************************
  48  * Initialization, etc.
  49  **************************************************/
  50 
  51 static int drm_name_info(struct seq_file *m, void *data)
  52 {
  53         struct drm_info_node *node = (struct drm_info_node *) m->private;
  54         struct drm_minor *minor = node->minor;
  55         struct drm_device *dev = minor->dev;
  56         struct drm_master *master;
  57 
  58         mutex_lock(&dev->master_mutex);
  59         master = dev->master;
  60         seq_printf(m, "%s", dev->driver->name);
  61         if (dev->dev)
  62                 seq_printf(m, " dev=%s", dev_name(dev->dev));
  63         if (master && master->unique)
  64                 seq_printf(m, " master=%s", master->unique);
  65         if (dev->unique)
  66                 seq_printf(m, " unique=%s", dev->unique);
  67         seq_printf(m, "\n");
  68         mutex_unlock(&dev->master_mutex);
  69 
  70         return 0;
  71 }
  72 
  73 static int drm_clients_info(struct seq_file *m, void *data)
  74 {
  75         struct drm_info_node *node = (struct drm_info_node *) m->private;
  76         struct drm_device *dev = node->minor->dev;
  77         struct drm_file *priv;
  78         kuid_t uid;
  79 
  80         seq_printf(m,
  81                    "%20s %5s %3s master a %5s %10s\n",
  82                    "command",
  83                    "pid",
  84                    "dev",
  85                    "uid",
  86                    "magic");
  87 
  88         /* dev->filelist is sorted youngest first, but we want to present
  89          * oldest first (i.e. kernel, servers, clients), so walk backwardss.
  90          */
  91         mutex_lock(&dev->filelist_mutex);
  92         list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
  93                 struct task_struct *task;
  94 
  95                 rcu_read_lock(); /* locks pid_task()->comm */
  96                 task = pid_task(priv->pid, PIDTYPE_PID);
  97                 uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID;
  98                 seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
  99                            task ? task->comm : "<unknown>",
 100                            pid_vnr(priv->pid),
 101                            priv->minor->index,
 102                            drm_is_current_master(priv) ? 'y' : 'n',
 103                            priv->authenticated ? 'y' : 'n',
 104                            from_kuid_munged(seq_user_ns(m), uid),
 105                            priv->magic);
 106                 rcu_read_unlock();
 107         }
 108         mutex_unlock(&dev->filelist_mutex);
 109         return 0;
 110 }
 111 
 112 static int drm_gem_one_name_info(int id, void *ptr, void *data)
 113 {
 114         struct drm_gem_object *obj = ptr;
 115         struct seq_file *m = data;
 116 
 117         seq_printf(m, "%6d %8zd %7d %8d\n",
 118                    obj->name, obj->size,
 119                    obj->handle_count,
 120                    kref_read(&obj->refcount));
 121         return 0;
 122 }
 123 
 124 static int drm_gem_name_info(struct seq_file *m, void *data)
 125 {
 126         struct drm_info_node *node = (struct drm_info_node *) m->private;
 127         struct drm_device *dev = node->minor->dev;
 128 
 129         seq_printf(m, "  name     size handles refcount\n");
 130 
 131         mutex_lock(&dev->object_name_lock);
 132         idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m);
 133         mutex_unlock(&dev->object_name_lock);
 134 
 135         return 0;
 136 }
 137 
 138 static const struct drm_info_list drm_debugfs_list[] = {
 139         {"name", drm_name_info, 0},
 140         {"clients", drm_clients_info, 0},
 141         {"gem_names", drm_gem_name_info, DRIVER_GEM},
 142 };
 143 #define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
 144 
 145 
 146 static int drm_debugfs_open(struct inode *inode, struct file *file)
 147 {
 148         struct drm_info_node *node = inode->i_private;
 149 
 150         return single_open(file, node->info_ent->show, node);
 151 }
 152 
 153 
 154 static const struct file_operations drm_debugfs_fops = {
 155         .owner = THIS_MODULE,
 156         .open = drm_debugfs_open,
 157         .read = seq_read,
 158         .llseek = seq_lseek,
 159         .release = single_release,
 160 };
 161 
 162 
 163 /**
 164  * drm_debugfs_create_files - Initialize a given set of debugfs files for DRM
 165  *                      minor
 166  * @files: The array of files to create
 167  * @count: The number of files given
 168  * @root: DRI debugfs dir entry.
 169  * @minor: device minor number
 170  *
 171  * Create a given set of debugfs files represented by an array of
 172  * &struct drm_info_list in the given root directory. These files will be removed
 173  * automatically on drm_debugfs_cleanup().
 174  */
 175 int drm_debugfs_create_files(const struct drm_info_list *files, int count,
 176                              struct dentry *root, struct drm_minor *minor)
 177 {
 178         struct drm_device *dev = minor->dev;
 179         struct drm_info_node *tmp;
 180         int i;
 181 
 182         for (i = 0; i < count; i++) {
 183                 u32 features = files[i].driver_features;
 184 
 185                 if (features != 0 &&
 186                     (dev->driver->driver_features & features) != features)
 187                         continue;
 188 
 189                 tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
 190                 if (tmp == NULL)
 191                         continue;
 192 
 193                 tmp->minor = minor;
 194                 tmp->dent = debugfs_create_file(files[i].name,
 195                                                 S_IFREG | S_IRUGO, root, tmp,
 196                                                 &drm_debugfs_fops);
 197                 tmp->info_ent = &files[i];
 198 
 199                 mutex_lock(&minor->debugfs_lock);
 200                 list_add(&tmp->list, &minor->debugfs_list);
 201                 mutex_unlock(&minor->debugfs_lock);
 202         }
 203         return 0;
 204 }
 205 EXPORT_SYMBOL(drm_debugfs_create_files);
 206 
 207 int drm_debugfs_init(struct drm_minor *minor, int minor_id,
 208                      struct dentry *root)
 209 {
 210         struct drm_device *dev = minor->dev;
 211         char name[64];
 212         int ret;
 213 
 214         INIT_LIST_HEAD(&minor->debugfs_list);
 215         mutex_init(&minor->debugfs_lock);
 216         sprintf(name, "%d", minor_id);
 217         minor->debugfs_root = debugfs_create_dir(name, root);
 218 
 219         ret = drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
 220                                        minor->debugfs_root, minor);
 221         if (ret) {
 222                 debugfs_remove(minor->debugfs_root);
 223                 minor->debugfs_root = NULL;
 224                 DRM_ERROR("Failed to create core drm debugfs files\n");
 225                 return ret;
 226         }
 227 
 228         if (drm_drv_uses_atomic_modeset(dev)) {
 229                 ret = drm_atomic_debugfs_init(minor);
 230                 if (ret) {
 231                         DRM_ERROR("Failed to create atomic debugfs files\n");
 232                         return ret;
 233                 }
 234         }
 235 
 236         if (drm_core_check_feature(dev, DRIVER_MODESET)) {
 237                 ret = drm_framebuffer_debugfs_init(minor);
 238                 if (ret) {
 239                         DRM_ERROR("Failed to create framebuffer debugfs file\n");
 240                         return ret;
 241                 }
 242 
 243                 ret = drm_client_debugfs_init(minor);
 244                 if (ret) {
 245                         DRM_ERROR("Failed to create client debugfs file\n");
 246                         return ret;
 247                 }
 248         }
 249 
 250         if (dev->driver->debugfs_init) {
 251                 ret = dev->driver->debugfs_init(minor);
 252                 if (ret) {
 253                         DRM_ERROR("DRM: Driver failed to initialize "
 254                                   "/sys/kernel/debug/dri.\n");
 255                         return ret;
 256                 }
 257         }
 258         return 0;
 259 }
 260 
 261 
 262 int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
 263                              struct drm_minor *minor)
 264 {
 265         struct list_head *pos, *q;
 266         struct drm_info_node *tmp;
 267         int i;
 268 
 269         mutex_lock(&minor->debugfs_lock);
 270         for (i = 0; i < count; i++) {
 271                 list_for_each_safe(pos, q, &minor->debugfs_list) {
 272                         tmp = list_entry(pos, struct drm_info_node, list);
 273                         if (tmp->info_ent == &files[i]) {
 274                                 debugfs_remove(tmp->dent);
 275                                 list_del(pos);
 276                                 kfree(tmp);
 277                         }
 278                 }
 279         }
 280         mutex_unlock(&minor->debugfs_lock);
 281         return 0;
 282 }
 283 EXPORT_SYMBOL(drm_debugfs_remove_files);
 284 
 285 static void drm_debugfs_remove_all_files(struct drm_minor *minor)
 286 {
 287         struct drm_info_node *node, *tmp;
 288 
 289         mutex_lock(&minor->debugfs_lock);
 290         list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) {
 291                 debugfs_remove(node->dent);
 292                 list_del(&node->list);
 293                 kfree(node);
 294         }
 295         mutex_unlock(&minor->debugfs_lock);
 296 }
 297 
 298 void drm_debugfs_cleanup(struct drm_minor *minor)
 299 {
 300         if (!minor->debugfs_root)
 301                 return;
 302 
 303         drm_debugfs_remove_all_files(minor);
 304 
 305         debugfs_remove_recursive(minor->debugfs_root);
 306         minor->debugfs_root = NULL;
 307 }
 308 
 309 static int connector_show(struct seq_file *m, void *data)
 310 {
 311         struct drm_connector *connector = m->private;
 312 
 313         seq_printf(m, "%s\n", drm_get_connector_force_name(connector->force));
 314 
 315         return 0;
 316 }
 317 
 318 static int connector_open(struct inode *inode, struct file *file)
 319 {
 320         struct drm_connector *dev = inode->i_private;
 321 
 322         return single_open(file, connector_show, dev);
 323 }
 324 
 325 static ssize_t connector_write(struct file *file, const char __user *ubuf,
 326                                size_t len, loff_t *offp)
 327 {
 328         struct seq_file *m = file->private_data;
 329         struct drm_connector *connector = m->private;
 330         char buf[12];
 331 
 332         if (len > sizeof(buf) - 1)
 333                 return -EINVAL;
 334 
 335         if (copy_from_user(buf, ubuf, len))
 336                 return -EFAULT;
 337 
 338         buf[len] = '\0';
 339 
 340         if (!strcmp(buf, "on"))
 341                 connector->force = DRM_FORCE_ON;
 342         else if (!strcmp(buf, "digital"))
 343                 connector->force = DRM_FORCE_ON_DIGITAL;
 344         else if (!strcmp(buf, "off"))
 345                 connector->force = DRM_FORCE_OFF;
 346         else if (!strcmp(buf, "unspecified"))
 347                 connector->force = DRM_FORCE_UNSPECIFIED;
 348         else
 349                 return -EINVAL;
 350 
 351         return len;
 352 }
 353 
 354 static int edid_show(struct seq_file *m, void *data)
 355 {
 356         struct drm_connector *connector = m->private;
 357         struct drm_property_blob *edid = connector->edid_blob_ptr;
 358 
 359         if (connector->override_edid && edid)
 360                 seq_write(m, edid->data, edid->length);
 361 
 362         return 0;
 363 }
 364 
 365 static int edid_open(struct inode *inode, struct file *file)
 366 {
 367         struct drm_connector *dev = inode->i_private;
 368 
 369         return single_open(file, edid_show, dev);
 370 }
 371 
 372 static ssize_t edid_write(struct file *file, const char __user *ubuf,
 373                           size_t len, loff_t *offp)
 374 {
 375         struct seq_file *m = file->private_data;
 376         struct drm_connector *connector = m->private;
 377         char *buf;
 378         struct edid *edid;
 379         int ret;
 380 
 381         buf = memdup_user(ubuf, len);
 382         if (IS_ERR(buf))
 383                 return PTR_ERR(buf);
 384 
 385         edid = (struct edid *) buf;
 386 
 387         if (len == 5 && !strncmp(buf, "reset", 5)) {
 388                 connector->override_edid = false;
 389                 ret = drm_connector_update_edid_property(connector, NULL);
 390         } else if (len < EDID_LENGTH ||
 391                    EDID_LENGTH * (1 + edid->extensions) > len)
 392                 ret = -EINVAL;
 393         else {
 394                 connector->override_edid = false;
 395                 ret = drm_connector_update_edid_property(connector, edid);
 396                 if (!ret)
 397                         connector->override_edid = true;
 398         }
 399 
 400         kfree(buf);
 401 
 402         return (ret) ? ret : len;
 403 }
 404 
 405 static const struct file_operations drm_edid_fops = {
 406         .owner = THIS_MODULE,
 407         .open = edid_open,
 408         .read = seq_read,
 409         .llseek = seq_lseek,
 410         .release = single_release,
 411         .write = edid_write
 412 };
 413 
 414 
 415 static const struct file_operations drm_connector_fops = {
 416         .owner = THIS_MODULE,
 417         .open = connector_open,
 418         .read = seq_read,
 419         .llseek = seq_lseek,
 420         .release = single_release,
 421         .write = connector_write
 422 };
 423 
 424 void drm_debugfs_connector_add(struct drm_connector *connector)
 425 {
 426         struct drm_minor *minor = connector->dev->primary;
 427         struct dentry *root;
 428 
 429         if (!minor->debugfs_root)
 430                 return;
 431 
 432         root = debugfs_create_dir(connector->name, minor->debugfs_root);
 433         connector->debugfs_entry = root;
 434 
 435         /* force */
 436         debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector,
 437                             &drm_connector_fops);
 438 
 439         /* edid */
 440         debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, connector,
 441                             &drm_edid_fops);
 442 }
 443 
 444 void drm_debugfs_connector_remove(struct drm_connector *connector)
 445 {
 446         if (!connector->debugfs_entry)
 447                 return;
 448 
 449         debugfs_remove_recursive(connector->debugfs_entry);
 450 
 451         connector->debugfs_entry = NULL;
 452 }
 453 
 454 void drm_debugfs_crtc_add(struct drm_crtc *crtc)
 455 {
 456         struct drm_minor *minor = crtc->dev->primary;
 457         struct dentry *root;
 458         char *name;
 459 
 460         name = kasprintf(GFP_KERNEL, "crtc-%d", crtc->index);
 461         if (!name)
 462                 return;
 463 
 464         root = debugfs_create_dir(name, minor->debugfs_root);
 465         kfree(name);
 466 
 467         crtc->debugfs_entry = root;
 468 
 469         drm_debugfs_crtc_crc_add(crtc);
 470 }
 471 
 472 void drm_debugfs_crtc_remove(struct drm_crtc *crtc)
 473 {
 474         debugfs_remove_recursive(crtc->debugfs_entry);
 475         crtc->debugfs_entry = NULL;
 476 }
 477 
 478 #endif /* CONFIG_DEBUG_FS */

/* [<][>][^][v][top][bottom][index][help] */