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