@@ -1186,6 +1186,16 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_forcewake_count_info(struct seq_file *m, void *unused)
+{
+ 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;
+ seq_printf(m, "forcewake_count: %d\n",
+ dev_priv->gen6_gt_forcewake_count);
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -1324,6 +1334,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+ {"i915_forcewake_count", i915_forcewake_count_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
@@ -2026,6 +2026,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock);
+ if (IS_GEN6(dev))
+ spin_lock_init(&dev_priv->gen6_gt_forcewake_lock);
+
if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2;
else
@@ -266,6 +266,17 @@ void intel_detect_pch (struct drm_device *dev)
void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
{
int count;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->gen6_gt_forcewake_lock, flags);
+ if (++dev_priv->gen6_gt_forcewake_count > 1) {
+ count = 0;
+ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
+ udelay(10);
+ spin_unlock_irqrestore(&dev_priv->gen6_gt_forcewake_lock, flags);
+ return;
+ }
+ WARN_ON(dev_priv->gen6_gt_forcewake_count != 1);
count = 0;
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
@@ -277,12 +288,25 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
count = 0;
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0)
udelay(10);
+
+ spin_unlock_irqrestore(&dev_priv->gen6_gt_forcewake_lock, flags);
}
void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->gen6_gt_forcewake_lock, flags);
+ if (--dev_priv->gen6_gt_forcewake_count > 0) {
+ spin_unlock_irqrestore(&dev_priv->gen6_gt_forcewake_lock, flags);
+ return;
+ }
+ WARN_ON(dev_priv->gen6_gt_forcewake_count != 0);
+
I915_WRITE_NOTRACE(FORCEWAKE, 0);
POSTING_READ(FORCEWAKE);
+
+ spin_unlock_irqrestore(&dev_priv->gen6_gt_forcewake_lock, flags);
}
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
@@ -703,6 +703,10 @@ typedef struct drm_i915_private {
struct intel_fbdev *fbdev;
struct drm_property *broadcast_rgb_property;
+
+ /* gen6 forcewake state */
+ spinlock_t gen6_gt_forcewake_lock;
+ int gen6_gt_forcewake_count;
} drm_i915_private_t;
struct drm_i915_gem_object {