diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-10-16 07:30:34 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-10-16 07:32:04 -0400 |
commit | 926321d503406d1fefb2fae9651beca14160529a (patch) | |
tree | 593caafe1fbc7df1427190df3e0cc8d990de4287 /drivers/gpu/drm/i915/i915_debugfs.c | |
parent | 8bf1e9f1d2aa1fafd2b262683a13cbb7f934c6d0 (diff) |
drm/i915: Add a control file for pipe CRCs
Note the "return -ENODEV;" in pipe_crc_set_source(). The ctl file is
disabled until the end of the series to be able to do incremental
improvements.
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_debugfs.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 217 |
1 files changed, 215 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e1d45aaf6881..0d8a9a397a24 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -27,6 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
30 | #include <linux/ctype.h> | ||
30 | #include <linux/debugfs.h> | 31 | #include <linux/debugfs.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | #include <linux/export.h> | 33 | #include <linux/export.h> |
@@ -1742,8 +1743,8 @@ static int i915_pipe_crc(struct seq_file *m, void *data) | |||
1742 | int i; | 1743 | int i; |
1743 | int start; | 1744 | int start; |
1744 | 1745 | ||
1745 | if (!IS_IVYBRIDGE(dev)) { | 1746 | if (dev_priv->pipe_crc[pipe].source == INTEL_PIPE_CRC_SOURCE_NONE) { |
1746 | seq_puts(m, "unsupported\n"); | 1747 | seq_puts(m, "none\n"); |
1747 | return 0; | 1748 | return 0; |
1748 | } | 1749 | } |
1749 | 1750 | ||
@@ -1762,6 +1763,217 @@ static int i915_pipe_crc(struct seq_file *m, void *data) | |||
1762 | return 0; | 1763 | return 0; |
1763 | } | 1764 | } |
1764 | 1765 | ||
1766 | static const char *pipe_crc_sources[] = { | ||
1767 | "none", | ||
1768 | "plane1", | ||
1769 | "plane2", | ||
1770 | "pf", | ||
1771 | }; | ||
1772 | |||
1773 | static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) | ||
1774 | { | ||
1775 | BUILD_BUG_ON(ARRAY_SIZE(pipe_crc_sources) != INTEL_PIPE_CRC_SOURCE_MAX); | ||
1776 | return pipe_crc_sources[source]; | ||
1777 | } | ||
1778 | |||
1779 | static int pipe_crc_ctl_show(struct seq_file *m, void *data) | ||
1780 | { | ||
1781 | struct drm_device *dev = m->private; | ||
1782 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1783 | int i; | ||
1784 | |||
1785 | for (i = 0; i < I915_MAX_PIPES; i++) | ||
1786 | seq_printf(m, "%c %s\n", pipe_name(i), | ||
1787 | pipe_crc_source_name(dev_priv->pipe_crc[i].source)); | ||
1788 | |||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1792 | static int pipe_crc_ctl_open(struct inode *inode, struct file *file) | ||
1793 | { | ||
1794 | struct drm_device *dev = inode->i_private; | ||
1795 | |||
1796 | return single_open(file, pipe_crc_ctl_show, dev); | ||
1797 | } | ||
1798 | |||
1799 | static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, | ||
1800 | enum intel_pipe_crc_source source) | ||
1801 | { | ||
1802 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1803 | u32 val; | ||
1804 | |||
1805 | |||
1806 | return -ENODEV; | ||
1807 | |||
1808 | if (!IS_IVYBRIDGE(dev)) | ||
1809 | return -ENODEV; | ||
1810 | |||
1811 | dev_priv->pipe_crc[pipe].source = source; | ||
1812 | |||
1813 | switch (source) { | ||
1814 | case INTEL_PIPE_CRC_SOURCE_PLANE1: | ||
1815 | val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; | ||
1816 | break; | ||
1817 | case INTEL_PIPE_CRC_SOURCE_PLANE2: | ||
1818 | val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; | ||
1819 | break; | ||
1820 | case INTEL_PIPE_CRC_SOURCE_PF: | ||
1821 | val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; | ||
1822 | break; | ||
1823 | case INTEL_PIPE_CRC_SOURCE_NONE: | ||
1824 | default: | ||
1825 | val = 0; | ||
1826 | break; | ||
1827 | } | ||
1828 | |||
1829 | I915_WRITE(PIPE_CRC_CTL(pipe), val); | ||
1830 | POSTING_READ(PIPE_CRC_CTL(pipe)); | ||
1831 | |||
1832 | return 0; | ||
1833 | } | ||
1834 | |||
1835 | /* | ||
1836 | * Parse pipe CRC command strings: | ||
1837 | * command: wsp* pipe wsp+ source wsp* | ||
1838 | * pipe: (A | B | C) | ||
1839 | * source: (none | plane1 | plane2 | pf) | ||
1840 | * wsp: (#0x20 | #0x9 | #0xA)+ | ||
1841 | * | ||
1842 | * eg.: | ||
1843 | * "A plane1" -> Start CRC computations on plane1 of pipe A | ||
1844 | * "A none" -> Stop CRC | ||
1845 | */ | ||
1846 | static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) | ||
1847 | { | ||
1848 | int n_words = 0; | ||
1849 | |||
1850 | while (*buf) { | ||
1851 | char *end; | ||
1852 | |||
1853 | /* skip leading white space */ | ||
1854 | buf = skip_spaces(buf); | ||
1855 | if (!*buf) | ||
1856 | break; /* end of buffer */ | ||
1857 | |||
1858 | /* find end of word */ | ||
1859 | for (end = buf; *end && !isspace(*end); end++) | ||
1860 | ; | ||
1861 | |||
1862 | if (n_words == max_words) { | ||
1863 | DRM_DEBUG_DRIVER("too many words, allowed <= %d\n", | ||
1864 | max_words); | ||
1865 | return -EINVAL; /* ran out of words[] before bytes */ | ||
1866 | } | ||
1867 | |||
1868 | if (*end) | ||
1869 | *end++ = '\0'; | ||
1870 | words[n_words++] = buf; | ||
1871 | buf = end; | ||
1872 | } | ||
1873 | |||
1874 | return n_words; | ||
1875 | } | ||
1876 | |||
1877 | static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) | ||
1878 | { | ||
1879 | const char name = buf[0]; | ||
1880 | |||
1881 | if (name < 'A' || name >= pipe_name(I915_MAX_PIPES)) | ||
1882 | return -EINVAL; | ||
1883 | |||
1884 | *pipe = name - 'A'; | ||
1885 | |||
1886 | return 0; | ||
1887 | } | ||
1888 | |||
1889 | static int | ||
1890 | pipe_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *source) | ||
1891 | { | ||
1892 | int i; | ||
1893 | |||
1894 | for (i = 0; i < ARRAY_SIZE(pipe_crc_sources); i++) | ||
1895 | if (!strcmp(buf, pipe_crc_sources[i])) { | ||
1896 | *source = i; | ||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | return -EINVAL; | ||
1901 | } | ||
1902 | |||
1903 | static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) | ||
1904 | { | ||
1905 | #define MAX_WORDS 2 | ||
1906 | int n_words; | ||
1907 | char *words[MAX_WORDS]; | ||
1908 | enum pipe pipe; | ||
1909 | enum intel_pipe_crc_source source; | ||
1910 | |||
1911 | n_words = pipe_crc_ctl_tokenize(buf, words, MAX_WORDS); | ||
1912 | if (n_words != 2) { | ||
1913 | DRM_DEBUG_DRIVER("tokenize failed, a command is 2 words\n"); | ||
1914 | return -EINVAL; | ||
1915 | } | ||
1916 | |||
1917 | if (pipe_crc_ctl_parse_pipe(words[0], &pipe) < 0) { | ||
1918 | DRM_DEBUG_DRIVER("unknown pipe %s\n", words[0]); | ||
1919 | return -EINVAL; | ||
1920 | } | ||
1921 | |||
1922 | if (pipe_crc_ctl_parse_source(words[1], &source) < 0) { | ||
1923 | DRM_DEBUG_DRIVER("unknown source %s\n", words[1]); | ||
1924 | return -EINVAL; | ||
1925 | } | ||
1926 | |||
1927 | return pipe_crc_set_source(dev, pipe, source); | ||
1928 | } | ||
1929 | |||
1930 | static ssize_t pipe_crc_ctl_write(struct file *file, const char __user *ubuf, | ||
1931 | size_t len, loff_t *offp) | ||
1932 | { | ||
1933 | struct seq_file *m = file->private_data; | ||
1934 | struct drm_device *dev = m->private; | ||
1935 | char *tmpbuf; | ||
1936 | int ret; | ||
1937 | |||
1938 | if (len == 0) | ||
1939 | return 0; | ||
1940 | |||
1941 | if (len > PAGE_SIZE - 1) { | ||
1942 | DRM_DEBUG_DRIVER("expected <%lu bytes into pipe crc control\n", | ||
1943 | PAGE_SIZE); | ||
1944 | return -E2BIG; | ||
1945 | } | ||
1946 | |||
1947 | tmpbuf = kmalloc(len + 1, GFP_KERNEL); | ||
1948 | if (!tmpbuf) | ||
1949 | return -ENOMEM; | ||
1950 | |||
1951 | if (copy_from_user(tmpbuf, ubuf, len)) { | ||
1952 | ret = -EFAULT; | ||
1953 | goto out; | ||
1954 | } | ||
1955 | tmpbuf[len] = '\0'; | ||
1956 | |||
1957 | ret = pipe_crc_ctl_parse(dev, tmpbuf, len); | ||
1958 | |||
1959 | out: | ||
1960 | kfree(tmpbuf); | ||
1961 | if (ret < 0) | ||
1962 | return ret; | ||
1963 | |||
1964 | *offp += len; | ||
1965 | return len; | ||
1966 | } | ||
1967 | |||
1968 | static const struct file_operations i915_pipe_crc_ctl_fops = { | ||
1969 | .owner = THIS_MODULE, | ||
1970 | .open = pipe_crc_ctl_open, | ||
1971 | .read = seq_read, | ||
1972 | .llseek = seq_lseek, | ||
1973 | .release = single_release, | ||
1974 | .write = pipe_crc_ctl_write | ||
1975 | }; | ||
1976 | |||
1765 | static int | 1977 | static int |
1766 | i915_wedged_get(void *data, u64 *val) | 1978 | i915_wedged_get(void *data, u64 *val) |
1767 | { | 1979 | { |
@@ -2297,6 +2509,7 @@ static struct i915_debugfs_files { | |||
2297 | {"i915_gem_drop_caches", &i915_drop_caches_fops}, | 2509 | {"i915_gem_drop_caches", &i915_drop_caches_fops}, |
2298 | {"i915_error_state", &i915_error_state_fops}, | 2510 | {"i915_error_state", &i915_error_state_fops}, |
2299 | {"i915_next_seqno", &i915_next_seqno_fops}, | 2511 | {"i915_next_seqno", &i915_next_seqno_fops}, |
2512 | {"i915_pipe_crc_ctl", &i915_pipe_crc_ctl_fops}, | ||
2300 | }; | 2513 | }; |
2301 | 2514 | ||
2302 | int i915_debugfs_init(struct drm_minor *minor) | 2515 | int i915_debugfs_init(struct drm_minor *minor) |