Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c19415c authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-intel-next-2012-06-04' of...

Merge tag 'drm-intel-next-2012-06-04' of git://people.freedesktop.org/~danvet/drm-intel into drm-core-next

Daniel Vetter writes:
rc2 is out the door so I've figured I'll annoy you with the first -next
pull request for 3.6 already. Highlights:
- new wait_rendring_timeout interface (Ben)
- l3 cache remapping and error uevent support (Ben)
- even more infoframes work from Paulo
- gen4 hotplug rework from Chris
- prep work to make Laurent Pincharts original mode constification for
 connector->mode_fixup possible

QA reported a few new bugs this time around, but no regressions afact. For
3.5 the only thing I'm aware of is the edp vdd dmesg spam Linus originally
reported - it looks like that might have been introduced in 3.5. But
somehow my brain is routinely offline when I work on that issue, so things
seem to take forever (and atm I'm at patch v4 for that little problem).

* tag 'drm-intel-next-2012-06-04' of git://people.freedesktop.org/~danvet/drm-intel: (39 commits)
  drm/i915: add min freq control to debugfs
  drm/i915: don't chnage the original mode in dp_mode_fixup
  drm/i915: adjusted_mode->clock in the dp mode_fixup
  drm/i915: compute the target_clock for edp directly
  drm/i915: extract object active state flushing code
  drm/i915: clarify IBX dp workaround
  drm/i915: simplify sysfs setup code
  drm/i915: initialize the parity work only once
  drm/i915: ivybridge_handle_parity_error should be static
  drm/i915: l3 parity sysfs interface
  drm/i915: remap l3 on hw init
  drm/i915: enable parity error interrupts
  drm/i915: Dynamic Parity Detection handling
  drm/i915: s/mdelay/msleep/ in the sdvo detect function
  drm/i915: reuse the sdvo tv clock adjustment in ilk mode_set
  drm/i915: there's no cxsr on ilk
  drm/i915: add some barriers when changing DIPs
  drm/i915: remove comment about HSW HDMI DIPs
  drm/i915: don't set SDVO_BORDER_ENABLE when we're HDMI
  drm/i915: don't write 0 to DIP control at HDMI init
  ...
parents fb09185a 1523c310
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -1764,6 +1764,64 @@ static const struct file_operations i915_max_freq_fops = {
	.llseek = default_llseek,
};

static ssize_t
i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
		   loff_t *ppos)
{
	struct drm_device *dev = filp->private_data;
	drm_i915_private_t *dev_priv = dev->dev_private;
	char buf[80];
	int len;

	len = snprintf(buf, sizeof(buf),
		       "min freq: %d\n", dev_priv->min_delay * 50);

	if (len > sizeof(buf))
		len = sizeof(buf);

	return simple_read_from_buffer(ubuf, max, ppos, buf, len);
}

static ssize_t
i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
		    loff_t *ppos)
{
	struct drm_device *dev = filp->private_data;
	struct drm_i915_private *dev_priv = dev->dev_private;
	char buf[20];
	int val = 1;

	if (cnt > 0) {
		if (cnt > sizeof(buf) - 1)
			return -EINVAL;

		if (copy_from_user(buf, ubuf, cnt))
			return -EFAULT;
		buf[cnt] = 0;

		val = simple_strtoul(buf, NULL, 0);
	}

	DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);

	/*
	 * Turbo will still be enabled, but won't go below the set value.
	 */
	dev_priv->min_delay = val / 50;

	gen6_set_rps(dev, val / 50);

	return cnt;
}

static const struct file_operations i915_min_freq_fops = {
	.owner = THIS_MODULE,
	.open = simple_open,
	.read = i915_min_freq_read,
	.write = i915_min_freq_write,
	.llseek = default_llseek,
};

static ssize_t
i915_cache_sharing_read(struct file *filp,
		   char __user *ubuf,
@@ -1996,6 +2054,12 @@ int i915_debugfs_init(struct drm_minor *minor)
	if (ret)
		return ret;

	ret = i915_debugfs_create(minor->debugfs_root, minor,
				  "i915_min_freq",
				  &i915_min_freq_fops);
	if (ret)
		return ret;

	ret = i915_debugfs_create(minor->debugfs_root, minor,
				  "i915_cache_sharing",
				  &i915_cache_sharing_fops);
@@ -2028,6 +2092,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
				 1, minor);
	drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops,
				 1, minor);
	drm_debugfs_remove_files((struct drm_info_list *) &i915_min_freq_fops,
				 1, minor);
	drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
				 1, minor);
	drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
+1 −0
Original line number Diff line number Diff line
@@ -1803,6 +1803,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
	DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, intel_sprite_get_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED),
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
+9 −2
Original line number Diff line number Diff line
@@ -657,6 +657,8 @@ typedef struct drm_i915_private {
		/** PPGTT used for aliasing the PPGTT with the GTT */
		struct i915_hw_ppgtt *aliasing_ppgtt;

		u32 *l3_remap_info;

		struct shrinker inactive_shrinker;

		/**
@@ -817,6 +819,8 @@ typedef struct drm_i915_private {

	struct drm_property *broadcast_rgb_property;
	struct drm_property *force_audio_property;

	struct work_struct parity_error_work;
} drm_i915_private_t;

/* Iterate over initialised rings */
@@ -1237,6 +1241,8 @@ int i915_gem_get_tiling(struct drm_device *dev, void *data,
			struct drm_file *file_priv);
int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
				struct drm_file *file_priv);
int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
			struct drm_file *file_priv);
void i915_gem_load(struct drm_device *dev);
int i915_gem_init_object(struct drm_gem_object *obj);
int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring,
@@ -1315,6 +1321,7 @@ int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
int __must_check i915_gem_init(struct drm_device *dev);
int __must_check i915_gem_init_hw(struct drm_device *dev);
void i915_gem_l3_remap(struct drm_device *dev);
void i915_gem_init_swizzling(struct drm_device *dev);
void i915_gem_init_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
@@ -1323,7 +1330,7 @@ int __must_check i915_gem_idle(struct drm_device *dev);
int __must_check i915_add_request(struct intel_ring_buffer *ring,
				  struct drm_file *file,
				  struct drm_i915_gem_request *request);
int __must_check i915_wait_request(struct intel_ring_buffer *ring,
int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
				 uint32_t seqno);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int __must_check
+202 −40
Original line number Diff line number Diff line
@@ -1899,34 +1899,82 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
	return ret;
}

/**
 * __wait_seqno - wait until execution of seqno has finished
 * @ring: the ring expected to report seqno
 * @seqno: duh!
 * @interruptible: do an interruptible wait (normally yes)
 * @timeout: in - how long to wait (NULL forever); out - how much time remaining
 *
 * Returns 0 if the seqno was found within the alloted time. Else returns the
 * errno with remaining time filled in timeout argument.
 */
static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
			bool interruptible)
			bool interruptible, struct timespec *timeout)
{
	drm_i915_private_t *dev_priv = ring->dev->dev_private;
	int ret = 0;
	struct timespec before, now, wait_time={1,0};
	unsigned long timeout_jiffies;
	long end;
	bool wait_forever = true;

	if (i915_seqno_passed(ring->get_seqno(ring), seqno))
		return 0;

	trace_i915_gem_request_wait_begin(ring, seqno);

	if (timeout != NULL) {
		wait_time = *timeout;
		wait_forever = false;
	}

	timeout_jiffies = timespec_to_jiffies(&wait_time);

	if (WARN_ON(!ring->irq_get(ring)))
		return -ENODEV;

	/* Record current time in case interrupted by signal, or wedged * */
	getrawmonotonic(&before);

#define EXIT_COND \
	(i915_seqno_passed(ring->get_seqno(ring), seqno) || \
	atomic_read(&dev_priv->mm.wedged))

	do {
		if (interruptible)
		ret = wait_event_interruptible(ring->irq_queue,
					       EXIT_COND);
			end = wait_event_interruptible_timeout(ring->irq_queue,
							       EXIT_COND,
							       timeout_jiffies);
		else
		wait_event(ring->irq_queue, EXIT_COND);
			end = wait_event_timeout(ring->irq_queue, EXIT_COND,
						 timeout_jiffies);

		if (atomic_read(&dev_priv->mm.wedged))
			end = -EAGAIN;
	} while (end == 0 && wait_forever);

	getrawmonotonic(&now);

	ring->irq_put(ring);
	trace_i915_gem_request_wait_end(ring, seqno);
#undef EXIT_COND

	return ret;
	if (timeout) {
		struct timespec sleep_time = timespec_sub(now, before);
		*timeout = timespec_sub(*timeout, sleep_time);
	}

	switch (end) {
	case -EAGAIN: /* Wedged */
	case -ERESTARTSYS: /* Signal */
		return (int)end;
	case 0: /* Timeout */
		if (timeout)
			set_normalized_timespec(timeout, 0, 0);
		return -ETIME;
	default: /* Completed */
		WARN_ON(end < 0); /* We're not aware of other errors */
		return 0;
	}
}

/**
@@ -1934,8 +1982,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
 * request and object lists appropriately for that event.
 */
int
i915_wait_request(struct intel_ring_buffer *ring,
		  uint32_t seqno)
i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
{
	drm_i915_private_t *dev_priv = ring->dev->dev_private;
	int ret = 0;
@@ -1950,9 +1997,7 @@ i915_wait_request(struct intel_ring_buffer *ring,
	if (ret)
		return ret;

	ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible);
	if (atomic_read(&dev_priv->mm.wedged))
		ret = -EAGAIN;
	ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible, NULL);

	return ret;
}
@@ -1975,7 +2020,32 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
	 * it.
	 */
	if (obj->active) {
		ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
		ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno);
		if (ret)
			return ret;
		i915_gem_retire_requests_ring(obj->ring);
	}

	return 0;
}

/**
 * Ensures that an object will eventually get non-busy by flushing any required
 * write domains, emitting any outstanding lazy request and retiring and
 * completed requests.
 */
static int
i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
{
	int ret;

	if (obj->active) {
		ret = i915_gem_object_flush_gpu_write_domain(obj);
		if (ret)
			return ret;

		ret = i915_gem_check_olr(obj->ring,
					 obj->last_rendering_seqno);
		if (ret)
			return ret;
		i915_gem_retire_requests_ring(obj->ring);
@@ -1984,6 +2054,85 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
	return 0;
}

/**
 * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
 * @DRM_IOCTL_ARGS: standard ioctl arguments
 *
 * Returns 0 if successful, else an error is returned with the remaining time in
 * the timeout parameter.
 *  -ETIME: object is still busy after timeout
 *  -ERESTARTSYS: signal interrupted the wait
 *  -ENONENT: object doesn't exist
 * Also possible, but rare:
 *  -EAGAIN: GPU wedged
 *  -ENOMEM: damn
 *  -ENODEV: Internal IRQ fail
 *  -E?: The add request failed
 *
 * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
 * non-zero timeout parameter the wait ioctl will wait for the given number of
 * nanoseconds on an object becoming unbusy. Since the wait itself does so
 * without holding struct_mutex the object may become re-busied before this
 * function completes. A similar but shorter * race condition exists in the busy
 * ioctl
 */
int
i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
	struct drm_i915_gem_wait *args = data;
	struct drm_i915_gem_object *obj;
	struct intel_ring_buffer *ring = NULL;
	struct timespec timeout;
	u32 seqno = 0;
	int ret = 0;

	timeout = ns_to_timespec(args->timeout_ns);

	ret = i915_mutex_lock_interruptible(dev);
	if (ret)
		return ret;

	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->bo_handle));
	if (&obj->base == NULL) {
		mutex_unlock(&dev->struct_mutex);
		return -ENOENT;
	}

	/* Need to make sure the object gets inactive eventually. */
	ret = i915_gem_object_flush_active(obj);
	if (ret)
		goto out;

	if (obj->active) {
		seqno = obj->last_rendering_seqno;
		ring = obj->ring;
	}

	if (seqno == 0)
		 goto out;

	/* Do this after OLR check to make sure we make forward progress polling
	 * on this IOCTL with a 0 timeout (like busy ioctl)
	 */
	if (!args->timeout_ns) {
		ret = -ETIME;
		goto out;
	}

	drm_gem_object_unreference(&obj->base);
	mutex_unlock(&dev->struct_mutex);

	ret = __wait_seqno(ring, seqno, true, &timeout);
	WARN_ON(!timespec_valid(&timeout));
	args->timeout_ns = timespec_to_ns(&timeout);
	return ret;

out:
	drm_gem_object_unreference(&obj->base);
	mutex_unlock(&dev->struct_mutex);
	return ret;
}

/**
 * i915_gem_object_sync - sync an object to a ring.
 *
@@ -2160,7 +2309,7 @@ static int i915_ring_idle(struct intel_ring_buffer *ring)
			return ret;
	}

	return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
	return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring));
}

int i915_gpu_idle(struct drm_device *dev)
@@ -2364,7 +2513,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
	}

	if (obj->last_fenced_seqno) {
		ret = i915_wait_request(obj->ring, obj->last_fenced_seqno);
		ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
		if (ret)
			return ret;

@@ -3030,7 +3179,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
	if (seqno == 0)
		return 0;

	ret = __wait_seqno(ring, seqno, true);
	ret = __wait_seqno(ring, seqno, true, NULL);
	if (ret == 0)
		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);

@@ -3199,30 +3348,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
	 * become non-busy without any further actions, therefore emit any
	 * necessary flushes here.
	 */
	args->busy = obj->active;
	if (args->busy) {
		/* Unconditionally flush objects, even when the gpu still uses this
		 * object. Userspace calling this function indicates that it wants to
		 * use this buffer rather sooner than later, so issuing the required
		 * flush earlier is beneficial.
		 */
		if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
			ret = i915_gem_flush_ring(obj->ring,
						  0, obj->base.write_domain);
		} else {
			ret = i915_gem_check_olr(obj->ring,
						 obj->last_rendering_seqno);
		}

		/* Update the active list for the hardware's current position.
		 * Otherwise this only updates on a delayed timer or when irqs
		 * are actually unmasked, and our working set ends up being
		 * larger than required.
		 */
		i915_gem_retire_requests_ring(obj->ring);
	ret = i915_gem_object_flush_active(obj);

	args->busy = obj->active;
	}

	drm_gem_object_unreference(&obj->base);
unlock:
@@ -3435,6 +3563,38 @@ i915_gem_idle(struct drm_device *dev)
	return 0;
}

void i915_gem_l3_remap(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	u32 misccpctl;
	int i;

	if (!IS_IVYBRIDGE(dev))
		return;

	if (!dev_priv->mm.l3_remap_info)
		return;

	misccpctl = I915_READ(GEN7_MISCCPCTL);
	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
	POSTING_READ(GEN7_MISCCPCTL);

	for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
		u32 remap = I915_READ(GEN7_L3LOG_BASE + i);
		if (remap && remap != dev_priv->mm.l3_remap_info[i/4])
			DRM_DEBUG("0x%x was already programmed to %x\n",
				  GEN7_L3LOG_BASE + i, remap);
		if (remap && !dev_priv->mm.l3_remap_info[i/4])
			DRM_DEBUG_DRIVER("Clearing remapped register\n");
		I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->mm.l3_remap_info[i/4]);
	}

	/* Make sure all the writes land before disabling dop clock gating */
	POSTING_READ(GEN7_L3LOG_BASE);

	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
}

void i915_gem_init_swizzling(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -3524,6 +3684,8 @@ i915_gem_init_hw(struct drm_device *dev)
	drm_i915_private_t *dev_priv = dev->dev_private;
	int ret;

	i915_gem_l3_remap(dev);

	i915_gem_init_swizzling(dev);

	ret = intel_init_render_ring_buffer(dev);
+124 −47
Original line number Diff line number Diff line
@@ -375,6 +375,86 @@ static void gen6_pm_rps_work(struct work_struct *work)
	mutex_unlock(&dev_priv->dev->struct_mutex);
}


/**
 * ivybridge_parity_work - Workqueue called when a parity error interrupt
 * occurred.
 * @work: workqueue struct
 *
 * Doesn't actually do anything except notify userspace. As a consequence of
 * this event, userspace should try to remap the bad rows since statistically
 * it is likely the same row is more likely to go bad again.
 */
static void ivybridge_parity_work(struct work_struct *work)
{
	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
						    parity_error_work);
	u32 error_status, row, bank, subbank;
	char *parity_event[5];
	uint32_t misccpctl;
	unsigned long flags;

	/* We must turn off DOP level clock gating to access the L3 registers.
	 * In order to prevent a get/put style interface, acquire struct mutex
	 * any time we access those registers.
	 */
	mutex_lock(&dev_priv->dev->struct_mutex);

	misccpctl = I915_READ(GEN7_MISCCPCTL);
	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
	POSTING_READ(GEN7_MISCCPCTL);

	error_status = I915_READ(GEN7_L3CDERRST1);
	row = GEN7_PARITY_ERROR_ROW(error_status);
	bank = GEN7_PARITY_ERROR_BANK(error_status);
	subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);

	I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
				    GEN7_L3CDERRST1_ENABLE);
	POSTING_READ(GEN7_L3CDERRST1);

	I915_WRITE(GEN7_MISCCPCTL, misccpctl);

	spin_lock_irqsave(&dev_priv->irq_lock, flags);
	dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);

	mutex_unlock(&dev_priv->dev->struct_mutex);

	parity_event[0] = "L3_PARITY_ERROR=1";
	parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
	parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
	parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
	parity_event[4] = NULL;

	kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
			   KOBJ_CHANGE, parity_event);

	DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
		  row, bank, subbank);

	kfree(parity_event[3]);
	kfree(parity_event[2]);
	kfree(parity_event[1]);
}

static void ivybridge_handle_parity_error(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	unsigned long flags;

	if (!IS_IVYBRIDGE(dev))
		return;

	spin_lock_irqsave(&dev_priv->irq_lock, flags);
	dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);

	queue_work(dev_priv->wq, &dev_priv->parity_error_work);
}

static void snb_gt_irq_handler(struct drm_device *dev,
			       struct drm_i915_private *dev_priv,
			       u32 gt_iir)
@@ -394,6 +474,9 @@ static void snb_gt_irq_handler(struct drm_device *dev,
		DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
		i915_handle_error(dev, false);
	}

	if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
		ivybridge_handle_parity_error(dev);
}

static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
@@ -1649,7 +1732,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)

	atomic_set(&dev_priv->irq_received, 0);


	I915_WRITE(HWSTAM, 0xeffe);

	/* XXX hotplug from PCH */
@@ -1812,13 +1894,13 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
		   DE_PIPEA_VBLANK_IVB);
	POSTING_READ(DEIER);

	dev_priv->gt_irq_mask = ~0;
	dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;

	I915_WRITE(GTIIR, I915_READ(GTIIR));
	I915_WRITE(GTIMR, dev_priv->gt_irq_mask);

	render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
		GEN6_BLITTER_USER_INTERRUPT;
		GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
	I915_WRITE(GTIER, render_irqs);
	POSTING_READ(GTIER);

@@ -2167,9 +2249,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
			hotplug_en |= HDMIC_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
			hotplug_en |= HDMID_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915)
			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915)
			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
			hotplug_en |= CRT_HOTPLUG_INT_EN;
@@ -2329,10 +2411,8 @@ static void i965_irq_preinstall(struct drm_device * dev)

	atomic_set(&dev_priv->irq_received, 0);

	if (I915_HAS_HOTPLUG(dev)) {
	I915_WRITE(PORT_HOTPLUG_EN, 0);
	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
	}

	I915_WRITE(HWSTAM, 0xeffe);
	for_each_pipe(pipe)
@@ -2345,11 +2425,13 @@ static void i965_irq_preinstall(struct drm_device * dev)
static int i965_irq_postinstall(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	u32 hotplug_en;
	u32 enable_mask;
	u32 error_mask;

	/* Unmask the interrupts that we always want on. */
	dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
			       I915_DISPLAY_PORT_INTERRUPT |
			       I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
			       I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
			       I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
@@ -2365,13 +2447,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
	dev_priv->pipestat[0] = 0;
	dev_priv->pipestat[1] = 0;

	if (I915_HAS_HOTPLUG(dev)) {
		/* Enable in IER... */
		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
		/* and unmask in IMR */
		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
	}

	/*
	 * Enable some error detection, note the instruction error mask
	 * bit is reserved, so we leave it masked.
@@ -2391,20 +2466,25 @@ static int i965_irq_postinstall(struct drm_device *dev)
	I915_WRITE(IER, enable_mask);
	POSTING_READ(IER);

	if (I915_HAS_HOTPLUG(dev)) {
		u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);

		/* Note HDMI and DP share bits */
	/* Note HDMI and DP share hotplug bits */
	hotplug_en = 0;
	if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
		hotplug_en |= HDMIB_HOTPLUG_INT_EN;
	if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
		hotplug_en |= HDMIC_HOTPLUG_INT_EN;
	if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
		hotplug_en |= HDMID_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
	if (IS_G4X(dev)) {
		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X)
			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X)
			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
	} else {
		if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965)
			hotplug_en |= SDVOC_HOTPLUG_INT_EN;
		if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965)
			hotplug_en |= SDVOB_HOTPLUG_INT_EN;
	}
	if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
		hotplug_en |= CRT_HOTPLUG_INT_EN;

@@ -2420,7 +2500,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
	/* Ignore TV since it's buggy */

	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
	}

	intel_opregion_enable_asle(dev);

@@ -2478,8 +2557,7 @@ static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS)
		ret = IRQ_HANDLED;

		/* Consume port.  Then clear IIR or we'll miss events */
		if ((I915_HAS_HOTPLUG(dev)) &&
		    (iir & I915_DISPLAY_PORT_INTERRUPT)) {
		if (iir & I915_DISPLAY_PORT_INTERRUPT) {
			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);

			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
@@ -2552,10 +2630,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
	if (!dev_priv)
		return;

	if (I915_HAS_HOTPLUG(dev)) {
	I915_WRITE(PORT_HOTPLUG_EN, 0);
	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
	}

	I915_WRITE(HWSTAM, 0xffffffff);
	for_each_pipe(pipe)
@@ -2576,6 +2652,7 @@ void intel_irq_init(struct drm_device *dev)
	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
	INIT_WORK(&dev_priv->error_work, i915_error_work_func);
	INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
	INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work);

	dev->driver->get_vblank_counter = i915_get_vblank_counter;
	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
Loading