Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Created: Sun Dec 21 13:08:50 2008 by bgamari@gmail.com
0003  *
0004  * Copyright 2008 Ben Gamari <bgamari@gmail.com>
0005  *
0006  * Permission is hereby granted, free of charge, to any person obtaining a
0007  * copy of this software and associated documentation files (the "Software"),
0008  * to deal in the Software without restriction, including without limitation
0009  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0010  * and/or sell copies of the Software, and to permit persons to whom the
0011  * Software is furnished to do so, subject to the following conditions:
0012  *
0013  * The above copyright notice and this permission notice (including the next
0014  * paragraph) shall be included in all copies or substantial portions of the
0015  * Software.
0016  *
0017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0018  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0019  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0020  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0021  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0022  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0023  * OTHER DEALINGS IN THE SOFTWARE.
0024  */
0025 
0026 #include <linux/debugfs.h>
0027 #include <linux/export.h>
0028 #include <linux/seq_file.h>
0029 #include <linux/slab.h>
0030 #include <linux/uaccess.h>
0031 
0032 #include <drm/drm_atomic.h>
0033 #include <drm/drm_auth.h>
0034 #include <drm/drm_client.h>
0035 #include <drm/drm_debugfs.h>
0036 #include <drm/drm_device.h>
0037 #include <drm/drm_drv.h>
0038 #include <drm/drm_edid.h>
0039 #include <drm/drm_file.h>
0040 #include <drm/drm_gem.h>
0041 
0042 #include "drm_crtc_internal.h"
0043 #include "drm_internal.h"
0044 
0045 #if defined(CONFIG_DEBUG_FS)
0046 
0047 /***************************************************
0048  * Initialization, etc.
0049  **************************************************/
0050 
0051 static int drm_name_info(struct seq_file *m, void *data)
0052 {
0053     struct drm_info_node *node = (struct drm_info_node *) m->private;
0054     struct drm_minor *minor = node->minor;
0055     struct drm_device *dev = minor->dev;
0056     struct drm_master *master;
0057 
0058     mutex_lock(&dev->master_mutex);
0059     master = dev->master;
0060     seq_printf(m, "%s", dev->driver->name);
0061     if (dev->dev)
0062         seq_printf(m, " dev=%s", dev_name(dev->dev));
0063     if (master && master->unique)
0064         seq_printf(m, " master=%s", master->unique);
0065     if (dev->unique)
0066         seq_printf(m, " unique=%s", dev->unique);
0067     seq_printf(m, "\n");
0068     mutex_unlock(&dev->master_mutex);
0069 
0070     return 0;
0071 }
0072 
0073 static int drm_clients_info(struct seq_file *m, void *data)
0074 {
0075     struct drm_info_node *node = (struct drm_info_node *) m->private;
0076     struct drm_device *dev = node->minor->dev;
0077     struct drm_file *priv;
0078     kuid_t uid;
0079 
0080     seq_printf(m,
0081            "%20s %5s %3s master a %5s %10s\n",
0082            "command",
0083            "pid",
0084            "dev",
0085            "uid",
0086            "magic");
0087 
0088     /* dev->filelist is sorted youngest first, but we want to present
0089      * oldest first (i.e. kernel, servers, clients), so walk backwardss.
0090      */
0091     mutex_lock(&dev->filelist_mutex);
0092     list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
0093         struct task_struct *task;
0094         bool is_current_master = drm_is_current_master(priv);
0095 
0096         rcu_read_lock(); /* locks pid_task()->comm */
0097         task = pid_task(priv->pid, PIDTYPE_PID);
0098         uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID;
0099         seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u\n",
0100                task ? task->comm : "<unknown>",
0101                pid_vnr(priv->pid),
0102                priv->minor->index,
0103                is_current_master ? 'y' : 'n',
0104                priv->authenticated ? 'y' : 'n',
0105                from_kuid_munged(seq_user_ns(m), uid),
0106                priv->magic);
0107         rcu_read_unlock();
0108     }
0109     mutex_unlock(&dev->filelist_mutex);
0110     return 0;
0111 }
0112 
0113 static int drm_gem_one_name_info(int id, void *ptr, void *data)
0114 {
0115     struct drm_gem_object *obj = ptr;
0116     struct seq_file *m = data;
0117 
0118     seq_printf(m, "%6d %8zd %7d %8d\n",
0119            obj->name, obj->size,
0120            obj->handle_count,
0121            kref_read(&obj->refcount));
0122     return 0;
0123 }
0124 
0125 static int drm_gem_name_info(struct seq_file *m, void *data)
0126 {
0127     struct drm_info_node *node = (struct drm_info_node *) m->private;
0128     struct drm_device *dev = node->minor->dev;
0129 
0130     seq_printf(m, "  name     size handles refcount\n");
0131 
0132     mutex_lock(&dev->object_name_lock);
0133     idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m);
0134     mutex_unlock(&dev->object_name_lock);
0135 
0136     return 0;
0137 }
0138 
0139 static const struct drm_info_list drm_debugfs_list[] = {
0140     {"name", drm_name_info, 0},
0141     {"clients", drm_clients_info, 0},
0142     {"gem_names", drm_gem_name_info, DRIVER_GEM},
0143 };
0144 #define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
0145 
0146 
0147 static int drm_debugfs_open(struct inode *inode, struct file *file)
0148 {
0149     struct drm_info_node *node = inode->i_private;
0150 
0151     return single_open(file, node->info_ent->show, node);
0152 }
0153 
0154 
0155 static const struct file_operations drm_debugfs_fops = {
0156     .owner = THIS_MODULE,
0157     .open = drm_debugfs_open,
0158     .read = seq_read,
0159     .llseek = seq_lseek,
0160     .release = single_release,
0161 };
0162 
0163 
0164 /**
0165  * drm_debugfs_create_files - Initialize a given set of debugfs files for DRM
0166  *          minor
0167  * @files: The array of files to create
0168  * @count: The number of files given
0169  * @root: DRI debugfs dir entry.
0170  * @minor: device minor number
0171  *
0172  * Create a given set of debugfs files represented by an array of
0173  * &struct drm_info_list in the given root directory. These files will be removed
0174  * automatically on drm_debugfs_cleanup().
0175  */
0176 void drm_debugfs_create_files(const struct drm_info_list *files, int count,
0177                   struct dentry *root, struct drm_minor *minor)
0178 {
0179     struct drm_device *dev = minor->dev;
0180     struct drm_info_node *tmp;
0181     int i;
0182 
0183     for (i = 0; i < count; i++) {
0184         u32 features = files[i].driver_features;
0185 
0186         if (features && !drm_core_check_all_features(dev, features))
0187             continue;
0188 
0189         tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
0190         if (tmp == NULL)
0191             continue;
0192 
0193         tmp->minor = minor;
0194         tmp->dent = debugfs_create_file(files[i].name,
0195                         S_IFREG | S_IRUGO, root, tmp,
0196                         &drm_debugfs_fops);
0197         tmp->info_ent = &files[i];
0198 
0199         mutex_lock(&minor->debugfs_lock);
0200         list_add(&tmp->list, &minor->debugfs_list);
0201         mutex_unlock(&minor->debugfs_lock);
0202     }
0203 }
0204 EXPORT_SYMBOL(drm_debugfs_create_files);
0205 
0206 int drm_debugfs_init(struct drm_minor *minor, int minor_id,
0207              struct dentry *root)
0208 {
0209     struct drm_device *dev = minor->dev;
0210     char name[64];
0211 
0212     INIT_LIST_HEAD(&minor->debugfs_list);
0213     mutex_init(&minor->debugfs_lock);
0214     sprintf(name, "%d", minor_id);
0215     minor->debugfs_root = debugfs_create_dir(name, root);
0216 
0217     drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
0218                  minor->debugfs_root, minor);
0219 
0220     if (drm_drv_uses_atomic_modeset(dev)) {
0221         drm_atomic_debugfs_init(minor);
0222     }
0223 
0224     if (drm_core_check_feature(dev, DRIVER_MODESET)) {
0225         drm_framebuffer_debugfs_init(minor);
0226 
0227         drm_client_debugfs_init(minor);
0228     }
0229 
0230     if (dev->driver->debugfs_init)
0231         dev->driver->debugfs_init(minor);
0232 
0233     return 0;
0234 }
0235 
0236 
0237 int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
0238                  struct drm_minor *minor)
0239 {
0240     struct list_head *pos, *q;
0241     struct drm_info_node *tmp;
0242     int i;
0243 
0244     mutex_lock(&minor->debugfs_lock);
0245     for (i = 0; i < count; i++) {
0246         list_for_each_safe(pos, q, &minor->debugfs_list) {
0247             tmp = list_entry(pos, struct drm_info_node, list);
0248             if (tmp->info_ent == &files[i]) {
0249                 debugfs_remove(tmp->dent);
0250                 list_del(pos);
0251                 kfree(tmp);
0252             }
0253         }
0254     }
0255     mutex_unlock(&minor->debugfs_lock);
0256     return 0;
0257 }
0258 EXPORT_SYMBOL(drm_debugfs_remove_files);
0259 
0260 static void drm_debugfs_remove_all_files(struct drm_minor *minor)
0261 {
0262     struct drm_info_node *node, *tmp;
0263 
0264     mutex_lock(&minor->debugfs_lock);
0265     list_for_each_entry_safe(node, tmp, &minor->debugfs_list, list) {
0266         debugfs_remove(node->dent);
0267         list_del(&node->list);
0268         kfree(node);
0269     }
0270     mutex_unlock(&minor->debugfs_lock);
0271 }
0272 
0273 void drm_debugfs_cleanup(struct drm_minor *minor)
0274 {
0275     if (!minor->debugfs_root)
0276         return;
0277 
0278     drm_debugfs_remove_all_files(minor);
0279 
0280     debugfs_remove_recursive(minor->debugfs_root);
0281     minor->debugfs_root = NULL;
0282 }
0283 
0284 static int connector_show(struct seq_file *m, void *data)
0285 {
0286     struct drm_connector *connector = m->private;
0287 
0288     seq_printf(m, "%s\n", drm_get_connector_force_name(connector->force));
0289 
0290     return 0;
0291 }
0292 
0293 static int connector_open(struct inode *inode, struct file *file)
0294 {
0295     struct drm_connector *dev = inode->i_private;
0296 
0297     return single_open(file, connector_show, dev);
0298 }
0299 
0300 static ssize_t connector_write(struct file *file, const char __user *ubuf,
0301                    size_t len, loff_t *offp)
0302 {
0303     struct seq_file *m = file->private_data;
0304     struct drm_connector *connector = m->private;
0305     char buf[12];
0306 
0307     if (len > sizeof(buf) - 1)
0308         return -EINVAL;
0309 
0310     if (copy_from_user(buf, ubuf, len))
0311         return -EFAULT;
0312 
0313     buf[len] = '\0';
0314 
0315     if (sysfs_streq(buf, "on"))
0316         connector->force = DRM_FORCE_ON;
0317     else if (sysfs_streq(buf, "digital"))
0318         connector->force = DRM_FORCE_ON_DIGITAL;
0319     else if (sysfs_streq(buf, "off"))
0320         connector->force = DRM_FORCE_OFF;
0321     else if (sysfs_streq(buf, "unspecified"))
0322         connector->force = DRM_FORCE_UNSPECIFIED;
0323     else
0324         return -EINVAL;
0325 
0326     return len;
0327 }
0328 
0329 static int edid_show(struct seq_file *m, void *data)
0330 {
0331     struct drm_connector *connector = m->private;
0332     struct drm_property_blob *edid = connector->edid_blob_ptr;
0333 
0334     if (connector->override_edid && edid)
0335         seq_write(m, edid->data, edid->length);
0336 
0337     return 0;
0338 }
0339 
0340 static int edid_open(struct inode *inode, struct file *file)
0341 {
0342     struct drm_connector *dev = inode->i_private;
0343 
0344     return single_open(file, edid_show, dev);
0345 }
0346 
0347 static ssize_t edid_write(struct file *file, const char __user *ubuf,
0348               size_t len, loff_t *offp)
0349 {
0350     struct seq_file *m = file->private_data;
0351     struct drm_connector *connector = m->private;
0352     char *buf;
0353     int ret;
0354 
0355     buf = memdup_user(ubuf, len);
0356     if (IS_ERR(buf))
0357         return PTR_ERR(buf);
0358 
0359     if (len == 5 && !strncmp(buf, "reset", 5))
0360         ret = drm_edid_override_reset(connector);
0361     else
0362         ret = drm_edid_override_set(connector, buf, len);
0363 
0364     kfree(buf);
0365 
0366     return ret ? ret : len;
0367 }
0368 
0369 /*
0370  * Returns the min and max vrr vfreq through the connector's debugfs file.
0371  * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range
0372  */
0373 static int vrr_range_show(struct seq_file *m, void *data)
0374 {
0375     struct drm_connector *connector = m->private;
0376 
0377     if (connector->status != connector_status_connected)
0378         return -ENODEV;
0379 
0380     seq_printf(m, "Min: %u\n", connector->display_info.monitor_range.min_vfreq);
0381     seq_printf(m, "Max: %u\n", connector->display_info.monitor_range.max_vfreq);
0382 
0383     return 0;
0384 }
0385 DEFINE_SHOW_ATTRIBUTE(vrr_range);
0386 
0387 /*
0388  * Returns Connector's max supported bpc through debugfs file.
0389  * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc
0390  */
0391 static int output_bpc_show(struct seq_file *m, void *data)
0392 {
0393     struct drm_connector *connector = m->private;
0394 
0395     if (connector->status != connector_status_connected)
0396         return -ENODEV;
0397 
0398     seq_printf(m, "Maximum: %u\n", connector->display_info.bpc);
0399 
0400     return 0;
0401 }
0402 DEFINE_SHOW_ATTRIBUTE(output_bpc);
0403 
0404 static const struct file_operations drm_edid_fops = {
0405     .owner = THIS_MODULE,
0406     .open = edid_open,
0407     .read = seq_read,
0408     .llseek = seq_lseek,
0409     .release = single_release,
0410     .write = edid_write
0411 };
0412 
0413 
0414 static const struct file_operations drm_connector_fops = {
0415     .owner = THIS_MODULE,
0416     .open = connector_open,
0417     .read = seq_read,
0418     .llseek = seq_lseek,
0419     .release = single_release,
0420     .write = connector_write
0421 };
0422 
0423 void drm_debugfs_connector_add(struct drm_connector *connector)
0424 {
0425     struct drm_minor *minor = connector->dev->primary;
0426     struct dentry *root;
0427 
0428     if (!minor->debugfs_root)
0429         return;
0430 
0431     root = debugfs_create_dir(connector->name, minor->debugfs_root);
0432     connector->debugfs_entry = root;
0433 
0434     /* force */
0435     debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector,
0436                 &drm_connector_fops);
0437 
0438     /* edid */
0439     debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, connector,
0440                 &drm_edid_fops);
0441 
0442     /* vrr range */
0443     debugfs_create_file("vrr_range", S_IRUGO, root, connector,
0444                 &vrr_range_fops);
0445 
0446     /* max bpc */
0447     debugfs_create_file("output_bpc", 0444, root, connector,
0448                 &output_bpc_fops);
0449 
0450     if (connector->funcs->debugfs_init)
0451         connector->funcs->debugfs_init(connector, root);
0452 }
0453 
0454 void drm_debugfs_connector_remove(struct drm_connector *connector)
0455 {
0456     if (!connector->debugfs_entry)
0457         return;
0458 
0459     debugfs_remove_recursive(connector->debugfs_entry);
0460 
0461     connector->debugfs_entry = NULL;
0462 }
0463 
0464 void drm_debugfs_crtc_add(struct drm_crtc *crtc)
0465 {
0466     struct drm_minor *minor = crtc->dev->primary;
0467     struct dentry *root;
0468     char *name;
0469 
0470     name = kasprintf(GFP_KERNEL, "crtc-%d", crtc->index);
0471     if (!name)
0472         return;
0473 
0474     root = debugfs_create_dir(name, minor->debugfs_root);
0475     kfree(name);
0476 
0477     crtc->debugfs_entry = root;
0478 
0479     drm_debugfs_crtc_crc_add(crtc);
0480 }
0481 
0482 void drm_debugfs_crtc_remove(struct drm_crtc *crtc)
0483 {
0484     debugfs_remove_recursive(crtc->debugfs_entry);
0485     crtc->debugfs_entry = NULL;
0486 }
0487 
0488 #endif /* CONFIG_DEBUG_FS */