diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pipe_crc.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_pipe_crc.c | 445 |
1 files changed, 0 insertions, 445 deletions
diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 39a4e4edda07..849e1b69ba73 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c | |||
@@ -30,160 +30,6 @@ | |||
30 | #include <linux/debugfs.h> | 30 | #include <linux/debugfs.h> |
31 | #include "intel_drv.h" | 31 | #include "intel_drv.h" |
32 | 32 | ||
33 | struct pipe_crc_info { | ||
34 | const char *name; | ||
35 | struct drm_i915_private *dev_priv; | ||
36 | enum pipe pipe; | ||
37 | }; | ||
38 | |||
39 | static int i915_pipe_crc_open(struct inode *inode, struct file *filep) | ||
40 | { | ||
41 | struct pipe_crc_info *info = inode->i_private; | ||
42 | struct drm_i915_private *dev_priv = info->dev_priv; | ||
43 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; | ||
44 | |||
45 | if (info->pipe >= INTEL_INFO(dev_priv)->num_pipes) | ||
46 | return -ENODEV; | ||
47 | |||
48 | spin_lock_irq(&pipe_crc->lock); | ||
49 | |||
50 | if (pipe_crc->opened) { | ||
51 | spin_unlock_irq(&pipe_crc->lock); | ||
52 | return -EBUSY; /* already open */ | ||
53 | } | ||
54 | |||
55 | pipe_crc->opened = true; | ||
56 | filep->private_data = inode->i_private; | ||
57 | |||
58 | spin_unlock_irq(&pipe_crc->lock); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int i915_pipe_crc_release(struct inode *inode, struct file *filep) | ||
64 | { | ||
65 | struct pipe_crc_info *info = inode->i_private; | ||
66 | struct drm_i915_private *dev_priv = info->dev_priv; | ||
67 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; | ||
68 | |||
69 | spin_lock_irq(&pipe_crc->lock); | ||
70 | pipe_crc->opened = false; | ||
71 | spin_unlock_irq(&pipe_crc->lock); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | /* (6 fields, 8 chars each, space separated (5) + '\n') */ | ||
77 | #define PIPE_CRC_LINE_LEN (6 * 8 + 5 + 1) | ||
78 | /* account for \'0' */ | ||
79 | #define PIPE_CRC_BUFFER_LEN (PIPE_CRC_LINE_LEN + 1) | ||
80 | |||
81 | static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) | ||
82 | { | ||
83 | lockdep_assert_held(&pipe_crc->lock); | ||
84 | return CIRC_CNT(pipe_crc->head, pipe_crc->tail, | ||
85 | INTEL_PIPE_CRC_ENTRIES_NR); | ||
86 | } | ||
87 | |||
88 | static ssize_t | ||
89 | i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, | ||
90 | loff_t *pos) | ||
91 | { | ||
92 | struct pipe_crc_info *info = filep->private_data; | ||
93 | struct drm_i915_private *dev_priv = info->dev_priv; | ||
94 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; | ||
95 | char buf[PIPE_CRC_BUFFER_LEN]; | ||
96 | int n_entries; | ||
97 | ssize_t bytes_read; | ||
98 | |||
99 | /* | ||
100 | * Don't allow user space to provide buffers not big enough to hold | ||
101 | * a line of data. | ||
102 | */ | ||
103 | if (count < PIPE_CRC_LINE_LEN) | ||
104 | return -EINVAL; | ||
105 | |||
106 | if (pipe_crc->source == INTEL_PIPE_CRC_SOURCE_NONE) | ||
107 | return 0; | ||
108 | |||
109 | /* nothing to read */ | ||
110 | spin_lock_irq(&pipe_crc->lock); | ||
111 | while (pipe_crc_data_count(pipe_crc) == 0) { | ||
112 | int ret; | ||
113 | |||
114 | if (filep->f_flags & O_NONBLOCK) { | ||
115 | spin_unlock_irq(&pipe_crc->lock); | ||
116 | return -EAGAIN; | ||
117 | } | ||
118 | |||
119 | ret = wait_event_interruptible_lock_irq(pipe_crc->wq, | ||
120 | pipe_crc_data_count(pipe_crc), pipe_crc->lock); | ||
121 | if (ret) { | ||
122 | spin_unlock_irq(&pipe_crc->lock); | ||
123 | return ret; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /* We now have one or more entries to read */ | ||
128 | n_entries = count / PIPE_CRC_LINE_LEN; | ||
129 | |||
130 | bytes_read = 0; | ||
131 | while (n_entries > 0) { | ||
132 | struct intel_pipe_crc_entry *entry = | ||
133 | &pipe_crc->entries[pipe_crc->tail]; | ||
134 | |||
135 | if (CIRC_CNT(pipe_crc->head, pipe_crc->tail, | ||
136 | INTEL_PIPE_CRC_ENTRIES_NR) < 1) | ||
137 | break; | ||
138 | |||
139 | BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); | ||
140 | pipe_crc->tail = (pipe_crc->tail + 1) & | ||
141 | (INTEL_PIPE_CRC_ENTRIES_NR - 1); | ||
142 | |||
143 | bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN, | ||
144 | "%8u %8x %8x %8x %8x %8x\n", | ||
145 | entry->frame, entry->crc[0], | ||
146 | entry->crc[1], entry->crc[2], | ||
147 | entry->crc[3], entry->crc[4]); | ||
148 | |||
149 | spin_unlock_irq(&pipe_crc->lock); | ||
150 | |||
151 | if (copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN)) | ||
152 | return -EFAULT; | ||
153 | |||
154 | user_buf += PIPE_CRC_LINE_LEN; | ||
155 | n_entries--; | ||
156 | |||
157 | spin_lock_irq(&pipe_crc->lock); | ||
158 | } | ||
159 | |||
160 | spin_unlock_irq(&pipe_crc->lock); | ||
161 | |||
162 | return bytes_read; | ||
163 | } | ||
164 | |||
165 | static const struct file_operations i915_pipe_crc_fops = { | ||
166 | .owner = THIS_MODULE, | ||
167 | .open = i915_pipe_crc_open, | ||
168 | .read = i915_pipe_crc_read, | ||
169 | .release = i915_pipe_crc_release, | ||
170 | }; | ||
171 | |||
172 | static struct pipe_crc_info i915_pipe_crc_data[I915_MAX_PIPES] = { | ||
173 | { | ||
174 | .name = "i915_pipe_A_crc", | ||
175 | .pipe = PIPE_A, | ||
176 | }, | ||
177 | { | ||
178 | .name = "i915_pipe_B_crc", | ||
179 | .pipe = PIPE_B, | ||
180 | }, | ||
181 | { | ||
182 | .name = "i915_pipe_C_crc", | ||
183 | .pipe = PIPE_C, | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | static const char * const pipe_crc_sources[] = { | 33 | static const char * const pipe_crc_sources[] = { |
188 | "none", | 34 | "none", |
189 | "plane1", | 35 | "plane1", |
@@ -197,29 +43,6 @@ static const char * const pipe_crc_sources[] = { | |||
197 | "auto", | 43 | "auto", |
198 | }; | 44 | }; |
199 | 45 | ||
200 | static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) | ||
201 | { | ||
202 | BUILD_BUG_ON(ARRAY_SIZE(pipe_crc_sources) != INTEL_PIPE_CRC_SOURCE_MAX); | ||
203 | return pipe_crc_sources[source]; | ||
204 | } | ||
205 | |||
206 | static int display_crc_ctl_show(struct seq_file *m, void *data) | ||
207 | { | ||
208 | struct drm_i915_private *dev_priv = m->private; | ||
209 | enum pipe pipe; | ||
210 | |||
211 | for_each_pipe(dev_priv, pipe) | ||
212 | seq_printf(m, "%c %s\n", pipe_name(pipe), | ||
213 | pipe_crc_source_name(dev_priv->pipe_crc[pipe].source)); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int display_crc_ctl_open(struct inode *inode, struct file *file) | ||
219 | { | ||
220 | return single_open(file, display_crc_ctl_show, inode->i_private); | ||
221 | } | ||
222 | |||
223 | static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, | 46 | static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, |
224 | uint32_t *val) | 47 | uint32_t *val) |
225 | { | 48 | { |
@@ -616,177 +439,6 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, | |||
616 | return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa); | 439 | return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa); |
617 | } | 440 | } |
618 | 441 | ||
619 | static int pipe_crc_set_source(struct drm_i915_private *dev_priv, | ||
620 | enum pipe pipe, | ||
621 | enum intel_pipe_crc_source source) | ||
622 | { | ||
623 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; | ||
624 | enum intel_display_power_domain power_domain; | ||
625 | u32 val = 0; /* shut up gcc */ | ||
626 | int ret; | ||
627 | |||
628 | if (pipe_crc->source == source) | ||
629 | return 0; | ||
630 | |||
631 | /* forbid changing the source without going back to 'none' */ | ||
632 | if (pipe_crc->source && source) | ||
633 | return -EINVAL; | ||
634 | |||
635 | power_domain = POWER_DOMAIN_PIPE(pipe); | ||
636 | if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) { | ||
637 | DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n"); | ||
638 | return -EIO; | ||
639 | } | ||
640 | |||
641 | ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val, true); | ||
642 | if (ret != 0) | ||
643 | goto out; | ||
644 | |||
645 | /* none -> real source transition */ | ||
646 | if (source) { | ||
647 | struct intel_pipe_crc_entry *entries; | ||
648 | |||
649 | DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", | ||
650 | pipe_name(pipe), pipe_crc_source_name(source)); | ||
651 | |||
652 | entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR, | ||
653 | sizeof(pipe_crc->entries[0]), | ||
654 | GFP_KERNEL); | ||
655 | if (!entries) { | ||
656 | ret = -ENOMEM; | ||
657 | goto out; | ||
658 | } | ||
659 | |||
660 | spin_lock_irq(&pipe_crc->lock); | ||
661 | kfree(pipe_crc->entries); | ||
662 | pipe_crc->entries = entries; | ||
663 | pipe_crc->head = 0; | ||
664 | pipe_crc->tail = 0; | ||
665 | spin_unlock_irq(&pipe_crc->lock); | ||
666 | } | ||
667 | |||
668 | pipe_crc->source = source; | ||
669 | |||
670 | I915_WRITE(PIPE_CRC_CTL(pipe), val); | ||
671 | POSTING_READ(PIPE_CRC_CTL(pipe)); | ||
672 | |||
673 | /* real source -> none transition */ | ||
674 | if (!source) { | ||
675 | struct intel_pipe_crc_entry *entries; | ||
676 | struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, | ||
677 | pipe); | ||
678 | |||
679 | DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", | ||
680 | pipe_name(pipe)); | ||
681 | |||
682 | drm_modeset_lock(&crtc->base.mutex, NULL); | ||
683 | if (crtc->base.state->active) | ||
684 | intel_wait_for_vblank(dev_priv, pipe); | ||
685 | drm_modeset_unlock(&crtc->base.mutex); | ||
686 | |||
687 | spin_lock_irq(&pipe_crc->lock); | ||
688 | entries = pipe_crc->entries; | ||
689 | pipe_crc->entries = NULL; | ||
690 | pipe_crc->head = 0; | ||
691 | pipe_crc->tail = 0; | ||
692 | spin_unlock_irq(&pipe_crc->lock); | ||
693 | |||
694 | kfree(entries); | ||
695 | |||
696 | if (IS_G4X(dev_priv)) | ||
697 | g4x_undo_pipe_scramble_reset(dev_priv, pipe); | ||
698 | else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) | ||
699 | vlv_undo_pipe_scramble_reset(dev_priv, pipe); | ||
700 | else if ((IS_HASWELL(dev_priv) || | ||
701 | IS_BROADWELL(dev_priv)) && pipe == PIPE_A) | ||
702 | hsw_pipe_A_crc_wa(dev_priv, false); | ||
703 | } | ||
704 | |||
705 | ret = 0; | ||
706 | |||
707 | out: | ||
708 | intel_display_power_put(dev_priv, power_domain); | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | /* | ||
714 | * Parse pipe CRC command strings: | ||
715 | * command: wsp* object wsp+ name wsp+ source wsp* | ||
716 | * object: 'pipe' | ||
717 | * name: (A | B | C) | ||
718 | * source: (none | plane1 | plane2 | pf) | ||
719 | * wsp: (#0x20 | #0x9 | #0xA)+ | ||
720 | * | ||
721 | * eg.: | ||
722 | * "pipe A plane1" -> Start CRC computations on plane1 of pipe A | ||
723 | * "pipe A none" -> Stop CRC | ||
724 | */ | ||
725 | static int display_crc_ctl_tokenize(char *buf, char *words[], int max_words) | ||
726 | { | ||
727 | int n_words = 0; | ||
728 | |||
729 | while (*buf) { | ||
730 | char *end; | ||
731 | |||
732 | /* skip leading white space */ | ||
733 | buf = skip_spaces(buf); | ||
734 | if (!*buf) | ||
735 | break; /* end of buffer */ | ||
736 | |||
737 | /* find end of word */ | ||
738 | for (end = buf; *end && !isspace(*end); end++) | ||
739 | ; | ||
740 | |||
741 | if (n_words == max_words) { | ||
742 | DRM_DEBUG_DRIVER("too many words, allowed <= %d\n", | ||
743 | max_words); | ||
744 | return -EINVAL; /* ran out of words[] before bytes */ | ||
745 | } | ||
746 | |||
747 | if (*end) | ||
748 | *end++ = '\0'; | ||
749 | words[n_words++] = buf; | ||
750 | buf = end; | ||
751 | } | ||
752 | |||
753 | return n_words; | ||
754 | } | ||
755 | |||
756 | enum intel_pipe_crc_object { | ||
757 | PIPE_CRC_OBJECT_PIPE, | ||
758 | }; | ||
759 | |||
760 | static const char * const pipe_crc_objects[] = { | ||
761 | "pipe", | ||
762 | }; | ||
763 | |||
764 | static int | ||
765 | display_crc_ctl_parse_object(const char *buf, enum intel_pipe_crc_object *o) | ||
766 | { | ||
767 | int i; | ||
768 | |||
769 | i = match_string(pipe_crc_objects, ARRAY_SIZE(pipe_crc_objects), buf); | ||
770 | if (i < 0) | ||
771 | return i; | ||
772 | |||
773 | *o = i; | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static int display_crc_ctl_parse_pipe(struct drm_i915_private *dev_priv, | ||
778 | const char *buf, enum pipe *pipe) | ||
779 | { | ||
780 | const char name = buf[0]; | ||
781 | |||
782 | if (name < 'A' || name >= pipe_name(INTEL_INFO(dev_priv)->num_pipes)) | ||
783 | return -EINVAL; | ||
784 | |||
785 | *pipe = name - 'A'; | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int | 442 | static int |
791 | display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) | 443 | display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) |
792 | { | 444 | { |
@@ -805,81 +457,6 @@ display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) | |||
805 | return 0; | 457 | return 0; |
806 | } | 458 | } |
807 | 459 | ||
808 | static int display_crc_ctl_parse(struct drm_i915_private *dev_priv, | ||
809 | char *buf, size_t len) | ||
810 | { | ||
811 | #define N_WORDS 3 | ||
812 | int n_words; | ||
813 | char *words[N_WORDS]; | ||
814 | enum pipe pipe; | ||
815 | enum intel_pipe_crc_object object; | ||
816 | enum intel_pipe_crc_source source; | ||
817 | |||
818 | n_words = display_crc_ctl_tokenize(buf, words, N_WORDS); | ||
819 | if (n_words != N_WORDS) { | ||
820 | DRM_DEBUG_DRIVER("tokenize failed, a command is %d words\n", | ||
821 | N_WORDS); | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | if (display_crc_ctl_parse_object(words[0], &object) < 0) { | ||
826 | DRM_DEBUG_DRIVER("unknown object %s\n", words[0]); | ||
827 | return -EINVAL; | ||
828 | } | ||
829 | |||
830 | if (display_crc_ctl_parse_pipe(dev_priv, words[1], &pipe) < 0) { | ||
831 | DRM_DEBUG_DRIVER("unknown pipe %s\n", words[1]); | ||
832 | return -EINVAL; | ||
833 | } | ||
834 | |||
835 | if (display_crc_ctl_parse_source(words[2], &source) < 0) { | ||
836 | DRM_DEBUG_DRIVER("unknown source %s\n", words[2]); | ||
837 | return -EINVAL; | ||
838 | } | ||
839 | |||
840 | return pipe_crc_set_source(dev_priv, pipe, source); | ||
841 | } | ||
842 | |||
843 | static ssize_t display_crc_ctl_write(struct file *file, const char __user *ubuf, | ||
844 | size_t len, loff_t *offp) | ||
845 | { | ||
846 | struct seq_file *m = file->private_data; | ||
847 | struct drm_i915_private *dev_priv = m->private; | ||
848 | char *tmpbuf; | ||
849 | int ret; | ||
850 | |||
851 | if (len == 0) | ||
852 | return 0; | ||
853 | |||
854 | if (len > PAGE_SIZE - 1) { | ||
855 | DRM_DEBUG_DRIVER("expected <%lu bytes into pipe crc control\n", | ||
856 | PAGE_SIZE); | ||
857 | return -E2BIG; | ||
858 | } | ||
859 | |||
860 | tmpbuf = memdup_user_nul(ubuf, len); | ||
861 | if (IS_ERR(tmpbuf)) | ||
862 | return PTR_ERR(tmpbuf); | ||
863 | |||
864 | ret = display_crc_ctl_parse(dev_priv, tmpbuf, len); | ||
865 | |||
866 | kfree(tmpbuf); | ||
867 | if (ret < 0) | ||
868 | return ret; | ||
869 | |||
870 | *offp += len; | ||
871 | return len; | ||
872 | } | ||
873 | |||
874 | const struct file_operations i915_display_crc_ctl_fops = { | ||
875 | .owner = THIS_MODULE, | ||
876 | .open = display_crc_ctl_open, | ||
877 | .read = seq_read, | ||
878 | .llseek = seq_lseek, | ||
879 | .release = single_release, | ||
880 | .write = display_crc_ctl_write | ||
881 | }; | ||
882 | |||
883 | void intel_display_crc_init(struct drm_i915_private *dev_priv) | 460 | void intel_display_crc_init(struct drm_i915_private *dev_priv) |
884 | { | 461 | { |
885 | enum pipe pipe; | 462 | enum pipe pipe; |
@@ -887,30 +464,8 @@ void intel_display_crc_init(struct drm_i915_private *dev_priv) | |||
887 | for_each_pipe(dev_priv, pipe) { | 464 | for_each_pipe(dev_priv, pipe) { |
888 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; | 465 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; |
889 | 466 | ||
890 | pipe_crc->opened = false; | ||
891 | spin_lock_init(&pipe_crc->lock); | 467 | spin_lock_init(&pipe_crc->lock); |
892 | init_waitqueue_head(&pipe_crc->wq); | ||
893 | } | ||
894 | } | ||
895 | |||
896 | int intel_pipe_crc_create(struct drm_minor *minor) | ||
897 | { | ||
898 | struct drm_i915_private *dev_priv = to_i915(minor->dev); | ||
899 | struct dentry *ent; | ||
900 | int i; | ||
901 | |||
902 | for (i = 0; i < ARRAY_SIZE(i915_pipe_crc_data); i++) { | ||
903 | struct pipe_crc_info *info = &i915_pipe_crc_data[i]; | ||
904 | |||
905 | info->dev_priv = dev_priv; | ||
906 | ent = debugfs_create_file(info->name, S_IRUGO, | ||
907 | minor->debugfs_root, info, | ||
908 | &i915_pipe_crc_fops); | ||
909 | if (!ent) | ||
910 | return -ENOMEM; | ||
911 | } | 468 | } |
912 | |||
913 | return 0; | ||
914 | } | 469 | } |
915 | 470 | ||
916 | int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, | 471 | int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, |