LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_debugfs_crc.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 181 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 10 0.0 %
Branches: 0 94 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright © 2008 Intel Corporation
       3                 :            :  * Copyright © 2016 Collabora Ltd
       4                 :            :  *
       5                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a
       6                 :            :  * copy of this software and associated documentation files (the "Software"),
       7                 :            :  * to deal in the Software without restriction, including without limitation
       8                 :            :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       9                 :            :  * and/or sell copies of the Software, and to permit persons to whom the
      10                 :            :  * Software is furnished to do so, subject to the following conditions:
      11                 :            :  *
      12                 :            :  * The above copyright notice and this permission notice (including the next
      13                 :            :  * paragraph) shall be included in all copies or substantial portions of the
      14                 :            :  * Software.
      15                 :            :  *
      16                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      19                 :            :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      21                 :            :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      22                 :            :  * IN THE SOFTWARE.
      23                 :            :  *
      24                 :            :  * Based on code from the i915 driver.
      25                 :            :  * Original author: Damien Lespiau <damien.lespiau@intel.com>
      26                 :            :  *
      27                 :            :  */
      28                 :            : 
      29                 :            : #include <linux/circ_buf.h>
      30                 :            : #include <linux/ctype.h>
      31                 :            : #include <linux/debugfs.h>
      32                 :            : #include <linux/poll.h>
      33                 :            : #include <linux/uaccess.h>
      34                 :            : 
      35                 :            : #include <drm/drm_crtc.h>
      36                 :            : #include <drm/drm_debugfs_crc.h>
      37                 :            : #include <drm/drm_drv.h>
      38                 :            : #include <drm/drm_print.h>
      39                 :            : 
      40                 :            : #include "drm_internal.h"
      41                 :            : 
      42                 :            : /**
      43                 :            :  * DOC: CRC ABI
      44                 :            :  *
      45                 :            :  * DRM device drivers can provide to userspace CRC information of each frame as
      46                 :            :  * it reached a given hardware component (a CRC sampling "source").
      47                 :            :  *
      48                 :            :  * Userspace can control generation of CRCs in a given CRTC by writing to the
      49                 :            :  * file dri/0/crtc-N/crc/control in debugfs, with N being the index of the CRTC.
      50                 :            :  * Accepted values are source names (which are driver-specific) and the "auto"
      51                 :            :  * keyword, which will let the driver select a default source of frame CRCs
      52                 :            :  * for this CRTC.
      53                 :            :  *
      54                 :            :  * Once frame CRC generation is enabled, userspace can capture them by reading
      55                 :            :  * the dri/0/crtc-N/crc/data file. Each line in that file contains the frame
      56                 :            :  * number in the first field and then a number of unsigned integer fields
      57                 :            :  * containing the CRC data. Fields are separated by a single space and the number
      58                 :            :  * of CRC fields is source-specific.
      59                 :            :  *
      60                 :            :  * Note that though in some cases the CRC is computed in a specified way and on
      61                 :            :  * the frame contents as supplied by userspace (eDP 1.3), in general the CRC
      62                 :            :  * computation is performed in an unspecified way and on frame contents that have
      63                 :            :  * been already processed in also an unspecified way and thus userspace cannot
      64                 :            :  * rely on being able to generate matching CRC values for the frame contents that
      65                 :            :  * it submits. In this general case, the maximum userspace can do is to compare
      66                 :            :  * the reported CRCs of frames that should have the same contents.
      67                 :            :  *
      68                 :            :  * On the driver side the implementation effort is minimal, drivers only need to
      69                 :            :  * implement &drm_crtc_funcs.set_crc_source and &drm_crtc_funcs.verify_crc_source.
      70                 :            :  * The debugfs files are automatically set up if those vfuncs are set. CRC samples
      71                 :            :  * need to be captured in the driver by calling drm_crtc_add_crc_entry().
      72                 :            :  * Depending on the driver and HW requirements, &drm_crtc_funcs.set_crc_source
      73                 :            :  * may result in a commit (even a full modeset).
      74                 :            :  *
      75                 :            :  * CRC results must be reliable across non-full-modeset atomic commits, so if a
      76                 :            :  * commit via DRM_IOCTL_MODE_ATOMIC would disable or otherwise interfere with
      77                 :            :  * CRC generation, then the driver must mark that commit as a full modeset
      78                 :            :  * (drm_atomic_crtc_needs_modeset() should return true). As a result, to ensure
      79                 :            :  * consistent results, generic userspace must re-setup CRC generation after a
      80                 :            :  * legacy SETCRTC or an atomic commit with DRM_MODE_ATOMIC_ALLOW_MODESET.
      81                 :            :  */
      82                 :            : 
      83                 :          0 : static int crc_control_show(struct seq_file *m, void *data)
      84                 :            : {
      85                 :          0 :         struct drm_crtc *crtc = m->private;
      86                 :            : 
      87         [ #  # ]:          0 :         if (crtc->funcs->get_crc_sources) {
      88                 :          0 :                 size_t count;
      89                 :          0 :                 const char *const *sources = crtc->funcs->get_crc_sources(crtc,
      90                 :            :                                                                         &count);
      91                 :          0 :                 size_t values_cnt;
      92                 :          0 :                 int i;
      93                 :            : 
      94   [ #  #  #  # ]:          0 :                 if (count == 0 || !sources)
      95                 :          0 :                         goto out;
      96                 :            : 
      97         [ #  # ]:          0 :                 for (i = 0; i < count; i++)
      98         [ #  # ]:          0 :                         if (!crtc->funcs->verify_crc_source(crtc, sources[i],
      99                 :            :                                                             &values_cnt)) {
     100         [ #  # ]:          0 :                                 if (strcmp(sources[i], crtc->crc.source))
     101                 :          0 :                                         seq_printf(m, "%s\n", sources[i]);
     102                 :            :                                 else
     103                 :          0 :                                         seq_printf(m, "%s*\n", sources[i]);
     104                 :            :                         }
     105                 :            :         }
     106                 :            :         return 0;
     107                 :            : 
     108                 :            : out:
     109                 :          0 :         seq_printf(m, "%s*\n", crtc->crc.source);
     110                 :          0 :         return 0;
     111                 :            : }
     112                 :            : 
     113                 :          0 : static int crc_control_open(struct inode *inode, struct file *file)
     114                 :            : {
     115                 :          0 :         struct drm_crtc *crtc = inode->i_private;
     116                 :            : 
     117                 :          0 :         return single_open(file, crc_control_show, crtc);
     118                 :            : }
     119                 :            : 
     120                 :          0 : static ssize_t crc_control_write(struct file *file, const char __user *ubuf,
     121                 :            :                                  size_t len, loff_t *offp)
     122                 :            : {
     123                 :          0 :         struct seq_file *m = file->private_data;
     124                 :          0 :         struct drm_crtc *crtc = m->private;
     125                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     126                 :          0 :         char *source;
     127                 :          0 :         size_t values_cnt;
     128                 :          0 :         int ret;
     129                 :            : 
     130         [ #  # ]:          0 :         if (len == 0)
     131                 :            :                 return 0;
     132                 :            : 
     133         [ #  # ]:          0 :         if (len > PAGE_SIZE - 1) {
     134                 :          0 :                 DRM_DEBUG_KMS("Expected < %lu bytes into crtc crc control\n",
     135                 :            :                               PAGE_SIZE);
     136                 :          0 :                 return -E2BIG;
     137                 :            :         }
     138                 :            : 
     139                 :          0 :         source = memdup_user_nul(ubuf, len);
     140         [ #  # ]:          0 :         if (IS_ERR(source))
     141                 :          0 :                 return PTR_ERR(source);
     142                 :            : 
     143         [ #  # ]:          0 :         if (source[len - 1] == '\n')
     144                 :          0 :                 source[len - 1] = '\0';
     145                 :            : 
     146                 :          0 :         ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt);
     147         [ #  # ]:          0 :         if (ret)
     148                 :          0 :                 return ret;
     149                 :            : 
     150                 :          0 :         spin_lock_irq(&crc->lock);
     151                 :            : 
     152         [ #  # ]:          0 :         if (crc->opened) {
     153                 :          0 :                 spin_unlock_irq(&crc->lock);
     154                 :          0 :                 kfree(source);
     155                 :          0 :                 return -EBUSY;
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         kfree(crc->source);
     159                 :          0 :         crc->source = source;
     160                 :            : 
     161                 :          0 :         spin_unlock_irq(&crc->lock);
     162                 :            : 
     163                 :          0 :         *offp += len;
     164                 :          0 :         return len;
     165                 :            : }
     166                 :            : 
     167                 :            : static const struct file_operations drm_crtc_crc_control_fops = {
     168                 :            :         .owner = THIS_MODULE,
     169                 :            :         .open = crc_control_open,
     170                 :            :         .read = seq_read,
     171                 :            :         .llseek = seq_lseek,
     172                 :            :         .release = single_release,
     173                 :            :         .write = crc_control_write
     174                 :            : };
     175                 :            : 
     176                 :          0 : static int crtc_crc_data_count(struct drm_crtc_crc *crc)
     177                 :            : {
     178         [ #  # ]:          0 :         assert_spin_locked(&crc->lock);
     179                 :          0 :         return CIRC_CNT(crc->head, crc->tail, DRM_CRC_ENTRIES_NR);
     180                 :            : }
     181                 :            : 
     182                 :          0 : static void crtc_crc_cleanup(struct drm_crtc_crc *crc)
     183                 :            : {
     184                 :          0 :         kfree(crc->entries);
     185                 :          0 :         crc->overflow = false;
     186                 :          0 :         crc->entries = NULL;
     187                 :          0 :         crc->head = 0;
     188                 :          0 :         crc->tail = 0;
     189                 :          0 :         crc->values_cnt = 0;
     190                 :          0 :         crc->opened = false;
     191                 :            : }
     192                 :            : 
     193                 :          0 : static int crtc_crc_open(struct inode *inode, struct file *filep)
     194                 :            : {
     195                 :          0 :         struct drm_crtc *crtc = inode->i_private;
     196                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     197                 :          0 :         struct drm_crtc_crc_entry *entries = NULL;
     198                 :          0 :         size_t values_cnt;
     199                 :          0 :         int ret = 0;
     200                 :            : 
     201   [ #  #  #  # ]:          0 :         if (drm_drv_uses_atomic_modeset(crtc->dev)) {
     202                 :          0 :                 ret = drm_modeset_lock_single_interruptible(&crtc->mutex);
     203         [ #  # ]:          0 :                 if (ret)
     204                 :            :                         return ret;
     205                 :            : 
     206         [ #  # ]:          0 :                 if (!crtc->state->active)
     207                 :          0 :                         ret = -EIO;
     208                 :          0 :                 drm_modeset_unlock(&crtc->mutex);
     209                 :            : 
     210         [ #  # ]:          0 :                 if (ret)
     211                 :            :                         return ret;
     212                 :            :         }
     213                 :            : 
     214                 :          0 :         ret = crtc->funcs->verify_crc_source(crtc, crc->source, &values_cnt);
     215         [ #  # ]:          0 :         if (ret)
     216                 :            :                 return ret;
     217                 :            : 
     218   [ #  #  #  # ]:          0 :         if (WARN_ON(values_cnt > DRM_MAX_CRC_NR))
     219                 :            :                 return -EINVAL;
     220                 :            : 
     221   [ #  #  #  # ]:          0 :         if (WARN_ON(values_cnt == 0))
     222                 :            :                 return -EINVAL;
     223                 :            : 
     224                 :          0 :         entries = kcalloc(DRM_CRC_ENTRIES_NR, sizeof(*entries), GFP_KERNEL);
     225         [ #  # ]:          0 :         if (!entries)
     226                 :            :                 return -ENOMEM;
     227                 :            : 
     228                 :          0 :         spin_lock_irq(&crc->lock);
     229         [ #  # ]:          0 :         if (!crc->opened) {
     230                 :          0 :                 crc->opened = true;
     231                 :          0 :                 crc->entries = entries;
     232                 :          0 :                 crc->values_cnt = values_cnt;
     233                 :            :         } else {
     234                 :            :                 ret = -EBUSY;
     235                 :            :         }
     236                 :          0 :         spin_unlock_irq(&crc->lock);
     237                 :            : 
     238         [ #  # ]:          0 :         if (ret) {
     239                 :          0 :                 kfree(entries);
     240                 :          0 :                 return ret;
     241                 :            :         }
     242                 :            : 
     243                 :          0 :         ret = crtc->funcs->set_crc_source(crtc, crc->source);
     244         [ #  # ]:          0 :         if (ret)
     245                 :          0 :                 goto err;
     246                 :            : 
     247                 :            :         return 0;
     248                 :            : 
     249                 :            : err:
     250                 :          0 :         spin_lock_irq(&crc->lock);
     251                 :          0 :         crtc_crc_cleanup(crc);
     252                 :          0 :         spin_unlock_irq(&crc->lock);
     253                 :          0 :         return ret;
     254                 :            : }
     255                 :            : 
     256                 :          0 : static int crtc_crc_release(struct inode *inode, struct file *filep)
     257                 :            : {
     258                 :          0 :         struct drm_crtc *crtc = filep->f_inode->i_private;
     259                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     260                 :            : 
     261                 :            :         /* terminate the infinite while loop if 'drm_dp_aux_crc_work' running */
     262                 :          0 :         spin_lock_irq(&crc->lock);
     263                 :          0 :         crc->opened = false;
     264                 :          0 :         spin_unlock_irq(&crc->lock);
     265                 :            : 
     266                 :          0 :         crtc->funcs->set_crc_source(crtc, NULL);
     267                 :            : 
     268                 :          0 :         spin_lock_irq(&crc->lock);
     269                 :          0 :         crtc_crc_cleanup(crc);
     270                 :          0 :         spin_unlock_irq(&crc->lock);
     271                 :            : 
     272                 :          0 :         return 0;
     273                 :            : }
     274                 :            : 
     275                 :            : /*
     276                 :            :  * 1 frame field of 10 chars plus a number of CRC fields of 10 chars each, space
     277                 :            :  * separated, with a newline at the end and null-terminated.
     278                 :            :  */
     279                 :            : #define LINE_LEN(values_cnt)    (10 + 11 * values_cnt + 1 + 1)
     280                 :            : #define MAX_LINE_LEN            (LINE_LEN(DRM_MAX_CRC_NR))
     281                 :            : 
     282                 :          0 : static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf,
     283                 :            :                              size_t count, loff_t *pos)
     284                 :            : {
     285                 :          0 :         struct drm_crtc *crtc = filep->f_inode->i_private;
     286                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     287                 :          0 :         struct drm_crtc_crc_entry *entry;
     288                 :          0 :         char buf[MAX_LINE_LEN];
     289                 :          0 :         int ret, i;
     290                 :            : 
     291                 :          0 :         spin_lock_irq(&crc->lock);
     292                 :            : 
     293         [ #  # ]:          0 :         if (!crc->source) {
     294                 :          0 :                 spin_unlock_irq(&crc->lock);
     295                 :          0 :                 return 0;
     296                 :            :         }
     297                 :            : 
     298                 :            :         /* Nothing to read? */
     299         [ #  # ]:          0 :         while (crtc_crc_data_count(crc) == 0) {
     300         [ #  # ]:          0 :                 if (filep->f_flags & O_NONBLOCK) {
     301                 :          0 :                         spin_unlock_irq(&crc->lock);
     302                 :          0 :                         return -EAGAIN;
     303                 :            :                 }
     304                 :            : 
     305   [ #  #  #  #  :          0 :                 ret = wait_event_interruptible_lock_irq(crc->wq,
                   #  # ]
     306                 :            :                                                         crtc_crc_data_count(crc),
     307                 :            :                                                         crc->lock);
     308         [ #  # ]:          0 :                 if (ret) {
     309                 :          0 :                         spin_unlock_irq(&crc->lock);
     310                 :          0 :                         return ret;
     311                 :            :                 }
     312                 :            :         }
     313                 :            : 
     314                 :            :         /* We know we have an entry to be read */
     315                 :          0 :         entry = &crc->entries[crc->tail];
     316                 :            : 
     317         [ #  # ]:          0 :         if (count < LINE_LEN(crc->values_cnt)) {
     318                 :          0 :                 spin_unlock_irq(&crc->lock);
     319                 :          0 :                 return -EINVAL;
     320                 :            :         }
     321                 :            : 
     322                 :          0 :         BUILD_BUG_ON_NOT_POWER_OF_2(DRM_CRC_ENTRIES_NR);
     323                 :          0 :         crc->tail = (crc->tail + 1) & (DRM_CRC_ENTRIES_NR - 1);
     324                 :            : 
     325                 :          0 :         spin_unlock_irq(&crc->lock);
     326                 :            : 
     327         [ #  # ]:          0 :         if (entry->has_frame_counter)
     328                 :          0 :                 sprintf(buf, "0x%08x", entry->frame);
     329                 :            :         else
     330                 :          0 :                 sprintf(buf, "XXXXXXXXXX");
     331                 :            : 
     332         [ #  # ]:          0 :         for (i = 0; i < crc->values_cnt; i++)
     333                 :          0 :                 sprintf(buf + 10 + i * 11, " 0x%08x", entry->crcs[i]);
     334                 :          0 :         sprintf(buf + 10 + crc->values_cnt * 11, "\n");
     335                 :            : 
     336   [ #  #  #  # ]:          0 :         if (copy_to_user(user_buf, buf, LINE_LEN(crc->values_cnt)))
     337                 :            :                 return -EFAULT;
     338                 :            : 
     339                 :          0 :         return LINE_LEN(crc->values_cnt);
     340                 :            : }
     341                 :            : 
     342                 :          0 : static __poll_t crtc_crc_poll(struct file *file, poll_table *wait)
     343                 :            : {
     344                 :          0 :         struct drm_crtc *crtc = file->f_inode->i_private;
     345                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     346                 :          0 :         __poll_t ret = 0;
     347                 :            : 
     348         [ #  # ]:          0 :         poll_wait(file, &crc->wq, wait);
     349                 :            : 
     350                 :          0 :         spin_lock_irq(&crc->lock);
     351   [ #  #  #  # ]:          0 :         if (crc->source && crtc_crc_data_count(crc))
     352                 :          0 :                 ret |= EPOLLIN | EPOLLRDNORM;
     353                 :          0 :         spin_unlock_irq(&crc->lock);
     354                 :            : 
     355                 :          0 :         return ret;
     356                 :            : }
     357                 :            : 
     358                 :            : static const struct file_operations drm_crtc_crc_data_fops = {
     359                 :            :         .owner = THIS_MODULE,
     360                 :            :         .open = crtc_crc_open,
     361                 :            :         .read = crtc_crc_read,
     362                 :            :         .poll = crtc_crc_poll,
     363                 :            :         .release = crtc_crc_release,
     364                 :            : };
     365                 :            : 
     366                 :          0 : void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc)
     367                 :            : {
     368                 :          0 :         struct dentry *crc_ent;
     369                 :            : 
     370   [ #  #  #  # ]:          0 :         if (!crtc->funcs->set_crc_source || !crtc->funcs->verify_crc_source)
     371                 :            :                 return;
     372                 :            : 
     373                 :          0 :         crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry);
     374                 :            : 
     375                 :          0 :         debugfs_create_file("control", S_IRUGO, crc_ent, crtc,
     376                 :            :                             &drm_crtc_crc_control_fops);
     377                 :          0 :         debugfs_create_file("data", S_IRUGO, crc_ent, crtc,
     378                 :            :                             &drm_crtc_crc_data_fops);
     379                 :            : }
     380                 :            : 
     381                 :            : /**
     382                 :            :  * drm_crtc_add_crc_entry - Add entry with CRC information for a frame
     383                 :            :  * @crtc: CRTC to which the frame belongs
     384                 :            :  * @has_frame: whether this entry has a frame number to go with
     385                 :            :  * @frame: number of the frame these CRCs are about
     386                 :            :  * @crcs: array of CRC values, with length matching #drm_crtc_crc.values_cnt
     387                 :            :  *
     388                 :            :  * For each frame, the driver polls the source of CRCs for new data and calls
     389                 :            :  * this function to add them to the buffer from where userspace reads.
     390                 :            :  */
     391                 :          0 : int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame,
     392                 :            :                            uint32_t frame, uint32_t *crcs)
     393                 :            : {
     394                 :          0 :         struct drm_crtc_crc *crc = &crtc->crc;
     395                 :          0 :         struct drm_crtc_crc_entry *entry;
     396                 :          0 :         int head, tail;
     397                 :          0 :         unsigned long flags;
     398                 :            : 
     399                 :          0 :         spin_lock_irqsave(&crc->lock, flags);
     400                 :            : 
     401                 :            :         /* Caller may not have noticed yet that userspace has stopped reading */
     402         [ #  # ]:          0 :         if (!crc->entries) {
     403                 :          0 :                 spin_unlock_irqrestore(&crc->lock, flags);
     404                 :          0 :                 return -EINVAL;
     405                 :            :         }
     406                 :            : 
     407                 :          0 :         head = crc->head;
     408                 :          0 :         tail = crc->tail;
     409                 :            : 
     410         [ #  # ]:          0 :         if (CIRC_SPACE(head, tail, DRM_CRC_ENTRIES_NR) < 1) {
     411                 :          0 :                 bool was_overflow = crc->overflow;
     412                 :            : 
     413                 :          0 :                 crc->overflow = true;
     414                 :          0 :                 spin_unlock_irqrestore(&crc->lock, flags);
     415                 :            : 
     416         [ #  # ]:          0 :                 if (!was_overflow)
     417                 :          0 :                         DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n");
     418                 :            : 
     419                 :          0 :                 return -ENOBUFS;
     420                 :            :         }
     421                 :            : 
     422                 :          0 :         entry = &crc->entries[head];
     423                 :          0 :         entry->frame = frame;
     424                 :          0 :         entry->has_frame_counter = has_frame;
     425                 :          0 :         memcpy(&entry->crcs, crcs, sizeof(*crcs) * crc->values_cnt);
     426                 :            : 
     427                 :          0 :         head = (head + 1) & (DRM_CRC_ENTRIES_NR - 1);
     428                 :          0 :         crc->head = head;
     429                 :            : 
     430                 :          0 :         spin_unlock_irqrestore(&crc->lock, flags);
     431                 :            : 
     432                 :          0 :         wake_up_interruptible(&crc->wq);
     433                 :            : 
     434                 :          0 :         return 0;
     435                 :            : }
     436                 :            : EXPORT_SYMBOL_GPL(drm_crtc_add_crc_entry);

Generated by: LCOV version 1.14