0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/circ_buf.h>
0030 #include <linux/ctype.h>
0031 #include <linux/debugfs.h>
0032 #include <linux/poll.h>
0033 #include <linux/uaccess.h>
0034
0035 #include <drm/drm_crtc.h>
0036 #include <drm/drm_debugfs_crc.h>
0037 #include <drm/drm_drv.h>
0038 #include <drm/drm_print.h>
0039
0040 #include "drm_internal.h"
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 static int crc_control_show(struct seq_file *m, void *data)
0084 {
0085 struct drm_crtc *crtc = m->private;
0086
0087 if (crtc->funcs->get_crc_sources) {
0088 size_t count;
0089 const char *const *sources = crtc->funcs->get_crc_sources(crtc,
0090 &count);
0091 size_t values_cnt;
0092 int i;
0093
0094 if (count == 0 || !sources)
0095 goto out;
0096
0097 for (i = 0; i < count; i++)
0098 if (!crtc->funcs->verify_crc_source(crtc, sources[i],
0099 &values_cnt)) {
0100 if (strcmp(sources[i], crtc->crc.source))
0101 seq_printf(m, "%s\n", sources[i]);
0102 else
0103 seq_printf(m, "%s*\n", sources[i]);
0104 }
0105 }
0106 return 0;
0107
0108 out:
0109 seq_printf(m, "%s*\n", crtc->crc.source);
0110 return 0;
0111 }
0112
0113 static int crc_control_open(struct inode *inode, struct file *file)
0114 {
0115 struct drm_crtc *crtc = inode->i_private;
0116
0117 return single_open(file, crc_control_show, crtc);
0118 }
0119
0120 static ssize_t crc_control_write(struct file *file, const char __user *ubuf,
0121 size_t len, loff_t *offp)
0122 {
0123 struct seq_file *m = file->private_data;
0124 struct drm_crtc *crtc = m->private;
0125 struct drm_crtc_crc *crc = &crtc->crc;
0126 char *source;
0127 size_t values_cnt;
0128 int ret;
0129
0130 if (len == 0)
0131 return 0;
0132
0133 if (len > PAGE_SIZE - 1) {
0134 DRM_DEBUG_KMS("Expected < %lu bytes into crtc crc control\n",
0135 PAGE_SIZE);
0136 return -E2BIG;
0137 }
0138
0139 source = memdup_user_nul(ubuf, len);
0140 if (IS_ERR(source))
0141 return PTR_ERR(source);
0142
0143 if (source[len - 1] == '\n')
0144 source[len - 1] = '\0';
0145
0146 ret = crtc->funcs->verify_crc_source(crtc, source, &values_cnt);
0147 if (ret) {
0148 kfree(source);
0149 return ret;
0150 }
0151
0152 spin_lock_irq(&crc->lock);
0153
0154 if (crc->opened) {
0155 spin_unlock_irq(&crc->lock);
0156 kfree(source);
0157 return -EBUSY;
0158 }
0159
0160 kfree(crc->source);
0161 crc->source = source;
0162
0163 spin_unlock_irq(&crc->lock);
0164
0165 *offp += len;
0166 return len;
0167 }
0168
0169 static const struct file_operations drm_crtc_crc_control_fops = {
0170 .owner = THIS_MODULE,
0171 .open = crc_control_open,
0172 .read = seq_read,
0173 .llseek = seq_lseek,
0174 .release = single_release,
0175 .write = crc_control_write
0176 };
0177
0178 static int crtc_crc_data_count(struct drm_crtc_crc *crc)
0179 {
0180 assert_spin_locked(&crc->lock);
0181 return CIRC_CNT(crc->head, crc->tail, DRM_CRC_ENTRIES_NR);
0182 }
0183
0184 static void crtc_crc_cleanup(struct drm_crtc_crc *crc)
0185 {
0186 kfree(crc->entries);
0187 crc->overflow = false;
0188 crc->entries = NULL;
0189 crc->head = 0;
0190 crc->tail = 0;
0191 crc->values_cnt = 0;
0192 crc->opened = false;
0193 }
0194
0195 static int crtc_crc_open(struct inode *inode, struct file *filep)
0196 {
0197 struct drm_crtc *crtc = inode->i_private;
0198 struct drm_crtc_crc *crc = &crtc->crc;
0199 struct drm_crtc_crc_entry *entries = NULL;
0200 size_t values_cnt;
0201 int ret = 0;
0202
0203 if (drm_drv_uses_atomic_modeset(crtc->dev)) {
0204 ret = drm_modeset_lock_single_interruptible(&crtc->mutex);
0205 if (ret)
0206 return ret;
0207
0208 if (!crtc->state->active)
0209 ret = -EIO;
0210 drm_modeset_unlock(&crtc->mutex);
0211
0212 if (ret)
0213 return ret;
0214 }
0215
0216 ret = crtc->funcs->verify_crc_source(crtc, crc->source, &values_cnt);
0217 if (ret)
0218 return ret;
0219
0220 if (WARN_ON(values_cnt > DRM_MAX_CRC_NR))
0221 return -EINVAL;
0222
0223 if (WARN_ON(values_cnt == 0))
0224 return -EINVAL;
0225
0226 entries = kcalloc(DRM_CRC_ENTRIES_NR, sizeof(*entries), GFP_KERNEL);
0227 if (!entries)
0228 return -ENOMEM;
0229
0230 spin_lock_irq(&crc->lock);
0231 if (!crc->opened) {
0232 crc->opened = true;
0233 crc->entries = entries;
0234 crc->values_cnt = values_cnt;
0235 } else {
0236 ret = -EBUSY;
0237 }
0238 spin_unlock_irq(&crc->lock);
0239
0240 if (ret) {
0241 kfree(entries);
0242 return ret;
0243 }
0244
0245 ret = crtc->funcs->set_crc_source(crtc, crc->source);
0246 if (ret)
0247 goto err;
0248
0249 return 0;
0250
0251 err:
0252 spin_lock_irq(&crc->lock);
0253 crtc_crc_cleanup(crc);
0254 spin_unlock_irq(&crc->lock);
0255 return ret;
0256 }
0257
0258 static int crtc_crc_release(struct inode *inode, struct file *filep)
0259 {
0260 struct drm_crtc *crtc = filep->f_inode->i_private;
0261 struct drm_crtc_crc *crc = &crtc->crc;
0262
0263
0264 spin_lock_irq(&crc->lock);
0265 crc->opened = false;
0266 spin_unlock_irq(&crc->lock);
0267
0268 crtc->funcs->set_crc_source(crtc, NULL);
0269
0270 spin_lock_irq(&crc->lock);
0271 crtc_crc_cleanup(crc);
0272 spin_unlock_irq(&crc->lock);
0273
0274 return 0;
0275 }
0276
0277
0278
0279
0280
0281 #define LINE_LEN(values_cnt) (10 + 11 * values_cnt + 1 + 1)
0282 #define MAX_LINE_LEN (LINE_LEN(DRM_MAX_CRC_NR))
0283
0284 static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf,
0285 size_t count, loff_t *pos)
0286 {
0287 struct drm_crtc *crtc = filep->f_inode->i_private;
0288 struct drm_crtc_crc *crc = &crtc->crc;
0289 struct drm_crtc_crc_entry *entry;
0290 char buf[MAX_LINE_LEN];
0291 int ret, i;
0292
0293 spin_lock_irq(&crc->lock);
0294
0295 if (!crc->source) {
0296 spin_unlock_irq(&crc->lock);
0297 return 0;
0298 }
0299
0300
0301 while (crtc_crc_data_count(crc) == 0) {
0302 if (filep->f_flags & O_NONBLOCK) {
0303 spin_unlock_irq(&crc->lock);
0304 return -EAGAIN;
0305 }
0306
0307 ret = wait_event_interruptible_lock_irq(crc->wq,
0308 crtc_crc_data_count(crc),
0309 crc->lock);
0310 if (ret) {
0311 spin_unlock_irq(&crc->lock);
0312 return ret;
0313 }
0314 }
0315
0316
0317 entry = &crc->entries[crc->tail];
0318
0319 if (count < LINE_LEN(crc->values_cnt)) {
0320 spin_unlock_irq(&crc->lock);
0321 return -EINVAL;
0322 }
0323
0324 BUILD_BUG_ON_NOT_POWER_OF_2(DRM_CRC_ENTRIES_NR);
0325 crc->tail = (crc->tail + 1) & (DRM_CRC_ENTRIES_NR - 1);
0326
0327 spin_unlock_irq(&crc->lock);
0328
0329 if (entry->has_frame_counter)
0330 sprintf(buf, "0x%08x", entry->frame);
0331 else
0332 sprintf(buf, "XXXXXXXXXX");
0333
0334 for (i = 0; i < crc->values_cnt; i++)
0335 sprintf(buf + 10 + i * 11, " 0x%08x", entry->crcs[i]);
0336 sprintf(buf + 10 + crc->values_cnt * 11, "\n");
0337
0338 if (copy_to_user(user_buf, buf, LINE_LEN(crc->values_cnt)))
0339 return -EFAULT;
0340
0341 return LINE_LEN(crc->values_cnt);
0342 }
0343
0344 static __poll_t crtc_crc_poll(struct file *file, poll_table *wait)
0345 {
0346 struct drm_crtc *crtc = file->f_inode->i_private;
0347 struct drm_crtc_crc *crc = &crtc->crc;
0348 __poll_t ret = 0;
0349
0350 poll_wait(file, &crc->wq, wait);
0351
0352 spin_lock_irq(&crc->lock);
0353 if (crc->source && crtc_crc_data_count(crc))
0354 ret |= EPOLLIN | EPOLLRDNORM;
0355 spin_unlock_irq(&crc->lock);
0356
0357 return ret;
0358 }
0359
0360 static const struct file_operations drm_crtc_crc_data_fops = {
0361 .owner = THIS_MODULE,
0362 .open = crtc_crc_open,
0363 .read = crtc_crc_read,
0364 .poll = crtc_crc_poll,
0365 .release = crtc_crc_release,
0366 };
0367
0368 void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc)
0369 {
0370 struct dentry *crc_ent;
0371
0372 if (!crtc->funcs->set_crc_source || !crtc->funcs->verify_crc_source)
0373 return;
0374
0375 crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry);
0376
0377 debugfs_create_file("control", S_IRUGO | S_IWUSR, crc_ent, crtc,
0378 &drm_crtc_crc_control_fops);
0379 debugfs_create_file("data", S_IRUGO, crc_ent, crtc,
0380 &drm_crtc_crc_data_fops);
0381 }
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393 int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame,
0394 uint32_t frame, uint32_t *crcs)
0395 {
0396 struct drm_crtc_crc *crc = &crtc->crc;
0397 struct drm_crtc_crc_entry *entry;
0398 int head, tail;
0399 unsigned long flags;
0400
0401 spin_lock_irqsave(&crc->lock, flags);
0402
0403
0404 if (!crc->entries) {
0405 spin_unlock_irqrestore(&crc->lock, flags);
0406 return -EINVAL;
0407 }
0408
0409 head = crc->head;
0410 tail = crc->tail;
0411
0412 if (CIRC_SPACE(head, tail, DRM_CRC_ENTRIES_NR) < 1) {
0413 bool was_overflow = crc->overflow;
0414
0415 crc->overflow = true;
0416 spin_unlock_irqrestore(&crc->lock, flags);
0417
0418 if (!was_overflow)
0419 DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n");
0420
0421 return -ENOBUFS;
0422 }
0423
0424 entry = &crc->entries[head];
0425 entry->frame = frame;
0426 entry->has_frame_counter = has_frame;
0427 memcpy(&entry->crcs, crcs, sizeof(*crcs) * crc->values_cnt);
0428
0429 head = (head + 1) & (DRM_CRC_ENTRIES_NR - 1);
0430 crc->head = head;
0431
0432 spin_unlock_irqrestore(&crc->lock, flags);
0433
0434 wake_up_interruptible(&crc->wq);
0435
0436 return 0;
0437 }
0438 EXPORT_SYMBOL_GPL(drm_crtc_add_crc_entry);