X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fi915%2Fi915_debugfs.c;h=0d8a9a397a245edd1c38731550dbfe42a32cc4ea;hb=926321d503406d1fefb2fae9651beca14160529a;hp=61fd61969e21b9eaaf5b39bb5dae85373393bf22;hpb=967ad7f1489da7babbe0746f81c283458ecd3f84;p=deliverable%2Flinux.git diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 61fd61969e21..0d8a9a397a24 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -38,9 +39,6 @@ #include #include "i915_drv.h" -#define DRM_I915_RING_DEBUG 1 - - #if defined(CONFIG_DEBUG_FS) enum { @@ -850,6 +848,8 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; int ret; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + if (IS_GEN5(dev)) { u16 rgvswctl = I915_READ16(MEMSWCTL); u16 rgvstat = I915_READ16(MEMSTAT_ILK); @@ -1328,6 +1328,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) return 0; } + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1402,12 +1404,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_fbdev *ifbdev; + struct intel_fbdev *ifbdev = NULL; struct intel_framebuffer *fb; - int ret; - ret = mutex_lock_interruptible(&dev->mode_config.mutex); +#ifdef CONFIG_DRM_I915_FBDEV + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (ret) return ret; @@ -1423,6 +1425,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) describe_obj(m, fb->obj); seq_putc(m, '\n'); mutex_unlock(&dev->mode_config.mutex); +#endif mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { @@ -1730,6 +1733,247 @@ static int i915_pc8_status(struct seq_file *m, void *unused) return 0; } +static int i915_pipe_crc(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = (enum pipe)node->info_ent->data; + const struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; + int i; + int start; + + if (dev_priv->pipe_crc[pipe].source == INTEL_PIPE_CRC_SOURCE_NONE) { + seq_puts(m, "none\n"); + return 0; + } + + start = atomic_read(&pipe_crc->slot) + 1; + seq_puts(m, " timestamp CRC1 CRC2 CRC3 CRC4 CRC5\n"); + for (i = 0; i < INTEL_PIPE_CRC_ENTRIES_NR; i++) { + const struct intel_pipe_crc_entry *entry = + &pipe_crc->entries[(start + i) % + INTEL_PIPE_CRC_ENTRIES_NR]; + + seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp, + entry->crc[0], entry->crc[1], entry->crc[2], + entry->crc[3], entry->crc[4]); + } + + return 0; +} + +static const char *pipe_crc_sources[] = { + "none", + "plane1", + "plane2", + "pf", +}; + +static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) +{ + BUILD_BUG_ON(ARRAY_SIZE(pipe_crc_sources) != INTEL_PIPE_CRC_SOURCE_MAX); + return pipe_crc_sources[source]; +} + +static int pipe_crc_ctl_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < I915_MAX_PIPES; i++) + seq_printf(m, "%c %s\n", pipe_name(i), + pipe_crc_source_name(dev_priv->pipe_crc[i].source)); + + return 0; +} + +static int pipe_crc_ctl_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + + return single_open(file, pipe_crc_ctl_show, dev); +} + +static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, + enum intel_pipe_crc_source source) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + + return -ENODEV; + + if (!IS_IVYBRIDGE(dev)) + return -ENODEV; + + dev_priv->pipe_crc[pipe].source = source; + + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PLANE1: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PLANE2: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_PF: + val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; + break; + case INTEL_PIPE_CRC_SOURCE_NONE: + default: + val = 0; + break; + } + + I915_WRITE(PIPE_CRC_CTL(pipe), val); + POSTING_READ(PIPE_CRC_CTL(pipe)); + + return 0; +} + +/* + * Parse pipe CRC command strings: + * command: wsp* pipe wsp+ source wsp* + * pipe: (A | B | C) + * source: (none | plane1 | plane2 | pf) + * wsp: (#0x20 | #0x9 | #0xA)+ + * + * eg.: + * "A plane1" -> Start CRC computations on plane1 of pipe A + * "A none" -> Stop CRC + */ +static int pipe_crc_ctl_tokenize(char *buf, char *words[], int max_words) +{ + int n_words = 0; + + while (*buf) { + char *end; + + /* skip leading white space */ + buf = skip_spaces(buf); + if (!*buf) + break; /* end of buffer */ + + /* find end of word */ + for (end = buf; *end && !isspace(*end); end++) + ; + + if (n_words == max_words) { + DRM_DEBUG_DRIVER("too many words, allowed <= %d\n", + max_words); + return -EINVAL; /* ran out of words[] before bytes */ + } + + if (*end) + *end++ = '\0'; + words[n_words++] = buf; + buf = end; + } + + return n_words; +} + +static int pipe_crc_ctl_parse_pipe(const char *buf, enum pipe *pipe) +{ + const char name = buf[0]; + + if (name < 'A' || name >= pipe_name(I915_MAX_PIPES)) + return -EINVAL; + + *pipe = name - 'A'; + + return 0; +} + +static int +pipe_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *source) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pipe_crc_sources); i++) + if (!strcmp(buf, pipe_crc_sources[i])) { + *source = i; + return 0; + } + + return -EINVAL; +} + +static int pipe_crc_ctl_parse(struct drm_device *dev, char *buf, size_t len) +{ +#define MAX_WORDS 2 + int n_words; + char *words[MAX_WORDS]; + enum pipe pipe; + enum intel_pipe_crc_source source; + + n_words = pipe_crc_ctl_tokenize(buf, words, MAX_WORDS); + if (n_words != 2) { + DRM_DEBUG_DRIVER("tokenize failed, a command is 2 words\n"); + return -EINVAL; + } + + if (pipe_crc_ctl_parse_pipe(words[0], &pipe) < 0) { + DRM_DEBUG_DRIVER("unknown pipe %s\n", words[0]); + return -EINVAL; + } + + if (pipe_crc_ctl_parse_source(words[1], &source) < 0) { + DRM_DEBUG_DRIVER("unknown source %s\n", words[1]); + return -EINVAL; + } + + return pipe_crc_set_source(dev, pipe, source); +} + +static ssize_t pipe_crc_ctl_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *dev = m->private; + char *tmpbuf; + int ret; + + if (len == 0) + return 0; + + if (len > PAGE_SIZE - 1) { + DRM_DEBUG_DRIVER("expected <%lu bytes into pipe crc control\n", + PAGE_SIZE); + return -E2BIG; + } + + tmpbuf = kmalloc(len + 1, GFP_KERNEL); + if (!tmpbuf) + return -ENOMEM; + + if (copy_from_user(tmpbuf, ubuf, len)) { + ret = -EFAULT; + goto out; + } + tmpbuf[len] = '\0'; + + ret = pipe_crc_ctl_parse(dev, tmpbuf, len); + +out: + kfree(tmpbuf); + if (ret < 0) + return ret; + + *offp += len; + return len; +} + +static const struct file_operations i915_pipe_crc_ctl_fops = { + .owner = THIS_MODULE, + .open = pipe_crc_ctl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pipe_crc_ctl_write +}; + static int i915_wedged_get(void *data, u64 *val) { @@ -1943,6 +2187,8 @@ i915_max_freq_get(void *data, u64 *val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1967,6 +2213,8 @@ i915_max_freq_set(void *data, u64 val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); @@ -2005,6 +2253,8 @@ i915_min_freq_get(void *data, u64 *val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -2029,6 +2279,8 @@ i915_min_freq_set(void *data, u64 val) if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); @@ -2237,6 +2489,9 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, + {"i915_pipe_A_crc", i915_pipe_crc, 0, (void *)PIPE_A}, + {"i915_pipe_B_crc", i915_pipe_crc, 0, (void *)PIPE_B}, + {"i915_pipe_C_crc", i915_pipe_crc, 0, (void *)PIPE_C}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -2254,6 +2509,7 @@ static struct i915_debugfs_files { {"i915_gem_drop_caches", &i915_drop_caches_fops}, {"i915_error_state", &i915_error_state_fops}, {"i915_next_seqno", &i915_next_seqno_fops}, + {"i915_pipe_crc_ctl", &i915_pipe_crc_ctl_fops}, }; int i915_debugfs_init(struct drm_minor *minor)