drm/i915: Keep the CRC values into a circular buffer
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index dfa5c68c276340a866f1e82d1fa4f6d9310d5a66..73d76af13ed438ccf2460f8fce8084ccc5b8be8b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/sysrq.h>
 #include <linux/slab.h>
+#include <linux/circ_buf.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -518,6 +519,12 @@ i915_pipe_enabled(struct drm_device *dev, int pipe)
        }
 }
 
+static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
+{
+       /* Gen2 doesn't have a hardware frame counter */
+       return 0;
+}
+
 /* Called from drm generic code, passed a 'crtc', which
  * we use as a pipe index
  */
@@ -592,7 +599,7 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
        return I915_READ(reg);
 }
 
-static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe)
+static bool intel_pipe_in_vblank(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t status;
@@ -603,7 +610,13 @@ static bool g4x_pipe_in_vblank(struct drm_device *dev, enum pipe pipe)
                        I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
                return I915_READ(VLV_ISR) & status;
-       } else if (IS_G4X(dev)) {
+       } else if (IS_GEN2(dev)) {
+               status = pipe == PIPE_A ?
+                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
+                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+               return I915_READ16(ISR) & status;
+       } else if (INTEL_INFO(dev)->gen < 5) {
                status = pipe == PIPE_A ?
                        I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
                        I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
@@ -658,11 +671,14 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
 
        ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
 
-       if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
                /* No obvious pixelcount register. Only query vertical
                 * scanout position from Display scan line register.
                 */
-               position = I915_READ(PIPEDSL(pipe)) & 0x1fff;
+               if (IS_GEN2(dev))
+                       position = I915_READ(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
+               else
+                       position = I915_READ(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
                /*
                 * The scanline counter increments at the leading edge
@@ -671,7 +687,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                 * to get a more accurate picture whether we're in vblank
                 * or not.
                 */
-               in_vbl = g4x_pipe_in_vblank(dev, pipe);
+               in_vbl = intel_pipe_in_vblank(dev, pipe);
                if ((in_vbl && position == vbl_start - 1) ||
                    (!in_vbl && position == vbl_end - 1))
                        position = (position + 1) % vtotal;
@@ -701,7 +717,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        else
                position += vtotal - vbl_end;
 
-       if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
                *vpos = position;
                *hpos = 0;
        } else {
@@ -1173,6 +1189,42 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
+#if defined(CONFIG_DEBUG_FS)
+static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
+       struct intel_pipe_crc_entry *entry;
+       ktime_t now;
+       int ts, head, tail;
+
+       head = atomic_read(&pipe_crc->head);
+       tail = atomic_read(&pipe_crc->tail);
+
+       if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
+               DRM_ERROR("CRC buffer overflowing\n");
+               return;
+       }
+
+       entry = &pipe_crc->entries[head];
+
+       now = ktime_get();
+       ts = ktime_to_us(now);
+
+       entry->timestamp = ts;
+       entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe));
+       entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe));
+       entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe));
+       entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe));
+       entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe));
+
+       head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
+       atomic_set(&pipe_crc->head, head);
+}
+#else
+static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {}
+#endif
+
 /* The RPS events need forcewake, so we add them to a work queue and mask their
  * IMR bits until the work is done. Other interrupts can be processed without
  * the work queue. */
@@ -1351,6 +1403,15 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
                        DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
 
+       if (err_int & ERR_INT_PIPE_CRC_DONE_A)
+               ivb_pipe_crc_update(dev, PIPE_A);
+
+       if (err_int & ERR_INT_PIPE_CRC_DONE_B)
+               ivb_pipe_crc_update(dev, PIPE_B);
+
+       if (err_int & ERR_INT_PIPE_CRC_DONE_C)
+               ivb_pipe_crc_update(dev, PIPE_C);
+
        I915_WRITE(GEN7_ERR_INT, err_int);
 }
 
@@ -3236,7 +3297,10 @@ void intel_irq_init(struct drm_device *dev)
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 
-       if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev)) {
+               dev->max_vblank_count = 0;
+               dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
+       } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        } else {
This page took 0.024963 seconds and 5 git commands to generate.