Merge tag 'drm-intel-next-2014-02-07' of ssh://git.freedesktop.org/git/drm-intel into drm-next
- Yet more steps towards atomic modeset from Ville. - DP panel power sequencing improvements from Paulo. - irq code cleanups from Ville. - 5.4 GHz dp lane clock support for bdw/hsw from Todd. - Clock readout support for hsw/bdw (aka fastboot) from Jesse. - Make pipe underruns report at ERROR level (Ville). This is to check our improved watermarks code. - Full ppgtt support from Ben for gen7. - More fbc fixes and improvements from Ville all over the place, unfortunately not yet enabled by default on more platforms. - w/a cleanups from Ville. - HiZ stall optimization settings (Chia-I Wu). - Display register mmio offset refactor patch from Antti. - RPS improvements for corner-cases from Jeff McGee. * tag 'drm-intel-next-2014-02-07' of ssh://git.freedesktop.org/git/drm-intel: (166 commits) drm/i915: Update rps interrupt limits drm/i915: Restore rps/rc6 on reset drm/i915: Prevent recursion by retiring requests when the ring is full drm/i915: Generate a hang error code drm/i915: unify FLIP_DONE macro names drm/i915: vlv: s/spin_lock_irqsave/spin_lock/ in irq handler drm/i915: factor out valleyview_pipestat_irq_handler drm/i915: vlv: don't unmask IIR[DISPLAY_PIPE_A/B_VBLANK] interrupt drm/i915: Reorganize display pipe register accesses drm/i915: Treat using a purged buffer as a source of EFAULT drm/i915: Convert EFAULT into a silent SIGBUS drm/i915: release mutex in i915_gem_init()'s error path drm/i915: check for oom when allocating private_default_ctx drm/i915/vlv: WA to fix Voltage not getting dropped to Vmin when Gfx is power gated. drm/i915: Get rid of acthd based guilty batch search drm/i915: Use hangcheck score to find guilty context drm/i915: Drop WaDisablePSDDualDispatchEnable:ivb for IVB GT2 drm/i915: Fix IVB GT2 WaDisableDopClockGating and WaDisablePSDDualDispatchEnable drm/i915: Don't access snooped pages through the GTT (even for error capture) drm/i915: Only print information for filing bug reports once ... Conflicts: drivers/gpu/drm/i915/intel_dp.c
This commit is contained in:
		
				commit
				
					
						3e09dcd5bd
					
				
			
		
					 35 changed files with 3355 additions and 1689 deletions
				
			
		| 
						 | 
				
			
			@ -14,6 +14,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
 | 
			
		|||
	  i915_gem_gtt.o \
 | 
			
		||||
	  i915_gem_stolen.o \
 | 
			
		||||
	  i915_gem_tiling.o \
 | 
			
		||||
	  i915_params.o \
 | 
			
		||||
	  i915_sysfs.o \
 | 
			
		||||
	  i915_trace_points.o \
 | 
			
		||||
	  i915_ums.o \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ static const char *get_pin_flag(struct drm_i915_gem_object *obj)
 | 
			
		|||
{
 | 
			
		||||
	if (obj->user_pin_count > 0)
 | 
			
		||||
		return "P";
 | 
			
		||||
	else if (obj->pin_count > 0)
 | 
			
		||||
	else if (i915_gem_obj_is_pinned(obj))
 | 
			
		||||
		return "p";
 | 
			
		||||
	else
 | 
			
		||||
		return " ";
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +123,8 @@ static void
 | 
			
		|||
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
	int pin_count = 0;
 | 
			
		||||
 | 
			
		||||
	seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s",
 | 
			
		||||
		   &obj->base,
 | 
			
		||||
		   get_pin_flag(obj),
 | 
			
		||||
| 
						 | 
				
			
			@ -139,8 +141,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 | 
			
		|||
		   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
 | 
			
		||||
	if (obj->base.name)
 | 
			
		||||
		seq_printf(m, " (name: %d)", obj->base.name);
 | 
			
		||||
	if (obj->pin_count)
 | 
			
		||||
		seq_printf(m, " (pinned x %d)", obj->pin_count);
 | 
			
		||||
	list_for_each_entry(vma, &obj->vma_list, vma_link)
 | 
			
		||||
		if (vma->pin_count > 0)
 | 
			
		||||
			pin_count++;
 | 
			
		||||
		seq_printf(m, " (pinned x %d)", pin_count);
 | 
			
		||||
	if (obj->pin_display)
 | 
			
		||||
		seq_printf(m, " (display)");
 | 
			
		||||
	if (obj->fence_reg != I915_FENCE_REG_NONE)
 | 
			
		||||
| 
						 | 
				
			
			@ -447,7 +451,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
 | 
			
		|||
 | 
			
		||||
	total_obj_size = total_gtt_size = count = 0;
 | 
			
		||||
	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
 | 
			
		||||
		if (list == PINNED_LIST && obj->pin_count == 0)
 | 
			
		||||
		if (list == PINNED_LIST && !i915_gem_obj_is_pinned(obj))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		seq_puts(m, "   ");
 | 
			
		||||
| 
						 | 
				
			
			@ -712,8 +716,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
 | 
			
		|||
		seq_printf(m, "Graphics Interrupt mask:		%08x\n",
 | 
			
		||||
			   I915_READ(GTIMR));
 | 
			
		||||
	}
 | 
			
		||||
	seq_printf(m, "Interrupts received: %d\n",
 | 
			
		||||
		   atomic_read(&dev_priv->irq_received));
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		if (INTEL_INFO(dev)->gen >= 6) {
 | 
			
		||||
			seq_printf(m,
 | 
			
		||||
| 
						 | 
				
			
			@ -1733,6 +1735,17 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int per_file_ctx(int id, void *ptr, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_hw_context *ctx = ptr;
 | 
			
		||||
	struct seq_file *m = data;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx);
 | 
			
		||||
 | 
			
		||||
	ppgtt->debug_dump(ppgtt, m);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1762,6 +1775,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	struct drm_file *file;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 6)
 | 
			
		||||
| 
						 | 
				
			
			@ -1780,6 +1794,20 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
		seq_puts(m, "aliasing PPGTT:\n");
 | 
			
		||||
		seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
 | 
			
		||||
 | 
			
		||||
		ppgtt->debug_dump(ppgtt, m);
 | 
			
		||||
	} else
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_reverse(file, &dev->filelist, lhead) {
 | 
			
		||||
		struct drm_i915_file_private *file_priv = file->driver_priv;
 | 
			
		||||
		struct i915_hw_ppgtt *pvt_ppgtt;
 | 
			
		||||
 | 
			
		||||
		pvt_ppgtt = ctx_to_ppgtt(file_priv->private_default_ctx);
 | 
			
		||||
		seq_printf(m, "proc: %s\n",
 | 
			
		||||
			   get_pid_task(file->pid, PIDTYPE_PID)->comm);
 | 
			
		||||
		seq_puts(m, "  default context:\n");
 | 
			
		||||
		idr_for_each(&file_priv->context_idr, per_file_ctx, m);
 | 
			
		||||
	}
 | 
			
		||||
	seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1892,6 +1920,44 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int i915_sink_crc(struct seq_file *m, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_info_node *node = m->private;
 | 
			
		||||
	struct drm_device *dev = node->minor->dev;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
	struct intel_dp *intel_dp = NULL;
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 crc[6];
 | 
			
		||||
 | 
			
		||||
	drm_modeset_lock_all(dev);
 | 
			
		||||
	list_for_each_entry(connector, &dev->mode_config.connector_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
 | 
			
		||||
		if (connector->base.dpms != DRM_MODE_DPMS_ON)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		encoder = to_intel_encoder(connector->base.encoder);
 | 
			
		||||
		if (encoder->type != INTEL_OUTPUT_EDP)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		intel_dp = enc_to_intel_dp(&encoder->base);
 | 
			
		||||
 | 
			
		||||
		ret = intel_dp_sink_crc(intel_dp, crc);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		seq_printf(m, "%02x%02x%02x%02x%02x%02x\n",
 | 
			
		||||
			   crc[0], crc[1], crc[2],
 | 
			
		||||
			   crc[3], crc[4], crc[5]);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	ret = -ENODEV;
 | 
			
		||||
out:
 | 
			
		||||
	drm_modeset_unlock_all(dev);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int i915_energy_uJ(struct seq_file *m, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_info_node *node = m->private;
 | 
			
		||||
| 
						 | 
				
			
			@ -2756,6 +2822,174 @@ static const struct file_operations i915_display_crc_ctl_fops = {
 | 
			
		|||
	.write = display_crc_ctl_write
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void wm_latency_show(struct seq_file *m, const uint16_t wm[5])
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = m->private;
 | 
			
		||||
	int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
 | 
			
		||||
	int level;
 | 
			
		||||
 | 
			
		||||
	drm_modeset_lock_all(dev);
 | 
			
		||||
 | 
			
		||||
	for (level = 0; level < num_levels; level++) {
 | 
			
		||||
		unsigned int latency = wm[level];
 | 
			
		||||
 | 
			
		||||
		/* WM1+ latency values in 0.5us units */
 | 
			
		||||
		if (level > 0)
 | 
			
		||||
			latency *= 5;
 | 
			
		||||
 | 
			
		||||
		seq_printf(m, "WM%d %u (%u.%u usec)\n",
 | 
			
		||||
			   level, wm[level],
 | 
			
		||||
			   latency / 10, latency % 10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drm_modeset_unlock_all(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pri_wm_latency_show(struct seq_file *m, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = m->private;
 | 
			
		||||
 | 
			
		||||
	wm_latency_show(m, to_i915(dev)->wm.pri_latency);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int spr_wm_latency_show(struct seq_file *m, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = m->private;
 | 
			
		||||
 | 
			
		||||
	wm_latency_show(m, to_i915(dev)->wm.spr_latency);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cur_wm_latency_show(struct seq_file *m, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = m->private;
 | 
			
		||||
 | 
			
		||||
	wm_latency_show(m, to_i915(dev)->wm.cur_latency);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pri_wm_latency_open(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = inode->i_private;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_PCH_SPLIT(dev))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return single_open(file, pri_wm_latency_show, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int spr_wm_latency_open(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = inode->i_private;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_PCH_SPLIT(dev))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return single_open(file, spr_wm_latency_show, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cur_wm_latency_open(struct inode *inode, struct file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = inode->i_private;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_PCH_SPLIT(dev))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return single_open(file, cur_wm_latency_show, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
 | 
			
		||||
				size_t len, loff_t *offp, uint16_t wm[5])
 | 
			
		||||
{
 | 
			
		||||
	struct seq_file *m = file->private_data;
 | 
			
		||||
	struct drm_device *dev = m->private;
 | 
			
		||||
	uint16_t new[5] = { 0 };
 | 
			
		||||
	int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
 | 
			
		||||
	int level;
 | 
			
		||||
	int ret;
 | 
			
		||||
	char tmp[32];
 | 
			
		||||
 | 
			
		||||
	if (len >= sizeof(tmp))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (copy_from_user(tmp, ubuf, len))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	tmp[len] = '\0';
 | 
			
		||||
 | 
			
		||||
	ret = sscanf(tmp, "%hu %hu %hu %hu %hu", &new[0], &new[1], &new[2], &new[3], &new[4]);
 | 
			
		||||
	if (ret != num_levels)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	drm_modeset_lock_all(dev);
 | 
			
		||||
 | 
			
		||||
	for (level = 0; level < num_levels; level++)
 | 
			
		||||
		wm[level] = new[level];
 | 
			
		||||
 | 
			
		||||
	drm_modeset_unlock_all(dev);
 | 
			
		||||
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static ssize_t pri_wm_latency_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;
 | 
			
		||||
 | 
			
		||||
	return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t spr_wm_latency_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;
 | 
			
		||||
 | 
			
		||||
	return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t cur_wm_latency_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;
 | 
			
		||||
 | 
			
		||||
	return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct file_operations i915_pri_wm_latency_fops = {
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.open = pri_wm_latency_open,
 | 
			
		||||
	.read = seq_read,
 | 
			
		||||
	.llseek = seq_lseek,
 | 
			
		||||
	.release = single_release,
 | 
			
		||||
	.write = pri_wm_latency_write
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct file_operations i915_spr_wm_latency_fops = {
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.open = spr_wm_latency_open,
 | 
			
		||||
	.read = seq_read,
 | 
			
		||||
	.llseek = seq_lseek,
 | 
			
		||||
	.release = single_release,
 | 
			
		||||
	.write = spr_wm_latency_write
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct file_operations i915_cur_wm_latency_fops = {
 | 
			
		||||
	.owner = THIS_MODULE,
 | 
			
		||||
	.open = cur_wm_latency_open,
 | 
			
		||||
	.read = seq_read,
 | 
			
		||||
	.llseek = seq_lseek,
 | 
			
		||||
	.release = single_release,
 | 
			
		||||
	.write = cur_wm_latency_write
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
i915_wedged_get(void *data, u64 *val)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2929,7 +3163,7 @@ i915_drop_caches_set(void *data, u64 val)
 | 
			
		|||
		list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
 | 
			
		||||
			list_for_each_entry_safe(vma, x, &vm->inactive_list,
 | 
			
		||||
						 mm_list) {
 | 
			
		||||
				if (vma->obj->pin_count)
 | 
			
		||||
				if (vma->pin_count)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				ret = i915_vma_unbind(vma);
 | 
			
		||||
| 
						 | 
				
			
			@ -2989,6 +3223,7 @@ i915_max_freq_set(void *data, u64 val)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_device *dev = data;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	u32 rp_state_cap, hw_max, hw_min;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!(IS_GEN6(dev) || IS_GEN7(dev)))
 | 
			
		||||
| 
						 | 
				
			
			@ -3007,14 +3242,29 @@ i915_max_freq_set(void *data, u64 val)
 | 
			
		|||
	 */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev)) {
 | 
			
		||||
		val = vlv_freq_opcode(dev_priv, val);
 | 
			
		||||
		dev_priv->rps.max_delay = val;
 | 
			
		||||
		valleyview_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
		hw_max = valleyview_rps_max_freq(dev_priv);
 | 
			
		||||
		hw_min = valleyview_rps_min_freq(dev_priv);
 | 
			
		||||
	} else {
 | 
			
		||||
		do_div(val, GT_FREQUENCY_MULTIPLIER);
 | 
			
		||||
		dev_priv->rps.max_delay = val;
 | 
			
		||||
		gen6_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 | 
			
		||||
		hw_max = dev_priv->rps.hw_max;
 | 
			
		||||
		hw_min = (rp_state_cap >> 16) & 0xff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
 | 
			
		||||
		mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.max_delay = val;
 | 
			
		||||
 | 
			
		||||
	if (IS_VALLEYVIEW(dev))
 | 
			
		||||
		valleyview_set_rps(dev, val);
 | 
			
		||||
	else
 | 
			
		||||
		gen6_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3054,6 +3304,7 @@ i915_min_freq_set(void *data, u64 val)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_device *dev = data;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	u32 rp_state_cap, hw_max, hw_min;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!(IS_GEN6(dev) || IS_GEN7(dev)))
 | 
			
		||||
| 
						 | 
				
			
			@ -3072,13 +3323,29 @@ i915_min_freq_set(void *data, u64 val)
 | 
			
		|||
	 */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev)) {
 | 
			
		||||
		val = vlv_freq_opcode(dev_priv, val);
 | 
			
		||||
		dev_priv->rps.min_delay = val;
 | 
			
		||||
		valleyview_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
		hw_max = valleyview_rps_max_freq(dev_priv);
 | 
			
		||||
		hw_min = valleyview_rps_min_freq(dev_priv);
 | 
			
		||||
	} else {
 | 
			
		||||
		do_div(val, GT_FREQUENCY_MULTIPLIER);
 | 
			
		||||
		dev_priv->rps.min_delay = val;
 | 
			
		||||
		gen6_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 | 
			
		||||
		hw_max = dev_priv->rps.hw_max;
 | 
			
		||||
		hw_min = (rp_state_cap >> 16) & 0xff;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
 | 
			
		||||
		mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.min_delay = val;
 | 
			
		||||
 | 
			
		||||
	if (IS_VALLEYVIEW(dev))
 | 
			
		||||
		valleyview_set_rps(dev, val);
 | 
			
		||||
	else
 | 
			
		||||
		gen6_set_rps(dev, val);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3248,6 +3515,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
 | 
			
		|||
	{"i915_dpio", i915_dpio_info, 0},
 | 
			
		||||
	{"i915_llc", i915_llc, 0},
 | 
			
		||||
	{"i915_edp_psr_status", i915_edp_psr_status, 0},
 | 
			
		||||
	{"i915_sink_crc_eDP1", i915_sink_crc, 0},
 | 
			
		||||
	{"i915_energy_uJ", i915_energy_uJ, 0},
 | 
			
		||||
	{"i915_pc8_status", i915_pc8_status, 0},
 | 
			
		||||
	{"i915_power_domain_info", i915_power_domain_info, 0},
 | 
			
		||||
| 
						 | 
				
			
			@ -3269,6 +3537,9 @@ static const struct i915_debugfs_files {
 | 
			
		|||
	{"i915_error_state", &i915_error_state_fops},
 | 
			
		||||
	{"i915_next_seqno", &i915_next_seqno_fops},
 | 
			
		||||
	{"i915_display_crc_ctl", &i915_display_crc_ctl_fops},
 | 
			
		||||
	{"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
 | 
			
		||||
	{"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
 | 
			
		||||
	{"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void intel_display_crc_init(struct drm_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -990,7 +990,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 | 
			
		|||
		value = HAS_WT(dev);
 | 
			
		||||
		break;
 | 
			
		||||
	case I915_PARAM_HAS_ALIASING_PPGTT:
 | 
			
		||||
		value = dev_priv->mm.aliasing_ppgtt ? 1 : 0;
 | 
			
		||||
		value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev);
 | 
			
		||||
		break;
 | 
			
		||||
	case I915_PARAM_HAS_WAIT_TIMEOUT:
 | 
			
		||||
		value = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1374,7 +1374,7 @@ cleanup_gem:
 | 
			
		|||
	i915_gem_cleanup_ringbuffer(dev);
 | 
			
		||||
	i915_gem_context_fini(dev);
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
	i915_gem_cleanup_aliasing_ppgtt(dev);
 | 
			
		||||
	WARN_ON(dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
	drm_mm_takedown(&dev_priv->gtt.base.mm);
 | 
			
		||||
cleanup_power:
 | 
			
		||||
	intel_display_power_put(dev, POWER_DOMAIN_VGA);
 | 
			
		||||
| 
						 | 
				
			
			@ -1776,8 +1776,8 @@ int i915_driver_unload(struct drm_device *dev)
 | 
			
		|||
		i915_gem_free_all_phys_object(dev);
 | 
			
		||||
		i915_gem_cleanup_ringbuffer(dev);
 | 
			
		||||
		i915_gem_context_fini(dev);
 | 
			
		||||
		WARN_ON(dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		i915_gem_cleanup_aliasing_ppgtt(dev);
 | 
			
		||||
		i915_gem_cleanup_stolen(dev);
 | 
			
		||||
 | 
			
		||||
		if (!I915_NEED_GFX_HWS(dev))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,134 +38,30 @@
 | 
			
		|||
#include <linux/module.h>
 | 
			
		||||
#include <drm/drm_crtc_helper.h>
 | 
			
		||||
 | 
			
		||||
static int i915_modeset __read_mostly = -1;
 | 
			
		||||
module_param_named(modeset, i915_modeset, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(modeset,
 | 
			
		||||
		"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
 | 
			
		||||
		"1=on, -1=force vga console preference [default])");
 | 
			
		||||
 | 
			
		||||
unsigned int i915_fbpercrtc __always_unused = 0;
 | 
			
		||||
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 | 
			
		||||
 | 
			
		||||
int i915_panel_ignore_lid __read_mostly = 1;
 | 
			
		||||
module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(panel_ignore_lid,
 | 
			
		||||
		"Override lid status (0=autodetect, 1=autodetect disabled [default], "
 | 
			
		||||
		"-1=force lid closed, -2=force lid open)");
 | 
			
		||||
 | 
			
		||||
unsigned int i915_powersave __read_mostly = 1;
 | 
			
		||||
module_param_named(powersave, i915_powersave, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(powersave,
 | 
			
		||||
		"Enable powersavings, fbc, downclocking, etc. (default: true)");
 | 
			
		||||
 | 
			
		||||
int i915_semaphores __read_mostly = -1;
 | 
			
		||||
module_param_named(semaphores, i915_semaphores, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(semaphores,
 | 
			
		||||
		"Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))");
 | 
			
		||||
 | 
			
		||||
int i915_enable_rc6 __read_mostly = -1;
 | 
			
		||||
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(i915_enable_rc6,
 | 
			
		||||
		"Enable power-saving render C-state 6. "
 | 
			
		||||
		"Different stages can be selected via bitmask values "
 | 
			
		||||
		"(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
 | 
			
		||||
		"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
 | 
			
		||||
		"default: -1 (use per-chip default)");
 | 
			
		||||
 | 
			
		||||
int i915_enable_fbc __read_mostly = -1;
 | 
			
		||||
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(i915_enable_fbc,
 | 
			
		||||
		"Enable frame buffer compression for power savings "
 | 
			
		||||
		"(default: -1 (use per-chip default))");
 | 
			
		||||
 | 
			
		||||
unsigned int i915_lvds_downclock __read_mostly = 0;
 | 
			
		||||
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(lvds_downclock,
 | 
			
		||||
		"Use panel (LVDS/eDP) downclocking for power savings "
 | 
			
		||||
		"(default: false)");
 | 
			
		||||
 | 
			
		||||
int i915_lvds_channel_mode __read_mostly;
 | 
			
		||||
module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(lvds_channel_mode,
 | 
			
		||||
		 "Specify LVDS channel mode "
 | 
			
		||||
		 "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
 | 
			
		||||
 | 
			
		||||
int i915_panel_use_ssc __read_mostly = -1;
 | 
			
		||||
module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(lvds_use_ssc,
 | 
			
		||||
		"Use Spread Spectrum Clock with panels [LVDS/eDP] "
 | 
			
		||||
		"(default: auto from VBT)");
 | 
			
		||||
 | 
			
		||||
int i915_vbt_sdvo_panel_type __read_mostly = -1;
 | 
			
		||||
module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(vbt_sdvo_panel_type,
 | 
			
		||||
		"Override/Ignore selection of SDVO panel mode in the VBT "
 | 
			
		||||
		"(-2=ignore, -1=auto [default], index in VBT BIOS table)");
 | 
			
		||||
 | 
			
		||||
static bool i915_try_reset __read_mostly = true;
 | 
			
		||||
module_param_named(reset, i915_try_reset, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
 | 
			
		||||
 | 
			
		||||
bool i915_enable_hangcheck __read_mostly = true;
 | 
			
		||||
module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644);
 | 
			
		||||
MODULE_PARM_DESC(enable_hangcheck,
 | 
			
		||||
		"Periodically check GPU activity for detecting hangs. "
 | 
			
		||||
		"WARNING: Disabling this can cause system wide hangs. "
 | 
			
		||||
		"(default: true)");
 | 
			
		||||
 | 
			
		||||
int i915_enable_ppgtt __read_mostly = -1;
 | 
			
		||||
module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(i915_enable_ppgtt,
 | 
			
		||||
		"Enable PPGTT (default: true)");
 | 
			
		||||
 | 
			
		||||
int i915_enable_psr __read_mostly = 0;
 | 
			
		||||
module_param_named(enable_psr, i915_enable_psr, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
 | 
			
		||||
 | 
			
		||||
unsigned int i915_preliminary_hw_support __read_mostly = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT);
 | 
			
		||||
module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(preliminary_hw_support,
 | 
			
		||||
		"Enable preliminary hardware support.");
 | 
			
		||||
 | 
			
		||||
int i915_disable_power_well __read_mostly = 1;
 | 
			
		||||
module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(disable_power_well,
 | 
			
		||||
		 "Disable the power well when possible (default: true)");
 | 
			
		||||
 | 
			
		||||
int i915_enable_ips __read_mostly = 1;
 | 
			
		||||
module_param_named(enable_ips, i915_enable_ips, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
 | 
			
		||||
 | 
			
		||||
bool i915_fastboot __read_mostly = 0;
 | 
			
		||||
module_param_named(fastboot, i915_fastboot, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time "
 | 
			
		||||
		 "(default: false)");
 | 
			
		||||
 | 
			
		||||
int i915_enable_pc8 __read_mostly = 1;
 | 
			
		||||
module_param_named(enable_pc8, i915_enable_pc8, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_pc8, "Enable support for low power package C states (PC8+) (default: true)");
 | 
			
		||||
 | 
			
		||||
int i915_pc8_timeout __read_mostly = 5000;
 | 
			
		||||
module_param_named(pc8_timeout, i915_pc8_timeout, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(pc8_timeout, "Number of msecs of idleness required to enter PC8+ (default: 5000)");
 | 
			
		||||
 | 
			
		||||
bool i915_prefault_disable __read_mostly;
 | 
			
		||||
module_param_named(prefault_disable, i915_prefault_disable, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(prefault_disable,
 | 
			
		||||
		"Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only.");
 | 
			
		||||
 | 
			
		||||
static struct drm_driver driver;
 | 
			
		||||
 | 
			
		||||
#define GEN_DEFAULT_PIPEOFFSETS \
 | 
			
		||||
	.pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
 | 
			
		||||
			  PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \
 | 
			
		||||
	.trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \
 | 
			
		||||
			   TRANSCODER_C_OFFSET, TRANSCODER_EDP_OFFSET }, \
 | 
			
		||||
	.dpll_offsets = { DPLL_A_OFFSET, DPLL_B_OFFSET }, \
 | 
			
		||||
	.dpll_md_offsets = { DPLL_A_MD_OFFSET, DPLL_B_MD_OFFSET }, \
 | 
			
		||||
	.palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i830_info = {
 | 
			
		||||
	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
 | 
			
		||||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_845g_info = {
 | 
			
		||||
	.gen = 2, .num_pipes = 1,
 | 
			
		||||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i85x_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -174,18 +70,21 @@ static const struct intel_device_info intel_i85x_info = {
 | 
			
		|||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i865g_info = {
 | 
			
		||||
	.gen = 2, .num_pipes = 1,
 | 
			
		||||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i915g_info = {
 | 
			
		||||
	.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
 | 
			
		||||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
static const struct intel_device_info intel_i915gm_info = {
 | 
			
		||||
	.gen = 3, .is_mobile = 1, .num_pipes = 2,
 | 
			
		||||
| 
						 | 
				
			
			@ -194,11 +93,13 @@ static const struct intel_device_info intel_i915gm_info = {
 | 
			
		|||
	.supports_tv = 1,
 | 
			
		||||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
static const struct intel_device_info intel_i945g_info = {
 | 
			
		||||
	.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
 | 
			
		||||
	.has_overlay = 1, .overlay_needs_physical = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
static const struct intel_device_info intel_i945gm_info = {
 | 
			
		||||
	.gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +108,7 @@ static const struct intel_device_info intel_i945gm_info = {
 | 
			
		|||
	.supports_tv = 1,
 | 
			
		||||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i965g_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -214,6 +116,7 @@ static const struct intel_device_info intel_i965g_info = {
 | 
			
		|||
	.has_hotplug = 1,
 | 
			
		||||
	.has_overlay = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_i965gm_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +125,7 @@ static const struct intel_device_info intel_i965gm_info = {
 | 
			
		|||
	.has_overlay = 1,
 | 
			
		||||
	.supports_tv = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_g33_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -229,12 +133,14 @@ static const struct intel_device_info intel_g33_info = {
 | 
			
		|||
	.need_gfx_hws = 1, .has_hotplug = 1,
 | 
			
		||||
	.has_overlay = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_g45_info = {
 | 
			
		||||
	.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
 | 
			
		||||
	.has_pipe_cxsr = 1, .has_hotplug = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_gm45_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -243,18 +149,21 @@ static const struct intel_device_info intel_gm45_info = {
 | 
			
		|||
	.has_pipe_cxsr = 1, .has_hotplug = 1,
 | 
			
		||||
	.supports_tv = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_pineview_info = {
 | 
			
		||||
	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
 | 
			
		||||
	.need_gfx_hws = 1, .has_hotplug = 1,
 | 
			
		||||
	.has_overlay = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_ironlake_d_info = {
 | 
			
		||||
	.gen = 5, .num_pipes = 2,
 | 
			
		||||
	.need_gfx_hws = 1, .has_hotplug = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_ironlake_m_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -262,6 +171,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
 | 
			
		|||
	.need_gfx_hws = 1, .has_hotplug = 1,
 | 
			
		||||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_sandybridge_d_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -270,6 +180,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
 | 
			
		|||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
 | 
			
		||||
	.has_llc = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_sandybridge_m_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +189,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
 | 
			
		|||
	.has_fbc = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
 | 
			
		||||
	.has_llc = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define GEN7_FEATURES  \
 | 
			
		||||
| 
						 | 
				
			
			@ -290,18 +202,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
 | 
			
		|||
static const struct intel_device_info intel_ivybridge_d_info = {
 | 
			
		||||
	GEN7_FEATURES,
 | 
			
		||||
	.is_ivybridge = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_ivybridge_m_info = {
 | 
			
		||||
	GEN7_FEATURES,
 | 
			
		||||
	.is_ivybridge = 1,
 | 
			
		||||
	.is_mobile = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_ivybridge_q_info = {
 | 
			
		||||
	GEN7_FEATURES,
 | 
			
		||||
	.is_ivybridge = 1,
 | 
			
		||||
	.num_pipes = 0, /* legal, last one wins */
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_valleyview_m_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -312,6 +227,7 @@ static const struct intel_device_info intel_valleyview_m_info = {
 | 
			
		|||
	.display_mmio_offset = VLV_DISPLAY_BASE,
 | 
			
		||||
	.has_fbc = 0, /* legal, last one wins */
 | 
			
		||||
	.has_llc = 0, /* legal, last one wins */
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_valleyview_d_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -321,6 +237,7 @@ static const struct intel_device_info intel_valleyview_d_info = {
 | 
			
		|||
	.display_mmio_offset = VLV_DISPLAY_BASE,
 | 
			
		||||
	.has_fbc = 0, /* legal, last one wins */
 | 
			
		||||
	.has_llc = 0, /* legal, last one wins */
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_haswell_d_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -329,6 +246,7 @@ static const struct intel_device_info intel_haswell_d_info = {
 | 
			
		|||
	.has_ddi = 1,
 | 
			
		||||
	.has_fpga_dbg = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_haswell_m_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,6 +256,7 @@ static const struct intel_device_info intel_haswell_m_info = {
 | 
			
		|||
	.has_ddi = 1,
 | 
			
		||||
	.has_fpga_dbg = 1,
 | 
			
		||||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_broadwell_d_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -346,6 +265,7 @@ static const struct intel_device_info intel_broadwell_d_info = {
 | 
			
		|||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 | 
			
		||||
	.has_llc = 1,
 | 
			
		||||
	.has_ddi = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct intel_device_info intel_broadwell_m_info = {
 | 
			
		||||
| 
						 | 
				
			
			@ -354,6 +274,7 @@ static const struct intel_device_info intel_broadwell_m_info = {
 | 
			
		|||
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 | 
			
		||||
	.has_llc = 1,
 | 
			
		||||
	.has_ddi = 1,
 | 
			
		||||
	GEN_DEFAULT_PIPEOFFSETS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -482,12 +403,12 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	/* Until we get further testing... */
 | 
			
		||||
	if (IS_GEN8(dev)) {
 | 
			
		||||
		WARN_ON(!i915_preliminary_hw_support);
 | 
			
		||||
		WARN_ON(!i915.preliminary_hw_support);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i915_semaphores >= 0)
 | 
			
		||||
		return i915_semaphores;
 | 
			
		||||
	if (i915.semaphores >= 0)
 | 
			
		||||
		return i915.semaphores;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_INTEL_IOMMU
 | 
			
		||||
	/* Enable semaphores on SNB when IO remapping is off */
 | 
			
		||||
| 
						 | 
				
			
			@ -643,6 +564,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 | 
			
		|||
	/* KMS EnterVT equivalent */
 | 
			
		||||
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
 | 
			
		||||
		intel_init_pch_refclk(dev);
 | 
			
		||||
		drm_mode_config_reset(dev);
 | 
			
		||||
 | 
			
		||||
		mutex_lock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -655,7 +577,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 | 
			
		|||
		intel_modeset_init_hw(dev);
 | 
			
		||||
 | 
			
		||||
		drm_modeset_lock_all(dev);
 | 
			
		||||
		drm_mode_config_reset(dev);
 | 
			
		||||
		intel_modeset_setup_hw_state(dev, true);
 | 
			
		||||
		drm_modeset_unlock_all(dev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -752,7 +673,7 @@ int i915_reset(struct drm_device *dev)
 | 
			
		|||
	bool simulated;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!i915_try_reset)
 | 
			
		||||
	if (!i915.reset)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->struct_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -807,6 +728,17 @@ int i915_reset(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
		drm_irq_uninstall(dev);
 | 
			
		||||
		drm_irq_install(dev);
 | 
			
		||||
 | 
			
		||||
		/* rps/rc6 re-init is necessary to restore state lost after the
 | 
			
		||||
		 * reset and the re-install of drm irq. Skip for ironlake per
 | 
			
		||||
		 * previous concerns that it doesn't respond well to some forms
 | 
			
		||||
		 * of re-init after reset. */
 | 
			
		||||
		if (INTEL_INFO(dev)->gen > 5) {
 | 
			
		||||
			mutex_lock(&dev->struct_mutex);
 | 
			
		||||
			intel_enable_gt_powersave(dev);
 | 
			
		||||
			mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		intel_hpd_init(dev);
 | 
			
		||||
	} else {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -820,7 +752,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
			
		|||
	struct intel_device_info *intel_info =
 | 
			
		||||
		(struct intel_device_info *) ent->driver_data;
 | 
			
		||||
 | 
			
		||||
	if (IS_PRELIMINARY_HW(intel_info) && !i915_preliminary_hw_support) {
 | 
			
		||||
	if (IS_PRELIMINARY_HW(intel_info) && !i915.preliminary_hw_support) {
 | 
			
		||||
		DRM_INFO("This hardware requires preliminary hardware support.\n"
 | 
			
		||||
			 "See CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT, and/or modparam preliminary_hw_support\n");
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
| 
						 | 
				
			
			@ -1051,14 +983,14 @@ static int __init i915_init(void)
 | 
			
		|||
	 * the default behavior.
 | 
			
		||||
	 */
 | 
			
		||||
#if defined(CONFIG_DRM_I915_KMS)
 | 
			
		||||
	if (i915_modeset != 0)
 | 
			
		||||
	if (i915.modeset != 0)
 | 
			
		||||
		driver.driver_features |= DRIVER_MODESET;
 | 
			
		||||
#endif
 | 
			
		||||
	if (i915_modeset == 1)
 | 
			
		||||
	if (i915.modeset == 1)
 | 
			
		||||
		driver.driver_features |= DRIVER_MODESET;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_VGA_CONSOLE
 | 
			
		||||
	if (vgacon_text_force() && i915_modeset == -1)
 | 
			
		||||
	if (vgacon_text_force() && i915.modeset == -1)
 | 
			
		||||
		driver.driver_features &= ~DRIVER_MODESET;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,8 @@ enum pipe {
 | 
			
		|||
	PIPE_A = 0,
 | 
			
		||||
	PIPE_B,
 | 
			
		||||
	PIPE_C,
 | 
			
		||||
	I915_MAX_PIPES
 | 
			
		||||
	_PIPE_EDP,
 | 
			
		||||
	I915_MAX_PIPES = _PIPE_EDP
 | 
			
		||||
};
 | 
			
		||||
#define pipe_name(p) ((p) + 'A')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +67,8 @@ enum transcoder {
 | 
			
		|||
	TRANSCODER_A = 0,
 | 
			
		||||
	TRANSCODER_B,
 | 
			
		||||
	TRANSCODER_C,
 | 
			
		||||
	TRANSCODER_EDP = 0xF,
 | 
			
		||||
	TRANSCODER_EDP,
 | 
			
		||||
	I915_MAX_TRANSCODERS
 | 
			
		||||
};
 | 
			
		||||
#define transcoder_name(t) ((t) + 'A')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -295,53 +297,80 @@ struct intel_display_error_state;
 | 
			
		|||
 | 
			
		||||
struct drm_i915_error_state {
 | 
			
		||||
	struct kref ref;
 | 
			
		||||
	struct timeval time;
 | 
			
		||||
 | 
			
		||||
	/* Generic register state */
 | 
			
		||||
	u32 eir;
 | 
			
		||||
	u32 pgtbl_er;
 | 
			
		||||
	u32 ier;
 | 
			
		||||
	u32 ccid;
 | 
			
		||||
	u32 derrmr;
 | 
			
		||||
	u32 forcewake;
 | 
			
		||||
	bool waiting[I915_NUM_RINGS];
 | 
			
		||||
	u32 pipestat[I915_MAX_PIPES];
 | 
			
		||||
	u32 tail[I915_NUM_RINGS];
 | 
			
		||||
	u32 head[I915_NUM_RINGS];
 | 
			
		||||
	u32 ctl[I915_NUM_RINGS];
 | 
			
		||||
	u32 ipeir[I915_NUM_RINGS];
 | 
			
		||||
	u32 ipehr[I915_NUM_RINGS];
 | 
			
		||||
	u32 instdone[I915_NUM_RINGS];
 | 
			
		||||
	u32 acthd[I915_NUM_RINGS];
 | 
			
		||||
	u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
 | 
			
		||||
	u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1];
 | 
			
		||||
	u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */
 | 
			
		||||
	/* our own tracking of ring head and tail */
 | 
			
		||||
	u32 cpu_ring_head[I915_NUM_RINGS];
 | 
			
		||||
	u32 cpu_ring_tail[I915_NUM_RINGS];
 | 
			
		||||
	u32 error; /* gen6+ */
 | 
			
		||||
	u32 err_int; /* gen7 */
 | 
			
		||||
	u32 bbstate[I915_NUM_RINGS];
 | 
			
		||||
	u32 instpm[I915_NUM_RINGS];
 | 
			
		||||
	u32 instps[I915_NUM_RINGS];
 | 
			
		||||
	u32 extra_instdone[I915_NUM_INSTDONE_REG];
 | 
			
		||||
	u32 seqno[I915_NUM_RINGS];
 | 
			
		||||
	u64 bbaddr[I915_NUM_RINGS];
 | 
			
		||||
	u32 fault_reg[I915_NUM_RINGS];
 | 
			
		||||
	u32 done_reg;
 | 
			
		||||
	u32 faddr[I915_NUM_RINGS];
 | 
			
		||||
	u32 gac_eco;
 | 
			
		||||
	u32 gam_ecochk;
 | 
			
		||||
	u32 gab_ctl;
 | 
			
		||||
	u32 gfx_mode;
 | 
			
		||||
	u32 extra_instdone[I915_NUM_INSTDONE_REG];
 | 
			
		||||
	u32 pipestat[I915_MAX_PIPES];
 | 
			
		||||
	u64 fence[I915_MAX_NUM_FENCES];
 | 
			
		||||
	struct timeval time;
 | 
			
		||||
	struct intel_overlay_error_state *overlay;
 | 
			
		||||
	struct intel_display_error_state *display;
 | 
			
		||||
 | 
			
		||||
	struct drm_i915_error_ring {
 | 
			
		||||
		bool valid;
 | 
			
		||||
		/* Software tracked state */
 | 
			
		||||
		bool waiting;
 | 
			
		||||
		int hangcheck_score;
 | 
			
		||||
		enum intel_ring_hangcheck_action hangcheck_action;
 | 
			
		||||
		int num_requests;
 | 
			
		||||
 | 
			
		||||
		/* our own tracking of ring head and tail */
 | 
			
		||||
		u32 cpu_ring_head;
 | 
			
		||||
		u32 cpu_ring_tail;
 | 
			
		||||
 | 
			
		||||
		u32 semaphore_seqno[I915_NUM_RINGS - 1];
 | 
			
		||||
 | 
			
		||||
		/* Register state */
 | 
			
		||||
		u32 tail;
 | 
			
		||||
		u32 head;
 | 
			
		||||
		u32 ctl;
 | 
			
		||||
		u32 hws;
 | 
			
		||||
		u32 ipeir;
 | 
			
		||||
		u32 ipehr;
 | 
			
		||||
		u32 instdone;
 | 
			
		||||
		u32 acthd;
 | 
			
		||||
		u32 bbstate;
 | 
			
		||||
		u32 instpm;
 | 
			
		||||
		u32 instps;
 | 
			
		||||
		u32 seqno;
 | 
			
		||||
		u64 bbaddr;
 | 
			
		||||
		u32 fault_reg;
 | 
			
		||||
		u32 faddr;
 | 
			
		||||
		u32 rc_psmi; /* sleep state */
 | 
			
		||||
		u32 semaphore_mboxes[I915_NUM_RINGS - 1];
 | 
			
		||||
 | 
			
		||||
		struct drm_i915_error_object {
 | 
			
		||||
			int page_count;
 | 
			
		||||
			u32 gtt_offset;
 | 
			
		||||
			u32 *pages[0];
 | 
			
		||||
		} *ringbuffer, *batchbuffer, *ctx;
 | 
			
		||||
		} *ringbuffer, *batchbuffer, *ctx, *hws_page;
 | 
			
		||||
 | 
			
		||||
		struct drm_i915_error_request {
 | 
			
		||||
			long jiffies;
 | 
			
		||||
			u32 seqno;
 | 
			
		||||
			u32 tail;
 | 
			
		||||
		} *requests;
 | 
			
		||||
		int num_requests;
 | 
			
		||||
 | 
			
		||||
		struct {
 | 
			
		||||
			u32 gfx_mode;
 | 
			
		||||
			union {
 | 
			
		||||
				u64 pdp[4];
 | 
			
		||||
				u32 pp_dir_base;
 | 
			
		||||
			};
 | 
			
		||||
		} vm_info;
 | 
			
		||||
	} ring[I915_NUM_RINGS];
 | 
			
		||||
	struct drm_i915_error_buffer {
 | 
			
		||||
		u32 size;
 | 
			
		||||
| 
						 | 
				
			
			@ -358,11 +387,8 @@ struct drm_i915_error_state {
 | 
			
		|||
		s32 ring:4;
 | 
			
		||||
		u32 cache_level:3;
 | 
			
		||||
	} **active_bo, **pinned_bo;
 | 
			
		||||
 | 
			
		||||
	u32 *active_bo_count, *pinned_bo_count;
 | 
			
		||||
	struct intel_overlay_error_state *overlay;
 | 
			
		||||
	struct intel_display_error_state *display;
 | 
			
		||||
	int hangcheck_score[I915_NUM_RINGS];
 | 
			
		||||
	enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct intel_connector;
 | 
			
		||||
| 
						 | 
				
			
			@ -507,6 +533,12 @@ struct intel_device_info {
 | 
			
		|||
	u8 gen;
 | 
			
		||||
	u8 ring_mask; /* Rings supported by the HW */
 | 
			
		||||
	DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
 | 
			
		||||
	/* Register offsets for the various display pipes and transcoders */
 | 
			
		||||
	int pipe_offsets[I915_MAX_TRANSCODERS];
 | 
			
		||||
	int trans_offsets[I915_MAX_TRANSCODERS];
 | 
			
		||||
	int dpll_offsets[I915_MAX_PIPES];
 | 
			
		||||
	int dpll_md_offsets[I915_MAX_PIPES];
 | 
			
		||||
	int palette_offsets[I915_MAX_PIPES];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#undef DEFINE_FLAG
 | 
			
		||||
| 
						 | 
				
			
			@ -524,6 +556,57 @@ enum i915_cache_level {
 | 
			
		|||
 | 
			
		||||
typedef uint32_t gen6_gtt_pte_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A VMA represents a GEM BO that is bound into an address space. Therefore, a
 | 
			
		||||
 * VMA's presence cannot be guaranteed before binding, or after unbinding the
 | 
			
		||||
 * object into/from the address space.
 | 
			
		||||
 *
 | 
			
		||||
 * To make things as simple as possible (ie. no refcounting), a VMA's lifetime
 | 
			
		||||
 * will always be <= an objects lifetime. So object refcounting should cover us.
 | 
			
		||||
 */
 | 
			
		||||
struct i915_vma {
 | 
			
		||||
	struct drm_mm_node node;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
 | 
			
		||||
	/** This object's place on the active/inactive lists */
 | 
			
		||||
	struct list_head mm_list;
 | 
			
		||||
 | 
			
		||||
	struct list_head vma_link; /* Link in the object's VMA list */
 | 
			
		||||
 | 
			
		||||
	/** This vma's place in the batchbuffer or on the eviction list */
 | 
			
		||||
	struct list_head exec_list;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Used for performing relocations during execbuffer insertion.
 | 
			
		||||
	 */
 | 
			
		||||
	struct hlist_node exec_node;
 | 
			
		||||
	unsigned long exec_handle;
 | 
			
		||||
	struct drm_i915_gem_exec_object2 *exec_entry;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * How many users have pinned this object in GTT space. The following
 | 
			
		||||
	 * users can each hold at most one reference: pwrite/pread, pin_ioctl
 | 
			
		||||
	 * (via user_pin_count), execbuffer (objects are not allowed multiple
 | 
			
		||||
	 * times for the same batchbuffer), and the framebuffer code. When
 | 
			
		||||
	 * switching/pageflipping, the framebuffer code has at most two buffers
 | 
			
		||||
	 * pinned per crtc.
 | 
			
		||||
	 *
 | 
			
		||||
	 * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
 | 
			
		||||
	 * bits with absolutely no headroom. So use 4 bits. */
 | 
			
		||||
	unsigned int pin_count:4;
 | 
			
		||||
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
 | 
			
		||||
 | 
			
		||||
	/** Unmap an object from an address space. This usually consists of
 | 
			
		||||
	 * setting the valid PTE entries to a reserved scratch page. */
 | 
			
		||||
	void (*unbind_vma)(struct i915_vma *vma);
 | 
			
		||||
	/* Map an object into an address space with the given cache flags. */
 | 
			
		||||
#define GLOBAL_BIND (1<<0)
 | 
			
		||||
	void (*bind_vma)(struct i915_vma *vma,
 | 
			
		||||
			 enum i915_cache_level cache_level,
 | 
			
		||||
			 u32 flags);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct i915_address_space {
 | 
			
		||||
	struct drm_mm mm;
 | 
			
		||||
	struct drm_device *dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -605,6 +688,8 @@ struct i915_gtt {
 | 
			
		|||
 | 
			
		||||
struct i915_hw_ppgtt {
 | 
			
		||||
	struct i915_address_space base;
 | 
			
		||||
	struct kref ref;
 | 
			
		||||
	struct drm_mm_node node;
 | 
			
		||||
	unsigned num_pd_entries;
 | 
			
		||||
	union {
 | 
			
		||||
		struct page **pt_pages;
 | 
			
		||||
| 
						 | 
				
			
			@ -621,37 +706,12 @@ struct i915_hw_ppgtt {
 | 
			
		|||
		dma_addr_t *pt_dma_addr;
 | 
			
		||||
		dma_addr_t *gen8_pt_dma_addr[4];
 | 
			
		||||
	};
 | 
			
		||||
	int (*enable)(struct drm_device *dev);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A VMA represents a GEM BO that is bound into an address space. Therefore, a
 | 
			
		||||
 * VMA's presence cannot be guaranteed before binding, or after unbinding the
 | 
			
		||||
 * object into/from the address space.
 | 
			
		||||
 *
 | 
			
		||||
 * To make things as simple as possible (ie. no refcounting), a VMA's lifetime
 | 
			
		||||
 * will always be <= an objects lifetime. So object refcounting should cover us.
 | 
			
		||||
 */
 | 
			
		||||
struct i915_vma {
 | 
			
		||||
	struct drm_mm_node node;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
 | 
			
		||||
	/** This object's place on the active/inactive lists */
 | 
			
		||||
	struct list_head mm_list;
 | 
			
		||||
 | 
			
		||||
	struct list_head vma_link; /* Link in the object's VMA list */
 | 
			
		||||
 | 
			
		||||
	/** This vma's place in the batchbuffer or on the eviction list */
 | 
			
		||||
	struct list_head exec_list;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Used for performing relocations during execbuffer insertion.
 | 
			
		||||
	 */
 | 
			
		||||
	struct hlist_node exec_node;
 | 
			
		||||
	unsigned long exec_handle;
 | 
			
		||||
	struct drm_i915_gem_exec_object2 *exec_entry;
 | 
			
		||||
 | 
			
		||||
	int (*enable)(struct i915_hw_ppgtt *ppgtt);
 | 
			
		||||
	int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			 struct intel_ring_buffer *ring,
 | 
			
		||||
			 bool synchronous);
 | 
			
		||||
	void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct i915_ctx_hang_stats {
 | 
			
		||||
| 
						 | 
				
			
			@ -676,9 +736,10 @@ struct i915_hw_context {
 | 
			
		|||
	bool is_initialized;
 | 
			
		||||
	uint8_t remap_slice;
 | 
			
		||||
	struct drm_i915_file_private *file_priv;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	struct intel_ring_buffer *last_ring;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	struct i915_ctx_hang_stats hang_stats;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
 | 
			
		||||
	struct list_head link;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -831,11 +892,7 @@ struct i915_suspend_saved_registers {
 | 
			
		|||
	u32 savePFIT_CONTROL;
 | 
			
		||||
	u32 save_palette_a[256];
 | 
			
		||||
	u32 save_palette_b[256];
 | 
			
		||||
	u32 saveDPFC_CB_BASE;
 | 
			
		||||
	u32 saveFBC_CFB_BASE;
 | 
			
		||||
	u32 saveFBC_LL_BASE;
 | 
			
		||||
	u32 saveFBC_CONTROL;
 | 
			
		||||
	u32 saveFBC_CONTROL2;
 | 
			
		||||
	u32 saveIER;
 | 
			
		||||
	u32 saveIIR;
 | 
			
		||||
	u32 saveIMR;
 | 
			
		||||
| 
						 | 
				
			
			@ -905,8 +962,6 @@ struct intel_gen6_power_mgmt {
 | 
			
		|||
	struct work_struct work;
 | 
			
		||||
	u32 pm_iir;
 | 
			
		||||
 | 
			
		||||
	/* The below variables an all the rps hw state are protected by
 | 
			
		||||
	 * dev->struct mutext. */
 | 
			
		||||
	u8 cur_delay;
 | 
			
		||||
	u8 min_delay;
 | 
			
		||||
	u8 max_delay;
 | 
			
		||||
| 
						 | 
				
			
			@ -915,6 +970,9 @@ struct intel_gen6_power_mgmt {
 | 
			
		|||
	u8 rp0_delay;
 | 
			
		||||
	u8 hw_max;
 | 
			
		||||
 | 
			
		||||
	bool rp_up_masked;
 | 
			
		||||
	bool rp_down_masked;
 | 
			
		||||
 | 
			
		||||
	int last_adj;
 | 
			
		||||
	enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1361,8 +1419,6 @@ typedef struct drm_i915_private {
 | 
			
		|||
	drm_dma_handle_t *status_page_dmah;
 | 
			
		||||
	struct resource mch_res;
 | 
			
		||||
 | 
			
		||||
	atomic_t irq_received;
 | 
			
		||||
 | 
			
		||||
	/* protects the irq masks */
 | 
			
		||||
	spinlock_t irq_lock;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1627,18 +1683,6 @@ struct drm_i915_gem_object {
 | 
			
		|||
	 */
 | 
			
		||||
	unsigned int fence_dirty:1;
 | 
			
		||||
 | 
			
		||||
	/** How many users have pinned this object in GTT space. The following
 | 
			
		||||
	 * users can each hold at most one reference: pwrite/pread, pin_ioctl
 | 
			
		||||
	 * (via user_pin_count), execbuffer (objects are not allowed multiple
 | 
			
		||||
	 * times for the same batchbuffer), and the framebuffer code. When
 | 
			
		||||
	 * switching/pageflipping, the framebuffer code has at most two buffers
 | 
			
		||||
	 * pinned per crtc.
 | 
			
		||||
	 *
 | 
			
		||||
	 * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
 | 
			
		||||
	 * bits with absolutely no headroom. So use 4 bits. */
 | 
			
		||||
	unsigned int pin_count:4;
 | 
			
		||||
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Is the object at the current location in the gtt mappable and
 | 
			
		||||
	 * fenceable? Used to avoid costly recalculations.
 | 
			
		||||
| 
						 | 
				
			
			@ -1751,7 +1795,7 @@ struct drm_i915_file_private {
 | 
			
		|||
	} mm;
 | 
			
		||||
	struct idr context_idr;
 | 
			
		||||
 | 
			
		||||
	struct i915_ctx_hang_stats hang_stats;
 | 
			
		||||
	struct i915_hw_context *private_default_ctx;
 | 
			
		||||
	atomic_t rps_wait_boost;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1824,7 +1868,11 @@ struct drm_i915_file_private {
 | 
			
		|||
#define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 | 
			
		||||
 | 
			
		||||
#define HAS_HW_CONTEXTS(dev)	(INTEL_INFO(dev)->gen >= 6)
 | 
			
		||||
#define HAS_ALIASING_PPGTT(dev)	(INTEL_INFO(dev)->gen >=6 && !IS_VALLEYVIEW(dev))
 | 
			
		||||
#define HAS_ALIASING_PPGTT(dev)	(INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev))
 | 
			
		||||
#define HAS_PPGTT(dev)		(INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) \
 | 
			
		||||
				 && !IS_BROADWELL(dev))
 | 
			
		||||
#define USES_PPGTT(dev)		intel_enable_ppgtt(dev, false)
 | 
			
		||||
#define USES_FULL_PPGTT(dev)	intel_enable_ppgtt(dev, true)
 | 
			
		||||
 | 
			
		||||
#define HAS_OVERLAY(dev)		(INTEL_INFO(dev)->has_overlay)
 | 
			
		||||
#define OVERLAY_NEEDS_PHYSICAL(dev)	(INTEL_INFO(dev)->overlay_needs_physical)
 | 
			
		||||
| 
						 | 
				
			
			@ -1887,32 +1935,39 @@ struct drm_i915_file_private {
 | 
			
		|||
 | 
			
		||||
extern const struct drm_ioctl_desc i915_ioctls[];
 | 
			
		||||
extern int i915_max_ioctl;
 | 
			
		||||
extern unsigned int i915_fbpercrtc __always_unused;
 | 
			
		||||
extern int i915_panel_ignore_lid __read_mostly;
 | 
			
		||||
extern unsigned int i915_powersave __read_mostly;
 | 
			
		||||
extern int i915_semaphores __read_mostly;
 | 
			
		||||
extern unsigned int i915_lvds_downclock __read_mostly;
 | 
			
		||||
extern int i915_lvds_channel_mode __read_mostly;
 | 
			
		||||
extern int i915_panel_use_ssc __read_mostly;
 | 
			
		||||
extern int i915_vbt_sdvo_panel_type __read_mostly;
 | 
			
		||||
extern int i915_enable_rc6 __read_mostly;
 | 
			
		||||
extern int i915_enable_fbc __read_mostly;
 | 
			
		||||
extern bool i915_enable_hangcheck __read_mostly;
 | 
			
		||||
extern int i915_enable_ppgtt __read_mostly;
 | 
			
		||||
extern int i915_enable_psr __read_mostly;
 | 
			
		||||
extern unsigned int i915_preliminary_hw_support __read_mostly;
 | 
			
		||||
extern int i915_disable_power_well __read_mostly;
 | 
			
		||||
extern int i915_enable_ips __read_mostly;
 | 
			
		||||
extern bool i915_fastboot __read_mostly;
 | 
			
		||||
extern int i915_enable_pc8 __read_mostly;
 | 
			
		||||
extern int i915_pc8_timeout __read_mostly;
 | 
			
		||||
extern bool i915_prefault_disable __read_mostly;
 | 
			
		||||
 | 
			
		||||
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 | 
			
		||||
extern int i915_resume(struct drm_device *dev);
 | 
			
		||||
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
 | 
			
		||||
extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
 | 
			
		||||
 | 
			
		||||
/* i915_params.c */
 | 
			
		||||
struct i915_params {
 | 
			
		||||
	int modeset;
 | 
			
		||||
	int panel_ignore_lid;
 | 
			
		||||
	unsigned int powersave;
 | 
			
		||||
	int semaphores;
 | 
			
		||||
	unsigned int lvds_downclock;
 | 
			
		||||
	int lvds_channel_mode;
 | 
			
		||||
	int panel_use_ssc;
 | 
			
		||||
	int vbt_sdvo_panel_type;
 | 
			
		||||
	int enable_rc6;
 | 
			
		||||
	int enable_fbc;
 | 
			
		||||
	bool enable_hangcheck;
 | 
			
		||||
	int enable_ppgtt;
 | 
			
		||||
	int enable_psr;
 | 
			
		||||
	unsigned int preliminary_hw_support;
 | 
			
		||||
	int disable_power_well;
 | 
			
		||||
	int enable_ips;
 | 
			
		||||
	bool fastboot;
 | 
			
		||||
	int enable_pc8;
 | 
			
		||||
	int pc8_timeout;
 | 
			
		||||
	bool prefault_disable;
 | 
			
		||||
	bool reset;
 | 
			
		||||
	int invert_brightness;
 | 
			
		||||
};
 | 
			
		||||
extern struct i915_params i915 __read_mostly;
 | 
			
		||||
 | 
			
		||||
				/* i915_dma.c */
 | 
			
		||||
void i915_update_dri1_breadcrumb(struct drm_device *dev);
 | 
			
		||||
extern void i915_kernel_lost_context(struct drm_device * dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1945,6 +2000,8 @@ extern void intel_console_resume(struct work_struct *work);
 | 
			
		|||
void i915_queue_hangcheck(struct drm_device *dev);
 | 
			
		||||
void i915_handle_error(struct drm_device *dev, bool wedged);
 | 
			
		||||
 | 
			
		||||
void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
 | 
			
		||||
							int new_delay);
 | 
			
		||||
extern void intel_irq_init(struct drm_device *dev);
 | 
			
		||||
extern void intel_hpd_init(struct drm_device *dev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2014,6 +2071,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 | 
			
		|||
			 const struct drm_i915_gem_object_ops *ops);
 | 
			
		||||
struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
 | 
			
		||||
						  size_t size);
 | 
			
		||||
void i915_init_vm(struct drm_i915_private *dev_priv,
 | 
			
		||||
		  struct i915_address_space *vm);
 | 
			
		||||
void i915_gem_free_object(struct drm_gem_object *obj);
 | 
			
		||||
void i915_gem_vma_destroy(struct i915_vma *vma);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2022,7 +2081,7 @@ int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
 | 
			
		|||
				     uint32_t alignment,
 | 
			
		||||
				     bool map_and_fenceable,
 | 
			
		||||
				     bool nonblocking);
 | 
			
		||||
void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
 | 
			
		||||
int __must_check i915_vma_unbind(struct i915_vma *vma);
 | 
			
		||||
int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj);
 | 
			
		||||
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
 | 
			
		||||
| 
						 | 
				
			
			@ -2186,6 +2245,13 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 | 
			
		|||
				  struct i915_address_space *vm);
 | 
			
		||||
 | 
			
		||||
struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
 | 
			
		||||
static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
	list_for_each_entry(vma, &obj->vma_list, vma_link)
 | 
			
		||||
		if (vma->pin_count > 0)
 | 
			
		||||
			return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Some GGTT VM helpers */
 | 
			
		||||
#define obj_to_ggtt(obj) \
 | 
			
		||||
| 
						 | 
				
			
			@ -2225,58 +2291,40 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* i915_gem_context.c */
 | 
			
		||||
#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
 | 
			
		||||
int __must_check i915_gem_context_init(struct drm_device *dev);
 | 
			
		||||
void i915_gem_context_fini(struct drm_device *dev);
 | 
			
		||||
void i915_gem_context_reset(struct drm_device *dev);
 | 
			
		||||
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
 | 
			
		||||
int i915_gem_context_enable(struct drm_i915_private *dev_priv);
 | 
			
		||||
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
 | 
			
		||||
int i915_switch_context(struct intel_ring_buffer *ring,
 | 
			
		||||
			struct drm_file *file, int to_id);
 | 
			
		||||
			struct drm_file *file, struct i915_hw_context *to);
 | 
			
		||||
struct i915_hw_context *
 | 
			
		||||
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 | 
			
		||||
void i915_gem_context_free(struct kref *ctx_ref);
 | 
			
		||||
static inline void i915_gem_context_reference(struct i915_hw_context *ctx)
 | 
			
		||||
{
 | 
			
		||||
	if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
 | 
			
		||||
		kref_get(&ctx->ref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
 | 
			
		||||
{
 | 
			
		||||
	if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
 | 
			
		||||
		kref_put(&ctx->ref, i915_gem_context_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct i915_ctx_hang_stats * __must_check
 | 
			
		||||
i915_gem_context_get_hang_stats(struct drm_device *dev,
 | 
			
		||||
				struct drm_file *file,
 | 
			
		||||
				u32 id);
 | 
			
		||||
static inline bool i915_gem_context_is_default(const struct i915_hw_context *c)
 | 
			
		||||
{
 | 
			
		||||
	return c->id == DEFAULT_CONTEXT_ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 | 
			
		||||
				  struct drm_file *file);
 | 
			
		||||
int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 | 
			
		||||
				   struct drm_file *file);
 | 
			
		||||
 | 
			
		||||
/* i915_gem_gtt.c */
 | 
			
		||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
 | 
			
		||||
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			    struct drm_i915_gem_object *obj,
 | 
			
		||||
			    enum i915_cache_level cache_level);
 | 
			
		||||
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			      struct drm_i915_gem_object *obj);
 | 
			
		||||
 | 
			
		||||
void i915_check_and_clear_faults(struct drm_device *dev);
 | 
			
		||||
void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
 | 
			
		||||
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 | 
			
		||||
int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
 | 
			
		||||
				enum i915_cache_level cache_level);
 | 
			
		||||
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_init_global_gtt(struct drm_device *dev);
 | 
			
		||||
void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
 | 
			
		||||
			       unsigned long mappable_end, unsigned long end);
 | 
			
		||||
int i915_gem_gtt_init(struct drm_device *dev);
 | 
			
		||||
static inline void i915_gem_chipset_flush(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (INTEL_INFO(dev)->gen < 6)
 | 
			
		||||
		intel_gtt_chipset_flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* i915_gem_evict.c */
 | 
			
		||||
int __must_check i915_gem_evict_something(struct drm_device *dev,
 | 
			
		||||
					  struct i915_address_space *vm,
 | 
			
		||||
| 
						 | 
				
			
			@ -2288,6 +2336,80 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
 | 
			
		|||
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
 | 
			
		||||
int i915_gem_evict_everything(struct drm_device *dev);
 | 
			
		||||
 | 
			
		||||
/* i915_gem_gtt.c */
 | 
			
		||||
void i915_check_and_clear_faults(struct drm_device *dev);
 | 
			
		||||
void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
 | 
			
		||||
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 | 
			
		||||
int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 | 
			
		||||
void i915_gem_init_global_gtt(struct drm_device *dev);
 | 
			
		||||
void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
 | 
			
		||||
			       unsigned long mappable_end, unsigned long end);
 | 
			
		||||
int i915_gem_gtt_init(struct drm_device *dev);
 | 
			
		||||
static inline void i915_gem_chipset_flush(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (INTEL_INFO(dev)->gen < 6)
 | 
			
		||||
		intel_gtt_chipset_flush();
 | 
			
		||||
}
 | 
			
		||||
int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
 | 
			
		||||
static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full)
 | 
			
		||||
{
 | 
			
		||||
	if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (i915.enable_ppgtt == 1 && full)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_INTEL_IOMMU
 | 
			
		||||
	/* Disable ppgtt on SNB if VT-d is on. */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {
 | 
			
		||||
		DRM_INFO("Disabling PPGTT because VT-d is on\n");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (full)
 | 
			
		||||
		return HAS_PPGTT(dev);
 | 
			
		||||
	else
 | 
			
		||||
		return HAS_ALIASING_PPGTT(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ppgtt_release(struct kref *kref)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref);
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_address_space *vm = &ppgtt->base;
 | 
			
		||||
 | 
			
		||||
	if (ppgtt == dev_priv->mm.aliasing_ppgtt ||
 | 
			
		||||
	    (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) {
 | 
			
		||||
		ppgtt->base.cleanup(&ppgtt->base);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Make sure vmas are unbound before we take down the drm_mm
 | 
			
		||||
	 *
 | 
			
		||||
	 * FIXME: Proper refcounting should take care of this, this shouldn't be
 | 
			
		||||
	 * needed at all.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!list_empty(&vm->active_list)) {
 | 
			
		||||
		struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(vma, &vm->active_list, mm_list)
 | 
			
		||||
			if (WARN_ON(list_empty(&vma->vma_link) ||
 | 
			
		||||
				    list_is_singular(&vma->vma_link)))
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
		i915_gem_evict_vm(&ppgtt->base, true);
 | 
			
		||||
	} else {
 | 
			
		||||
		i915_gem_retire_requests(dev);
 | 
			
		||||
		i915_gem_evict_vm(&ppgtt->base, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ppgtt->base.cleanup(&ppgtt->base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* i915_gem_stolen.c */
 | 
			
		||||
int i915_gem_init_stolen(struct drm_device *dev);
 | 
			
		||||
int i915_gem_stolen_setup_compression(struct drm_device *dev, int size);
 | 
			
		||||
| 
						 | 
				
			
			@ -2566,4 +2688,31 @@ timespec_to_jiffies_timeout(const struct timespec *value)
 | 
			
		|||
	return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * If you need to wait X milliseconds between events A and B, but event B
 | 
			
		||||
 * doesn't happen exactly after event A, you record the timestamp (jiffies) of
 | 
			
		||||
 * when event A happened, then just before event B you call this function and
 | 
			
		||||
 * pass the timestamp as the first argument, and X as the second argument.
 | 
			
		||||
 */
 | 
			
		||||
static inline void
 | 
			
		||||
wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long target_jiffies, tmp_jiffies, remaining_jiffies;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Don't re-read the value of "jiffies" every time since it may change
 | 
			
		||||
	 * behind our back and break the math.
 | 
			
		||||
	 */
 | 
			
		||||
	tmp_jiffies = jiffies;
 | 
			
		||||
	target_jiffies = timestamp_jiffies +
 | 
			
		||||
			 msecs_to_jiffies_timeout(to_wait_ms);
 | 
			
		||||
 | 
			
		||||
	if (time_after(target_jiffies, tmp_jiffies)) {
 | 
			
		||||
		remaining_jiffies = target_jiffies - tmp_jiffies;
 | 
			
		||||
		while (remaining_jiffies)
 | 
			
		||||
			remaining_jiffies =
 | 
			
		||||
			    schedule_timeout_uninterruptible(remaining_jiffies);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
	pinned = 0;
 | 
			
		||||
	mutex_lock(&dev->struct_mutex);
 | 
			
		||||
	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
 | 
			
		||||
		if (obj->pin_count)
 | 
			
		||||
		if (i915_gem_obj_is_pinned(obj))
 | 
			
		||||
			pinned += i915_gem_obj_ggtt_size(obj);
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -476,7 +476,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
 | 
			
		|||
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
		if (likely(!i915_prefault_disable) && !prefaulted) {
 | 
			
		||||
		if (likely(!i915.prefault_disable) && !prefaulted) {
 | 
			
		||||
			ret = fault_in_multipages_writeable(user_data, remain);
 | 
			
		||||
			/* Userspace is tricking us, but we've already clobbered
 | 
			
		||||
			 * its pages with the prefault and promised to write the
 | 
			
		||||
| 
						 | 
				
			
			@ -651,7 +651,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
out_unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -868,7 +868,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
		       args->size))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	if (likely(!i915_prefault_disable)) {
 | 
			
		||||
	if (likely(!i915.prefault_disable)) {
 | 
			
		||||
		ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
 | 
			
		||||
						   args->size);
 | 
			
		||||
		if (ret)
 | 
			
		||||
| 
						 | 
				
			
			@ -1420,7 +1420,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 | 
			
		|||
	/* Finally, remap it using the new GTT offset */
 | 
			
		||||
	ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
 | 
			
		||||
unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
unlock:
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
out:
 | 
			
		||||
| 
						 | 
				
			
			@ -1453,6 +1453,7 @@ out:
 | 
			
		|||
		ret = VM_FAULT_OOM;
 | 
			
		||||
		break;
 | 
			
		||||
	case -ENOSPC:
 | 
			
		||||
	case -EFAULT:
 | 
			
		||||
		ret = VM_FAULT_SIGBUS;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
| 
						 | 
				
			
			@ -1618,7 +1619,7 @@ i915_gem_mmap_gtt(struct drm_file *file,
 | 
			
		|||
 | 
			
		||||
	if (obj->madv != I915_MADV_WILLNEED) {
 | 
			
		||||
		DRM_ERROR("Attempting to mmap a purgeable buffer\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		ret = -EFAULT;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1972,7 +1973,7 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
 | 
			
		|||
 | 
			
		||||
	if (obj->madv != I915_MADV_WILLNEED) {
 | 
			
		||||
		DRM_ERROR("Attempting to obtain a purgeable object\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BUG_ON(obj->pages_pin_count);
 | 
			
		||||
| 
						 | 
				
			
			@ -2035,13 +2036,17 @@ static void
 | 
			
		|||
i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 | 
			
		||||
	struct i915_address_space *ggtt_vm = &dev_priv->gtt.base;
 | 
			
		||||
	struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
 | 
			
		||||
	BUG_ON(!obj->active);
 | 
			
		||||
 | 
			
		||||
	list_move_tail(&vma->mm_list, &ggtt_vm->inactive_list);
 | 
			
		||||
	list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
 | 
			
		||||
		vma = i915_gem_obj_to_vma(obj, vm);
 | 
			
		||||
		if (vma && !list_empty(&vma->mm_list))
 | 
			
		||||
			list_move_tail(&vma->mm_list, &vm->inactive_list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_del_init(&obj->ring_list);
 | 
			
		||||
	obj->ring = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -2237,126 +2242,48 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 | 
			
		|||
	spin_unlock(&file_priv->mm.lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj,
 | 
			
		||||
				    struct i915_address_space *vm)
 | 
			
		||||
static bool i915_context_is_banned(struct drm_i915_private *dev_priv,
 | 
			
		||||
				   const struct i915_hw_context *ctx)
 | 
			
		||||
{
 | 
			
		||||
	if (acthd >= i915_gem_obj_offset(obj, vm) &&
 | 
			
		||||
	    acthd < i915_gem_obj_offset(obj, vm) + obj->base.size)
 | 
			
		||||
		return true;
 | 
			
		||||
	unsigned long elapsed;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
	elapsed = get_seconds() - ctx->hang_stats.guilty_ts;
 | 
			
		||||
 | 
			
		||||
static bool i915_head_inside_request(const u32 acthd_unmasked,
 | 
			
		||||
				     const u32 request_start,
 | 
			
		||||
				     const u32 request_end)
 | 
			
		||||
{
 | 
			
		||||
	const u32 acthd = acthd_unmasked & HEAD_ADDR;
 | 
			
		||||
 | 
			
		||||
	if (request_start < request_end) {
 | 
			
		||||
		if (acthd >= request_start && acthd < request_end)
 | 
			
		||||
			return true;
 | 
			
		||||
	} else if (request_start > request_end) {
 | 
			
		||||
		if (acthd >= request_start || acthd < request_end)
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_address_space *
 | 
			
		||||
request_to_vm(struct drm_i915_gem_request *request)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = request->ring->dev->dev_private;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
 | 
			
		||||
	vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	return vm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool i915_request_guilty(struct drm_i915_gem_request *request,
 | 
			
		||||
				const u32 acthd, bool *inside)
 | 
			
		||||
{
 | 
			
		||||
	/* There is a possibility that unmasked head address
 | 
			
		||||
	 * pointing inside the ring, matches the batch_obj address range.
 | 
			
		||||
	 * However this is extremely unlikely.
 | 
			
		||||
	 */
 | 
			
		||||
	if (request->batch_obj) {
 | 
			
		||||
		if (i915_head_inside_object(acthd, request->batch_obj,
 | 
			
		||||
					    request_to_vm(request))) {
 | 
			
		||||
			*inside = true;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i915_head_inside_request(acthd, request->head, request->tail)) {
 | 
			
		||||
		*inside = false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool i915_context_is_banned(const struct i915_ctx_hang_stats *hs)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned long elapsed = get_seconds() - hs->guilty_ts;
 | 
			
		||||
 | 
			
		||||
	if (hs->banned)
 | 
			
		||||
	if (ctx->hang_stats.banned)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
 | 
			
		||||
		DRM_ERROR("context hanging too fast, declaring banned!\n");
 | 
			
		||||
		if (dev_priv->gpu_error.stop_rings == 0 &&
 | 
			
		||||
		    i915_gem_context_is_default(ctx)) {
 | 
			
		||||
			DRM_ERROR("gpu hanging too fast, banning!\n");
 | 
			
		||||
		} else {
 | 
			
		||||
			DRM_DEBUG("context hanging too fast, banning!\n");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_set_reset_status(struct intel_ring_buffer *ring,
 | 
			
		||||
				  struct drm_i915_gem_request *request,
 | 
			
		||||
				  u32 acthd)
 | 
			
		||||
static void i915_set_reset_status(struct drm_i915_private *dev_priv,
 | 
			
		||||
				  struct i915_hw_context *ctx,
 | 
			
		||||
				  const bool guilty)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_ctx_hang_stats *hs = NULL;
 | 
			
		||||
	bool inside, guilty;
 | 
			
		||||
	unsigned long offset = 0;
 | 
			
		||||
	struct i915_ctx_hang_stats *hs;
 | 
			
		||||
 | 
			
		||||
	/* Innocent until proven guilty */
 | 
			
		||||
	guilty = false;
 | 
			
		||||
	if (WARN_ON(!ctx))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (request->batch_obj)
 | 
			
		||||
		offset = i915_gem_obj_offset(request->batch_obj,
 | 
			
		||||
					     request_to_vm(request));
 | 
			
		||||
	hs = &ctx->hang_stats;
 | 
			
		||||
 | 
			
		||||
	if (ring->hangcheck.action != HANGCHECK_WAIT &&
 | 
			
		||||
	    i915_request_guilty(request, acthd, &inside)) {
 | 
			
		||||
		DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
 | 
			
		||||
			  ring->name,
 | 
			
		||||
			  inside ? "inside" : "flushing",
 | 
			
		||||
			  offset,
 | 
			
		||||
			  request->ctx ? request->ctx->id : 0,
 | 
			
		||||
			  acthd);
 | 
			
		||||
 | 
			
		||||
		guilty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If contexts are disabled or this is the default context, use
 | 
			
		||||
	 * file_priv->reset_state
 | 
			
		||||
	 */
 | 
			
		||||
	if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID)
 | 
			
		||||
		hs = &request->ctx->hang_stats;
 | 
			
		||||
	else if (request->file_priv)
 | 
			
		||||
		hs = &request->file_priv->hang_stats;
 | 
			
		||||
 | 
			
		||||
	if (hs) {
 | 
			
		||||
	if (guilty) {
 | 
			
		||||
			hs->banned = i915_context_is_banned(hs);
 | 
			
		||||
		hs->banned = i915_context_is_banned(dev_priv, ctx);
 | 
			
		||||
		hs->batch_active++;
 | 
			
		||||
		hs->guilty_ts = get_seconds();
 | 
			
		||||
	} else {
 | 
			
		||||
		hs->batch_pending++;
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_gem_free_request(struct drm_i915_gem_request *request)
 | 
			
		||||
| 
						 | 
				
			
			@ -2370,19 +2297,39 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
 | 
			
		|||
	kfree(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
 | 
			
		||||
				       struct intel_ring_buffer *ring)
 | 
			
		||||
static struct drm_i915_gem_request *
 | 
			
		||||
i915_gem_find_first_non_complete(struct intel_ring_buffer *ring)
 | 
			
		||||
{
 | 
			
		||||
	u32 completed_seqno = ring->get_seqno(ring, false);
 | 
			
		||||
	u32 acthd = intel_ring_get_active_head(ring);
 | 
			
		||||
	struct drm_i915_gem_request *request;
 | 
			
		||||
	const u32 completed_seqno = ring->get_seqno(ring, false);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(request, &ring->request_list, list) {
 | 
			
		||||
		if (i915_seqno_passed(completed_seqno, request->seqno))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		i915_set_reset_status(ring, request, acthd);
 | 
			
		||||
		return request;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
 | 
			
		||||
				       struct intel_ring_buffer *ring)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_gem_request *request;
 | 
			
		||||
	bool ring_hung;
 | 
			
		||||
 | 
			
		||||
	request = i915_gem_find_first_non_complete(ring);
 | 
			
		||||
 | 
			
		||||
	if (request == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ring_hung = ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
 | 
			
		||||
 | 
			
		||||
	i915_set_reset_status(dev_priv, request->ctx, ring_hung);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_continue(request, &ring->request_list, list)
 | 
			
		||||
		i915_set_reset_status(dev_priv, request->ctx, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 | 
			
		||||
| 
						 | 
				
			
			@ -2456,6 +2403,8 @@ void i915_gem_reset(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	i915_gem_cleanup_ringbuffer(dev);
 | 
			
		||||
 | 
			
		||||
	i915_gem_context_reset(dev);
 | 
			
		||||
 | 
			
		||||
	i915_gem_restore_fences(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2474,6 +2423,24 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 | 
			
		|||
 | 
			
		||||
	seqno = ring->get_seqno(ring, true);
 | 
			
		||||
 | 
			
		||||
	/* Move any buffers on the active list that are no longer referenced
 | 
			
		||||
	 * by the ringbuffer to the flushing/inactive lists as appropriate,
 | 
			
		||||
	 * before we free the context associated with the requests.
 | 
			
		||||
	 */
 | 
			
		||||
	while (!list_empty(&ring->active_list)) {
 | 
			
		||||
		struct drm_i915_gem_object *obj;
 | 
			
		||||
 | 
			
		||||
		obj = list_first_entry(&ring->active_list,
 | 
			
		||||
				      struct drm_i915_gem_object,
 | 
			
		||||
				      ring_list);
 | 
			
		||||
 | 
			
		||||
		if (!i915_seqno_passed(seqno, obj->last_read_seqno))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		i915_gem_object_move_to_inactive(obj);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	while (!list_empty(&ring->request_list)) {
 | 
			
		||||
		struct drm_i915_gem_request *request;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2495,22 +2462,6 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 | 
			
		|||
		i915_gem_free_request(request);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Move any buffers on the active list that are no longer referenced
 | 
			
		||||
	 * by the ringbuffer to the flushing/inactive lists as appropriate.
 | 
			
		||||
	 */
 | 
			
		||||
	while (!list_empty(&ring->active_list)) {
 | 
			
		||||
		struct drm_i915_gem_object *obj;
 | 
			
		||||
 | 
			
		||||
		obj = list_first_entry(&ring->active_list,
 | 
			
		||||
				      struct drm_i915_gem_object,
 | 
			
		||||
				      ring_list);
 | 
			
		||||
 | 
			
		||||
		if (!i915_seqno_passed(seqno, obj->last_read_seqno))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		i915_gem_object_move_to_inactive(obj);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ring->trace_irq_seqno &&
 | 
			
		||||
		     i915_seqno_passed(seqno, ring->trace_irq_seqno))) {
 | 
			
		||||
		ring->irq_put(ring);
 | 
			
		||||
| 
						 | 
				
			
			@ -2753,9 +2704,6 @@ int i915_vma_unbind(struct i915_vma *vma)
 | 
			
		|||
	drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* For now we only ever use 1 vma per object */
 | 
			
		||||
	WARN_ON(!list_is_singular(&obj->vma_list));
 | 
			
		||||
 | 
			
		||||
	if (list_empty(&vma->vma_link))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2765,7 +2713,7 @@ int i915_vma_unbind(struct i915_vma *vma)
 | 
			
		|||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (obj->pin_count)
 | 
			
		||||
	if (vma->pin_count)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(obj->pages == NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -2787,12 +2735,8 @@ int i915_vma_unbind(struct i915_vma *vma)
 | 
			
		|||
 | 
			
		||||
	trace_i915_vma_unbind(vma);
 | 
			
		||||
 | 
			
		||||
	if (obj->has_global_gtt_mapping)
 | 
			
		||||
		i915_gem_gtt_unbind_object(obj);
 | 
			
		||||
	if (obj->has_aliasing_ppgtt_mapping) {
 | 
			
		||||
		i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj);
 | 
			
		||||
		obj->has_aliasing_ppgtt_mapping = 0;
 | 
			
		||||
	}
 | 
			
		||||
	vma->unbind_vma(vma);
 | 
			
		||||
 | 
			
		||||
	i915_gem_gtt_finish_object(obj);
 | 
			
		||||
 | 
			
		||||
	list_del(&vma->mm_list);
 | 
			
		||||
| 
						 | 
				
			
			@ -2829,7 +2773,7 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
 | 
			
		|||
	if (!i915_gem_obj_ggtt_bound(obj))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (obj->pin_count)
 | 
			
		||||
	if (i915_gem_obj_to_ggtt(obj)->pin_count)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(obj->pages == NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -2845,7 +2789,7 @@ int i915_gpu_idle(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	/* Flush everything onto the inactive list. */
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID);
 | 
			
		||||
		ret = i915_switch_context(ring, NULL, ring->default_context);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3312,17 +3256,12 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
 | 
			
		|||
 | 
			
		||||
	i915_gem_object_pin_pages(obj);
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!i915_is_ggtt(vm));
 | 
			
		||||
 | 
			
		||||
	vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
 | 
			
		||||
	if (IS_ERR(vma)) {
 | 
			
		||||
		ret = PTR_ERR(vma);
 | 
			
		||||
		goto err_unpin;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* For now we only ever use 1 vma per object */
 | 
			
		||||
	WARN_ON(!list_is_singular(&obj->vma_list));
 | 
			
		||||
 | 
			
		||||
search_free:
 | 
			
		||||
	ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
 | 
			
		||||
						  size, alignment,
 | 
			
		||||
| 
						 | 
				
			
			@ -3528,14 +3467,13 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
 | 
			
		|||
				    enum i915_cache_level cache_level)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = obj->base.dev;
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (obj->cache_level == cache_level)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (obj->pin_count) {
 | 
			
		||||
	if (i915_gem_obj_is_pinned(obj)) {
 | 
			
		||||
		DRM_DEBUG("can not change the cache level of pinned objects\n");
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -3567,11 +3505,8 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
 | 
			
		|||
				return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (obj->has_global_gtt_mapping)
 | 
			
		||||
			i915_gem_gtt_bind_object(obj, cache_level);
 | 
			
		||||
		if (obj->has_aliasing_ppgtt_mapping)
 | 
			
		||||
			i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
 | 
			
		||||
					       obj, cache_level);
 | 
			
		||||
		list_for_each_entry(vma, &obj->vma_list, vma_link)
 | 
			
		||||
			vma->bind_vma(vma, cache_level, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(vma, &obj->vma_list, vma_link)
 | 
			
		||||
| 
						 | 
				
			
			@ -3695,7 +3630,7 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 | 
			
		|||
	 * subtracting the potential reference by the user, any pin_count
 | 
			
		||||
	 * remains, it must be due to another use by the display engine.
 | 
			
		||||
	 */
 | 
			
		||||
	return obj->pin_count - !!obj->user_pin_count;
 | 
			
		||||
	return i915_gem_obj_to_ggtt(obj)->pin_count - !!obj->user_pin_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -3769,7 +3704,7 @@ err_unpin_display:
 | 
			
		|||
void
 | 
			
		||||
i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	obj->pin_display = is_pin_display(obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3899,21 +3834,22 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
 | 
			
		|||
		    bool map_and_fenceable,
 | 
			
		||||
		    bool nonblocking)
 | 
			
		||||
{
 | 
			
		||||
	const u32 flags = map_and_fenceable ? GLOBAL_BIND : 0;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(map_and_fenceable && !i915_is_ggtt(vm));
 | 
			
		||||
 | 
			
		||||
	vma = i915_gem_obj_to_vma(obj, vm);
 | 
			
		||||
 | 
			
		||||
	if (vma) {
 | 
			
		||||
		if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
 | 
			
		||||
			return -EBUSY;
 | 
			
		||||
 | 
			
		||||
		if ((alignment &&
 | 
			
		||||
		     vma->node.start & (alignment - 1)) ||
 | 
			
		||||
		    (map_and_fenceable && !obj->map_and_fenceable)) {
 | 
			
		||||
			WARN(obj->pin_count,
 | 
			
		||||
			WARN(vma->pin_count,
 | 
			
		||||
			     "bo is already pinned with incorrect alignment:"
 | 
			
		||||
			     " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
 | 
			
		||||
			     " obj->map_and_fenceable=%d\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -3927,34 +3863,34 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (!i915_gem_obj_bound(obj, vm)) {
 | 
			
		||||
		struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 | 
			
		||||
 | 
			
		||||
		ret = i915_gem_object_bind_to_vm(obj, vm, alignment,
 | 
			
		||||
						 map_and_fenceable,
 | 
			
		||||
						 nonblocking);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		if (!dev_priv->mm.aliasing_ppgtt)
 | 
			
		||||
			i915_gem_gtt_bind_object(obj, obj->cache_level);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!obj->has_global_gtt_mapping && map_and_fenceable)
 | 
			
		||||
		i915_gem_gtt_bind_object(obj, obj->cache_level);
 | 
			
		||||
	vma = i915_gem_obj_to_vma(obj, vm);
 | 
			
		||||
 | 
			
		||||
	obj->pin_count++;
 | 
			
		||||
	vma->bind_vma(vma, obj->cache_level, flags);
 | 
			
		||||
 | 
			
		||||
	i915_gem_obj_to_vma(obj, vm)->pin_count++;
 | 
			
		||||
	obj->pin_mappable |= map_and_fenceable;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
i915_gem_object_unpin(struct drm_i915_gem_object *obj)
 | 
			
		||||
i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	BUG_ON(obj->pin_count == 0);
 | 
			
		||||
	BUG_ON(!i915_gem_obj_bound_any(obj));
 | 
			
		||||
	struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
 | 
			
		||||
 | 
			
		||||
	if (--obj->pin_count == 0)
 | 
			
		||||
	BUG_ON(!vma);
 | 
			
		||||
	BUG_ON(vma->pin_count == 0);
 | 
			
		||||
	BUG_ON(!i915_gem_obj_ggtt_bound(obj));
 | 
			
		||||
 | 
			
		||||
	if (--vma->pin_count == 0)
 | 
			
		||||
		obj->pin_mappable = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3966,6 +3902,9 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	ret = i915_mutex_lock_interruptible(dev);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -3978,7 +3917,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
 | 
			
		||||
	if (obj->madv != I915_MADV_WILLNEED) {
 | 
			
		||||
		DRM_ERROR("Attempting to pin a purgeable buffer\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		ret = -EFAULT;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4038,7 +3977,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
	obj->user_pin_count--;
 | 
			
		||||
	if (obj->user_pin_count == 0) {
 | 
			
		||||
		obj->pin_filp = NULL;
 | 
			
		||||
		i915_gem_object_unpin(obj);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
| 
						 | 
				
			
			@ -4118,7 +4057,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (obj->pin_count) {
 | 
			
		||||
	if (i915_gem_obj_is_pinned(obj)) {
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4229,12 +4168,11 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 | 
			
		|||
	if (obj->phys_obj)
 | 
			
		||||
		i915_gem_detach_phys_object(dev, obj);
 | 
			
		||||
 | 
			
		||||
	obj->pin_count = 0;
 | 
			
		||||
	/* NB: 0 or 1 elements */
 | 
			
		||||
	WARN_ON(!list_empty(&obj->vma_list) &&
 | 
			
		||||
		!list_is_singular(&obj->vma_list));
 | 
			
		||||
	list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
 | 
			
		||||
		int ret = i915_vma_unbind(vma);
 | 
			
		||||
		int ret;
 | 
			
		||||
 | 
			
		||||
		vma->pin_count = 0;
 | 
			
		||||
		ret = i915_vma_unbind(vma);
 | 
			
		||||
		if (WARN_ON(ret == -ERESTARTSYS)) {
 | 
			
		||||
			bool was_interruptible;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4283,41 +4221,6 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 | 
			
		|||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
 | 
			
		||||
					      struct i915_address_space *vm)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 | 
			
		||||
	if (vma == NULL)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&vma->vma_link);
 | 
			
		||||
	INIT_LIST_HEAD(&vma->mm_list);
 | 
			
		||||
	INIT_LIST_HEAD(&vma->exec_list);
 | 
			
		||||
	vma->vm = vm;
 | 
			
		||||
	vma->obj = obj;
 | 
			
		||||
 | 
			
		||||
	/* Keep GGTT vmas first to make debug easier */
 | 
			
		||||
	if (i915_is_ggtt(vm))
 | 
			
		||||
		list_add(&vma->vma_link, &obj->vma_list);
 | 
			
		||||
	else
 | 
			
		||||
		list_add_tail(&vma->vma_link, &obj->vma_list);
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct i915_vma *
 | 
			
		||||
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 | 
			
		||||
				  struct i915_address_space *vm)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
	vma = i915_gem_obj_to_vma(obj, vm);
 | 
			
		||||
	if (!vma)
 | 
			
		||||
		vma = __i915_gem_vma_create(obj, vm);
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_vma_destroy(struct i915_vma *vma)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(vma->node.allocated);
 | 
			
		||||
| 
						 | 
				
			
			@ -4508,9 +4411,15 @@ i915_gem_init_hw(struct drm_device *dev)
 | 
			
		|||
			   LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED);
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_NOP(dev)) {
 | 
			
		||||
		if (IS_IVYBRIDGE(dev)) {
 | 
			
		||||
			u32 temp = I915_READ(GEN7_MSG_CTL);
 | 
			
		||||
			temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
 | 
			
		||||
			I915_WRITE(GEN7_MSG_CTL, temp);
 | 
			
		||||
		} else if (INTEL_INFO(dev)->gen >= 7) {
 | 
			
		||||
			u32 temp = I915_READ(HSW_NDE_RSTWRN_OPT);
 | 
			
		||||
			temp &= ~RESET_PCH_HANDSHAKE_ENABLE;
 | 
			
		||||
			I915_WRITE(HSW_NDE_RSTWRN_OPT, temp);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i915_gem_init_swizzling(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -4523,25 +4432,23 @@ i915_gem_init_hw(struct drm_device *dev)
 | 
			
		|||
		i915_gem_l3_remap(&dev_priv->ring[RCS], i);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * XXX: There was some w/a described somewhere suggesting loading
 | 
			
		||||
	 * contexts before PPGTT.
 | 
			
		||||
	 * XXX: Contexts should only be initialized once. Doing a switch to the
 | 
			
		||||
	 * default context switch however is something we'd like to do after
 | 
			
		||||
	 * reset or thaw (the latter may not actually be necessary for HW, but
 | 
			
		||||
	 * goes with our code better). Context switching requires rings (for
 | 
			
		||||
	 * the do_switch), but before enabling PPGTT. So don't move this.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = i915_gem_context_init(dev);
 | 
			
		||||
	ret = i915_gem_context_enable(dev_priv);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		i915_gem_cleanup_ringbuffer(dev);
 | 
			
		||||
		DRM_ERROR("Context initialization failed %d\n", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->mm.aliasing_ppgtt) {
 | 
			
		||||
		ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			i915_gem_cleanup_aliasing_ppgtt(dev);
 | 
			
		||||
			DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n");
 | 
			
		||||
		}
 | 
			
		||||
		DRM_ERROR("Context enable failed %d\n", ret);
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_out:
 | 
			
		||||
	i915_gem_cleanup_ringbuffer(dev);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i915_gem_init(struct drm_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -4560,10 +4467,18 @@ int i915_gem_init(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	i915_gem_init_global_gtt(dev);
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_context_init(dev);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_init_hw(dev);
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		i915_gem_cleanup_aliasing_ppgtt(dev);
 | 
			
		||||
		WARN_ON(dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
		i915_gem_context_fini(dev);
 | 
			
		||||
		drm_mm_takedown(&dev_priv->gtt.base.mm);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4658,14 +4573,16 @@ init_ring_lists(struct intel_ring_buffer *ring)
 | 
			
		|||
	INIT_LIST_HEAD(&ring->request_list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_init_vm(struct drm_i915_private *dev_priv,
 | 
			
		||||
void i915_init_vm(struct drm_i915_private *dev_priv,
 | 
			
		||||
		  struct i915_address_space *vm)
 | 
			
		||||
{
 | 
			
		||||
	if (!i915_is_ggtt(vm))
 | 
			
		||||
		drm_mm_init(&vm->mm, vm->start, vm->total);
 | 
			
		||||
	vm->dev = dev_priv->dev;
 | 
			
		||||
	INIT_LIST_HEAD(&vm->active_list);
 | 
			
		||||
	INIT_LIST_HEAD(&vm->inactive_list);
 | 
			
		||||
	INIT_LIST_HEAD(&vm->global_link);
 | 
			
		||||
	list_add(&vm->global_link, &dev_priv->vm_list);
 | 
			
		||||
	list_add_tail(&vm->global_link, &dev_priv->vm_list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -4950,6 +4867,7 @@ i915_gem_file_idle_work_handler(struct work_struct *work)
 | 
			
		|||
int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_file_private *file_priv;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_DRIVER("\n");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4965,9 +4883,11 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 | 
			
		|||
	INIT_DELAYED_WORK(&file_priv->mm.idle_work,
 | 
			
		||||
			  i915_gem_file_idle_work_handler);
 | 
			
		||||
 | 
			
		||||
	idr_init(&file_priv->context_idr);
 | 
			
		||||
	ret = i915_gem_context_open(dev, file);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		kfree(file_priv);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
 | 
			
		||||
| 
						 | 
				
			
			@ -5014,7 +4934,7 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
 | 
			
		|||
		if (obj->active)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (obj->pin_count == 0 && obj->pages_pin_count == 0)
 | 
			
		||||
		if (!i915_gem_obj_is_pinned(obj) && obj->pages_pin_count == 0)
 | 
			
		||||
			count += obj->base.size >> PAGE_SHIFT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5031,7 +4951,8 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
 | 
			
		|||
	struct drm_i915_private *dev_priv = o->base.dev->dev_private;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
	if (vm == &dev_priv->mm.aliasing_ppgtt->base)
 | 
			
		||||
	if (!dev_priv->mm.aliasing_ppgtt ||
 | 
			
		||||
	    vm == &dev_priv->mm.aliasing_ppgtt->base)
 | 
			
		||||
		vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(list_empty(&o->vma_list));
 | 
			
		||||
| 
						 | 
				
			
			@ -5072,7 +4993,8 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
 | 
			
		|||
	struct drm_i915_private *dev_priv = o->base.dev->dev_private;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
	if (vm == &dev_priv->mm.aliasing_ppgtt->base)
 | 
			
		||||
	if (!dev_priv->mm.aliasing_ppgtt ||
 | 
			
		||||
	    vm == &dev_priv->mm.aliasing_ppgtt->base)
 | 
			
		||||
		vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(list_empty(&o->vma_list));
 | 
			
		||||
| 
						 | 
				
			
			@ -5127,7 +5049,7 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
 | 
			
		|||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
 | 
			
		||||
	if (WARN_ON(vma->vm != obj_to_ggtt(obj)))
 | 
			
		||||
	if (vma->vm != obj_to_ggtt(obj))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,11 +93,19 @@
 | 
			
		|||
 * I've seen in a spec to date, and that was a workaround for a non-shipping
 | 
			
		||||
 * part. It should be safe to decrease this, but it's more future proof as is.
 | 
			
		||||
 */
 | 
			
		||||
#define CONTEXT_ALIGN (64<<10)
 | 
			
		||||
#define GEN6_CONTEXT_ALIGN (64<<10)
 | 
			
		||||
#define GEN7_CONTEXT_ALIGN 4096
 | 
			
		||||
 | 
			
		||||
static struct i915_hw_context *
 | 
			
		||||
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 | 
			
		||||
static int do_switch(struct i915_hw_context *to);
 | 
			
		||||
static int do_switch(struct intel_ring_buffer *ring,
 | 
			
		||||
		     struct i915_hw_context *to);
 | 
			
		||||
 | 
			
		||||
static size_t get_context_alignment(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (IS_GEN6(dev))
 | 
			
		||||
		return GEN6_CONTEXT_ALIGN;
 | 
			
		||||
 | 
			
		||||
	return GEN7_CONTEXT_ALIGN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int get_context_size(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -131,14 +139,43 @@ void i915_gem_context_free(struct kref *ctx_ref)
 | 
			
		|||
{
 | 
			
		||||
	struct i915_hw_context *ctx = container_of(ctx_ref,
 | 
			
		||||
						   typeof(*ctx), ref);
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = NULL;
 | 
			
		||||
 | 
			
		||||
	list_del(&ctx->link);
 | 
			
		||||
	/* We refcount even the aliasing PPGTT to keep the code symmetric */
 | 
			
		||||
	if (USES_PPGTT(ctx->obj->base.dev))
 | 
			
		||||
		ppgtt = ctx_to_ppgtt(ctx);
 | 
			
		||||
 | 
			
		||||
	/* XXX: Free up the object before tearing down the address space, in
 | 
			
		||||
	 * case we're bound in the PPGTT */
 | 
			
		||||
	drm_gem_object_unreference(&ctx->obj->base);
 | 
			
		||||
 | 
			
		||||
	if (ppgtt)
 | 
			
		||||
		kref_put(&ppgtt->ref, ppgtt_release);
 | 
			
		||||
	list_del(&ctx->link);
 | 
			
		||||
	kfree(ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_hw_ppgtt *
 | 
			
		||||
create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
 | 
			
		||||
	if (!ppgtt)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_init_ppgtt(dev, ppgtt);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		kfree(ppgtt);
 | 
			
		||||
		return ERR_PTR(ret);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ppgtt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_hw_context *
 | 
			
		||||
create_hw_context(struct drm_device *dev,
 | 
			
		||||
__create_hw_context(struct drm_device *dev,
 | 
			
		||||
		  struct drm_i915_file_private *file_priv)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -166,18 +203,13 @@ create_hw_context(struct drm_device *dev,
 | 
			
		|||
			goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The ring associated with the context object is handled by the normal
 | 
			
		||||
	 * object tracking code. We give an initial ring value simple to pass an
 | 
			
		||||
	 * assertion in the context switch code.
 | 
			
		||||
	 */
 | 
			
		||||
	ctx->ring = &dev_priv->ring[RCS];
 | 
			
		||||
	list_add_tail(&ctx->link, &dev_priv->context_list);
 | 
			
		||||
 | 
			
		||||
	/* Default context will never have a file_priv */
 | 
			
		||||
	if (file_priv == NULL)
 | 
			
		||||
		return ctx;
 | 
			
		||||
 | 
			
		||||
	ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
 | 
			
		||||
	ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0,
 | 
			
		||||
			GFP_KERNEL);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		goto err_out;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,67 +228,138 @@ err_out:
 | 
			
		|||
	return ERR_PTR(ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool is_default_context(struct i915_hw_context *ctx)
 | 
			
		||||
{
 | 
			
		||||
	return (ctx == ctx->ring->default_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The default context needs to exist per ring that uses contexts. It stores the
 | 
			
		||||
 * context state of the GPU for applications that don't utilize HW contexts, as
 | 
			
		||||
 * well as an idle case.
 | 
			
		||||
 */
 | 
			
		||||
static int create_default_context(struct drm_i915_private *dev_priv)
 | 
			
		||||
static struct i915_hw_context *
 | 
			
		||||
i915_gem_create_context(struct drm_device *dev,
 | 
			
		||||
			struct drm_i915_file_private *file_priv,
 | 
			
		||||
			bool create_vm)
 | 
			
		||||
{
 | 
			
		||||
	const bool is_global_default_ctx = file_priv == NULL;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_hw_context *ctx;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 | 
			
		||||
	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 | 
			
		||||
 | 
			
		||||
	ctx = create_hw_context(dev_priv->dev, NULL);
 | 
			
		||||
	ctx = __create_hw_context(dev, file_priv);
 | 
			
		||||
	if (IS_ERR(ctx))
 | 
			
		||||
		return PTR_ERR(ctx);
 | 
			
		||||
		return ctx;
 | 
			
		||||
 | 
			
		||||
	/* We may need to do things with the shrinker which require us to
 | 
			
		||||
	 * immediately switch back to the default context. This can cause a
 | 
			
		||||
	 * problem as pinning the default context also requires GTT space which
 | 
			
		||||
	 * may not be available. To avoid this we always pin the
 | 
			
		||||
	 * default context.
 | 
			
		||||
	if (is_global_default_ctx) {
 | 
			
		||||
		/* We may need to do things with the shrinker which
 | 
			
		||||
		 * require us to immediately switch back to the default
 | 
			
		||||
		 * context. This can cause a problem as pinning the
 | 
			
		||||
		 * default context also requires GTT space which may not
 | 
			
		||||
		 * be available. To avoid this we always pin the default
 | 
			
		||||
		 * context.
 | 
			
		||||
		 */
 | 
			
		||||
	ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false);
 | 
			
		||||
		ret = i915_gem_obj_ggtt_pin(ctx->obj,
 | 
			
		||||
					    get_context_alignment(dev),
 | 
			
		||||
					    false, false);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
 | 
			
		||||
			goto err_destroy;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = do_switch(ctx);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
 | 
			
		||||
	if (create_vm) {
 | 
			
		||||
		struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
 | 
			
		||||
 | 
			
		||||
		if (IS_ERR_OR_NULL(ppgtt)) {
 | 
			
		||||
			DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
 | 
			
		||||
					 PTR_ERR(ppgtt));
 | 
			
		||||
			ret = PTR_ERR(ppgtt);
 | 
			
		||||
			goto err_unpin;
 | 
			
		||||
		} else
 | 
			
		||||
			ctx->vm = &ppgtt->base;
 | 
			
		||||
 | 
			
		||||
		/* This case is reserved for the global default context and
 | 
			
		||||
		 * should only happen once. */
 | 
			
		||||
		if (is_global_default_ctx) {
 | 
			
		||||
			if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
 | 
			
		||||
				ret = -EEXIST;
 | 
			
		||||
				goto err_unpin;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
	dev_priv->ring[RCS].default_context = ctx;
 | 
			
		||||
			dev_priv->mm.aliasing_ppgtt = ppgtt;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (USES_PPGTT(dev)) {
 | 
			
		||||
		/* For platforms which only have aliasing PPGTT, we fake the
 | 
			
		||||
		 * address space and refcounting. */
 | 
			
		||||
		ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
 | 
			
		||||
		kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
 | 
			
		||||
	} else
 | 
			
		||||
		ctx->vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_DRIVER("Default HW context loaded\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
	return ctx;
 | 
			
		||||
 | 
			
		||||
err_unpin:
 | 
			
		||||
	i915_gem_object_unpin(ctx->obj);
 | 
			
		||||
	if (is_global_default_ctx)
 | 
			
		||||
		i915_gem_object_ggtt_unpin(ctx->obj);
 | 
			
		||||
err_destroy:
 | 
			
		||||
	i915_gem_context_unreference(ctx);
 | 
			
		||||
	return ret;
 | 
			
		||||
	return ERR_PTR(ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_context_reset(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Prevent the hardware from restoring the last context (which hung) on
 | 
			
		||||
	 * the next switch */
 | 
			
		||||
	for (i = 0; i < I915_NUM_RINGS; i++) {
 | 
			
		||||
		struct i915_hw_context *dctx;
 | 
			
		||||
		if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Do a fake switch to the default context */
 | 
			
		||||
		ring = &dev_priv->ring[i];
 | 
			
		||||
		dctx = ring->default_context;
 | 
			
		||||
		if (WARN_ON(!dctx))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!ring->last_context)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (ring->last_context == dctx)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (i == RCS) {
 | 
			
		||||
			WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj,
 | 
			
		||||
						      get_context_alignment(dev),
 | 
			
		||||
						      false, false));
 | 
			
		||||
			/* Fake a finish/inactive */
 | 
			
		||||
			dctx->obj->base.write_domain = 0;
 | 
			
		||||
			dctx->obj->active = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i915_gem_context_unreference(ring->last_context);
 | 
			
		||||
		i915_gem_context_reference(dctx);
 | 
			
		||||
		ring->last_context = dctx;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i915_gem_context_init(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* If called from reset, or thaw... we've been here already */
 | 
			
		||||
	if (dev_priv->ring[RCS].default_context)
 | 
			
		||||
	/* Init should only be called once per module load. Eventually the
 | 
			
		||||
	 * restriction on the context_disabled check can be loosened. */
 | 
			
		||||
	if (WARN_ON(dev_priv->ring[RCS].default_context))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
 | 
			
		||||
| 
						 | 
				
			
			@ -266,11 +369,23 @@ int i915_gem_context_init(struct drm_device *dev)
 | 
			
		|||
		return -E2BIG;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = create_default_context(dev_priv);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n",
 | 
			
		||||
				 ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	dev_priv->ring[RCS].default_context =
 | 
			
		||||
		i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
 | 
			
		||||
 | 
			
		||||
	if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) {
 | 
			
		||||
		DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n",
 | 
			
		||||
				 PTR_ERR(dev_priv->ring[RCS].default_context));
 | 
			
		||||
		return PTR_ERR(dev_priv->ring[RCS].default_context);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = RCS + 1; i < I915_NUM_RINGS; i++) {
 | 
			
		||||
		if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ring = &dev_priv->ring[i];
 | 
			
		||||
 | 
			
		||||
		/* NB: RCS will hold a ref for all rings */
 | 
			
		||||
		ring->default_context = dev_priv->ring[RCS].default_context;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_DRIVER("HW context support initialized\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -281,6 +396,7 @@ void i915_gem_context_fini(struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -300,59 +416,129 @@ void i915_gem_context_fini(struct drm_device *dev)
 | 
			
		|||
	if (dev_priv->ring[RCS].last_context == dctx) {
 | 
			
		||||
		/* Fake switch to NULL context */
 | 
			
		||||
		WARN_ON(dctx->obj->active);
 | 
			
		||||
		i915_gem_object_unpin(dctx->obj);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(dctx->obj);
 | 
			
		||||
		i915_gem_context_unreference(dctx);
 | 
			
		||||
		dev_priv->ring[RCS].last_context = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i915_gem_object_unpin(dctx->obj);
 | 
			
		||||
	for (i = 0; i < I915_NUM_RINGS; i++) {
 | 
			
		||||
		struct intel_ring_buffer *ring = &dev_priv->ring[i];
 | 
			
		||||
		if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (ring->last_context)
 | 
			
		||||
			i915_gem_context_unreference(ring->last_context);
 | 
			
		||||
 | 
			
		||||
		ring->default_context = NULL;
 | 
			
		||||
		ring->last_context = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i915_gem_object_ggtt_unpin(dctx->obj);
 | 
			
		||||
	i915_gem_context_unreference(dctx);
 | 
			
		||||
	dev_priv->ring[RCS].default_context = NULL;
 | 
			
		||||
	dev_priv->ring[RCS].last_context = NULL;
 | 
			
		||||
	dev_priv->mm.aliasing_ppgtt = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	int ret, i;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev_priv->dev))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* This is the only place the aliasing PPGTT gets enabled, which means
 | 
			
		||||
	 * it has to happen before we bail on reset */
 | 
			
		||||
	if (dev_priv->mm.aliasing_ppgtt) {
 | 
			
		||||
		struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
		ppgtt->enable(ppgtt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: We should make this work, even in reset */
 | 
			
		||||
	if (i915_reset_in_progress(&dev_priv->gpu_error))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!dev_priv->ring[RCS].default_context);
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		ret = do_switch(ring, ring->default_context);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int context_idr_cleanup(int id, void *p, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_hw_context *ctx = p;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(id == DEFAULT_CONTEXT_ID);
 | 
			
		||||
	/* Ignore the default context because close will handle it */
 | 
			
		||||
	if (i915_gem_context_is_default(ctx))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	i915_gem_context_unreference(ctx);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct i915_ctx_hang_stats *
 | 
			
		||||
i915_gem_context_get_hang_stats(struct drm_device *dev,
 | 
			
		||||
				struct drm_file *file,
 | 
			
		||||
				u32 id)
 | 
			
		||||
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_file_private *file_priv = file->driver_priv;
 | 
			
		||||
	struct i915_hw_context *ctx;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	if (id == DEFAULT_CONTEXT_ID)
 | 
			
		||||
		return &file_priv->hang_stats;
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev)) {
 | 
			
		||||
		/* Cheat for hang stats */
 | 
			
		||||
		file_priv->private_default_ctx =
 | 
			
		||||
			kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		return ERR_PTR(-ENOENT);
 | 
			
		||||
		if (file_priv->private_default_ctx == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	ctx = i915_gem_context_get(file->driver_priv, id);
 | 
			
		||||
	if (ctx == NULL)
 | 
			
		||||
		return ERR_PTR(-ENOENT);
 | 
			
		||||
		file_priv->private_default_ctx->vm = &dev_priv->gtt.base;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &ctx->hang_stats;
 | 
			
		||||
	idr_init(&file_priv->context_idr);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->struct_mutex);
 | 
			
		||||
	file_priv->private_default_ctx =
 | 
			
		||||
		i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
	if (IS_ERR(file_priv->private_default_ctx)) {
 | 
			
		||||
		idr_destroy(&file_priv->context_idr);
 | 
			
		||||
		return PTR_ERR(file_priv->private_default_ctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_file_private *file_priv = file->driver_priv;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(dev)) {
 | 
			
		||||
		kfree(file_priv->private_default_ctx);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
 | 
			
		||||
	i915_gem_context_unreference(file_priv->private_default_ctx);
 | 
			
		||||
	idr_destroy(&file_priv->context_idr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_hw_context *
 | 
			
		||||
struct i915_hw_context *
 | 
			
		||||
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
 | 
			
		||||
{
 | 
			
		||||
	return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
 | 
			
		||||
	struct i915_hw_context *ctx;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev))
 | 
			
		||||
		return file_priv->private_default_ctx;
 | 
			
		||||
 | 
			
		||||
	ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
 | 
			
		||||
	if (!ctx)
 | 
			
		||||
		return ERR_PTR(-ENOENT);
 | 
			
		||||
 | 
			
		||||
	return ctx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +576,10 @@ mi_set_context(struct intel_ring_buffer *ring,
 | 
			
		|||
			MI_SAVE_EXT_STATE_EN |
 | 
			
		||||
			MI_RESTORE_EXT_STATE_EN |
 | 
			
		||||
			hw_flags);
 | 
			
		||||
	/* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */
 | 
			
		||||
	/*
 | 
			
		||||
	 * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
 | 
			
		||||
	 * WaMiSetContext_Hang:snb,ivb,vlv
 | 
			
		||||
	 */
 | 
			
		||||
	intel_ring_emit(ring, MI_NOOP);
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN7(ring->dev))
 | 
			
		||||
| 
						 | 
				
			
			@ -403,21 +592,31 @@ mi_set_context(struct intel_ring_buffer *ring,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_switch(struct i915_hw_context *to)
 | 
			
		||||
static int do_switch(struct intel_ring_buffer *ring,
 | 
			
		||||
		     struct i915_hw_context *to)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_ring_buffer *ring = to->ring;
 | 
			
		||||
	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 | 
			
		||||
	struct i915_hw_context *from = ring->last_context;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
 | 
			
		||||
	u32 hw_flags = 0;
 | 
			
		||||
	int ret, i;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
 | 
			
		||||
	if (from != NULL && ring == &dev_priv->ring[RCS]) {
 | 
			
		||||
		BUG_ON(from->obj == NULL);
 | 
			
		||||
		BUG_ON(!i915_gem_obj_is_pinned(from->obj));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (from == to && !to->remap_slice)
 | 
			
		||||
	if (from == to && from->last_ring == ring && !to->remap_slice)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false);
 | 
			
		||||
	/* Trying to pin first makes error handling easier. */
 | 
			
		||||
	if (ring == &dev_priv->ring[RCS]) {
 | 
			
		||||
		ret = i915_gem_obj_ggtt_pin(to->obj,
 | 
			
		||||
					    get_context_alignment(ring->dev),
 | 
			
		||||
					    false, false);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Pin can switch back to the default context if we end up calling into
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +625,18 @@ static int do_switch(struct i915_hw_context *to)
 | 
			
		|||
	 */
 | 
			
		||||
	from = ring->last_context;
 | 
			
		||||
 | 
			
		||||
	if (USES_FULL_PPGTT(ring->dev)) {
 | 
			
		||||
		ret = ppgtt->switch_mm(ppgtt, ring, false);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto unpin_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ring != &dev_priv->ring[RCS]) {
 | 
			
		||||
		if (from)
 | 
			
		||||
			i915_gem_context_unreference(from);
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Clear this page out of any CPU caches for coherent swap-in/out. Note
 | 
			
		||||
	 * that thanks to write = false in this call and us not setting any gpu
 | 
			
		||||
| 
						 | 
				
			
			@ -435,22 +646,21 @@ static int do_switch(struct i915_hw_context *to)
 | 
			
		|||
	 * XXX: We need a real interface to do this instead of trickery.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = i915_gem_object_set_to_gtt_domain(to->obj, false);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		i915_gem_object_unpin(to->obj);
 | 
			
		||||
		return ret;
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto unpin_out;
 | 
			
		||||
 | 
			
		||||
	if (!to->obj->has_global_gtt_mapping) {
 | 
			
		||||
		struct i915_vma *vma = i915_gem_obj_to_vma(to->obj,
 | 
			
		||||
							   &dev_priv->gtt.base);
 | 
			
		||||
		vma->bind_vma(vma, to->obj->cache_level, GLOBAL_BIND);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!to->obj->has_global_gtt_mapping)
 | 
			
		||||
		i915_gem_gtt_bind_object(to->obj, to->obj->cache_level);
 | 
			
		||||
 | 
			
		||||
	if (!to->is_initialized || is_default_context(to))
 | 
			
		||||
	if (!to->is_initialized || i915_gem_context_is_default(to))
 | 
			
		||||
		hw_flags |= MI_RESTORE_INHIBIT;
 | 
			
		||||
 | 
			
		||||
	ret = mi_set_context(ring, to, hw_flags);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		i915_gem_object_unpin(to->obj);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto unpin_out;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < MAX_L3_SLICES; i++) {
 | 
			
		||||
		if (!(to->remap_slice & (1<<i)))
 | 
			
		||||
| 
						 | 
				
			
			@ -484,15 +694,23 @@ static int do_switch(struct i915_hw_context *to)
 | 
			
		|||
		BUG_ON(from->obj->ring != ring);
 | 
			
		||||
 | 
			
		||||
		/* obj is kept alive until the next request by its active ref */
 | 
			
		||||
		i915_gem_object_unpin(from->obj);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(from->obj);
 | 
			
		||||
		i915_gem_context_unreference(from);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i915_gem_context_reference(to);
 | 
			
		||||
	ring->last_context = to;
 | 
			
		||||
	to->is_initialized = true;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	i915_gem_context_reference(to);
 | 
			
		||||
	ring->last_context = to;
 | 
			
		||||
	to->last_ring = ring;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
unpin_out:
 | 
			
		||||
	if (ring->id == RCS)
 | 
			
		||||
		i915_gem_object_ggtt_unpin(to->obj);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -508,31 +726,19 @@ static int do_switch(struct i915_hw_context *to)
 | 
			
		|||
 */
 | 
			
		||||
int i915_switch_context(struct intel_ring_buffer *ring,
 | 
			
		||||
			struct drm_file *file,
 | 
			
		||||
			int to_id)
 | 
			
		||||
			struct i915_hw_context *to)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 | 
			
		||||
	struct i915_hw_context *to;
 | 
			
		||||
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(ring->dev))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 | 
			
		||||
 | 
			
		||||
	if (ring != &dev_priv->ring[RCS])
 | 
			
		||||
	BUG_ON(file && to == NULL);
 | 
			
		||||
 | 
			
		||||
	/* We have the fake context, but don't supports switching. */
 | 
			
		||||
	if (!HAS_HW_CONTEXTS(ring->dev))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (to_id == DEFAULT_CONTEXT_ID) {
 | 
			
		||||
		to = ring->default_context;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (file == NULL)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		to = i915_gem_context_get(file->driver_priv, to_id);
 | 
			
		||||
		if (to == NULL)
 | 
			
		||||
			return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return do_switch(to);
 | 
			
		||||
	return do_switch(ring, to);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 | 
			
		||||
| 
						 | 
				
			
			@ -553,7 +759,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ctx = create_hw_context(dev, file_priv);
 | 
			
		||||
	ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
	if (IS_ERR(ctx))
 | 
			
		||||
		return PTR_ERR(ctx);
 | 
			
		||||
| 
						 | 
				
			
			@ -575,14 +781,17 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 | 
			
		|||
	if (!(dev->driver->driver_features & DRIVER_GEM))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (args->ctx_id == DEFAULT_CONTEXT_ID)
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
	ret = i915_mutex_lock_interruptible(dev);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ctx = i915_gem_context_get(file_priv, args->ctx_id);
 | 
			
		||||
	if (!ctx) {
 | 
			
		||||
	if (IS_ERR(ctx)) {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
		return PTR_ERR(ctx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idr_remove(&ctx->file_priv->context_idr, ctx->id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@
 | 
			
		|||
static bool
 | 
			
		||||
mark_free(struct i915_vma *vma, struct list_head *unwind)
 | 
			
		||||
{
 | 
			
		||||
	if (vma->obj->pin_count)
 | 
			
		||||
	if (vma->pin_count)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(!list_empty(&vma->exec_list)))
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +46,25 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
 | 
			
		|||
	return drm_mm_scan_add_block(&vma->node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i915_gem_evict_something - Evict vmas to make room for binding a new one
 | 
			
		||||
 * @dev: drm_device
 | 
			
		||||
 * @vm: address space to evict from
 | 
			
		||||
 * @size: size of the desired free space
 | 
			
		||||
 * @alignment: alignment constraint of the desired free space
 | 
			
		||||
 * @cache_level: cache_level for the desired space
 | 
			
		||||
 * @mappable: whether the free space must be mappable
 | 
			
		||||
 * @nonblocking: whether evicting active objects is allowed or not
 | 
			
		||||
 *
 | 
			
		||||
 * This function will try to evict vmas until a free space satisfying the
 | 
			
		||||
 * requirements is found. Callers must check first whether any such hole exists
 | 
			
		||||
 * already before calling this function.
 | 
			
		||||
 *
 | 
			
		||||
 * This function is used by the object/vma binding code.
 | 
			
		||||
 *
 | 
			
		||||
 * To clarify: This is for freeing up virtual address space, not for freeing
 | 
			
		||||
 * memory in e.g. the shrinker.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
 | 
			
		||||
			 int min_size, unsigned alignment, unsigned cache_level,
 | 
			
		||||
| 
						 | 
				
			
			@ -177,19 +196,19 @@ found:
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i915_gem_evict_vm - Try to free up VM space
 | 
			
		||||
 * i915_gem_evict_vm - Evict all idle vmas from a vm
 | 
			
		||||
 *
 | 
			
		||||
 * @vm: Address space to evict from
 | 
			
		||||
 * @vm: Address space to cleanse
 | 
			
		||||
 * @do_idle: Boolean directing whether to idle first.
 | 
			
		||||
 *
 | 
			
		||||
 * VM eviction is about freeing up virtual address space. If one wants fine
 | 
			
		||||
 * grained eviction, they should see evict something for more details. In terms
 | 
			
		||||
 * of freeing up actual system memory, this function may not accomplish the
 | 
			
		||||
 * desired result. An object may be shared in multiple address space, and this
 | 
			
		||||
 * function will not assert those objects be freed.
 | 
			
		||||
 * This function evicts all idles vmas from a vm. If all unpinned vmas should be
 | 
			
		||||
 * evicted the @do_idle needs to be set to true.
 | 
			
		||||
 *
 | 
			
		||||
 * Using do_idle will result in a more complete eviction because it retires, and
 | 
			
		||||
 * inactivates current BOs.
 | 
			
		||||
 * This is used by the execbuf code as a last-ditch effort to defragment the
 | 
			
		||||
 * address space.
 | 
			
		||||
 *
 | 
			
		||||
 * To clarify: This is for freeing up virtual address space, not for freeing
 | 
			
		||||
 * memory in e.g. the shrinker.
 | 
			
		||||
 */
 | 
			
		||||
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -207,12 +226,20 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
 | 
			
		||||
		if (vma->obj->pin_count == 0)
 | 
			
		||||
		if (vma->pin_count == 0)
 | 
			
		||||
			WARN_ON(i915_vma_unbind(vma));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i915_gem_evict_everything - Try to evict all objects
 | 
			
		||||
 * @dev: Device to evict objects for
 | 
			
		||||
 *
 | 
			
		||||
 * This functions tries to evict all gem objects from all address spaces. Used
 | 
			
		||||
 * by the shrinker as a last-ditch effort and for suspend, before releasing the
 | 
			
		||||
 * backing storage of all unbound objects.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
i915_gem_evict_everything(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
 | 
			
		|||
	       struct i915_address_space *vm,
 | 
			
		||||
	       struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = vm->dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	struct list_head objects;
 | 
			
		||||
	int i, ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +126,20 @@ eb_lookup_vmas(struct eb_vmas *eb,
 | 
			
		|||
	i = 0;
 | 
			
		||||
	while (!list_empty(&objects)) {
 | 
			
		||||
		struct i915_vma *vma;
 | 
			
		||||
		struct i915_address_space *bind_vm = vm;
 | 
			
		||||
 | 
			
		||||
		if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT &&
 | 
			
		||||
		    USES_FULL_PPGTT(vm->dev)) {
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* If we have secure dispatch, or the userspace assures us that
 | 
			
		||||
		 * they know what they're doing, use the GGTT VM.
 | 
			
		||||
		 */
 | 
			
		||||
		if (((args->flags & I915_EXEC_SECURE) &&
 | 
			
		||||
		    (i == (args->buffer_count - 1))))
 | 
			
		||||
			bind_vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
		obj = list_first_entry(&objects,
 | 
			
		||||
				       struct drm_i915_gem_object,
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +153,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
 | 
			
		|||
		 * from the (obj, vm) we don't run the risk of creating
 | 
			
		||||
		 * duplicated vmas for the same vm.
 | 
			
		||||
		 */
 | 
			
		||||
		vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
 | 
			
		||||
		vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm);
 | 
			
		||||
		if (IS_ERR(vma)) {
 | 
			
		||||
			DRM_DEBUG("Failed to lookup VMA\n");
 | 
			
		||||
			ret = PTR_ERR(vma);
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +232,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
 | 
			
		|||
		i915_gem_object_unpin_fence(obj);
 | 
			
		||||
 | 
			
		||||
	if (entry->flags & __EXEC_OBJECT_HAS_PIN)
 | 
			
		||||
		i915_gem_object_unpin(obj);
 | 
			
		||||
		vma->pin_count--;
 | 
			
		||||
 | 
			
		||||
	entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -327,8 +342,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
 | 
			
		|||
static int
 | 
			
		||||
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 | 
			
		||||
				   struct eb_vmas *eb,
 | 
			
		||||
				   struct drm_i915_gem_relocation_entry *reloc,
 | 
			
		||||
				   struct i915_address_space *vm)
 | 
			
		||||
				   struct drm_i915_gem_relocation_entry *reloc)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = obj->base.dev;
 | 
			
		||||
	struct drm_gem_object *target_obj;
 | 
			
		||||
| 
						 | 
				
			
			@ -352,8 +366,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 | 
			
		|||
	if (unlikely(IS_GEN6(dev) &&
 | 
			
		||||
	    reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
 | 
			
		||||
	    !target_i915_obj->has_global_gtt_mapping)) {
 | 
			
		||||
		i915_gem_gtt_bind_object(target_i915_obj,
 | 
			
		||||
					 target_i915_obj->cache_level);
 | 
			
		||||
		struct i915_vma *vma =
 | 
			
		||||
			list_first_entry(&target_i915_obj->vma_list,
 | 
			
		||||
					 typeof(*vma), vma_link);
 | 
			
		||||
		vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Validate that the target is in a valid r/w GPU domain */
 | 
			
		||||
| 
						 | 
				
			
			@ -451,8 +467,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
 | 
			
		|||
		do {
 | 
			
		||||
			u64 offset = r->presumed_offset;
 | 
			
		||||
 | 
			
		||||
			ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r,
 | 
			
		||||
								 vma->vm);
 | 
			
		||||
			ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r);
 | 
			
		||||
			if (ret)
 | 
			
		||||
				return ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -481,8 +496,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma,
 | 
			
		|||
	int i, ret;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < entry->relocation_count; i++) {
 | 
			
		||||
		ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i],
 | 
			
		||||
							 vma->vm);
 | 
			
		||||
		ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i]);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -527,11 +541,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 | 
			
		|||
				struct intel_ring_buffer *ring,
 | 
			
		||||
				bool *need_reloc)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_object *obj = vma->obj;
 | 
			
		||||
	struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
 | 
			
		||||
	bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
 | 
			
		||||
	bool need_fence, need_mappable;
 | 
			
		||||
	struct drm_i915_gem_object *obj = vma->obj;
 | 
			
		||||
	u32 flags = (entry->flags & EXEC_OBJECT_NEEDS_GTT) &&
 | 
			
		||||
		!vma->obj->has_global_gtt_mapping ? GLOBAL_BIND : 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	need_fence =
 | 
			
		||||
| 
						 | 
				
			
			@ -560,14 +575,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ensure ppgtt mapping exists if needed */
 | 
			
		||||
	if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
 | 
			
		||||
		i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
 | 
			
		||||
				       obj, obj->cache_level);
 | 
			
		||||
 | 
			
		||||
		obj->has_aliasing_ppgtt_mapping = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (entry->offset != vma->node.start) {
 | 
			
		||||
		entry->offset = vma->node.start;
 | 
			
		||||
		*need_reloc = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -578,9 +585,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 | 
			
		|||
		obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (entry->flags & EXEC_OBJECT_NEEDS_GTT &&
 | 
			
		||||
	    !obj->has_global_gtt_mapping)
 | 
			
		||||
		i915_gem_gtt_bind_object(obj, obj->cache_level);
 | 
			
		||||
	vma->bind_vma(vma, obj->cache_level, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -891,7 +896,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
 | 
			
		|||
		if (!access_ok(VERIFY_WRITE, ptr, length))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
 | 
			
		||||
		if (likely(!i915_prefault_disable)) {
 | 
			
		||||
		if (likely(!i915.prefault_disable)) {
 | 
			
		||||
			if (fault_in_multipages_readable(ptr, length))
 | 
			
		||||
				return -EFAULT;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -900,22 +905,27 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
static struct i915_hw_context *
 | 
			
		||||
i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 | 
			
		||||
			  const u32 ctx_id)
 | 
			
		||||
			  struct intel_ring_buffer *ring, const u32 ctx_id)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_hw_context *ctx = NULL;
 | 
			
		||||
	struct i915_ctx_hang_stats *hs;
 | 
			
		||||
 | 
			
		||||
	hs = i915_gem_context_get_hang_stats(dev, file, ctx_id);
 | 
			
		||||
	if (IS_ERR(hs))
 | 
			
		||||
		return PTR_ERR(hs);
 | 
			
		||||
	if (ring->id != RCS && ctx_id != DEFAULT_CONTEXT_ID)
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
 | 
			
		||||
	ctx = i915_gem_context_get(file->driver_priv, ctx_id);
 | 
			
		||||
	if (IS_ERR(ctx))
 | 
			
		||||
		return ctx;
 | 
			
		||||
 | 
			
		||||
	hs = &ctx->hang_stats;
 | 
			
		||||
	if (hs->banned) {
 | 
			
		||||
		DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id);
 | 
			
		||||
		return -EIO;
 | 
			
		||||
		return ERR_PTR(-EIO);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return ctx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -939,7 +949,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 | 
			
		|||
		if (obj->base.write_domain) {
 | 
			
		||||
			obj->dirty = 1;
 | 
			
		||||
			obj->last_write_seqno = intel_ring_get_seqno(ring);
 | 
			
		||||
			if (obj->pin_count) /* check for potential scanout */
 | 
			
		||||
			/* check for potential scanout */
 | 
			
		||||
			if (i915_gem_obj_ggtt_bound(obj) &&
 | 
			
		||||
			    i915_gem_obj_to_ggtt(obj)->pin_count)
 | 
			
		||||
				intel_mark_fb_busy(obj, ring);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -989,16 +1001,17 @@ static int
 | 
			
		|||
i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		||||
		       struct drm_file *file,
 | 
			
		||||
		       struct drm_i915_gem_execbuffer2 *args,
 | 
			
		||||
		       struct drm_i915_gem_exec_object2 *exec,
 | 
			
		||||
		       struct i915_address_space *vm)
 | 
			
		||||
		       struct drm_i915_gem_exec_object2 *exec)
 | 
			
		||||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
	struct eb_vmas *eb;
 | 
			
		||||
	struct drm_i915_gem_object *batch_obj;
 | 
			
		||||
	struct drm_clip_rect *cliprects = NULL;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	struct i915_hw_context *ctx;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
	const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
 | 
			
		||||
	u32 exec_start, exec_len;
 | 
			
		||||
	u32 exec_start = args->batch_start_offset, exec_len;
 | 
			
		||||
	u32 mask, flags;
 | 
			
		||||
	int ret, mode, i;
 | 
			
		||||
	bool need_relocs;
 | 
			
		||||
| 
						 | 
				
			
			@ -1020,41 +1033,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
	if (args->flags & I915_EXEC_IS_PINNED)
 | 
			
		||||
		flags |= I915_DISPATCH_PINNED;
 | 
			
		||||
 | 
			
		||||
	switch (args->flags & I915_EXEC_RING_MASK) {
 | 
			
		||||
	case I915_EXEC_DEFAULT:
 | 
			
		||||
	case I915_EXEC_RENDER:
 | 
			
		||||
		ring = &dev_priv->ring[RCS];
 | 
			
		||||
		break;
 | 
			
		||||
	case I915_EXEC_BSD:
 | 
			
		||||
		ring = &dev_priv->ring[VCS];
 | 
			
		||||
		if (ctx_id != DEFAULT_CONTEXT_ID) {
 | 
			
		||||
			DRM_DEBUG("Ring %s doesn't support contexts\n",
 | 
			
		||||
				  ring->name);
 | 
			
		||||
			return -EPERM;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case I915_EXEC_BLT:
 | 
			
		||||
		ring = &dev_priv->ring[BCS];
 | 
			
		||||
		if (ctx_id != DEFAULT_CONTEXT_ID) {
 | 
			
		||||
			DRM_DEBUG("Ring %s doesn't support contexts\n",
 | 
			
		||||
				  ring->name);
 | 
			
		||||
			return -EPERM;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case I915_EXEC_VEBOX:
 | 
			
		||||
		ring = &dev_priv->ring[VECS];
 | 
			
		||||
		if (ctx_id != DEFAULT_CONTEXT_ID) {
 | 
			
		||||
			DRM_DEBUG("Ring %s doesn't support contexts\n",
 | 
			
		||||
				  ring->name);
 | 
			
		||||
			return -EPERM;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
	if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) {
 | 
			
		||||
		DRM_DEBUG("execbuf with unknown ring: %d\n",
 | 
			
		||||
			  (int)(args->flags & I915_EXEC_RING_MASK));
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
 | 
			
		||||
		ring = &dev_priv->ring[RCS];
 | 
			
		||||
	else
 | 
			
		||||
		ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1];
 | 
			
		||||
 | 
			
		||||
	if (!intel_ring_initialized(ring)) {
 | 
			
		||||
		DRM_DEBUG("execbuf with invalid ring: %d\n",
 | 
			
		||||
			  (int)(args->flags & I915_EXEC_RING_MASK));
 | 
			
		||||
| 
						 | 
				
			
			@ -1136,12 +1125,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
		goto pre_mutex_err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_validate_context(dev, file, ctx_id);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
	ctx = i915_gem_validate_context(dev, file, ring, ctx_id);
 | 
			
		||||
	if (IS_ERR(ctx)) {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		ret = PTR_ERR(ctx);
 | 
			
		||||
		goto pre_mutex_err;
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	i915_gem_context_reference(ctx);
 | 
			
		||||
 | 
			
		||||
	vm = ctx->vm;
 | 
			
		||||
	if (!USES_FULL_PPGTT(dev))
 | 
			
		||||
		vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	eb = eb_create(args);
 | 
			
		||||
	if (eb == NULL) {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -1187,14 +1183,25 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
	/* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
 | 
			
		||||
	 * batch" bit. Hence we need to pin secure batches into the global gtt.
 | 
			
		||||
	 * hsw should have this fixed, but bdw mucks it up again. */
 | 
			
		||||
	if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping)
 | 
			
		||||
		i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level);
 | 
			
		||||
	if (flags & I915_DISPATCH_SECURE &&
 | 
			
		||||
	    !batch_obj->has_global_gtt_mapping) {
 | 
			
		||||
		/* When we have multiple VMs, we'll need to make sure that we
 | 
			
		||||
		 * allocate space first */
 | 
			
		||||
		struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj);
 | 
			
		||||
		BUG_ON(!vma);
 | 
			
		||||
		vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (flags & I915_DISPATCH_SECURE)
 | 
			
		||||
		exec_start += i915_gem_obj_ggtt_offset(batch_obj);
 | 
			
		||||
	else
 | 
			
		||||
		exec_start += i915_gem_obj_offset(batch_obj, vm);
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	ret = i915_switch_context(ring, file, ctx_id);
 | 
			
		||||
	ret = i915_switch_context(ring, file, ctx);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1219,8 +1226,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
			goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exec_start = i915_gem_obj_offset(batch_obj, vm) +
 | 
			
		||||
		args->batch_start_offset;
 | 
			
		||||
 | 
			
		||||
	exec_len = args->batch_len;
 | 
			
		||||
	if (cliprects) {
 | 
			
		||||
		for (i = 0; i < args->num_cliprects; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1249,6 +1255,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
	i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	/* the request owns the ref now */
 | 
			
		||||
	i915_gem_context_unreference(ctx);
 | 
			
		||||
	eb_destroy(eb);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -1270,7 +1278,6 @@ int
 | 
			
		|||
i915_gem_execbuffer(struct drm_device *dev, void *data,
 | 
			
		||||
		    struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_execbuffer *args = data;
 | 
			
		||||
	struct drm_i915_gem_execbuffer2 exec2;
 | 
			
		||||
	struct drm_i915_gem_exec_object *exec_list = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1326,8 +1333,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 | 
			
		|||
	exec2.flags = I915_EXEC_RENDER;
 | 
			
		||||
	i915_execbuffer2_set_context_id(exec2, 0);
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list,
 | 
			
		||||
				     &dev_priv->gtt.base);
 | 
			
		||||
	ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		/* Copy the new buffer offsets back to the user's exec list. */
 | 
			
		||||
		for (i = 0; i < args->buffer_count; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -1353,7 +1359,6 @@ int
 | 
			
		|||
i915_gem_execbuffer2(struct drm_device *dev, void *data,
 | 
			
		||||
		     struct drm_file *file)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_execbuffer2 *args = data;
 | 
			
		||||
	struct drm_i915_gem_exec_object2 *exec2_list = NULL;
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -1384,8 +1389,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
 | 
			
		|||
		return -EFAULT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list,
 | 
			
		||||
				     &dev_priv->gtt.base);
 | 
			
		||||
	ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		/* Copy the new buffer offsets back to the user's exec list. */
 | 
			
		||||
		ret = copy_to_user(to_user_ptr(args->buffers_ptr),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/seq_file.h>
 | 
			
		||||
#include <drm/drmP.h>
 | 
			
		||||
#include <drm/i915_drm.h>
 | 
			
		||||
#include "i915_drv.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +71,12 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 | 
			
		|||
#define PPAT_CACHED_INDEX		_PAGE_PAT /* WB LLCeLLC */
 | 
			
		||||
#define PPAT_DISPLAY_ELLC_INDEX		_PAGE_PCD /* WT eLLC */
 | 
			
		||||
 | 
			
		||||
static void ppgtt_bind_vma(struct i915_vma *vma,
 | 
			
		||||
			   enum i915_cache_level cache_level,
 | 
			
		||||
			   u32 flags);
 | 
			
		||||
static void ppgtt_unbind_vma(struct i915_vma *vma);
 | 
			
		||||
static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt);
 | 
			
		||||
 | 
			
		||||
static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
 | 
			
		||||
					     enum i915_cache_level level,
 | 
			
		||||
					     bool valid)
 | 
			
		||||
| 
						 | 
				
			
			@ -199,12 +206,19 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
 | 
			
		|||
 | 
			
		||||
/* Broadwell Page Directory Pointer Descriptors */
 | 
			
		||||
static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
 | 
			
		||||
			   uint64_t val)
 | 
			
		||||
			   uint64_t val, bool synchronous)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(entry >= 4);
 | 
			
		||||
 | 
			
		||||
	if (synchronous) {
 | 
			
		||||
		I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32);
 | 
			
		||||
		I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = intel_ring_begin(ring, 6);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -220,36 +234,23 @@ static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen8_ppgtt_enable(struct drm_device *dev)
 | 
			
		||||
static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			  struct intel_ring_buffer *ring,
 | 
			
		||||
			  bool synchronous)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
	int i, j, ret;
 | 
			
		||||
	int i, ret;
 | 
			
		||||
 | 
			
		||||
	/* bit of a hack to find the actual last used pd */
 | 
			
		||||
	int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, j) {
 | 
			
		||||
		I915_WRITE(RING_MODE_GEN7(ring),
 | 
			
		||||
			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = used_pd - 1; i >= 0; i--) {
 | 
			
		||||
		dma_addr_t addr = ppgtt->pd_dma_addr[i];
 | 
			
		||||
		for_each_ring(ring, dev_priv, j) {
 | 
			
		||||
			ret = gen8_write_pdp(ring, i, addr);
 | 
			
		||||
		ret = gen8_write_pdp(ring, i, addr, synchronous);
 | 
			
		||||
		if (ret)
 | 
			
		||||
				goto err_out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_out:
 | 
			
		||||
	for_each_ring(ring, dev_priv, j)
 | 
			
		||||
		I915_WRITE(RING_MODE_GEN7(ring),
 | 
			
		||||
			   _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
 | 
			
		||||
| 
						 | 
				
			
			@ -324,6 +325,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
 | 
			
		|||
		container_of(vm, struct i915_hw_ppgtt, base);
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	list_del(&vm->global_link);
 | 
			
		||||
	drm_mm_takedown(&vm->mm);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ppgtt->num_pd_pages ; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -386,6 +388,7 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
 | 
			
		|||
	ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT);
 | 
			
		||||
	ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
 | 
			
		||||
	ppgtt->enable = gen8_ppgtt_enable;
 | 
			
		||||
	ppgtt->switch_mm = gen8_mm_switch;
 | 
			
		||||
	ppgtt->base.clear_range = gen8_ppgtt_clear_range;
 | 
			
		||||
	ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
 | 
			
		||||
	ppgtt->base.cleanup = gen8_ppgtt_cleanup;
 | 
			
		||||
| 
						 | 
				
			
			@ -458,6 +461,62 @@ err_out:
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
 | 
			
		||||
	struct i915_address_space *vm = &ppgtt->base;
 | 
			
		||||
	gen6_gtt_pte_t __iomem *pd_addr;
 | 
			
		||||
	gen6_gtt_pte_t scratch_pte;
 | 
			
		||||
	uint32_t pd_entry;
 | 
			
		||||
	int pte, pde;
 | 
			
		||||
 | 
			
		||||
	scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
 | 
			
		||||
 | 
			
		||||
	pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm +
 | 
			
		||||
		ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
 | 
			
		||||
 | 
			
		||||
	seq_printf(m, "  VM %p (pd_offset %x-%x):\n", vm,
 | 
			
		||||
		   ppgtt->pd_offset, ppgtt->pd_offset + ppgtt->num_pd_entries);
 | 
			
		||||
	for (pde = 0; pde < ppgtt->num_pd_entries; pde++) {
 | 
			
		||||
		u32 expected;
 | 
			
		||||
		gen6_gtt_pte_t *pt_vaddr;
 | 
			
		||||
		dma_addr_t pt_addr = ppgtt->pt_dma_addr[pde];
 | 
			
		||||
		pd_entry = readl(pd_addr + pde);
 | 
			
		||||
		expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID);
 | 
			
		||||
 | 
			
		||||
		if (pd_entry != expected)
 | 
			
		||||
			seq_printf(m, "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n",
 | 
			
		||||
				   pde,
 | 
			
		||||
				   pd_entry,
 | 
			
		||||
				   expected);
 | 
			
		||||
		seq_printf(m, "\tPDE: %x\n", pd_entry);
 | 
			
		||||
 | 
			
		||||
		pt_vaddr = kmap_atomic(ppgtt->pt_pages[pde]);
 | 
			
		||||
		for (pte = 0; pte < I915_PPGTT_PT_ENTRIES; pte+=4) {
 | 
			
		||||
			unsigned long va =
 | 
			
		||||
				(pde * PAGE_SIZE * I915_PPGTT_PT_ENTRIES) +
 | 
			
		||||
				(pte * PAGE_SIZE);
 | 
			
		||||
			int i;
 | 
			
		||||
			bool found = false;
 | 
			
		||||
			for (i = 0; i < 4; i++)
 | 
			
		||||
				if (pt_vaddr[pte + i] != scratch_pte)
 | 
			
		||||
					found = true;
 | 
			
		||||
			if (!found)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			seq_printf(m, "\t\t0x%lx [%03d,%04d]: =", va, pde, pte);
 | 
			
		||||
			for (i = 0; i < 4; i++) {
 | 
			
		||||
				if (pt_vaddr[pte + i] != scratch_pte)
 | 
			
		||||
					seq_printf(m, " %08x", pt_vaddr[pte + i]);
 | 
			
		||||
				else
 | 
			
		||||
					seq_puts(m, "  SCRATCH ");
 | 
			
		||||
			}
 | 
			
		||||
			seq_puts(m, "\n");
 | 
			
		||||
		}
 | 
			
		||||
		kunmap_atomic(pt_vaddr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -480,38 +539,163 @@ static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 | 
			
		|||
	readl(pd_addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen6_ppgtt_enable(struct drm_device *dev)
 | 
			
		||||
static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
	uint32_t pd_offset;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(ppgtt->pd_offset & 0x3f);
 | 
			
		||||
 | 
			
		||||
	gen6_write_pdes(ppgtt);
 | 
			
		||||
	return (ppgtt->pd_offset / 64) << 16;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	pd_offset = ppgtt->pd_offset;
 | 
			
		||||
	pd_offset /= 64; /* in cachelines, */
 | 
			
		||||
	pd_offset <<= 16;
 | 
			
		||||
static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			 struct intel_ring_buffer *ring,
 | 
			
		||||
			 bool synchronous)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 6) {
 | 
			
		||||
		uint32_t ecochk, gab_ctl, ecobits;
 | 
			
		||||
	/* If we're in reset, we can assume the GPU is sufficiently idle to
 | 
			
		||||
	 * manually frob these bits. Ideally we could use the ring functions,
 | 
			
		||||
	 * except our error handling makes it quite difficult (can't use
 | 
			
		||||
	 * intel_ring_begin, ring->flush, or intel_ring_advance)
 | 
			
		||||
	 *
 | 
			
		||||
	 * FIXME: We should try not to special case reset
 | 
			
		||||
	 */
 | 
			
		||||
	if (synchronous ||
 | 
			
		||||
	    i915_reset_in_progress(&dev_priv->gpu_error)) {
 | 
			
		||||
		WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
 | 
			
		||||
		POSTING_READ(RING_PP_DIR_BASE(ring));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		ecobits = I915_READ(GAC_ECO_BITS);
 | 
			
		||||
		I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
 | 
			
		||||
					 ECOBITS_PPGTT_CACHE64B);
 | 
			
		||||
	/* NB: TLBs must be flushed and invalidated before a switch */
 | 
			
		||||
	ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
		gab_ctl = I915_READ(GAB_CTL);
 | 
			
		||||
		I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
 | 
			
		||||
	ret = intel_ring_begin(ring, 6);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
		ecochk = I915_READ(GAM_ECOCHK);
 | 
			
		||||
		I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
 | 
			
		||||
				       ECOCHK_PPGTT_CACHE64B);
 | 
			
		||||
		I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
	} else if (INTEL_INFO(dev)->gen >= 7) {
 | 
			
		||||
	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
 | 
			
		||||
	intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
 | 
			
		||||
	intel_ring_emit(ring, PP_DIR_DCLV_2G);
 | 
			
		||||
	intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
 | 
			
		||||
	intel_ring_emit(ring, get_pd_offset(ppgtt));
 | 
			
		||||
	intel_ring_emit(ring, MI_NOOP);
 | 
			
		||||
	intel_ring_advance(ring);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			  struct intel_ring_buffer *ring,
 | 
			
		||||
			  bool synchronous)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* If we're in reset, we can assume the GPU is sufficiently idle to
 | 
			
		||||
	 * manually frob these bits. Ideally we could use the ring functions,
 | 
			
		||||
	 * except our error handling makes it quite difficult (can't use
 | 
			
		||||
	 * intel_ring_begin, ring->flush, or intel_ring_advance)
 | 
			
		||||
	 *
 | 
			
		||||
	 * FIXME: We should try not to special case reset
 | 
			
		||||
	 */
 | 
			
		||||
	if (synchronous ||
 | 
			
		||||
	    i915_reset_in_progress(&dev_priv->gpu_error)) {
 | 
			
		||||
		WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
 | 
			
		||||
		POSTING_READ(RING_PP_DIR_BASE(ring));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* NB: TLBs must be flushed and invalidated before a switch */
 | 
			
		||||
	ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	ret = intel_ring_begin(ring, 6);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
 | 
			
		||||
	intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
 | 
			
		||||
	intel_ring_emit(ring, PP_DIR_DCLV_2G);
 | 
			
		||||
	intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
 | 
			
		||||
	intel_ring_emit(ring, get_pd_offset(ppgtt));
 | 
			
		||||
	intel_ring_emit(ring, MI_NOOP);
 | 
			
		||||
	intel_ring_advance(ring);
 | 
			
		||||
 | 
			
		||||
	/* XXX: RCS is the only one to auto invalidate the TLBs? */
 | 
			
		||||
	if (ring->id != RCS) {
 | 
			
		||||
		ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			  struct intel_ring_buffer *ring,
 | 
			
		||||
			  bool synchronous)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	if (!synchronous)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
 | 
			
		||||
	I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
 | 
			
		||||
 | 
			
		||||
	POSTING_READ(RING_PP_DIR_DCLV(ring));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	int j, ret;
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, j) {
 | 
			
		||||
		I915_WRITE(RING_MODE_GEN7(ring),
 | 
			
		||||
			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
 | 
			
		||||
		/* We promise to do a switch later with FULL PPGTT. If this is
 | 
			
		||||
		 * aliasing, this is the one and only switch we'll do */
 | 
			
		||||
		if (USES_FULL_PPGTT(dev))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ret = ppgtt->switch_mm(ppgtt, ring, true);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_out:
 | 
			
		||||
	for_each_ring(ring, dev_priv, j)
 | 
			
		||||
		I915_WRITE(RING_MODE_GEN7(ring),
 | 
			
		||||
			   _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	uint32_t ecochk, ecobits;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ecobits = I915_READ(GAC_ECO_BITS);
 | 
			
		||||
	I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
 | 
			
		||||
| 
						 | 
				
			
			@ -524,17 +708,52 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
 | 
			
		|||
		ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
 | 
			
		||||
	}
 | 
			
		||||
	I915_WRITE(GAM_ECOCHK, ecochk);
 | 
			
		||||
		/* GFX_MODE is per-ring on gen7+ */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		if (INTEL_INFO(dev)->gen >= 7)
 | 
			
		||||
		int ret;
 | 
			
		||||
		/* GFX_MODE is per-ring on gen7+ */
 | 
			
		||||
		I915_WRITE(RING_MODE_GEN7(ring),
 | 
			
		||||
			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
 | 
			
		||||
		I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
 | 
			
		||||
		/* We promise to do a switch later with FULL PPGTT. If this is
 | 
			
		||||
		 * aliasing, this is the one and only switch we'll do */
 | 
			
		||||
		if (USES_FULL_PPGTT(dev))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ret = ppgtt->switch_mm(ppgtt, ring, true);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	uint32_t ecochk, gab_ctl, ecobits;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ecobits = I915_READ(GAC_ECO_BITS);
 | 
			
		||||
	I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
 | 
			
		||||
		   ECOBITS_PPGTT_CACHE64B);
 | 
			
		||||
 | 
			
		||||
	gab_ctl = I915_READ(GAB_CTL);
 | 
			
		||||
	I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
 | 
			
		||||
 | 
			
		||||
	ecochk = I915_READ(GAM_ECOCHK);
 | 
			
		||||
	I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		int ret = ppgtt->switch_mm(ppgtt, ring, true);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +827,9 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 | 
			
		|||
		container_of(vm, struct i915_hw_ppgtt, base);
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	list_del(&vm->global_link);
 | 
			
		||||
	drm_mm_takedown(&ppgtt->base.mm);
 | 
			
		||||
	drm_mm_remove_node(&ppgtt->node);
 | 
			
		||||
 | 
			
		||||
	if (ppgtt->pt_dma_addr) {
 | 
			
		||||
		for (i = 0; i < ppgtt->num_pd_entries; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -626,20 +847,51 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 | 
			
		|||
 | 
			
		||||
static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
#define GEN6_PD_ALIGN (PAGE_SIZE * 16)
 | 
			
		||||
#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
 | 
			
		||||
	struct drm_device *dev = ppgtt->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	unsigned first_pd_entry_in_global_pt;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret = -ENOMEM;
 | 
			
		||||
	bool retried = false;
 | 
			
		||||
	int i, ret;
 | 
			
		||||
 | 
			
		||||
	/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
 | 
			
		||||
	 * entries. For aliasing ppgtt support we just steal them at the end for
 | 
			
		||||
	 * now. */
 | 
			
		||||
	first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
 | 
			
		||||
	/* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
 | 
			
		||||
	 * allocator works in address space sizes, so it's multiplied by page
 | 
			
		||||
	 * size. We allocate at the top of the GTT to avoid fragmentation.
 | 
			
		||||
	 */
 | 
			
		||||
	BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm));
 | 
			
		||||
alloc:
 | 
			
		||||
	ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
 | 
			
		||||
						  &ppgtt->node, GEN6_PD_SIZE,
 | 
			
		||||
						  GEN6_PD_ALIGN, 0,
 | 
			
		||||
						  0, dev_priv->gtt.base.total,
 | 
			
		||||
						  DRM_MM_SEARCH_DEFAULT);
 | 
			
		||||
	if (ret == -ENOSPC && !retried) {
 | 
			
		||||
		ret = i915_gem_evict_something(dev, &dev_priv->gtt.base,
 | 
			
		||||
					       GEN6_PD_SIZE, GEN6_PD_ALIGN,
 | 
			
		||||
					       I915_CACHE_NONE, false, true);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		retried = true;
 | 
			
		||||
		goto alloc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ppgtt->node.start < dev_priv->gtt.mappable_end)
 | 
			
		||||
		DRM_DEBUG("Forced to use aperture for PDEs\n");
 | 
			
		||||
 | 
			
		||||
	ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
 | 
			
		||||
	ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
 | 
			
		||||
	if (IS_GEN6(dev)) {
 | 
			
		||||
		ppgtt->enable = gen6_ppgtt_enable;
 | 
			
		||||
		ppgtt->switch_mm = gen6_mm_switch;
 | 
			
		||||
	} else if (IS_HASWELL(dev)) {
 | 
			
		||||
		ppgtt->enable = gen7_ppgtt_enable;
 | 
			
		||||
		ppgtt->switch_mm = hsw_mm_switch;
 | 
			
		||||
	} else if (IS_GEN7(dev)) {
 | 
			
		||||
		ppgtt->enable = gen7_ppgtt_enable;
 | 
			
		||||
		ppgtt->switch_mm = gen7_mm_switch;
 | 
			
		||||
	} else
 | 
			
		||||
		BUG();
 | 
			
		||||
	ppgtt->base.clear_range = gen6_ppgtt_clear_range;
 | 
			
		||||
	ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
 | 
			
		||||
	ppgtt->base.cleanup = gen6_ppgtt_cleanup;
 | 
			
		||||
| 
						 | 
				
			
			@ -648,8 +900,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 | 
			
		|||
	ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
 | 
			
		||||
	ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *),
 | 
			
		||||
				  GFP_KERNEL);
 | 
			
		||||
	if (!ppgtt->pt_pages)
 | 
			
		||||
	if (!ppgtt->pt_pages) {
 | 
			
		||||
		drm_mm_remove_node(&ppgtt->node);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ppgtt->num_pd_entries; i++) {
 | 
			
		||||
		ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -678,8 +932,13 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 | 
			
		|||
 | 
			
		||||
	ppgtt->base.clear_range(&ppgtt->base, 0,
 | 
			
		||||
				ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true);
 | 
			
		||||
	ppgtt->debug_dump = gen6_dump_ppgtt;
 | 
			
		||||
 | 
			
		||||
	ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 | 
			
		||||
	DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n",
 | 
			
		||||
			 ppgtt->node.size >> 20,
 | 
			
		||||
			 ppgtt->node.start / PAGE_SIZE);
 | 
			
		||||
	ppgtt->pd_offset =
 | 
			
		||||
		ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -696,19 +955,15 @@ err_pt_alloc:
 | 
			
		|||
			__free_page(ppgtt->pt_pages[i]);
 | 
			
		||||
	}
 | 
			
		||||
	kfree(ppgtt->pt_pages);
 | 
			
		||||
	drm_mm_remove_node(&ppgtt->node);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
 | 
			
		||||
int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
 | 
			
		||||
	if (!ppgtt)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	ppgtt->base.dev = dev;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -719,44 +974,41 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
 | 
			
		|||
	else
 | 
			
		||||
		BUG();
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		kfree(ppgtt);
 | 
			
		||||
	else {
 | 
			
		||||
		dev_priv->mm.aliasing_ppgtt = ppgtt;
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
		kref_init(&ppgtt->ref);
 | 
			
		||||
		drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
 | 
			
		||||
			    ppgtt->base.total);
 | 
			
		||||
		i915_init_vm(dev_priv, &ppgtt->base);
 | 
			
		||||
		if (INTEL_INFO(dev)->gen < 8) {
 | 
			
		||||
			gen6_write_pdes(ppgtt);
 | 
			
		||||
			DRM_DEBUG("Adding PPGTT at offset %x\n",
 | 
			
		||||
				  ppgtt->pd_offset << 10);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
 | 
			
		||||
static void
 | 
			
		||||
ppgtt_bind_vma(struct i915_vma *vma,
 | 
			
		||||
	       enum i915_cache_level cache_level,
 | 
			
		||||
	       u32 flags)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
	const unsigned long entry = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (!ppgtt)
 | 
			
		||||
		return;
 | 
			
		||||
	WARN_ON(flags);
 | 
			
		||||
 | 
			
		||||
	ppgtt->base.cleanup(&ppgtt->base);
 | 
			
		||||
	dev_priv->mm.aliasing_ppgtt = NULL;
 | 
			
		||||
	vma->vm->insert_entries(vma->vm, vma->obj->pages, entry, cache_level);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			    struct drm_i915_gem_object *obj,
 | 
			
		||||
			    enum i915_cache_level cache_level)
 | 
			
		||||
static void ppgtt_unbind_vma(struct i915_vma *vma)
 | 
			
		||||
{
 | 
			
		||||
	ppgtt->base.insert_entries(&ppgtt->base, obj->pages,
 | 
			
		||||
				   i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
 | 
			
		||||
				   cache_level);
 | 
			
		||||
}
 | 
			
		||||
	const unsigned long entry = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
 | 
			
		||||
			      struct drm_i915_gem_object *obj)
 | 
			
		||||
{
 | 
			
		||||
	ppgtt->base.clear_range(&ppgtt->base,
 | 
			
		||||
				i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
 | 
			
		||||
				obj->base.size >> PAGE_SHIFT,
 | 
			
		||||
	vma->vm->clear_range(vma->vm,
 | 
			
		||||
			     entry,
 | 
			
		||||
			     vma->obj->base.size >> PAGE_SHIFT,
 | 
			
		||||
			     true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -849,6 +1101,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	struct i915_address_space *vm;
 | 
			
		||||
 | 
			
		||||
	i915_check_and_clear_faults(dev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -859,8 +1112,33 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 | 
			
		|||
				       true);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
 | 
			
		||||
		struct i915_vma *vma = i915_gem_obj_to_vma(obj,
 | 
			
		||||
							   &dev_priv->gtt.base);
 | 
			
		||||
		if (!vma)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		i915_gem_clflush_object(obj, obj->pin_display);
 | 
			
		||||
		i915_gem_gtt_bind_object(obj, obj->cache_level);
 | 
			
		||||
		/* The bind_vma code tries to be smart about tracking mappings.
 | 
			
		||||
		 * Unfortunately above, we've just wiped out the mappings
 | 
			
		||||
		 * without telling our object about it. So we need to fake it.
 | 
			
		||||
		 */
 | 
			
		||||
		obj->has_global_gtt_mapping = 0;
 | 
			
		||||
		vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 8)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
 | 
			
		||||
		/* TODO: Perhaps it shouldn't be gen6 specific */
 | 
			
		||||
		if (i915_is_ggtt(vm)) {
 | 
			
		||||
			if (dev_priv->mm.aliasing_ppgtt)
 | 
			
		||||
				gen6_write_pdes(dev_priv->mm.aliasing_ppgtt);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i915_gem_chipset_flush(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1017,16 +1295,18 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
 | 
			
		|||
	readl(gtt_base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_ggtt_insert_entries(struct i915_address_space *vm,
 | 
			
		||||
				     struct sg_table *st,
 | 
			
		||||
				     unsigned int pg_start,
 | 
			
		||||
				     enum i915_cache_level cache_level)
 | 
			
		||||
 | 
			
		||||
static void i915_ggtt_bind_vma(struct i915_vma *vma,
 | 
			
		||||
			       enum i915_cache_level cache_level,
 | 
			
		||||
			       u32 unused)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned long entry = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
	unsigned int flags = (cache_level == I915_CACHE_NONE) ?
 | 
			
		||||
		AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
 | 
			
		||||
 | 
			
		||||
	intel_gtt_insert_sg_entries(st, pg_start, flags);
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!i915_is_ggtt(vma->vm));
 | 
			
		||||
	intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags);
 | 
			
		||||
	vma->obj->has_global_gtt_mapping = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_ggtt_clear_range(struct i915_address_space *vm,
 | 
			
		||||
| 
						 | 
				
			
			@ -1037,33 +1317,77 @@ static void i915_ggtt_clear_range(struct i915_address_space *vm,
 | 
			
		|||
	intel_gtt_clear_range(first_entry, num_entries);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
 | 
			
		||||
			      enum i915_cache_level cache_level)
 | 
			
		||||
static void i915_ggtt_unbind_vma(struct i915_vma *vma)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = obj->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 | 
			
		||||
	const unsigned int first = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
	const unsigned int size = vma->obj->base.size >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages,
 | 
			
		||||
					  entry,
 | 
			
		||||
					  cache_level);
 | 
			
		||||
 | 
			
		||||
	obj->has_global_gtt_mapping = 1;
 | 
			
		||||
	BUG_ON(!i915_is_ggtt(vma->vm));
 | 
			
		||||
	vma->obj->has_global_gtt_mapping = 0;
 | 
			
		||||
	intel_gtt_clear_range(first, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 | 
			
		||||
static void ggtt_bind_vma(struct i915_vma *vma,
 | 
			
		||||
			  enum i915_cache_level cache_level,
 | 
			
		||||
			  u32 flags)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = obj->base.dev;
 | 
			
		||||
	struct drm_device *dev = vma->vm->dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 | 
			
		||||
	struct drm_i915_gem_object *obj = vma->obj;
 | 
			
		||||
	const unsigned long entry = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
 | 
			
		||||
	/* If there is no aliasing PPGTT, or the caller needs a global mapping,
 | 
			
		||||
	 * or we have a global mapping already but the cacheability flags have
 | 
			
		||||
	 * changed, set the global PTEs.
 | 
			
		||||
	 *
 | 
			
		||||
	 * If there is an aliasing PPGTT it is anecdotally faster, so use that
 | 
			
		||||
	 * instead if none of the above hold true.
 | 
			
		||||
	 *
 | 
			
		||||
	 * NB: A global mapping should only be needed for special regions like
 | 
			
		||||
	 * "gtt mappable", SNB errata, or if specified via special execbuf
 | 
			
		||||
	 * flags. At all other times, the GPU will use the aliasing PPGTT.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
 | 
			
		||||
		if (!obj->has_global_gtt_mapping ||
 | 
			
		||||
		    (cache_level != obj->cache_level)) {
 | 
			
		||||
			vma->vm->insert_entries(vma->vm, obj->pages, entry,
 | 
			
		||||
						cache_level);
 | 
			
		||||
			obj->has_global_gtt_mapping = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->mm.aliasing_ppgtt &&
 | 
			
		||||
	    (!obj->has_aliasing_ppgtt_mapping ||
 | 
			
		||||
	     (cache_level != obj->cache_level))) {
 | 
			
		||||
		struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
		appgtt->base.insert_entries(&appgtt->base,
 | 
			
		||||
					    vma->obj->pages, entry, cache_level);
 | 
			
		||||
		vma->obj->has_aliasing_ppgtt_mapping = 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ggtt_unbind_vma(struct i915_vma *vma)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = vma->vm->dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_gem_object *obj = vma->obj;
 | 
			
		||||
	const unsigned long entry = vma->node.start >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (obj->has_global_gtt_mapping) {
 | 
			
		||||
		vma->vm->clear_range(vma->vm, entry,
 | 
			
		||||
				     vma->obj->base.size >> PAGE_SHIFT,
 | 
			
		||||
				     true);
 | 
			
		||||
		obj->has_global_gtt_mapping = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (obj->has_aliasing_ppgtt_mapping) {
 | 
			
		||||
		struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
 | 
			
		||||
		appgtt->base.clear_range(&appgtt->base,
 | 
			
		||||
					 entry,
 | 
			
		||||
					 obj->base.size >> PAGE_SHIFT,
 | 
			
		||||
					 true);
 | 
			
		||||
 | 
			
		||||
	obj->has_global_gtt_mapping = 0;
 | 
			
		||||
		obj->has_aliasing_ppgtt_mapping = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 | 
			
		||||
| 
						 | 
				
			
			@ -1155,21 +1479,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
 | 
			
		|||
	ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
intel_enable_ppgtt(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	if (i915_enable_ppgtt >= 0)
 | 
			
		||||
		return i915_enable_ppgtt;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_INTEL_IOMMU
 | 
			
		||||
	/* Disable ppgtt on SNB if VT-d is on. */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
 | 
			
		||||
		return false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_gem_init_global_gtt(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,26 +1487,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
 | 
			
		|||
	gtt_size = dev_priv->gtt.base.total;
 | 
			
		||||
	mappable_size = dev_priv->gtt.mappable_end;
 | 
			
		||||
 | 
			
		||||
	if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
 | 
			
		||||
		int ret;
 | 
			
		||||
 | 
			
		||||
		if (INTEL_INFO(dev)->gen <= 7) {
 | 
			
		||||
			/* PPGTT pdes are stolen from global gtt ptes, so shrink the
 | 
			
		||||
			 * aperture accordingly when using aliasing ppgtt. */
 | 
			
		||||
			gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 | 
			
		||||
 | 
			
		||||
		ret = i915_gem_init_aliasing_ppgtt(dev);
 | 
			
		||||
		if (!ret)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
 | 
			
		||||
		drm_mm_takedown(&dev_priv->gtt.base.mm);
 | 
			
		||||
		if (INTEL_INFO(dev)->gen < 8)
 | 
			
		||||
			gtt_size += GEN6_PPGTT_PD_ENTRIES*PAGE_SIZE;
 | 
			
		||||
	}
 | 
			
		||||
	i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1253,7 +1542,7 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
 | 
			
		|||
	if (bdw_gmch_ctl)
 | 
			
		||||
		bdw_gmch_ctl = 1 << bdw_gmch_ctl;
 | 
			
		||||
	if (bdw_gmch_ctl > 4) {
 | 
			
		||||
		WARN_ON(!i915_preliminary_hw_support);
 | 
			
		||||
		WARN_ON(!i915.preliminary_hw_support);
 | 
			
		||||
		return 4<<20;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1438,7 +1727,6 @@ static int i915_gmch_probe(struct drm_device *dev,
 | 
			
		|||
 | 
			
		||||
	dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
 | 
			
		||||
	dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
 | 
			
		||||
	dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(dev_priv->gtt.do_idle_maps))
 | 
			
		||||
		DRM_INFO("applying Ironlake quirks for intel_iommu\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -1493,3 +1781,62 @@ int i915_gem_gtt_init(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
 | 
			
		||||
					      struct i915_address_space *vm)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 | 
			
		||||
	if (vma == NULL)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&vma->vma_link);
 | 
			
		||||
	INIT_LIST_HEAD(&vma->mm_list);
 | 
			
		||||
	INIT_LIST_HEAD(&vma->exec_list);
 | 
			
		||||
	vma->vm = vm;
 | 
			
		||||
	vma->obj = obj;
 | 
			
		||||
 | 
			
		||||
	switch (INTEL_INFO(vm->dev)->gen) {
 | 
			
		||||
	case 8:
 | 
			
		||||
	case 7:
 | 
			
		||||
	case 6:
 | 
			
		||||
		if (i915_is_ggtt(vm)) {
 | 
			
		||||
			vma->unbind_vma = ggtt_unbind_vma;
 | 
			
		||||
			vma->bind_vma = ggtt_bind_vma;
 | 
			
		||||
		} else {
 | 
			
		||||
			vma->unbind_vma = ppgtt_unbind_vma;
 | 
			
		||||
			vma->bind_vma = ppgtt_bind_vma;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case 5:
 | 
			
		||||
	case 4:
 | 
			
		||||
	case 3:
 | 
			
		||||
	case 2:
 | 
			
		||||
		BUG_ON(!i915_is_ggtt(vm));
 | 
			
		||||
		vma->unbind_vma = i915_ggtt_unbind_vma;
 | 
			
		||||
		vma->bind_vma = i915_ggtt_bind_vma;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		BUG();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Keep GGTT vmas first to make debug easier */
 | 
			
		||||
	if (i915_is_ggtt(vm))
 | 
			
		||||
		list_add(&vma->vma_link, &obj->vma_list);
 | 
			
		||||
	else
 | 
			
		||||
		list_add_tail(&vma->vma_link, &obj->vma_list);
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct i915_vma *
 | 
			
		||||
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 | 
			
		||||
				  struct i915_address_space *vm)
 | 
			
		||||
{
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
 | 
			
		||||
	vma = i915_gem_obj_to_vma(obj, vm);
 | 
			
		||||
	if (!vma)
 | 
			
		||||
		vma = __i915_gem_vma_create(obj, vm);
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,7 +308,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (obj->pin_count || obj->framebuffer_references) {
 | 
			
		||||
	if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
 | 
			
		||||
		drm_gem_object_unreference_unlocked(&obj->base);
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -238,50 +238,61 @@ static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a)
 | 
			
		|||
 | 
			
		||||
static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
 | 
			
		||||
				  struct drm_device *dev,
 | 
			
		||||
				  struct drm_i915_error_state *error,
 | 
			
		||||
				  unsigned ring)
 | 
			
		||||
				  struct drm_i915_error_ring *ring)
 | 
			
		||||
{
 | 
			
		||||
	BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
 | 
			
		||||
	if (!error->ring[ring].valid)
 | 
			
		||||
	if (!ring->valid)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	err_printf(m, "%s command stream:\n", ring_str(ring));
 | 
			
		||||
	err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
 | 
			
		||||
	err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
 | 
			
		||||
	err_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
 | 
			
		||||
	err_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
 | 
			
		||||
	err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
 | 
			
		||||
	err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
 | 
			
		||||
	err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
 | 
			
		||||
	err_printf(m, "  HEAD: 0x%08x\n", ring->head);
 | 
			
		||||
	err_printf(m, "  TAIL: 0x%08x\n", ring->tail);
 | 
			
		||||
	err_printf(m, "  CTL: 0x%08x\n", ring->ctl);
 | 
			
		||||
	err_printf(m, "  HWS: 0x%08x\n", ring->hws);
 | 
			
		||||
	err_printf(m, "  ACTHD: 0x%08x\n", ring->acthd);
 | 
			
		||||
	err_printf(m, "  IPEIR: 0x%08x\n", ring->ipeir);
 | 
			
		||||
	err_printf(m, "  IPEHR: 0x%08x\n", ring->ipehr);
 | 
			
		||||
	err_printf(m, "  INSTDONE: 0x%08x\n", ring->instdone);
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 4) {
 | 
			
		||||
		err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr[ring]);
 | 
			
		||||
		err_printf(m, "  BB_STATE: 0x%08x\n", error->bbstate[ring]);
 | 
			
		||||
		err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
 | 
			
		||||
		err_printf(m, "  BBADDR: 0x%08llx\n", ring->bbaddr);
 | 
			
		||||
		err_printf(m, "  BB_STATE: 0x%08x\n", ring->bbstate);
 | 
			
		||||
		err_printf(m, "  INSTPS: 0x%08x\n", ring->instps);
 | 
			
		||||
	}
 | 
			
		||||
	err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
 | 
			
		||||
	err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
 | 
			
		||||
	err_printf(m, "  INSTPM: 0x%08x\n", ring->instpm);
 | 
			
		||||
	err_printf(m, "  FADDR: 0x%08x\n", ring->faddr);
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6) {
 | 
			
		||||
		err_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
 | 
			
		||||
		err_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
 | 
			
		||||
		err_printf(m, "  RC PSMI: 0x%08x\n", ring->rc_psmi);
 | 
			
		||||
		err_printf(m, "  FAULT_REG: 0x%08x\n", ring->fault_reg);
 | 
			
		||||
		err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
 | 
			
		||||
			   error->semaphore_mboxes[ring][0],
 | 
			
		||||
			   error->semaphore_seqno[ring][0]);
 | 
			
		||||
			   ring->semaphore_mboxes[0],
 | 
			
		||||
			   ring->semaphore_seqno[0]);
 | 
			
		||||
		err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
 | 
			
		||||
			   error->semaphore_mboxes[ring][1],
 | 
			
		||||
			   error->semaphore_seqno[ring][1]);
 | 
			
		||||
			   ring->semaphore_mboxes[1],
 | 
			
		||||
			   ring->semaphore_seqno[1]);
 | 
			
		||||
		if (HAS_VEBOX(dev)) {
 | 
			
		||||
			err_printf(m, "  SYNC_2: 0x%08x [last synced 0x%08x]\n",
 | 
			
		||||
				   error->semaphore_mboxes[ring][2],
 | 
			
		||||
				   error->semaphore_seqno[ring][2]);
 | 
			
		||||
				   ring->semaphore_mboxes[2],
 | 
			
		||||
				   ring->semaphore_seqno[2]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
 | 
			
		||||
	err_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
 | 
			
		||||
	err_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
 | 
			
		||||
	err_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
 | 
			
		||||
	if (USES_PPGTT(dev)) {
 | 
			
		||||
		err_printf(m, "  GFX_MODE: 0x%08x\n", ring->vm_info.gfx_mode);
 | 
			
		||||
 | 
			
		||||
		if (INTEL_INFO(dev)->gen >= 8) {
 | 
			
		||||
			int i;
 | 
			
		||||
			for (i = 0; i < 4; i++)
 | 
			
		||||
				err_printf(m, "  PDP%d: 0x%016llx\n",
 | 
			
		||||
					   i, ring->vm_info.pdp[i]);
 | 
			
		||||
		} else {
 | 
			
		||||
			err_printf(m, "  PP_DIR_BASE: 0x%08x\n",
 | 
			
		||||
				   ring->vm_info.pp_dir_base);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err_printf(m, "  seqno: 0x%08x\n", ring->seqno);
 | 
			
		||||
	err_printf(m, "  waiting: %s\n", yesno(ring->waiting));
 | 
			
		||||
	err_printf(m, "  ring->head: 0x%08x\n", ring->cpu_ring_head);
 | 
			
		||||
	err_printf(m, "  ring->tail: 0x%08x\n", ring->cpu_ring_tail);
 | 
			
		||||
	err_printf(m, "  hangcheck: %s [%d]\n",
 | 
			
		||||
		   hangcheck_action_to_str(error->hangcheck_action[ring]),
 | 
			
		||||
		   error->hangcheck_score[ring]);
 | 
			
		||||
		   hangcheck_action_to_str(ring->hangcheck_action),
 | 
			
		||||
		   ring->hangcheck_score);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
 | 
			
		||||
| 
						 | 
				
			
			@ -333,8 +344,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 | 
			
		|||
	if (INTEL_INFO(dev)->gen == 7)
 | 
			
		||||
		err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(error->ring); i++)
 | 
			
		||||
		i915_ring_error_state(m, dev, error, i);
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
 | 
			
		||||
		err_printf(m, "%s command stream:\n", ring_str(i));
 | 
			
		||||
		i915_ring_error_state(m, dev, &error->ring[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (error->active_bo)
 | 
			
		||||
		print_error_buffers(m, "Active",
 | 
			
		||||
| 
						 | 
				
			
			@ -390,6 +403,22 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((obj = error->ring[i].hws_page)) {
 | 
			
		||||
			err_printf(m, "%s --- HW Status = 0x%08x\n",
 | 
			
		||||
				   dev_priv->ring[i].name,
 | 
			
		||||
				   obj->gtt_offset);
 | 
			
		||||
			offset = 0;
 | 
			
		||||
			for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
 | 
			
		||||
				err_printf(m, "[%04x] %08x %08x %08x %08x\n",
 | 
			
		||||
					   offset,
 | 
			
		||||
					   obj->pages[0][elt],
 | 
			
		||||
					   obj->pages[0][elt+1],
 | 
			
		||||
					   obj->pages[0][elt+2],
 | 
			
		||||
					   obj->pages[0][elt+3]);
 | 
			
		||||
					offset += 16;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((obj = error->ring[i].ctx)) {
 | 
			
		||||
			err_printf(m, "%s --- HW Context = 0x%08x\n",
 | 
			
		||||
				   dev_priv->ring[i].name,
 | 
			
		||||
| 
						 | 
				
			
			@ -472,6 +501,7 @@ static void i915_error_state_free(struct kref *error_ref)
 | 
			
		|||
	for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
 | 
			
		||||
		i915_error_object_free(error->ring[i].batchbuffer);
 | 
			
		||||
		i915_error_object_free(error->ring[i].ringbuffer);
 | 
			
		||||
		i915_error_object_free(error->ring[i].hws_page);
 | 
			
		||||
		i915_error_object_free(error->ring[i].ctx);
 | 
			
		||||
		kfree(error->ring[i].requests);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -485,6 +515,7 @@ static void i915_error_state_free(struct kref *error_ref)
 | 
			
		|||
static struct drm_i915_error_object *
 | 
			
		||||
i915_error_object_create_sized(struct drm_i915_private *dev_priv,
 | 
			
		||||
			       struct drm_i915_gem_object *src,
 | 
			
		||||
			       struct i915_address_space *vm,
 | 
			
		||||
			       const int num_pages)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_error_object *dst;
 | 
			
		||||
| 
						 | 
				
			
			@ -498,7 +529,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
 | 
			
		|||
	if (dst == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src);
 | 
			
		||||
	reloc_offset = dst->gtt_offset = i915_gem_obj_offset(src, vm);
 | 
			
		||||
	for (i = 0; i < num_pages; i++) {
 | 
			
		||||
		unsigned long flags;
 | 
			
		||||
		void *d;
 | 
			
		||||
| 
						 | 
				
			
			@ -508,8 +539,10 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
 | 
			
		|||
			goto unwind;
 | 
			
		||||
 | 
			
		||||
		local_irq_save(flags);
 | 
			
		||||
		if (reloc_offset < dev_priv->gtt.mappable_end &&
 | 
			
		||||
		    src->has_global_gtt_mapping) {
 | 
			
		||||
		if (src->cache_level == I915_CACHE_NONE &&
 | 
			
		||||
		    reloc_offset < dev_priv->gtt.mappable_end &&
 | 
			
		||||
		    src->has_global_gtt_mapping &&
 | 
			
		||||
		    i915_is_ggtt(vm)) {
 | 
			
		||||
			void __iomem *s;
 | 
			
		||||
 | 
			
		||||
			/* Simply ignore tiling or any overlapping fence.
 | 
			
		||||
| 
						 | 
				
			
			@ -559,8 +592,12 @@ unwind:
 | 
			
		|||
	kfree(dst);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#define i915_error_object_create(dev_priv, src) \
 | 
			
		||||
	i915_error_object_create_sized((dev_priv), (src), \
 | 
			
		||||
#define i915_error_object_create(dev_priv, src, vm) \
 | 
			
		||||
	i915_error_object_create_sized((dev_priv), (src), (vm), \
 | 
			
		||||
				       (src)->base.size>>PAGE_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define i915_error_ggtt_object_create(dev_priv, src) \
 | 
			
		||||
	i915_error_object_create_sized((dev_priv), (src), &(dev_priv)->gtt.base, \
 | 
			
		||||
				       (src)->base.size>>PAGE_SHIFT)
 | 
			
		||||
 | 
			
		||||
static void capture_bo(struct drm_i915_error_buffer *err,
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +612,7 @@ static void capture_bo(struct drm_i915_error_buffer *err,
 | 
			
		|||
	err->write_domain = obj->base.write_domain;
 | 
			
		||||
	err->fence_reg = obj->fence_reg;
 | 
			
		||||
	err->pinned = 0;
 | 
			
		||||
	if (obj->pin_count > 0)
 | 
			
		||||
	if (i915_gem_obj_is_pinned(obj))
 | 
			
		||||
		err->pinned = 1;
 | 
			
		||||
	if (obj->user_pin_count > 0)
 | 
			
		||||
		err->pinned = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +645,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
 | 
			
		|||
	int i = 0;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(obj, head, global_list) {
 | 
			
		||||
		if (obj->pin_count == 0)
 | 
			
		||||
		if (!i915_gem_obj_is_pinned(obj))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		capture_bo(err++, obj);
 | 
			
		||||
| 
						 | 
				
			
			@ -619,6 +656,33 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
 | 
			
		|||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Generate a semi-unique error code. The code is not meant to have meaning, The
 | 
			
		||||
 * code's only purpose is to try to prevent false duplicated bug reports by
 | 
			
		||||
 * grossly estimating a GPU error state.
 | 
			
		||||
 *
 | 
			
		||||
 * TODO Ideally, hashing the batchbuffer would be a very nice way to determine
 | 
			
		||||
 * the hang if we could strip the GTT offset information from it.
 | 
			
		||||
 *
 | 
			
		||||
 * It's only a small step better than a random number in its current form.
 | 
			
		||||
 */
 | 
			
		||||
static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv,
 | 
			
		||||
					 struct drm_i915_error_state *error)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t error_code = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* IPEHR would be an ideal way to detect errors, as it's the gross
 | 
			
		||||
	 * measure of "the command that hung." However, has some very common
 | 
			
		||||
	 * synchronization commands which almost always appear in the case
 | 
			
		||||
	 * strictly a client bug. Use instdone to differentiate those some.
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < I915_NUM_RINGS; i++)
 | 
			
		||||
		if (error->ring[i].hangcheck_action == HANGCHECK_HUNG)
 | 
			
		||||
			return error->ring[i].ipehr ^ error->ring[i].instdone;
 | 
			
		||||
 | 
			
		||||
	return error_code;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_gem_record_fences(struct drm_device *dev,
 | 
			
		||||
				   struct drm_i915_error_state *error)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -652,6 +716,32 @@ static void i915_gem_record_fences(struct drm_device *dev,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This assumes all batchbuffers are executed from the PPGTT. It might have to
 | 
			
		||||
 * change in the future. */
 | 
			
		||||
static bool is_active_vm(struct i915_address_space *vm,
 | 
			
		||||
			 struct intel_ring_buffer *ring)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = vm->dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct i915_hw_ppgtt *ppgtt;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen < 7)
 | 
			
		||||
		return i915_is_ggtt(vm);
 | 
			
		||||
 | 
			
		||||
	/* FIXME: This ignores that the global gtt vm is also on this list. */
 | 
			
		||||
	ppgtt = container_of(vm, struct i915_hw_ppgtt, base);
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 8) {
 | 
			
		||||
		u64 pdp0 = (u64)I915_READ(GEN8_RING_PDP_UDW(ring, 0)) << 32;
 | 
			
		||||
		pdp0 |=  I915_READ(GEN8_RING_PDP_LDW(ring, 0));
 | 
			
		||||
		return pdp0 == ppgtt->pd_dma_addr[0];
 | 
			
		||||
	} else {
 | 
			
		||||
		u32 pp_db;
 | 
			
		||||
		pp_db = I915_READ(RING_PP_DIR_BASE(ring));
 | 
			
		||||
		return (pp_db >> 10) == ppgtt->pd_offset;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct drm_i915_error_object *
 | 
			
		||||
i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
 | 
			
		||||
			     struct intel_ring_buffer *ring)
 | 
			
		||||
| 
						 | 
				
			
			@ -659,6 +749,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
 | 
			
		|||
	struct i915_address_space *vm;
 | 
			
		||||
	struct i915_vma *vma;
 | 
			
		||||
	struct drm_i915_gem_object *obj;
 | 
			
		||||
	bool found_active = false;
 | 
			
		||||
	u32 seqno;
 | 
			
		||||
 | 
			
		||||
	if (!ring->get_seqno)
 | 
			
		||||
| 
						 | 
				
			
			@ -674,11 +765,16 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
 | 
			
		|||
		if (obj != NULL &&
 | 
			
		||||
		    acthd >= i915_gem_obj_ggtt_offset(obj) &&
 | 
			
		||||
		    acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
 | 
			
		||||
			return i915_error_object_create(dev_priv, obj);
 | 
			
		||||
			return i915_error_ggtt_object_create(dev_priv, obj);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seqno = ring->get_seqno(ring, false);
 | 
			
		||||
	list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
 | 
			
		||||
		if (!is_active_vm(vm, ring))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		found_active = true;
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(vma, &vm->active_list, mm_list) {
 | 
			
		||||
			obj = vma->obj;
 | 
			
		||||
			if (obj->ring != ring)
 | 
			
		||||
| 
						 | 
				
			
			@ -693,66 +789,120 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
 | 
			
		|||
			/* We need to copy these to an anonymous buffer as the simplest
 | 
			
		||||
			 * method to avoid being overwritten by userspace.
 | 
			
		||||
			 */
 | 
			
		||||
			return i915_error_object_create(dev_priv, obj);
 | 
			
		||||
			return i915_error_object_create(dev_priv, obj, vm);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!found_active);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_record_ring_state(struct drm_device *dev,
 | 
			
		||||
				   struct drm_i915_error_state *error,
 | 
			
		||||
				   struct intel_ring_buffer *ring)
 | 
			
		||||
				   struct intel_ring_buffer *ring,
 | 
			
		||||
				   struct drm_i915_error_ring *ering)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6) {
 | 
			
		||||
		error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50);
 | 
			
		||||
		error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
 | 
			
		||||
		error->semaphore_mboxes[ring->id][0]
 | 
			
		||||
		ering->rc_psmi = I915_READ(ring->mmio_base + 0x50);
 | 
			
		||||
		ering->fault_reg = I915_READ(RING_FAULT_REG(ring));
 | 
			
		||||
		ering->semaphore_mboxes[0]
 | 
			
		||||
			= I915_READ(RING_SYNC_0(ring->mmio_base));
 | 
			
		||||
		error->semaphore_mboxes[ring->id][1]
 | 
			
		||||
		ering->semaphore_mboxes[1]
 | 
			
		||||
			= I915_READ(RING_SYNC_1(ring->mmio_base));
 | 
			
		||||
		error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0];
 | 
			
		||||
		error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1];
 | 
			
		||||
		ering->semaphore_seqno[0] = ring->sync_seqno[0];
 | 
			
		||||
		ering->semaphore_seqno[1] = ring->sync_seqno[1];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (HAS_VEBOX(dev)) {
 | 
			
		||||
		error->semaphore_mboxes[ring->id][2] =
 | 
			
		||||
		ering->semaphore_mboxes[2] =
 | 
			
		||||
			I915_READ(RING_SYNC_2(ring->mmio_base));
 | 
			
		||||
		error->semaphore_seqno[ring->id][2] = ring->sync_seqno[2];
 | 
			
		||||
		ering->semaphore_seqno[2] = ring->sync_seqno[2];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 4) {
 | 
			
		||||
		error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
 | 
			
		||||
		error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
 | 
			
		||||
		error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
 | 
			
		||||
		error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
 | 
			
		||||
		error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
 | 
			
		||||
		error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base));
 | 
			
		||||
		ering->faddr = I915_READ(RING_DMA_FADD(ring->mmio_base));
 | 
			
		||||
		ering->ipeir = I915_READ(RING_IPEIR(ring->mmio_base));
 | 
			
		||||
		ering->ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
 | 
			
		||||
		ering->instdone = I915_READ(RING_INSTDONE(ring->mmio_base));
 | 
			
		||||
		ering->instps = I915_READ(RING_INSTPS(ring->mmio_base));
 | 
			
		||||
		ering->bbaddr = I915_READ(RING_BBADDR(ring->mmio_base));
 | 
			
		||||
		if (INTEL_INFO(dev)->gen >= 8)
 | 
			
		||||
			error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
 | 
			
		||||
		error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base));
 | 
			
		||||
			ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
 | 
			
		||||
		ering->bbstate = I915_READ(RING_BBSTATE(ring->mmio_base));
 | 
			
		||||
	} else {
 | 
			
		||||
		error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
 | 
			
		||||
		error->ipeir[ring->id] = I915_READ(IPEIR);
 | 
			
		||||
		error->ipehr[ring->id] = I915_READ(IPEHR);
 | 
			
		||||
		error->instdone[ring->id] = I915_READ(INSTDONE);
 | 
			
		||||
		ering->faddr = I915_READ(DMA_FADD_I8XX);
 | 
			
		||||
		ering->ipeir = I915_READ(IPEIR);
 | 
			
		||||
		ering->ipehr = I915_READ(IPEHR);
 | 
			
		||||
		ering->instdone = I915_READ(INSTDONE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
 | 
			
		||||
	error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
 | 
			
		||||
	error->seqno[ring->id] = ring->get_seqno(ring, false);
 | 
			
		||||
	error->acthd[ring->id] = intel_ring_get_active_head(ring);
 | 
			
		||||
	error->head[ring->id] = I915_READ_HEAD(ring);
 | 
			
		||||
	error->tail[ring->id] = I915_READ_TAIL(ring);
 | 
			
		||||
	error->ctl[ring->id] = I915_READ_CTL(ring);
 | 
			
		||||
	ering->waiting = waitqueue_active(&ring->irq_queue);
 | 
			
		||||
	ering->instpm = I915_READ(RING_INSTPM(ring->mmio_base));
 | 
			
		||||
	ering->seqno = ring->get_seqno(ring, false);
 | 
			
		||||
	ering->acthd = intel_ring_get_active_head(ring);
 | 
			
		||||
	ering->head = I915_READ_HEAD(ring);
 | 
			
		||||
	ering->tail = I915_READ_TAIL(ring);
 | 
			
		||||
	ering->ctl = I915_READ_CTL(ring);
 | 
			
		||||
 | 
			
		||||
	error->cpu_ring_head[ring->id] = ring->head;
 | 
			
		||||
	error->cpu_ring_tail[ring->id] = ring->tail;
 | 
			
		||||
	if (I915_NEED_GFX_HWS(dev)) {
 | 
			
		||||
		int mmio;
 | 
			
		||||
 | 
			
		||||
	error->hangcheck_score[ring->id] = ring->hangcheck.score;
 | 
			
		||||
	error->hangcheck_action[ring->id] = ring->hangcheck.action;
 | 
			
		||||
		if (IS_GEN7(dev)) {
 | 
			
		||||
			switch (ring->id) {
 | 
			
		||||
			default:
 | 
			
		||||
			case RCS:
 | 
			
		||||
				mmio = RENDER_HWS_PGA_GEN7;
 | 
			
		||||
				break;
 | 
			
		||||
			case BCS:
 | 
			
		||||
				mmio = BLT_HWS_PGA_GEN7;
 | 
			
		||||
				break;
 | 
			
		||||
			case VCS:
 | 
			
		||||
				mmio = BSD_HWS_PGA_GEN7;
 | 
			
		||||
				break;
 | 
			
		||||
			case VECS:
 | 
			
		||||
				mmio = VEBOX_HWS_PGA_GEN7;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (IS_GEN6(ring->dev)) {
 | 
			
		||||
			mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* XXX: gen8 returns to sanity */
 | 
			
		||||
			mmio = RING_HWS_PGA(ring->mmio_base);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ering->hws = I915_READ(mmio);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ering->cpu_ring_head = ring->head;
 | 
			
		||||
	ering->cpu_ring_tail = ring->tail;
 | 
			
		||||
 | 
			
		||||
	ering->hangcheck_score = ring->hangcheck.score;
 | 
			
		||||
	ering->hangcheck_action = ring->hangcheck.action;
 | 
			
		||||
 | 
			
		||||
	if (USES_PPGTT(dev)) {
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring));
 | 
			
		||||
 | 
			
		||||
		switch (INTEL_INFO(dev)->gen) {
 | 
			
		||||
		case 8:
 | 
			
		||||
			for (i = 0; i < 4; i++) {
 | 
			
		||||
				ering->vm_info.pdp[i] =
 | 
			
		||||
					I915_READ(GEN8_RING_PDP_UDW(ring, i));
 | 
			
		||||
				ering->vm_info.pdp[i] <<= 32;
 | 
			
		||||
				ering->vm_info.pdp[i] |=
 | 
			
		||||
					I915_READ(GEN8_RING_PDP_LDW(ring, i));
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case 7:
 | 
			
		||||
			ering->vm_info.pp_dir_base = RING_PP_DIR_BASE(ring);
 | 
			
		||||
			break;
 | 
			
		||||
		case 6:
 | 
			
		||||
			ering->vm_info.pp_dir_base = RING_PP_DIR_BASE_READ(ring);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -770,7 +920,9 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
 | 
			
		|||
	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
 | 
			
		||||
		if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) {
 | 
			
		||||
			ering->ctx = i915_error_object_create_sized(dev_priv,
 | 
			
		||||
								    obj, 1);
 | 
			
		||||
								    obj,
 | 
			
		||||
								    &dev_priv->gtt.base,
 | 
			
		||||
								    1);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -791,14 +943,17 @@ static void i915_gem_record_rings(struct drm_device *dev,
 | 
			
		|||
 | 
			
		||||
		error->ring[i].valid = true;
 | 
			
		||||
 | 
			
		||||
		i915_record_ring_state(dev, error, ring);
 | 
			
		||||
		i915_record_ring_state(dev, ring, &error->ring[i]);
 | 
			
		||||
 | 
			
		||||
		error->ring[i].batchbuffer =
 | 
			
		||||
			i915_error_first_batchbuffer(dev_priv, ring);
 | 
			
		||||
 | 
			
		||||
		error->ring[i].ringbuffer =
 | 
			
		||||
			i915_error_object_create(dev_priv, ring->obj);
 | 
			
		||||
			i915_error_ggtt_object_create(dev_priv, ring->obj);
 | 
			
		||||
 | 
			
		||||
		if (ring->status_page.obj)
 | 
			
		||||
			error->ring[i].hws_page =
 | 
			
		||||
				i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
 | 
			
		||||
 | 
			
		||||
		i915_gem_record_active_context(ring, error, &error->ring[i]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -845,7 +1000,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
 | 
			
		|||
		i++;
 | 
			
		||||
	error->active_bo_count[ndx] = i;
 | 
			
		||||
	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
 | 
			
		||||
		if (obj->pin_count)
 | 
			
		||||
		if (i915_gem_obj_is_pinned(obj))
 | 
			
		||||
			i++;
 | 
			
		||||
	error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -879,11 +1034,6 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
 | 
			
		|||
	list_for_each_entry(vm, &dev_priv->vm_list, global_link)
 | 
			
		||||
		cnt++;
 | 
			
		||||
 | 
			
		||||
	if (WARN(cnt > 1, "Multiple VMs not yet supported\n"))
 | 
			
		||||
		cnt = 1;
 | 
			
		||||
 | 
			
		||||
	vm = &dev_priv->gtt.base;
 | 
			
		||||
 | 
			
		||||
	error->active_bo = kcalloc(cnt, sizeof(*error->active_bo), GFP_ATOMIC);
 | 
			
		||||
	error->pinned_bo = kcalloc(cnt, sizeof(*error->pinned_bo), GFP_ATOMIC);
 | 
			
		||||
	error->active_bo_count = kcalloc(cnt, sizeof(*error->active_bo_count),
 | 
			
		||||
| 
						 | 
				
			
			@ -895,6 +1045,74 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
 | 
			
		|||
		i915_gem_capture_vm(dev_priv, error, vm, i++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Capture all registers which don't fit into another category. */
 | 
			
		||||
static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
 | 
			
		||||
				   struct drm_i915_error_state *error)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = dev_priv->dev;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	/* General organization
 | 
			
		||||
	 * 1. Registers specific to a single generation
 | 
			
		||||
	 * 2. Registers which belong to multiple generations
 | 
			
		||||
	 * 3. Feature specific registers.
 | 
			
		||||
	 * 4. Everything else
 | 
			
		||||
	 * Please try to follow the order.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* 1: Registers specific to a single generation */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev)) {
 | 
			
		||||
		error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE_VLV);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN7(dev))
 | 
			
		||||
		error->err_int = I915_READ(GEN7_ERR_INT);
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN6(dev)) {
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE);
 | 
			
		||||
		error->gab_ctl = I915_READ(GAB_CTL);
 | 
			
		||||
		error->gfx_mode = I915_READ(GFX_MODE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN2(dev))
 | 
			
		||||
		error->ier = I915_READ16(IER);
 | 
			
		||||
 | 
			
		||||
	/* 2: Registers which belong to multiple generations */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 7)
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE_MT);
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6) {
 | 
			
		||||
		error->derrmr = I915_READ(DERRMR);
 | 
			
		||||
		error->error = I915_READ(ERROR_GEN6);
 | 
			
		||||
		error->done_reg = I915_READ(DONE_REG);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 3: Feature specific registers */
 | 
			
		||||
	if (IS_GEN6(dev) || IS_GEN7(dev)) {
 | 
			
		||||
		error->gam_ecochk = I915_READ(GAM_ECOCHK);
 | 
			
		||||
		error->gac_eco = I915_READ(GAC_ECO_BITS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 4: Everything else */
 | 
			
		||||
	if (HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		error->ccid = I915_READ(CCID);
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_SPLIT(dev))
 | 
			
		||||
		error->ier = I915_READ(DEIER) | I915_READ(GTIER);
 | 
			
		||||
	else {
 | 
			
		||||
		error->ier = I915_READ(IER);
 | 
			
		||||
		for_each_pipe(pipe)
 | 
			
		||||
			error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 4: Everything else */
 | 
			
		||||
	error->eir = I915_READ(EIR);
 | 
			
		||||
	error->pgtbl_er = I915_READ(PGTBL_ER);
 | 
			
		||||
 | 
			
		||||
	i915_get_extra_instdone(dev, error->extra_instdone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * i915_capture_error_state - capture an error record for later analysis
 | 
			
		||||
 * @dev: drm device
 | 
			
		||||
| 
						 | 
				
			
			@ -906,10 +1124,11 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
 | 
			
		|||
 */
 | 
			
		||||
void i915_capture_error_state(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	static bool warned;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_error_state *error;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	int pipe;
 | 
			
		||||
	uint32_t ecode;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
 | 
			
		||||
	error = dev_priv->gpu_error.first_error;
 | 
			
		||||
| 
						 | 
				
			
			@ -926,54 +1145,23 @@ void i915_capture_error_state(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n",
 | 
			
		||||
		 dev->primary->index);
 | 
			
		||||
	kref_init(&error->ref);
 | 
			
		||||
 | 
			
		||||
	i915_capture_reg_state(dev_priv, error);
 | 
			
		||||
	i915_gem_capture_buffers(dev_priv, error);
 | 
			
		||||
	i915_gem_record_fences(dev, error);
 | 
			
		||||
	i915_gem_record_rings(dev, error);
 | 
			
		||||
	ecode = i915_error_generate_code(dev_priv, error);
 | 
			
		||||
 | 
			
		||||
	if (!warned) {
 | 
			
		||||
		DRM_INFO("GPU HANG [%x]\n", ecode);
 | 
			
		||||
		DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n");
 | 
			
		||||
		DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n");
 | 
			
		||||
		DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n");
 | 
			
		||||
		DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n");
 | 
			
		||||
 | 
			
		||||
	kref_init(&error->ref);
 | 
			
		||||
	error->eir = I915_READ(EIR);
 | 
			
		||||
	error->pgtbl_er = I915_READ(PGTBL_ER);
 | 
			
		||||
	if (HAS_HW_CONTEXTS(dev))
 | 
			
		||||
		error->ccid = I915_READ(CCID);
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_SPLIT(dev))
 | 
			
		||||
		error->ier = I915_READ(DEIER) | I915_READ(GTIER);
 | 
			
		||||
	else if (IS_VALLEYVIEW(dev))
 | 
			
		||||
		error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
 | 
			
		||||
	else if (IS_GEN2(dev))
 | 
			
		||||
		error->ier = I915_READ16(IER);
 | 
			
		||||
	else
 | 
			
		||||
		error->ier = I915_READ(IER);
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6)
 | 
			
		||||
		error->derrmr = I915_READ(DERRMR);
 | 
			
		||||
 | 
			
		||||
	if (IS_VALLEYVIEW(dev))
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE_VLV);
 | 
			
		||||
	else if (INTEL_INFO(dev)->gen >= 7)
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE_MT);
 | 
			
		||||
	else if (INTEL_INFO(dev)->gen == 6)
 | 
			
		||||
		error->forcewake = I915_READ(FORCEWAKE);
 | 
			
		||||
 | 
			
		||||
	if (!HAS_PCH_SPLIT(dev))
 | 
			
		||||
		for_each_pipe(pipe)
 | 
			
		||||
			error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 6) {
 | 
			
		||||
		error->error = I915_READ(ERROR_GEN6);
 | 
			
		||||
		error->done_reg = I915_READ(DONE_REG);
 | 
			
		||||
		warned = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 7)
 | 
			
		||||
		error->err_int = I915_READ(GEN7_ERR_INT);
 | 
			
		||||
 | 
			
		||||
	i915_get_extra_instdone(dev, error->extra_instdone);
 | 
			
		||||
 | 
			
		||||
	i915_gem_capture_buffers(dev_priv, error);
 | 
			
		||||
	i915_gem_record_fences(dev, error);
 | 
			
		||||
	i915_gem_record_rings(dev, error);
 | 
			
		||||
 | 
			
		||||
	do_gettimeofday(&error->time);
 | 
			
		||||
 | 
			
		||||
	error->overlay = intel_overlay_capture_error_state(dev);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	u32 reg = PIPESTAT(pipe);
 | 
			
		||||
	u32 pipestat = I915_READ(reg) & 0x7fff0000;
 | 
			
		||||
 | 
			
		||||
	assert_spin_locked(&dev_priv->irq_lock);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
 | 
			
		||||
	POSTING_READ(reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
 | 
			
		||||
						 enum pipe pipe, bool enable)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +405,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 | 
			
		|||
 | 
			
		||||
	intel_crtc->cpu_fifo_underrun_disabled = !enable;
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN5(dev) || IS_GEN6(dev))
 | 
			
		||||
	if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
 | 
			
		||||
		i9xx_clear_fifo_underrun(dev, pipe);
 | 
			
		||||
	else if (IS_GEN5(dev) || IS_GEN6(dev))
 | 
			
		||||
		ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
 | 
			
		||||
	else if (IS_GEN7(dev))
 | 
			
		||||
		ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
 | 
			
		||||
| 
						 | 
				
			
			@ -915,6 +929,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
 | 
			
		|||
		drm_kms_helper_hotplug_event(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	del_timer_sync(&dev_priv->hotplug_reenable_timer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -966,6 +985,43 @@ static void notify_ring(struct drm_device *dev,
 | 
			
		|||
	i915_queue_hangcheck(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
 | 
			
		||||
			     u32 pm_iir, int new_delay)
 | 
			
		||||
{
 | 
			
		||||
	if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
 | 
			
		||||
		if (new_delay >= dev_priv->rps.max_delay) {
 | 
			
		||||
			/* Mask UP THRESHOLD Interrupts */
 | 
			
		||||
			I915_WRITE(GEN6_PMINTRMSK,
 | 
			
		||||
				   I915_READ(GEN6_PMINTRMSK) |
 | 
			
		||||
				   GEN6_PM_RP_UP_THRESHOLD);
 | 
			
		||||
			dev_priv->rps.rp_up_masked = true;
 | 
			
		||||
		}
 | 
			
		||||
		if (dev_priv->rps.rp_down_masked) {
 | 
			
		||||
			/* UnMask DOWN THRESHOLD Interrupts */
 | 
			
		||||
			I915_WRITE(GEN6_PMINTRMSK,
 | 
			
		||||
				   I915_READ(GEN6_PMINTRMSK) &
 | 
			
		||||
				   ~GEN6_PM_RP_DOWN_THRESHOLD);
 | 
			
		||||
			dev_priv->rps.rp_down_masked = false;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
 | 
			
		||||
		if (new_delay <= dev_priv->rps.min_delay) {
 | 
			
		||||
			/* Mask DOWN THRESHOLD Interrupts */
 | 
			
		||||
			I915_WRITE(GEN6_PMINTRMSK,
 | 
			
		||||
				   I915_READ(GEN6_PMINTRMSK) |
 | 
			
		||||
				   GEN6_PM_RP_DOWN_THRESHOLD);
 | 
			
		||||
			dev_priv->rps.rp_down_masked = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dev_priv->rps.rp_up_masked) {
 | 
			
		||||
			/* UnMask UP THRESHOLD Interrupts */
 | 
			
		||||
			I915_WRITE(GEN6_PMINTRMSK,
 | 
			
		||||
				   I915_READ(GEN6_PMINTRMSK) &
 | 
			
		||||
				   ~GEN6_PM_RP_UP_THRESHOLD);
 | 
			
		||||
			dev_priv->rps.rp_up_masked = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gen6_pm_rps_work(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,6 +1079,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
 | 
			
		|||
	 */
 | 
			
		||||
	new_delay = clamp_t(int, new_delay,
 | 
			
		||||
			    dev_priv->rps.min_delay, dev_priv->rps.max_delay);
 | 
			
		||||
 | 
			
		||||
	gen6_set_pm_mask(dev_priv, pm_iir, new_delay);
 | 
			
		||||
	dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
 | 
			
		||||
 | 
			
		||||
	if (IS_VALLEYVIEW(dev_priv->dev))
 | 
			
		||||
| 
						 | 
				
			
			@ -1236,6 +1294,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 | 
			
		|||
	if (!hotplug_trigger)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 | 
			
		||||
			  hotplug_trigger);
 | 
			
		||||
 | 
			
		||||
	spin_lock(&dev_priv->irq_lock);
 | 
			
		||||
	for (i = 1; i < HPD_NUM_PINS; i++) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1415,17 +1476,52 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	u32 pipe_stats[I915_MAX_PIPES];
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&dev_priv->irq_lock);
 | 
			
		||||
	for_each_pipe(pipe) {
 | 
			
		||||
		int reg = PIPESTAT(pipe);
 | 
			
		||||
		pipe_stats[pipe] = I915_READ(reg);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Clear the PIPE*STAT regs before the IIR
 | 
			
		||||
		 */
 | 
			
		||||
		if (pipe_stats[pipe] & 0x8000ffff)
 | 
			
		||||
			I915_WRITE(reg, pipe_stats[pipe]);
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock(&dev_priv->irq_lock);
 | 
			
		||||
 | 
			
		||||
	for_each_pipe(pipe) {
 | 
			
		||||
		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
 | 
			
		||||
			drm_handle_vblank(dev, pipe);
 | 
			
		||||
 | 
			
		||||
		if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
 | 
			
		||||
			intel_prepare_page_flip(dev, pipe);
 | 
			
		||||
			intel_finish_page_flip(dev, pipe);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 | 
			
		||||
			i9xx_pipe_crc_irq_handler(dev, pipe);
 | 
			
		||||
 | 
			
		||||
		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
 | 
			
		||||
		    intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
 | 
			
		||||
			DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
 | 
			
		||||
		gmbus_irq_handler(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = (struct drm_device *) arg;
 | 
			
		||||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	u32 iir, gt_iir, pm_iir;
 | 
			
		||||
	irqreturn_t ret = IRQ_NONE;
 | 
			
		||||
	unsigned long irqflags;
 | 
			
		||||
	int pipe;
 | 
			
		||||
	u32 pipe_stats[I915_MAX_PIPES];
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		iir = I915_READ(VLV_IIR);
 | 
			
		||||
| 
						 | 
				
			
			@ -1439,44 +1535,13 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 | 
			
		|||
 | 
			
		||||
		snb_gt_irq_handler(dev, dev_priv, gt_iir);
 | 
			
		||||
 | 
			
		||||
		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
		for_each_pipe(pipe) {
 | 
			
		||||
			int reg = PIPESTAT(pipe);
 | 
			
		||||
			pipe_stats[pipe] = I915_READ(reg);
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * Clear the PIPE*STAT regs before the IIR
 | 
			
		||||
			 */
 | 
			
		||||
			if (pipe_stats[pipe] & 0x8000ffff) {
 | 
			
		||||
				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
 | 
			
		||||
					DRM_DEBUG_DRIVER("pipe %c underrun\n",
 | 
			
		||||
							 pipe_name(pipe));
 | 
			
		||||
				I915_WRITE(reg, pipe_stats[pipe]);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
 | 
			
		||||
		for_each_pipe(pipe) {
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
 | 
			
		||||
				drm_handle_vblank(dev, pipe);
 | 
			
		||||
 | 
			
		||||
			if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
 | 
			
		||||
				intel_prepare_page_flip(dev, pipe);
 | 
			
		||||
				intel_finish_page_flip(dev, pipe);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 | 
			
		||||
				i9xx_pipe_crc_irq_handler(dev, pipe);
 | 
			
		||||
		}
 | 
			
		||||
		valleyview_pipestat_irq_handler(dev, iir);
 | 
			
		||||
 | 
			
		||||
		/* Consume port.  Then clear IIR or we'll miss events */
 | 
			
		||||
		if (iir & I915_DISPLAY_PORT_INTERRUPT) {
 | 
			
		||||
			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
 | 
			
		||||
			u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 | 
			
		||||
 | 
			
		||||
			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 | 
			
		||||
					 hotplug_status);
 | 
			
		||||
 | 
			
		||||
			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 | 
			
		||||
 | 
			
		||||
			if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
 | 
			
		||||
| 
						 | 
				
			
			@ -1486,8 +1551,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 | 
			
		|||
			I915_READ(PORT_HOTPLUG_STAT);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
 | 
			
		||||
			gmbus_irq_handler(dev);
 | 
			
		||||
 | 
			
		||||
		if (pm_iir)
 | 
			
		||||
			gen6_rps_irq_handler(dev_priv, pm_iir);
 | 
			
		||||
| 
						 | 
				
			
			@ -1546,12 +1609,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 | 
			
		|||
	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
 | 
			
		||||
		if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
 | 
			
		||||
							  false))
 | 
			
		||||
			DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
 | 
			
		||||
			DRM_ERROR("PCH transcoder A FIFO underrun\n");
 | 
			
		||||
 | 
			
		||||
	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
 | 
			
		||||
		if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
 | 
			
		||||
							  false))
 | 
			
		||||
			DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
 | 
			
		||||
			DRM_ERROR("PCH transcoder B FIFO underrun\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ivb_err_int_handler(struct drm_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -1567,7 +1630,7 @@ static void ivb_err_int_handler(struct drm_device *dev)
 | 
			
		|||
		if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
 | 
			
		||||
			if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
 | 
			
		||||
								  false))
 | 
			
		||||
				DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
 | 
			
		||||
				DRM_ERROR("Pipe %c FIFO underrun\n",
 | 
			
		||||
					  pipe_name(pipe));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1593,17 +1656,17 @@ static void cpt_serr_int_handler(struct drm_device *dev)
 | 
			
		|||
	if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
 | 
			
		||||
		if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
 | 
			
		||||
							  false))
 | 
			
		||||
			DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
 | 
			
		||||
			DRM_ERROR("PCH transcoder A FIFO underrun\n");
 | 
			
		||||
 | 
			
		||||
	if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
 | 
			
		||||
		if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
 | 
			
		||||
							  false))
 | 
			
		||||
			DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
 | 
			
		||||
			DRM_ERROR("PCH transcoder B FIFO underrun\n");
 | 
			
		||||
 | 
			
		||||
	if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
 | 
			
		||||
		if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
 | 
			
		||||
							  false))
 | 
			
		||||
			DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
 | 
			
		||||
			DRM_ERROR("PCH transcoder C FIFO underrun\n");
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(SERR_INT, serr_int);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1665,7 +1728,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 | 
			
		|||
 | 
			
		||||
		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
 | 
			
		||||
			if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
 | 
			
		||||
				DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
 | 
			
		||||
				DRM_ERROR("Pipe %c FIFO underrun\n",
 | 
			
		||||
					  pipe_name(pipe));
 | 
			
		||||
 | 
			
		||||
		if (de_iir & DE_PIPE_CRC_DONE(pipe))
 | 
			
		||||
| 
						 | 
				
			
			@ -1738,8 +1801,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 | 
			
		|||
	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
 | 
			
		||||
	irqreturn_t ret = IRQ_NONE;
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	/* We get interrupts on unclaimed registers, so check for this before we
 | 
			
		||||
	 * do any I915_{READ,WRITE}. */
 | 
			
		||||
	intel_uncore_check_errors(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -1808,8 +1869,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 | 
			
		|||
	uint32_t tmp = 0;
 | 
			
		||||
	enum pipe pipe;
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	master_ctl = I915_READ(GEN8_MASTER_IRQ);
 | 
			
		||||
	master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
 | 
			
		||||
	if (!master_ctl)
 | 
			
		||||
| 
						 | 
				
			
			@ -1871,7 +1930,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 | 
			
		|||
		if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
 | 
			
		||||
			if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
 | 
			
		||||
								  false))
 | 
			
		||||
				DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
 | 
			
		||||
				DRM_ERROR("Pipe %c FIFO underrun\n",
 | 
			
		||||
					  pipe_name(pipe));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2244,18 +2303,11 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 | 
			
		|||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	unsigned long irqflags;
 | 
			
		||||
	u32 imr;
 | 
			
		||||
 | 
			
		||||
	if (!i915_pipe_enabled(dev, pipe))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
	imr = I915_READ(VLV_IMR);
 | 
			
		||||
	if (pipe == PIPE_A)
 | 
			
		||||
		imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
 | 
			
		||||
	else
 | 
			
		||||
		imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 | 
			
		||||
	I915_WRITE(VLV_IMR, imr);
 | 
			
		||||
	i915_enable_pipestat(dev_priv, pipe,
 | 
			
		||||
			     PIPE_START_VBLANK_INTERRUPT_ENABLE);
 | 
			
		||||
	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
| 
						 | 
				
			
			@ -2313,17 +2365,10 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
 | 
			
		|||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	unsigned long irqflags;
 | 
			
		||||
	u32 imr;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
	i915_disable_pipestat(dev_priv, pipe,
 | 
			
		||||
			      PIPE_START_VBLANK_INTERRUPT_ENABLE);
 | 
			
		||||
	imr = I915_READ(VLV_IMR);
 | 
			
		||||
	if (pipe == PIPE_A)
 | 
			
		||||
		imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
 | 
			
		||||
	else
 | 
			
		||||
		imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 | 
			
		||||
	I915_WRITE(VLV_IMR, imr);
 | 
			
		||||
	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2479,9 +2524,8 @@ static void i915_hangcheck_elapsed(unsigned long data)
 | 
			
		|||
#define BUSY 1
 | 
			
		||||
#define KICK 5
 | 
			
		||||
#define HUNG 20
 | 
			
		||||
#define FIRE 30
 | 
			
		||||
 | 
			
		||||
	if (!i915_enable_hangcheck)
 | 
			
		||||
	if (!i915.enable_hangcheck)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2563,7 +2607,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_ring(ring, dev_priv, i) {
 | 
			
		||||
		if (ring->hangcheck.score > FIRE) {
 | 
			
		||||
		if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
 | 
			
		||||
			DRM_INFO("%s on %s\n",
 | 
			
		||||
				 stuck[i] ? "stuck" : "no progress",
 | 
			
		||||
				 ring->name);
 | 
			
		||||
| 
						 | 
				
			
			@ -2583,7 +2627,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 | 
			
		|||
void i915_queue_hangcheck(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	if (!i915_enable_hangcheck)
 | 
			
		||||
	if (!i915.enable_hangcheck)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mod_timer(&dev_priv->gpu_error.hangcheck_timer,
 | 
			
		||||
| 
						 | 
				
			
			@ -2632,8 +2676,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(HWSTAM, 0xeffe);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(DEIMR, 0xffffffff);
 | 
			
		||||
| 
						 | 
				
			
			@ -2650,8 +2692,6 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
 | 
			
		|||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	/* VLV magic */
 | 
			
		||||
	I915_WRITE(VLV_IMR, 0);
 | 
			
		||||
	I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -2681,8 +2721,6 @@ static void gen8_irq_preinstall(struct drm_device *dev)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(GEN8_MASTER_IRQ, 0);
 | 
			
		||||
	POSTING_READ(GEN8_MASTER_IRQ);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3007,8 +3045,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
 | 
			
		|||
	if (!dev_priv)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(GEN8_MASTER_IRQ, 0);
 | 
			
		||||
 | 
			
		||||
#define GEN8_IRQ_FINI_NDX(type, which) do { \
 | 
			
		||||
| 
						 | 
				
			
			@ -3049,7 +3085,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
 | 
			
		|||
	if (!dev_priv)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	del_timer_sync(&dev_priv->hotplug_reenable_timer);
 | 
			
		||||
	intel_hpd_irq_uninstall(dev_priv);
 | 
			
		||||
 | 
			
		||||
	for_each_pipe(pipe)
 | 
			
		||||
		I915_WRITE(PIPESTAT(pipe), 0xffff);
 | 
			
		||||
| 
						 | 
				
			
			@ -3072,7 +3108,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
 | 
			
		|||
	if (!dev_priv)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	del_timer_sync(&dev_priv->hotplug_reenable_timer);
 | 
			
		||||
	intel_hpd_irq_uninstall(dev_priv);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(HWSTAM, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3101,8 +3137,6 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
 | 
			
		|||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	for_each_pipe(pipe)
 | 
			
		||||
		I915_WRITE(PIPESTAT(pipe), 0);
 | 
			
		||||
	I915_WRITE16(IMR, 0xffff);
 | 
			
		||||
| 
						 | 
				
			
			@ -3187,8 +3221,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 | 
			
		|||
		I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
 | 
			
		||||
		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	iir = I915_READ16(IIR);
 | 
			
		||||
	if (iir == 0)
 | 
			
		||||
		return IRQ_NONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -3210,13 +3242,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 | 
			
		|||
			/*
 | 
			
		||||
			 * Clear the PIPE*STAT regs before the IIR
 | 
			
		||||
			 */
 | 
			
		||||
			if (pipe_stats[pipe] & 0x8000ffff) {
 | 
			
		||||
				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
 | 
			
		||||
					DRM_DEBUG_DRIVER("pipe %c underrun\n",
 | 
			
		||||
							 pipe_name(pipe));
 | 
			
		||||
			if (pipe_stats[pipe] & 0x8000ffff)
 | 
			
		||||
				I915_WRITE(reg, pipe_stats[pipe]);
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
 | 
			
		||||
		I915_WRITE16(IIR, iir & ~flip_mask);
 | 
			
		||||
| 
						 | 
				
			
			@ -3238,6 +3266,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 | 
			
		|||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 | 
			
		||||
				i9xx_pipe_crc_irq_handler(dev, pipe);
 | 
			
		||||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
 | 
			
		||||
			    intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
 | 
			
		||||
				DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iir = new_iir;
 | 
			
		||||
| 
						 | 
				
			
			@ -3266,8 +3298,6 @@ static void i915_irq_preinstall(struct drm_device * dev)
 | 
			
		|||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	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));
 | 
			
		||||
| 
						 | 
				
			
			@ -3373,8 +3403,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 | 
			
		|||
		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 | 
			
		||||
	int pipe, ret = IRQ_NONE;
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	iir = I915_READ(IIR);
 | 
			
		||||
	do {
 | 
			
		||||
		bool irq_received = (iir & ~flip_mask) != 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3395,9 +3423,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 | 
			
		|||
 | 
			
		||||
			/* Clear the PIPE*STAT regs before the IIR */
 | 
			
		||||
			if (pipe_stats[pipe] & 0x8000ffff) {
 | 
			
		||||
				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
 | 
			
		||||
					DRM_DEBUG_DRIVER("pipe %c underrun\n",
 | 
			
		||||
							 pipe_name(pipe));
 | 
			
		||||
				I915_WRITE(reg, pipe_stats[pipe]);
 | 
			
		||||
				irq_received = true;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -3413,9 +3438,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 | 
			
		|||
			u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
 | 
			
		||||
			u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 | 
			
		||||
 | 
			
		||||
			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 | 
			
		||||
				  hotplug_status);
 | 
			
		||||
 | 
			
		||||
			intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 | 
			
		||||
 | 
			
		||||
			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 | 
			
		||||
| 
						 | 
				
			
			@ -3442,6 +3464,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 | 
			
		|||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 | 
			
		||||
				i9xx_pipe_crc_irq_handler(dev, pipe);
 | 
			
		||||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
 | 
			
		||||
			    intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
 | 
			
		||||
				DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (blc_event || (iir & I915_ASLE_INTERRUPT))
 | 
			
		||||
| 
						 | 
				
			
			@ -3476,7 +3502,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
 | 
			
		|||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	del_timer_sync(&dev_priv->hotplug_reenable_timer);
 | 
			
		||||
	intel_hpd_irq_uninstall(dev_priv);
 | 
			
		||||
 | 
			
		||||
	if (I915_HAS_HOTPLUG(dev)) {
 | 
			
		||||
		I915_WRITE(PORT_HOTPLUG_EN, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -3500,8 +3526,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
 | 
			
		|||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 | 
			
		||||
	int pipe;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&dev_priv->irq_received, 0);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(PORT_HOTPLUG_EN, 0);
 | 
			
		||||
	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3610,21 +3634,17 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 | 
			
		|||
	u32 iir, new_iir;
 | 
			
		||||
	u32 pipe_stats[I915_MAX_PIPES];
 | 
			
		||||
	unsigned long irqflags;
 | 
			
		||||
	int irq_received;
 | 
			
		||||
	int ret = IRQ_NONE, pipe;
 | 
			
		||||
	u32 flip_mask =
 | 
			
		||||
		I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
 | 
			
		||||
		I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&dev_priv->irq_received);
 | 
			
		||||
 | 
			
		||||
	iir = I915_READ(IIR);
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		bool irq_received = (iir & ~flip_mask) != 0;
 | 
			
		||||
		bool blc_event = false;
 | 
			
		||||
 | 
			
		||||
		irq_received = (iir & ~flip_mask) != 0;
 | 
			
		||||
 | 
			
		||||
		/* Can't rely on pipestat interrupt bit in iir as it might
 | 
			
		||||
		 * have been cleared after the pipestat interrupt was received.
 | 
			
		||||
		 * It doesn't set the bit in iir again, but it still produces
 | 
			
		||||
| 
						 | 
				
			
			@ -3642,11 +3662,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 | 
			
		|||
			 * Clear the PIPE*STAT regs before the IIR
 | 
			
		||||
			 */
 | 
			
		||||
			if (pipe_stats[pipe] & 0x8000ffff) {
 | 
			
		||||
				if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
 | 
			
		||||
					DRM_DEBUG_DRIVER("pipe %c underrun\n",
 | 
			
		||||
							 pipe_name(pipe));
 | 
			
		||||
				I915_WRITE(reg, pipe_stats[pipe]);
 | 
			
		||||
				irq_received = 1;
 | 
			
		||||
				irq_received = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 | 
			
		||||
| 
						 | 
				
			
			@ -3663,9 +3680,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 | 
			
		|||
								  HOTPLUG_INT_STATUS_G4X :
 | 
			
		||||
								  HOTPLUG_INT_STATUS_I915);
 | 
			
		||||
 | 
			
		||||
			DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
 | 
			
		||||
				  hotplug_status);
 | 
			
		||||
 | 
			
		||||
			intel_hpd_irq_handler(dev, hotplug_trigger,
 | 
			
		||||
					      IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3695,8 +3709,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 | 
			
		|||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
 | 
			
		||||
				i9xx_pipe_crc_irq_handler(dev, pipe);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
 | 
			
		||||
			    intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
 | 
			
		||||
				DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (blc_event || (iir & I915_ASLE_INTERRUPT))
 | 
			
		||||
			intel_opregion_asle_intr(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -3735,7 +3752,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
 | 
			
		|||
	if (!dev_priv)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	del_timer_sync(&dev_priv->hotplug_reenable_timer);
 | 
			
		||||
	intel_hpd_irq_uninstall(dev_priv);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(PORT_HOTPLUG_EN, 0);
 | 
			
		||||
	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 | 
			
		||||
| 
						 | 
				
			
			@ -3752,7 +3769,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
 | 
			
		|||
	I915_WRITE(IIR, I915_READ(IIR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void i915_reenable_hotplug_timer_func(unsigned long data)
 | 
			
		||||
static void intel_hpd_irq_reenable(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
 | 
			
		||||
	struct drm_device *dev = dev_priv->dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -3799,7 +3816,7 @@ void intel_irq_init(struct drm_device *dev)
 | 
			
		|||
	setup_timer(&dev_priv->gpu_error.hangcheck_timer,
 | 
			
		||||
		    i915_hangcheck_elapsed,
 | 
			
		||||
		    (unsigned long) dev);
 | 
			
		||||
	setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
 | 
			
		||||
	setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
 | 
			
		||||
		    (unsigned long) dev_priv);
 | 
			
		||||
 | 
			
		||||
	pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										155
									
								
								drivers/gpu/drm/i915/i915_params.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								drivers/gpu/drm/i915/i915_params.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright © 2014 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
			
		||||
 * copy of this software and associated documentation files (the
 | 
			
		||||
 * "Software"), to deal in the Software without restriction, including
 | 
			
		||||
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
 * distribute, sub license, and/or sell copies of the Software, and to
 | 
			
		||||
 * permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
 * the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice (including the
 | 
			
		||||
 * next paragraph) shall be included in all copies or substantial portions
 | 
			
		||||
 * of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
 * IN THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "i915_drv.h"
 | 
			
		||||
 | 
			
		||||
struct i915_params i915 __read_mostly = {
 | 
			
		||||
	.modeset = -1,
 | 
			
		||||
	.panel_ignore_lid = 1,
 | 
			
		||||
	.powersave = 1,
 | 
			
		||||
	.semaphores = -1,
 | 
			
		||||
	.lvds_downclock = 0,
 | 
			
		||||
	.lvds_channel_mode = 0,
 | 
			
		||||
	.panel_use_ssc = -1,
 | 
			
		||||
	.vbt_sdvo_panel_type = -1,
 | 
			
		||||
	.enable_rc6 = -1,
 | 
			
		||||
	.enable_fbc = -1,
 | 
			
		||||
	.enable_hangcheck = true,
 | 
			
		||||
	.enable_ppgtt = -1,
 | 
			
		||||
	.enable_psr = 0,
 | 
			
		||||
	.preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
 | 
			
		||||
	.disable_power_well = 1,
 | 
			
		||||
	.enable_ips = 1,
 | 
			
		||||
	.fastboot = 0,
 | 
			
		||||
	.enable_pc8 = 1,
 | 
			
		||||
	.pc8_timeout = 5000,
 | 
			
		||||
	.prefault_disable = 0,
 | 
			
		||||
	.reset = true,
 | 
			
		||||
	.invert_brightness = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_param_named(modeset, i915.modeset, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(modeset,
 | 
			
		||||
	"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
 | 
			
		||||
	"1=on, -1=force vga console preference [default])");
 | 
			
		||||
 | 
			
		||||
module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(panel_ignore_lid,
 | 
			
		||||
	"Override lid status (0=autodetect, 1=autodetect disabled [default], "
 | 
			
		||||
	"-1=force lid closed, -2=force lid open)");
 | 
			
		||||
 | 
			
		||||
module_param_named(powersave, i915.powersave, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(powersave,
 | 
			
		||||
	"Enable powersavings, fbc, downclocking, etc. (default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(semaphores, i915.semaphores, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(semaphores,
 | 
			
		||||
	"Use semaphores for inter-ring sync "
 | 
			
		||||
	"(default: -1 (use per-chip defaults))");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_rc6, i915.enable_rc6, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(enable_rc6,
 | 
			
		||||
	"Enable power-saving render C-state 6. "
 | 
			
		||||
	"Different stages can be selected via bitmask values "
 | 
			
		||||
	"(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
 | 
			
		||||
	"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
 | 
			
		||||
	"default: -1 (use per-chip default)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_fbc, i915.enable_fbc, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_fbc,
 | 
			
		||||
	"Enable frame buffer compression for power savings "
 | 
			
		||||
	"(default: -1 (use per-chip default))");
 | 
			
		||||
 | 
			
		||||
module_param_named(lvds_downclock, i915.lvds_downclock, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(lvds_downclock,
 | 
			
		||||
	"Use panel (LVDS/eDP) downclocking for power savings "
 | 
			
		||||
	"(default: false)");
 | 
			
		||||
 | 
			
		||||
module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(lvds_channel_mode,
 | 
			
		||||
	 "Specify LVDS channel mode "
 | 
			
		||||
	 "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
 | 
			
		||||
 | 
			
		||||
module_param_named(lvds_use_ssc, i915.panel_use_ssc, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(lvds_use_ssc,
 | 
			
		||||
	"Use Spread Spectrum Clock with panels [LVDS/eDP] "
 | 
			
		||||
	"(default: auto from VBT)");
 | 
			
		||||
 | 
			
		||||
module_param_named(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(vbt_sdvo_panel_type,
 | 
			
		||||
	"Override/Ignore selection of SDVO panel mode in the VBT "
 | 
			
		||||
	"(-2=ignore, -1=auto [default], index in VBT BIOS table)");
 | 
			
		||||
 | 
			
		||||
module_param_named(reset, i915.reset, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644);
 | 
			
		||||
MODULE_PARM_DESC(enable_hangcheck,
 | 
			
		||||
	"Periodically check GPU activity for detecting hangs. "
 | 
			
		||||
	"WARNING: Disabling this can cause system wide hangs. "
 | 
			
		||||
	"(default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400);
 | 
			
		||||
MODULE_PARM_DESC(enable_ppgtt,
 | 
			
		||||
	"Override PPGTT usage. "
 | 
			
		||||
	"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_psr, i915.enable_psr, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
 | 
			
		||||
 | 
			
		||||
module_param_named(preliminary_hw_support, i915.preliminary_hw_support, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(preliminary_hw_support,
 | 
			
		||||
	"Enable preliminary hardware support.");
 | 
			
		||||
 | 
			
		||||
module_param_named(disable_power_well, i915.disable_power_well, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(disable_power_well,
 | 
			
		||||
	"Disable the power well when possible (default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_ips, i915.enable_ips, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(fastboot, i915.fastboot, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(fastboot,
 | 
			
		||||
	"Try to skip unnecessary mode sets at boot time (default: false)");
 | 
			
		||||
 | 
			
		||||
module_param_named(enable_pc8, i915.enable_pc8, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(enable_pc8,
 | 
			
		||||
	"Enable support for low power package C states (PC8+) (default: true)");
 | 
			
		||||
 | 
			
		||||
module_param_named(pc8_timeout, i915.pc8_timeout, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(pc8_timeout,
 | 
			
		||||
	"Number of msecs of idleness required to enter PC8+ (default: 5000)");
 | 
			
		||||
 | 
			
		||||
module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
 | 
			
		||||
MODULE_PARM_DESC(prefault_disable,
 | 
			
		||||
	"Disable page prefaulting for pread/pwrite/reloc (default:false). "
 | 
			
		||||
	"For developers only.");
 | 
			
		||||
 | 
			
		||||
module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
 | 
			
		||||
MODULE_PARM_DESC(invert_brightness,
 | 
			
		||||
	"Invert backlight brightness "
 | 
			
		||||
	"(-1 force normal, 0 machine defaults, 1 force inversion), please "
 | 
			
		||||
	"report PCI device ID, subsystem vendor and subsystem device ID "
 | 
			
		||||
	"to dri-devel@lists.freedesktop.org, if your machine needs it. "
 | 
			
		||||
	"It will then be included in an upcoming module version.");
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,6 @@
 | 
			
		|||
#define _I915_REG_H_
 | 
			
		||||
 | 
			
		||||
#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
 | 
			
		||||
#define _PIPE_INC(pipe, base, inc) ((base) + (pipe)*(inc))
 | 
			
		||||
#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a)))
 | 
			
		||||
 | 
			
		||||
#define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +72,8 @@
 | 
			
		|||
#define   I915_GC_RENDER_CLOCK_166_MHZ	(0 << 0)
 | 
			
		||||
#define   I915_GC_RENDER_CLOCK_200_MHZ	(1 << 0)
 | 
			
		||||
#define   I915_GC_RENDER_CLOCK_333_MHZ	(4 << 0)
 | 
			
		||||
#define LBB	0xf4
 | 
			
		||||
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes, also called LBB */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Graphics reset regs */
 | 
			
		||||
#define I965_GDRST 0xc0 /* PCI config register */
 | 
			
		||||
| 
						 | 
				
			
			@ -934,6 +934,8 @@
 | 
			
		|||
#define   ECO_GATING_CX_ONLY	(1<<3)
 | 
			
		||||
#define   ECO_FLIP_DONE		(1<<0)
 | 
			
		||||
 | 
			
		||||
#define CACHE_MODE_0_GEN7	0x7000 /* IVB+ */
 | 
			
		||||
#define   HIZ_RAW_STALL_OPT_DISABLE (1<<2)
 | 
			
		||||
#define CACHE_MODE_1		0x7004 /* IVB+ */
 | 
			
		||||
#define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,9 +1048,8 @@
 | 
			
		|||
#define   FBC_CTL_IDLE_LINE	(2<<2)
 | 
			
		||||
#define   FBC_CTL_IDLE_DEBUG	(3<<2)
 | 
			
		||||
#define   FBC_CTL_CPU_FENCE	(1<<1)
 | 
			
		||||
#define   FBC_CTL_PLANEA	(0<<0)
 | 
			
		||||
#define   FBC_CTL_PLANEB	(1<<0)
 | 
			
		||||
#define FBC_FENCE_OFF		0x0321b
 | 
			
		||||
#define   FBC_CTL_PLANE(plane)	((plane)<<0)
 | 
			
		||||
#define FBC_FENCE_OFF		0x03218 /* BSpec typo has 321Bh */
 | 
			
		||||
#define FBC_TAG			0x03300
 | 
			
		||||
 | 
			
		||||
#define FBC_LL_SIZE		(1536)
 | 
			
		||||
| 
						 | 
				
			
			@ -1057,9 +1058,8 @@
 | 
			
		|||
#define DPFC_CB_BASE		0x3200
 | 
			
		||||
#define DPFC_CONTROL		0x3208
 | 
			
		||||
#define   DPFC_CTL_EN		(1<<31)
 | 
			
		||||
#define   DPFC_CTL_PLANEA	(0<<30)
 | 
			
		||||
#define   DPFC_CTL_PLANEB	(1<<30)
 | 
			
		||||
#define   IVB_DPFC_CTL_PLANE_SHIFT	(29)
 | 
			
		||||
#define   DPFC_CTL_PLANE(plane)	((plane)<<30)
 | 
			
		||||
#define   IVB_DPFC_CTL_PLANE(plane)	((plane)<<29)
 | 
			
		||||
#define   DPFC_CTL_FENCE_EN	(1<<29)
 | 
			
		||||
#define   IVB_DPFC_CTL_FENCE_EN	(1<<28)
 | 
			
		||||
#define   DPFC_CTL_PERSISTENT_MODE	(1<<25)
 | 
			
		||||
| 
						 | 
				
			
			@ -1202,6 +1202,10 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Clock control & power management
 | 
			
		||||
 */
 | 
			
		||||
#define DPLL_A_OFFSET 0x6014
 | 
			
		||||
#define DPLL_B_OFFSET 0x6018
 | 
			
		||||
#define DPLL(pipe) (dev_priv->info->dpll_offsets[pipe] + \
 | 
			
		||||
		    dev_priv->info->display_mmio_offset)
 | 
			
		||||
 | 
			
		||||
#define VGA0	0x6000
 | 
			
		||||
#define VGA1	0x6004
 | 
			
		||||
| 
						 | 
				
			
			@ -1214,9 +1218,6 @@
 | 
			
		|||
#define   VGA1_PD_P1_DIV_2	(1 << 13)
 | 
			
		||||
#define   VGA1_PD_P1_SHIFT	8
 | 
			
		||||
#define   VGA1_PD_P1_MASK	(0x1f << 8)
 | 
			
		||||
#define _DPLL_A	(dev_priv->info->display_mmio_offset + 0x6014)
 | 
			
		||||
#define _DPLL_B	(dev_priv->info->display_mmio_offset + 0x6018)
 | 
			
		||||
#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B)
 | 
			
		||||
#define   DPLL_VCO_ENABLE		(1 << 31)
 | 
			
		||||
#define   DPLL_SDVO_HIGH_SPEED		(1 << 30)
 | 
			
		||||
#define   DPLL_DVO_2X_MODE		(1 << 30)
 | 
			
		||||
| 
						 | 
				
			
			@ -1278,7 +1279,12 @@
 | 
			
		|||
#define   SDVO_MULTIPLIER_MASK			0x000000ff
 | 
			
		||||
#define   SDVO_MULTIPLIER_SHIFT_HIRES		4
 | 
			
		||||
#define   SDVO_MULTIPLIER_SHIFT_VGA		0
 | 
			
		||||
#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */
 | 
			
		||||
 | 
			
		||||
#define DPLL_A_MD_OFFSET 0x601c /* 965+ only */
 | 
			
		||||
#define DPLL_B_MD_OFFSET 0x6020 /* 965+ only */
 | 
			
		||||
#define DPLL_MD(pipe) (dev_priv->info->dpll_md_offsets[pipe] + \
 | 
			
		||||
		       dev_priv->info->display_mmio_offset)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * UDI pixel divider, controlling how many pixels are stuffed into a packet.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1315,8 +1321,6 @@
 | 
			
		|||
 */
 | 
			
		||||
#define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK	0x0000003f
 | 
			
		||||
#define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT	0
 | 
			
		||||
#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */
 | 
			
		||||
#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD)
 | 
			
		||||
 | 
			
		||||
#define _FPA0	0x06040
 | 
			
		||||
#define _FPA1	0x06044
 | 
			
		||||
| 
						 | 
				
			
			@ -1472,10 +1476,10 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Palette regs
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _PALETTE_A		(dev_priv->info->display_mmio_offset + 0xa000)
 | 
			
		||||
#define _PALETTE_B		(dev_priv->info->display_mmio_offset + 0xa800)
 | 
			
		||||
#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B)
 | 
			
		||||
#define PALETTE_A_OFFSET 0xa000
 | 
			
		||||
#define PALETTE_B_OFFSET 0xa800
 | 
			
		||||
#define PALETTE(pipe) (dev_priv->info->palette_offsets[pipe] + \
 | 
			
		||||
		       dev_priv->info->display_mmio_offset)
 | 
			
		||||
 | 
			
		||||
/* MCH MMIO space */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1862,7 +1866,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
/* Pipe A CRC regs */
 | 
			
		||||
#define _PIPE_CRC_CTL_A		(dev_priv->info->display_mmio_offset + 0x60050)
 | 
			
		||||
#define _PIPE_CRC_CTL_A			0x60050
 | 
			
		||||
#define   PIPE_CRC_ENABLE		(1 << 31)
 | 
			
		||||
/* ivb+ source selection */
 | 
			
		||||
#define   PIPE_CRC_SOURCE_PRIMARY_IVB	(0 << 29)
 | 
			
		||||
| 
						 | 
				
			
			@ -1902,11 +1906,11 @@
 | 
			
		|||
#define _PIPE_CRC_RES_4_A_IVB		0x60070
 | 
			
		||||
#define _PIPE_CRC_RES_5_A_IVB		0x60074
 | 
			
		||||
 | 
			
		||||
#define _PIPE_CRC_RES_RED_A		(dev_priv->info->display_mmio_offset + 0x60060)
 | 
			
		||||
#define _PIPE_CRC_RES_GREEN_A		(dev_priv->info->display_mmio_offset + 0x60064)
 | 
			
		||||
#define _PIPE_CRC_RES_BLUE_A		(dev_priv->info->display_mmio_offset + 0x60068)
 | 
			
		||||
#define _PIPE_CRC_RES_RES1_A_I915	(dev_priv->info->display_mmio_offset + 0x6006c)
 | 
			
		||||
#define _PIPE_CRC_RES_RES2_A_G4X	(dev_priv->info->display_mmio_offset + 0x60080)
 | 
			
		||||
#define _PIPE_CRC_RES_RED_A		0x60060
 | 
			
		||||
#define _PIPE_CRC_RES_GREEN_A		0x60064
 | 
			
		||||
#define _PIPE_CRC_RES_BLUE_A		0x60068
 | 
			
		||||
#define _PIPE_CRC_RES_RES1_A_I915	0x6006c
 | 
			
		||||
#define _PIPE_CRC_RES_RES2_A_G4X	0x60080
 | 
			
		||||
 | 
			
		||||
/* Pipe B CRC regs */
 | 
			
		||||
#define _PIPE_CRC_RES_1_B_IVB		0x61064
 | 
			
		||||
| 
						 | 
				
			
			@ -1915,59 +1919,69 @@
 | 
			
		|||
#define _PIPE_CRC_RES_4_B_IVB		0x61070
 | 
			
		||||
#define _PIPE_CRC_RES_5_B_IVB		0x61074
 | 
			
		||||
 | 
			
		||||
#define PIPE_CRC_CTL(pipe)	_PIPE_INC(pipe, _PIPE_CRC_CTL_A, 0x01000)
 | 
			
		||||
#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A)
 | 
			
		||||
#define PIPE_CRC_RES_1_IVB(pipe)	\
 | 
			
		||||
	_PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB)
 | 
			
		||||
#define PIPE_CRC_RES_2_IVB(pipe)	\
 | 
			
		||||
	_PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB)
 | 
			
		||||
#define PIPE_CRC_RES_3_IVB(pipe)	\
 | 
			
		||||
	_PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB)
 | 
			
		||||
#define PIPE_CRC_RES_4_IVB(pipe)	\
 | 
			
		||||
	_PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB)
 | 
			
		||||
#define PIPE_CRC_RES_5_IVB(pipe)	\
 | 
			
		||||
	_PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB)
 | 
			
		||||
 | 
			
		||||
#define PIPE_CRC_RES_RED(pipe) \
 | 
			
		||||
	_PIPE_INC(pipe, _PIPE_CRC_RES_RED_A, 0x01000)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A)
 | 
			
		||||
#define PIPE_CRC_RES_GREEN(pipe) \
 | 
			
		||||
	_PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A, 0x01000)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A)
 | 
			
		||||
#define PIPE_CRC_RES_BLUE(pipe) \
 | 
			
		||||
	_PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A, 0x01000)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A)
 | 
			
		||||
#define PIPE_CRC_RES_RES1_I915(pipe) \
 | 
			
		||||
	_PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_I915, 0x01000)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915)
 | 
			
		||||
#define PIPE_CRC_RES_RES2_G4X(pipe) \
 | 
			
		||||
	_PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_G4X, 0x01000)
 | 
			
		||||
	_TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
 | 
			
		||||
 | 
			
		||||
/* Pipe A timing regs */
 | 
			
		||||
#define _HTOTAL_A	(dev_priv->info->display_mmio_offset + 0x60000)
 | 
			
		||||
#define _HBLANK_A	(dev_priv->info->display_mmio_offset + 0x60004)
 | 
			
		||||
#define _HSYNC_A	(dev_priv->info->display_mmio_offset + 0x60008)
 | 
			
		||||
#define _VTOTAL_A	(dev_priv->info->display_mmio_offset + 0x6000c)
 | 
			
		||||
#define _VBLANK_A	(dev_priv->info->display_mmio_offset + 0x60010)
 | 
			
		||||
#define _VSYNC_A	(dev_priv->info->display_mmio_offset + 0x60014)
 | 
			
		||||
#define _PIPEASRC	(dev_priv->info->display_mmio_offset + 0x6001c)
 | 
			
		||||
#define _BCLRPAT_A	(dev_priv->info->display_mmio_offset + 0x60020)
 | 
			
		||||
#define _VSYNCSHIFT_A	(dev_priv->info->display_mmio_offset + 0x60028)
 | 
			
		||||
#define _HTOTAL_A	0x60000
 | 
			
		||||
#define _HBLANK_A	0x60004
 | 
			
		||||
#define _HSYNC_A	0x60008
 | 
			
		||||
#define _VTOTAL_A	0x6000c
 | 
			
		||||
#define _VBLANK_A	0x60010
 | 
			
		||||
#define _VSYNC_A	0x60014
 | 
			
		||||
#define _PIPEASRC	0x6001c
 | 
			
		||||
#define _BCLRPAT_A	0x60020
 | 
			
		||||
#define _VSYNCSHIFT_A	0x60028
 | 
			
		||||
 | 
			
		||||
/* Pipe B timing regs */
 | 
			
		||||
#define _HTOTAL_B	(dev_priv->info->display_mmio_offset + 0x61000)
 | 
			
		||||
#define _HBLANK_B	(dev_priv->info->display_mmio_offset + 0x61004)
 | 
			
		||||
#define _HSYNC_B	(dev_priv->info->display_mmio_offset + 0x61008)
 | 
			
		||||
#define _VTOTAL_B	(dev_priv->info->display_mmio_offset + 0x6100c)
 | 
			
		||||
#define _VBLANK_B	(dev_priv->info->display_mmio_offset + 0x61010)
 | 
			
		||||
#define _VSYNC_B	(dev_priv->info->display_mmio_offset + 0x61014)
 | 
			
		||||
#define _PIPEBSRC	(dev_priv->info->display_mmio_offset + 0x6101c)
 | 
			
		||||
#define _BCLRPAT_B	(dev_priv->info->display_mmio_offset + 0x61020)
 | 
			
		||||
#define _VSYNCSHIFT_B	(dev_priv->info->display_mmio_offset + 0x61028)
 | 
			
		||||
#define _HTOTAL_B	0x61000
 | 
			
		||||
#define _HBLANK_B	0x61004
 | 
			
		||||
#define _HSYNC_B	0x61008
 | 
			
		||||
#define _VTOTAL_B	0x6100c
 | 
			
		||||
#define _VBLANK_B	0x61010
 | 
			
		||||
#define _VSYNC_B	0x61014
 | 
			
		||||
#define _PIPEBSRC	0x6101c
 | 
			
		||||
#define _BCLRPAT_B	0x61020
 | 
			
		||||
#define _VSYNCSHIFT_B	0x61028
 | 
			
		||||
 | 
			
		||||
#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B)
 | 
			
		||||
#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B)
 | 
			
		||||
#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B)
 | 
			
		||||
#define VTOTAL(trans) _TRANSCODER(trans, _VTOTAL_A, _VTOTAL_B)
 | 
			
		||||
#define VBLANK(trans) _TRANSCODER(trans, _VBLANK_A, _VBLANK_B)
 | 
			
		||||
#define VSYNC(trans) _TRANSCODER(trans, _VSYNC_A, _VSYNC_B)
 | 
			
		||||
#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 | 
			
		||||
#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 | 
			
		||||
#define TRANSCODER_A_OFFSET 0x60000
 | 
			
		||||
#define TRANSCODER_B_OFFSET 0x61000
 | 
			
		||||
#define TRANSCODER_C_OFFSET 0x62000
 | 
			
		||||
#define TRANSCODER_EDP_OFFSET 0x6f000
 | 
			
		||||
 | 
			
		||||
#define _TRANSCODER2(pipe, reg) (dev_priv->info->trans_offsets[(pipe)] - \
 | 
			
		||||
	dev_priv->info->trans_offsets[TRANSCODER_A] + (reg) + \
 | 
			
		||||
	dev_priv->info->display_mmio_offset)
 | 
			
		||||
 | 
			
		||||
#define HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A)
 | 
			
		||||
#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A)
 | 
			
		||||
#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A)
 | 
			
		||||
#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A)
 | 
			
		||||
#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A)
 | 
			
		||||
#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A)
 | 
			
		||||
#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A)
 | 
			
		||||
#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
 | 
			
		||||
#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
 | 
			
		||||
 | 
			
		||||
/* HSW+ eDP PSR registers */
 | 
			
		||||
#define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 | 
			
		||||
| 
						 | 
				
			
			@ -3178,10 +3192,10 @@
 | 
			
		|||
/* Display & cursor control */
 | 
			
		||||
 | 
			
		||||
/* Pipe A */
 | 
			
		||||
#define _PIPEADSL		(dev_priv->info->display_mmio_offset + 0x70000)
 | 
			
		||||
#define _PIPEADSL		0x70000
 | 
			
		||||
#define   DSL_LINEMASK_GEN2	0x00000fff
 | 
			
		||||
#define   DSL_LINEMASK_GEN3	0x00001fff
 | 
			
		||||
#define _PIPEACONF		(dev_priv->info->display_mmio_offset + 0x70008)
 | 
			
		||||
#define _PIPEACONF		0x70008
 | 
			
		||||
#define   PIPECONF_ENABLE	(1<<31)
 | 
			
		||||
#define   PIPECONF_DISABLE	0
 | 
			
		||||
#define   PIPECONF_DOUBLE_WIDE	(1<<30)
 | 
			
		||||
| 
						 | 
				
			
			@ -3224,9 +3238,9 @@
 | 
			
		|||
#define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
 | 
			
		||||
#define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
 | 
			
		||||
#define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 | 
			
		||||
#define _PIPEASTAT		(dev_priv->info->display_mmio_offset + 0x70024)
 | 
			
		||||
#define _PIPEASTAT		0x70024
 | 
			
		||||
#define   PIPE_FIFO_UNDERRUN_STATUS		(1UL<<31)
 | 
			
		||||
#define   SPRITE1_FLIPDONE_INT_EN_VLV		(1UL<<30)
 | 
			
		||||
#define   SPRITE1_FLIP_DONE_INT_EN_VLV		(1UL<<30)
 | 
			
		||||
#define   PIPE_CRC_ERROR_ENABLE			(1UL<<29)
 | 
			
		||||
#define   PIPE_CRC_DONE_ENABLE			(1UL<<28)
 | 
			
		||||
#define   PIPE_GMBUS_EVENT_ENABLE		(1UL<<27)
 | 
			
		||||
| 
						 | 
				
			
			@ -3244,12 +3258,12 @@
 | 
			
		|||
#define   PIPE_VBLANK_INTERRUPT_ENABLE		(1UL<<17)
 | 
			
		||||
#define   PIPEA_HBLANK_INT_EN_VLV		(1UL<<16)
 | 
			
		||||
#define   PIPE_OVERLAY_UPDATED_ENABLE		(1UL<<16)
 | 
			
		||||
#define   SPRITE1_FLIPDONE_INT_STATUS_VLV	(1UL<<15)
 | 
			
		||||
#define   SPRITE0_FLIPDONE_INT_STATUS_VLV	(1UL<<14)
 | 
			
		||||
#define   SPRITE1_FLIP_DONE_INT_STATUS_VLV	(1UL<<15)
 | 
			
		||||
#define   SPRITE0_FLIP_DONE_INT_STATUS_VLV	(1UL<<14)
 | 
			
		||||
#define   PIPE_CRC_ERROR_INTERRUPT_STATUS	(1UL<<13)
 | 
			
		||||
#define   PIPE_CRC_DONE_INTERRUPT_STATUS	(1UL<<12)
 | 
			
		||||
#define   PIPE_GMBUS_INTERRUPT_STATUS		(1UL<<11)
 | 
			
		||||
#define   PLANE_FLIPDONE_INT_STATUS_VLV		(1UL<<10)
 | 
			
		||||
#define   PLANE_FLIP_DONE_INT_STATUS_VLV	(1UL<<10)
 | 
			
		||||
#define   PIPE_HOTPLUG_INTERRUPT_STATUS		(1UL<<10)
 | 
			
		||||
#define   PIPE_VSYNC_INTERRUPT_STATUS		(1UL<<9)
 | 
			
		||||
#define   PIPE_DISPLAY_LINE_COMPARE_STATUS	(1UL<<8)
 | 
			
		||||
| 
						 | 
				
			
			@ -3262,12 +3276,26 @@
 | 
			
		|||
#define   PIPE_VBLANK_INTERRUPT_STATUS		(1UL<<1)
 | 
			
		||||
#define   PIPE_OVERLAY_UPDATED_STATUS		(1UL<<0)
 | 
			
		||||
 | 
			
		||||
#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC)
 | 
			
		||||
#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF)
 | 
			
		||||
#define PIPEDSL(pipe)  _PIPE(pipe, _PIPEADSL, _PIPEBDSL)
 | 
			
		||||
#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH)
 | 
			
		||||
#define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
 | 
			
		||||
#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
 | 
			
		||||
#define PIPE_A_OFFSET	0x70000
 | 
			
		||||
#define PIPE_B_OFFSET	0x71000
 | 
			
		||||
#define PIPE_C_OFFSET	0x72000
 | 
			
		||||
/*
 | 
			
		||||
 * There's actually no pipe EDP. Some pipe registers have
 | 
			
		||||
 * simply shifted from the pipe to the transcoder, while
 | 
			
		||||
 * keeping their original offset. Thus we need PIPE_EDP_OFFSET
 | 
			
		||||
 * to access such registers in transcoder EDP.
 | 
			
		||||
 */
 | 
			
		||||
#define PIPE_EDP_OFFSET	0x7f000
 | 
			
		||||
 | 
			
		||||
#define _PIPE2(pipe, reg) (dev_priv->info->pipe_offsets[pipe] - \
 | 
			
		||||
	dev_priv->info->pipe_offsets[PIPE_A] + (reg) + \
 | 
			
		||||
	dev_priv->info->display_mmio_offset)
 | 
			
		||||
 | 
			
		||||
#define PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF)
 | 
			
		||||
#define PIPEDSL(pipe)  _PIPE2(pipe, _PIPEADSL)
 | 
			
		||||
#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH)
 | 
			
		||||
#define PIPEFRAMEPIXEL(pipe)  _PIPE2(pipe, _PIPEAFRAMEPIXEL)
 | 
			
		||||
#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT)
 | 
			
		||||
 | 
			
		||||
#define _PIPE_MISC_A			0x70030
 | 
			
		||||
#define _PIPE_MISC_B			0x71030
 | 
			
		||||
| 
						 | 
				
			
			@ -3279,20 +3307,20 @@
 | 
			
		|||
#define   PIPEMISC_DITHER_ENABLE	(1<<4)
 | 
			
		||||
#define   PIPEMISC_DITHER_TYPE_MASK	(3<<2)
 | 
			
		||||
#define   PIPEMISC_DITHER_TYPE_SP	(0<<2)
 | 
			
		||||
#define PIPEMISC(pipe) _PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B)
 | 
			
		||||
#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A)
 | 
			
		||||
 | 
			
		||||
#define VLV_DPFLIPSTAT				(VLV_DISPLAY_BASE + 0x70028)
 | 
			
		||||
#define   PIPEB_LINE_COMPARE_INT_EN		(1<<29)
 | 
			
		||||
#define   PIPEB_HLINE_INT_EN			(1<<28)
 | 
			
		||||
#define   PIPEB_VBLANK_INT_EN			(1<<27)
 | 
			
		||||
#define   SPRITED_FLIPDONE_INT_EN		(1<<26)
 | 
			
		||||
#define   SPRITEC_FLIPDONE_INT_EN		(1<<25)
 | 
			
		||||
#define   PLANEB_FLIPDONE_INT_EN		(1<<24)
 | 
			
		||||
#define   SPRITED_FLIP_DONE_INT_EN		(1<<26)
 | 
			
		||||
#define   SPRITEC_FLIP_DONE_INT_EN		(1<<25)
 | 
			
		||||
#define   PLANEB_FLIP_DONE_INT_EN		(1<<24)
 | 
			
		||||
#define   PIPEA_LINE_COMPARE_INT_EN		(1<<21)
 | 
			
		||||
#define   PIPEA_HLINE_INT_EN			(1<<20)
 | 
			
		||||
#define   PIPEA_VBLANK_INT_EN			(1<<19)
 | 
			
		||||
#define   SPRITEB_FLIPDONE_INT_EN		(1<<18)
 | 
			
		||||
#define   SPRITEA_FLIPDONE_INT_EN		(1<<17)
 | 
			
		||||
#define   SPRITEB_FLIP_DONE_INT_EN		(1<<18)
 | 
			
		||||
#define   SPRITEA_FLIP_DONE_INT_EN		(1<<17)
 | 
			
		||||
#define   PLANEA_FLIPDONE_INT_EN		(1<<16)
 | 
			
		||||
 | 
			
		||||
#define DPINVGTT				(VLV_DISPLAY_BASE + 0x7002c) /* VLV only */
 | 
			
		||||
| 
						 | 
				
			
			@ -3520,7 +3548,7 @@
 | 
			
		|||
#define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
 | 
			
		||||
 | 
			
		||||
/* Display A control */
 | 
			
		||||
#define _DSPACNTR                (dev_priv->info->display_mmio_offset + 0x70180)
 | 
			
		||||
#define _DSPACNTR				0x70180
 | 
			
		||||
#define   DISPLAY_PLANE_ENABLE			(1<<31)
 | 
			
		||||
#define   DISPLAY_PLANE_DISABLE			0
 | 
			
		||||
#define   DISPPLANE_GAMMA_ENABLE		(1<<30)
 | 
			
		||||
| 
						 | 
				
			
			@ -3554,25 +3582,25 @@
 | 
			
		|||
#define   DISPPLANE_STEREO_POLARITY_SECOND	(1<<18)
 | 
			
		||||
#define   DISPPLANE_TRICKLE_FEED_DISABLE	(1<<14) /* Ironlake */
 | 
			
		||||
#define   DISPPLANE_TILED			(1<<10)
 | 
			
		||||
#define _DSPAADDR		(dev_priv->info->display_mmio_offset + 0x70184)
 | 
			
		||||
#define _DSPASTRIDE		(dev_priv->info->display_mmio_offset + 0x70188)
 | 
			
		||||
#define _DSPAPOS		(dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */
 | 
			
		||||
#define _DSPASIZE		(dev_priv->info->display_mmio_offset + 0x70190)
 | 
			
		||||
#define _DSPASURF		(dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */
 | 
			
		||||
#define _DSPATILEOFF		(dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */
 | 
			
		||||
#define _DSPAOFFSET		(dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */
 | 
			
		||||
#define _DSPASURFLIVE		(dev_priv->info->display_mmio_offset + 0x701AC)
 | 
			
		||||
#define _DSPAADDR				0x70184
 | 
			
		||||
#define _DSPASTRIDE				0x70188
 | 
			
		||||
#define _DSPAPOS				0x7018C /* reserved */
 | 
			
		||||
#define _DSPASIZE				0x70190
 | 
			
		||||
#define _DSPASURF				0x7019C /* 965+ only */
 | 
			
		||||
#define _DSPATILEOFF				0x701A4 /* 965+ only */
 | 
			
		||||
#define _DSPAOFFSET				0x701A4 /* HSW */
 | 
			
		||||
#define _DSPASURFLIVE				0x701AC
 | 
			
		||||
 | 
			
		||||
#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR)
 | 
			
		||||
#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR)
 | 
			
		||||
#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE)
 | 
			
		||||
#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS)
 | 
			
		||||
#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE)
 | 
			
		||||
#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF)
 | 
			
		||||
#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF)
 | 
			
		||||
#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR)
 | 
			
		||||
#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR)
 | 
			
		||||
#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE)
 | 
			
		||||
#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS)
 | 
			
		||||
#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE)
 | 
			
		||||
#define DSPSURF(plane) _PIPE2(plane, _DSPASURF)
 | 
			
		||||
#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF)
 | 
			
		||||
#define DSPLINOFF(plane) DSPADDR(plane)
 | 
			
		||||
#define DSPOFFSET(plane) _PIPE(plane, _DSPAOFFSET, _DSPBOFFSET)
 | 
			
		||||
#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE)
 | 
			
		||||
#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET)
 | 
			
		||||
#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE)
 | 
			
		||||
 | 
			
		||||
/* Display/Sprite base address macros */
 | 
			
		||||
#define DISP_BASEADDR_MASK	(0xfffff000)
 | 
			
		||||
| 
						 | 
				
			
			@ -3866,48 +3894,45 @@
 | 
			
		|||
#define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define _PIPEA_DATA_M1           (dev_priv->info->display_mmio_offset + 0x60030)
 | 
			
		||||
#define _PIPEA_DATA_M1		0x60030
 | 
			
		||||
#define  PIPE_DATA_M1_OFFSET    0
 | 
			
		||||
#define _PIPEA_DATA_N1           (dev_priv->info->display_mmio_offset + 0x60034)
 | 
			
		||||
#define _PIPEA_DATA_N1		0x60034
 | 
			
		||||
#define  PIPE_DATA_N1_OFFSET    0
 | 
			
		||||
 | 
			
		||||
#define _PIPEA_DATA_M2           (dev_priv->info->display_mmio_offset + 0x60038)
 | 
			
		||||
#define _PIPEA_DATA_M2		0x60038
 | 
			
		||||
#define  PIPE_DATA_M2_OFFSET    0
 | 
			
		||||
#define _PIPEA_DATA_N2           (dev_priv->info->display_mmio_offset + 0x6003c)
 | 
			
		||||
#define _PIPEA_DATA_N2		0x6003c
 | 
			
		||||
#define  PIPE_DATA_N2_OFFSET    0
 | 
			
		||||
 | 
			
		||||
#define _PIPEA_LINK_M1           (dev_priv->info->display_mmio_offset + 0x60040)
 | 
			
		||||
#define _PIPEA_LINK_M1		0x60040
 | 
			
		||||
#define  PIPE_LINK_M1_OFFSET    0
 | 
			
		||||
#define _PIPEA_LINK_N1           (dev_priv->info->display_mmio_offset + 0x60044)
 | 
			
		||||
#define _PIPEA_LINK_N1		0x60044
 | 
			
		||||
#define  PIPE_LINK_N1_OFFSET    0
 | 
			
		||||
 | 
			
		||||
#define _PIPEA_LINK_M2           (dev_priv->info->display_mmio_offset + 0x60048)
 | 
			
		||||
#define _PIPEA_LINK_M2		0x60048
 | 
			
		||||
#define  PIPE_LINK_M2_OFFSET    0
 | 
			
		||||
#define _PIPEA_LINK_N2           (dev_priv->info->display_mmio_offset + 0x6004c)
 | 
			
		||||
#define _PIPEA_LINK_N2		0x6004c
 | 
			
		||||
#define  PIPE_LINK_N2_OFFSET    0
 | 
			
		||||
 | 
			
		||||
/* PIPEB timing regs are same start from 0x61000 */
 | 
			
		||||
 | 
			
		||||
#define _PIPEB_DATA_M1           (dev_priv->info->display_mmio_offset + 0x61030)
 | 
			
		||||
#define _PIPEB_DATA_N1           (dev_priv->info->display_mmio_offset + 0x61034)
 | 
			
		||||
#define _PIPEB_DATA_M1		0x61030
 | 
			
		||||
#define _PIPEB_DATA_N1		0x61034
 | 
			
		||||
#define _PIPEB_DATA_M2		0x61038
 | 
			
		||||
#define _PIPEB_DATA_N2		0x6103c
 | 
			
		||||
#define _PIPEB_LINK_M1		0x61040
 | 
			
		||||
#define _PIPEB_LINK_N1		0x61044
 | 
			
		||||
#define _PIPEB_LINK_M2		0x61048
 | 
			
		||||
#define _PIPEB_LINK_N2		0x6104c
 | 
			
		||||
 | 
			
		||||
#define _PIPEB_DATA_M2           (dev_priv->info->display_mmio_offset + 0x61038)
 | 
			
		||||
#define _PIPEB_DATA_N2           (dev_priv->info->display_mmio_offset + 0x6103c)
 | 
			
		||||
 | 
			
		||||
#define _PIPEB_LINK_M1           (dev_priv->info->display_mmio_offset + 0x61040)
 | 
			
		||||
#define _PIPEB_LINK_N1           (dev_priv->info->display_mmio_offset + 0x61044)
 | 
			
		||||
 | 
			
		||||
#define _PIPEB_LINK_M2           (dev_priv->info->display_mmio_offset + 0x61048)
 | 
			
		||||
#define _PIPEB_LINK_N2           (dev_priv->info->display_mmio_offset + 0x6104c)
 | 
			
		||||
 | 
			
		||||
#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
 | 
			
		||||
#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
 | 
			
		||||
#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2)
 | 
			
		||||
#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2)
 | 
			
		||||
#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1)
 | 
			
		||||
#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1)
 | 
			
		||||
#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2)
 | 
			
		||||
#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2)
 | 
			
		||||
#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1)
 | 
			
		||||
#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1)
 | 
			
		||||
#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2)
 | 
			
		||||
#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2)
 | 
			
		||||
#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1)
 | 
			
		||||
#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1)
 | 
			
		||||
#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2)
 | 
			
		||||
#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2)
 | 
			
		||||
 | 
			
		||||
/* CPU panel fitter */
 | 
			
		||||
/* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
 | 
			
		||||
| 
						 | 
				
			
			@ -4120,6 +4145,8 @@
 | 
			
		|||
#define GEN7_MSG_CTL	0x45010
 | 
			
		||||
#define  WAIT_FOR_PCH_RESET_ACK		(1<<1)
 | 
			
		||||
#define  WAIT_FOR_PCH_FLR_ACK		(1<<0)
 | 
			
		||||
#define HSW_NDE_RSTWRN_OPT	0x46408
 | 
			
		||||
#define  RESET_PCH_HANDSHAKE_ENABLE	(1<<4)
 | 
			
		||||
 | 
			
		||||
/* GEN7 chicken */
 | 
			
		||||
#define GEN7_COMMON_SLICE_CHICKEN1		0x7010
 | 
			
		||||
| 
						 | 
				
			
			@ -4127,6 +4154,9 @@
 | 
			
		|||
#define COMMON_SLICE_CHICKEN2			0x7014
 | 
			
		||||
# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE	(1<<0)
 | 
			
		||||
 | 
			
		||||
#define GEN7_L3SQCREG1				0xB010
 | 
			
		||||
#define  VLV_B0_WA_L3SQCREG1_VALUE		0x00D30000
 | 
			
		||||
 | 
			
		||||
#define GEN7_L3CNTLREG1				0xB01C
 | 
			
		||||
#define  GEN7_WA_FOR_GEN7_L3_CONTROL			0x3C4FFF8C
 | 
			
		||||
#define  GEN7_L3AGDIS				(1<<19)
 | 
			
		||||
| 
						 | 
				
			
			@ -4436,24 +4466,24 @@
 | 
			
		|||
#define HSW_VIDEO_DIP_GCP_B		0x61210
 | 
			
		||||
 | 
			
		||||
#define HSW_TVIDEO_DIP_CTL(trans) \
 | 
			
		||||
	 _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
 | 
			
		||||
	 _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A)
 | 
			
		||||
#define HSW_TVIDEO_DIP_AVI_DATA(trans) \
 | 
			
		||||
	 _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
 | 
			
		||||
	 _TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A)
 | 
			
		||||
#define HSW_TVIDEO_DIP_VS_DATA(trans) \
 | 
			
		||||
	 _TRANSCODER(trans, HSW_VIDEO_DIP_VS_DATA_A, HSW_VIDEO_DIP_VS_DATA_B)
 | 
			
		||||
	 _TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A)
 | 
			
		||||
#define HSW_TVIDEO_DIP_SPD_DATA(trans) \
 | 
			
		||||
	 _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
 | 
			
		||||
	 _TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A)
 | 
			
		||||
#define HSW_TVIDEO_DIP_GCP(trans) \
 | 
			
		||||
	_TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
 | 
			
		||||
	_TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A)
 | 
			
		||||
#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
 | 
			
		||||
	 _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
 | 
			
		||||
	 _TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A)
 | 
			
		||||
 | 
			
		||||
#define HSW_STEREO_3D_CTL_A	0x70020
 | 
			
		||||
#define   S3D_ENABLE		(1<<31)
 | 
			
		||||
#define HSW_STEREO_3D_CTL_B	0x71020
 | 
			
		||||
 | 
			
		||||
#define HSW_STEREO_3D_CTL(trans) \
 | 
			
		||||
	_TRANSCODER(trans, HSW_STEREO_3D_CTL_A, HSW_STEREO_3D_CTL_A)
 | 
			
		||||
	_PIPE2(trans, HSW_STEREO_3D_CTL_A)
 | 
			
		||||
 | 
			
		||||
#define _PCH_TRANS_HTOTAL_B          0xe1000
 | 
			
		||||
#define _PCH_TRANS_HBLANK_B          0xe1004
 | 
			
		||||
| 
						 | 
				
			
			@ -4945,6 +4975,10 @@
 | 
			
		|||
						 GEN6_PM_RP_DOWN_THRESHOLD | \
 | 
			
		||||
						 GEN6_PM_RP_DOWN_TIMEOUT)
 | 
			
		||||
 | 
			
		||||
#define VLV_GTLC_SURVIVABILITY_REG              0x130098
 | 
			
		||||
#define VLV_GFX_CLK_STATUS_BIT			(1<<3)
 | 
			
		||||
#define VLV_GFX_CLK_FORCE_ON_BIT		(1<<2)
 | 
			
		||||
 | 
			
		||||
#define GEN6_GT_GFX_RC6_LOCKED			0x138104
 | 
			
		||||
#define VLV_COUNTER_CONTROL			0x138104
 | 
			
		||||
#define   VLV_COUNT_RANGE_HIGH			(1<<15)
 | 
			
		||||
| 
						 | 
				
			
			@ -5178,8 +5212,8 @@
 | 
			
		|||
#define TRANS_DDI_FUNC_CTL_B		0x61400
 | 
			
		||||
#define TRANS_DDI_FUNC_CTL_C		0x62400
 | 
			
		||||
#define TRANS_DDI_FUNC_CTL_EDP		0x6F400
 | 
			
		||||
#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER(tran, TRANS_DDI_FUNC_CTL_A, \
 | 
			
		||||
						   TRANS_DDI_FUNC_CTL_B)
 | 
			
		||||
#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A)
 | 
			
		||||
 | 
			
		||||
#define  TRANS_DDI_FUNC_ENABLE		(1<<31)
 | 
			
		||||
/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
 | 
			
		||||
#define  TRANS_DDI_PORT_MASK		(7<<28)
 | 
			
		||||
| 
						 | 
				
			
			@ -5311,8 +5345,12 @@
 | 
			
		|||
#define  SPLL_PLL_ENABLE		(1<<31)
 | 
			
		||||
#define  SPLL_PLL_SSC			(1<<28)
 | 
			
		||||
#define  SPLL_PLL_NON_SSC		(2<<28)
 | 
			
		||||
#define  SPLL_PLL_LCPLL			(3<<28)
 | 
			
		||||
#define  SPLL_PLL_REF_MASK		(3<<28)
 | 
			
		||||
#define  SPLL_PLL_FREQ_810MHz		(0<<26)
 | 
			
		||||
#define  SPLL_PLL_FREQ_1350MHz		(1<<26)
 | 
			
		||||
#define  SPLL_PLL_FREQ_2700MHz		(2<<26)
 | 
			
		||||
#define  SPLL_PLL_FREQ_MASK		(3<<26)
 | 
			
		||||
 | 
			
		||||
/* WRPLL */
 | 
			
		||||
#define WRPLL_CTL1			0x46040
 | 
			
		||||
| 
						 | 
				
			
			@ -5323,8 +5361,13 @@
 | 
			
		|||
#define  WRPLL_PLL_SELECT_LCPLL_2700	(0x03<<28)
 | 
			
		||||
/* WRPLL divider programming */
 | 
			
		||||
#define  WRPLL_DIVIDER_REFERENCE(x)	((x)<<0)
 | 
			
		||||
#define  WRPLL_DIVIDER_REF_MASK		(0xff)
 | 
			
		||||
#define  WRPLL_DIVIDER_POST(x)		((x)<<8)
 | 
			
		||||
#define  WRPLL_DIVIDER_POST_MASK	(0x3f<<8)
 | 
			
		||||
#define  WRPLL_DIVIDER_POST_SHIFT	8
 | 
			
		||||
#define  WRPLL_DIVIDER_FEEDBACK(x)	((x)<<16)
 | 
			
		||||
#define  WRPLL_DIVIDER_FB_SHIFT		16
 | 
			
		||||
#define  WRPLL_DIVIDER_FB_MASK		(0xff<<16)
 | 
			
		||||
 | 
			
		||||
/* Port clock selection */
 | 
			
		||||
#define PORT_CLK_SEL_A			0x46100
 | 
			
		||||
| 
						 | 
				
			
			@ -5337,6 +5380,7 @@
 | 
			
		|||
#define  PORT_CLK_SEL_WRPLL1		(4<<29)
 | 
			
		||||
#define  PORT_CLK_SEL_WRPLL2		(5<<29)
 | 
			
		||||
#define  PORT_CLK_SEL_NONE		(7<<29)
 | 
			
		||||
#define  PORT_CLK_SEL_MASK		(7<<29)
 | 
			
		||||
 | 
			
		||||
/* Transcoder clock selection */
 | 
			
		||||
#define TRANS_CLK_SEL_A			0x46140
 | 
			
		||||
| 
						 | 
				
			
			@ -5346,10 +5390,12 @@
 | 
			
		|||
#define  TRANS_CLK_SEL_DISABLED		(0x0<<29)
 | 
			
		||||
#define  TRANS_CLK_SEL_PORT(x)		((x+1)<<29)
 | 
			
		||||
 | 
			
		||||
#define _TRANSA_MSA_MISC		0x60410
 | 
			
		||||
#define _TRANSB_MSA_MISC		0x61410
 | 
			
		||||
#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \
 | 
			
		||||
					       _TRANSB_MSA_MISC)
 | 
			
		||||
#define TRANSA_MSA_MISC			0x60410
 | 
			
		||||
#define TRANSB_MSA_MISC			0x61410
 | 
			
		||||
#define TRANSC_MSA_MISC			0x62410
 | 
			
		||||
#define TRANS_EDP_MSA_MISC		0x6f410
 | 
			
		||||
#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC)
 | 
			
		||||
 | 
			
		||||
#define  TRANS_MSA_SYNC_CLK		(1<<0)
 | 
			
		||||
#define  TRANS_MSA_6_BPC		(0<<5)
 | 
			
		||||
#define  TRANS_MSA_8_BPC		(1<<5)
 | 
			
		||||
| 
						 | 
				
			
			@ -5857,4 +5903,12 @@
 | 
			
		|||
#define MIPI_READ_DATA_VALID(pipe)	_PIPE(pipe, _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID)
 | 
			
		||||
#define  READ_DATA_VALID(n)				(1 << (n))
 | 
			
		||||
 | 
			
		||||
/* For UMS only (deprecated): */
 | 
			
		||||
#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000)
 | 
			
		||||
#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800)
 | 
			
		||||
#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014)
 | 
			
		||||
#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018)
 | 
			
		||||
#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c)
 | 
			
		||||
#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020)
 | 
			
		||||
 | 
			
		||||
#endif /* _I915_REG_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -236,19 +236,9 @@ static void i915_save_display(struct drm_device *dev)
 | 
			
		|||
		dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Only regfile.save FBC state on the platform that supports FBC */
 | 
			
		||||
	if (HAS_FBC(dev)) {
 | 
			
		||||
		if (HAS_PCH_SPLIT(dev)) {
 | 
			
		||||
			dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
 | 
			
		||||
		} else if (IS_GM45(dev)) {
 | 
			
		||||
			dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
 | 
			
		||||
		} else {
 | 
			
		||||
			dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
 | 
			
		||||
			dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
 | 
			
		||||
			dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
 | 
			
		||||
	/* save FBC interval */
 | 
			
		||||
	if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
 | 
			
		||||
		dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 | 
			
		||||
		i915_save_vga(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -300,18 +290,10 @@ static void i915_restore_display(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	/* only restore FBC info on the platform that supports FBC*/
 | 
			
		||||
	intel_disable_fbc(dev);
 | 
			
		||||
	if (HAS_FBC(dev)) {
 | 
			
		||||
		if (HAS_PCH_SPLIT(dev)) {
 | 
			
		||||
			I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
 | 
			
		||||
		} else if (IS_GM45(dev)) {
 | 
			
		||||
			I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
 | 
			
		||||
		} else {
 | 
			
		||||
			I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE);
 | 
			
		||||
			I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE);
 | 
			
		||||
			I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2);
 | 
			
		||||
 | 
			
		||||
	/* restore FBC interval */
 | 
			
		||||
	if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
 | 
			
		||||
		I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 | 
			
		||||
		i915_restore_vga(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -324,10 +306,6 @@ int i915_save_state(struct drm_device *dev)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen <= 4)
 | 
			
		||||
		pci_read_config_byte(dev->pdev, LBB,
 | 
			
		||||
				     &dev_priv->regfile.saveLBB);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
	i915_save_display(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -377,10 +355,6 @@ int i915_restore_state(struct drm_device *dev)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen <= 4)
 | 
			
		||||
		pci_write_config_byte(dev->pdev, LBB,
 | 
			
		||||
				      dev_priv->regfile.saveLBB);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->struct_mutex);
 | 
			
		||||
 | 
			
		||||
	i915_gem_restore_fences(dev);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -357,6 +357,11 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
 | 
			
		|||
		else
 | 
			
		||||
			gen6_set_rps(dev, val);
 | 
			
		||||
	}
 | 
			
		||||
	else if (!IS_VALLEYVIEW(dev))
 | 
			
		||||
		/* We still need gen6_set_rps to process the new max_delay
 | 
			
		||||
		   and update the interrupt limits even though frequency
 | 
			
		||||
		   request is unchanged. */
 | 
			
		||||
		gen6_set_rps(dev, dev_priv->rps.cur_delay);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +431,11 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 | 
			
		|||
		else
 | 
			
		||||
			gen6_set_rps(dev, val);
 | 
			
		||||
	}
 | 
			
		||||
	else if (!IS_VALLEYVIEW(dev))
 | 
			
		||||
		/* We still need gen6_set_rps to process the new min_delay
 | 
			
		||||
		   and update the interrupt limits even though frequency
 | 
			
		||||
		   request is unchanged. */
 | 
			
		||||
		gen6_set_rps(dev, dev_priv->rps.cur_delay);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&dev_priv->rps.hw_lock);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,6 +271,10 @@ void i915_save_display_reg(struct drm_device *dev)
 | 
			
		|||
	/* FIXME: regfile.save TV & SDVO state */
 | 
			
		||||
 | 
			
		||||
	/* Backlight */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen <= 4)
 | 
			
		||||
		pci_read_config_byte(dev->pdev, PCI_LBPC,
 | 
			
		||||
				     &dev_priv->regfile.saveLBB);
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_SPLIT(dev)) {
 | 
			
		||||
		dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
 | 
			
		||||
		dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +297,10 @@ void i915_restore_display_reg(struct drm_device *dev)
 | 
			
		|||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* Backlight */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen <= 4)
 | 
			
		||||
		pci_write_config_byte(dev->pdev, PCI_LBPC,
 | 
			
		||||
				      dev_priv->regfile.saveLBB);
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_SPLIT(dev)) {
 | 
			
		||||
		I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL);
 | 
			
		||||
		I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -259,7 +259,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 | 
			
		|||
			downclock = dvo_timing->clock;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
 | 
			
		||||
	if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) {
 | 
			
		||||
		dev_priv->lvds_downclock_avail = 1;
 | 
			
		||||
		dev_priv->lvds_downclock = downclock * 10;
 | 
			
		||||
		DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
 | 
			
		||||
| 
						 | 
				
			
			@ -318,7 +318,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
 | 
			
		|||
	struct drm_display_mode *panel_fixed_mode;
 | 
			
		||||
	int index;
 | 
			
		||||
 | 
			
		||||
	index = i915_vbt_sdvo_panel_type;
 | 
			
		||||
	index = i915.vbt_sdvo_panel_type;
 | 
			
		||||
	if (index == -2) {
 | 
			
		||||
		DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n");
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -857,4 +857,6 @@ void intel_crt_init(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
		dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	intel_crt_reset(connector);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -633,6 +633,97 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
 | 
			
		|||
	/* Otherwise a < c && b >= d, do nothing */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
 | 
			
		||||
				     int reg)
 | 
			
		||||
{
 | 
			
		||||
	int refclk = LC_FREQ;
 | 
			
		||||
	int n, p, r;
 | 
			
		||||
	u32 wrpll;
 | 
			
		||||
 | 
			
		||||
	wrpll = I915_READ(reg);
 | 
			
		||||
	switch (wrpll & SPLL_PLL_REF_MASK) {
 | 
			
		||||
	case SPLL_PLL_SSC:
 | 
			
		||||
	case SPLL_PLL_NON_SSC:
 | 
			
		||||
		/*
 | 
			
		||||
		 * We could calculate spread here, but our checking
 | 
			
		||||
		 * code only cares about 5% accuracy, and spread is a max of
 | 
			
		||||
		 * 0.5% downspread.
 | 
			
		||||
		 */
 | 
			
		||||
		refclk = 135;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPLL_PLL_LCPLL:
 | 
			
		||||
		refclk = LC_FREQ;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		WARN(1, "bad wrpll refclk\n");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = wrpll & WRPLL_DIVIDER_REF_MASK;
 | 
			
		||||
	p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
 | 
			
		||||
	n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
 | 
			
		||||
 | 
			
		||||
	/* Convert to KHz, p & r have a fixed point portion */
 | 
			
		||||
	return (refclk * n * 100) / (p * r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void intel_ddi_clock_get(struct intel_encoder *encoder,
 | 
			
		||||
				struct intel_crtc_config *pipe_config)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 | 
			
		||||
	enum port port = intel_ddi_get_encoder_port(encoder);
 | 
			
		||||
	int link_clock = 0;
 | 
			
		||||
	u32 val, pll;
 | 
			
		||||
 | 
			
		||||
	val = I915_READ(PORT_CLK_SEL(port));
 | 
			
		||||
	switch (val & PORT_CLK_SEL_MASK) {
 | 
			
		||||
	case PORT_CLK_SEL_LCPLL_810:
 | 
			
		||||
		link_clock = 81000;
 | 
			
		||||
		break;
 | 
			
		||||
	case PORT_CLK_SEL_LCPLL_1350:
 | 
			
		||||
		link_clock = 135000;
 | 
			
		||||
		break;
 | 
			
		||||
	case PORT_CLK_SEL_LCPLL_2700:
 | 
			
		||||
		link_clock = 270000;
 | 
			
		||||
		break;
 | 
			
		||||
	case PORT_CLK_SEL_WRPLL1:
 | 
			
		||||
		link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
 | 
			
		||||
		break;
 | 
			
		||||
	case PORT_CLK_SEL_WRPLL2:
 | 
			
		||||
		link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
 | 
			
		||||
		break;
 | 
			
		||||
	case PORT_CLK_SEL_SPLL:
 | 
			
		||||
		pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
 | 
			
		||||
		if (pll == SPLL_PLL_FREQ_810MHz)
 | 
			
		||||
			link_clock = 81000;
 | 
			
		||||
		else if (pll == SPLL_PLL_FREQ_1350MHz)
 | 
			
		||||
			link_clock = 135000;
 | 
			
		||||
		else if (pll == SPLL_PLL_FREQ_2700MHz)
 | 
			
		||||
			link_clock = 270000;
 | 
			
		||||
		else {
 | 
			
		||||
			WARN(1, "bad spll freq\n");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		WARN(1, "bad port clock sel\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pipe_config->port_clock = link_clock * 2;
 | 
			
		||||
 | 
			
		||||
	if (pipe_config->has_pch_encoder)
 | 
			
		||||
		pipe_config->adjusted_mode.crtc_clock =
 | 
			
		||||
			intel_dotclock_calculate(pipe_config->port_clock,
 | 
			
		||||
						 &pipe_config->fdi_m_n);
 | 
			
		||||
	else if (pipe_config->has_dp_encoder)
 | 
			
		||||
		pipe_config->adjusted_mode.crtc_clock =
 | 
			
		||||
			intel_dotclock_calculate(pipe_config->port_clock,
 | 
			
		||||
						 &pipe_config->dp_m_n);
 | 
			
		||||
	else
 | 
			
		||||
		pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
intel_ddi_calculate_wrpll(int clock /* in Hz */,
 | 
			
		||||
			  unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
 | 
			
		||||
| 
						 | 
				
			
			@ -1200,7 +1291,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 | 
			
		|||
 | 
			
		||||
	if (type == INTEL_OUTPUT_EDP) {
 | 
			
		||||
		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 | 
			
		||||
		ironlake_edp_panel_on(intel_dp);
 | 
			
		||||
		intel_edp_panel_on(intel_dp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1244,7 +1335,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 | 
			
		|||
	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
 | 
			
		||||
		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 | 
			
		||||
		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 | 
			
		||||
		ironlake_edp_panel_off(intel_dp);
 | 
			
		||||
		intel_edp_panel_off(intel_dp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
 | 
			
		||||
| 
						 | 
				
			
			@ -1279,7 +1370,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 | 
			
		|||
		if (port == PORT_A)
 | 
			
		||||
			intel_dp_stop_link_train(intel_dp);
 | 
			
		||||
 | 
			
		||||
		ironlake_edp_backlight_on(intel_dp);
 | 
			
		||||
		intel_edp_backlight_on(intel_dp);
 | 
			
		||||
		intel_edp_psr_enable(intel_dp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,7 +1403,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 | 
			
		|||
		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 | 
			
		||||
 | 
			
		||||
		intel_edp_psr_disable(intel_dp);
 | 
			
		||||
		ironlake_edp_backlight_off(intel_dp);
 | 
			
		||||
		intel_edp_backlight_off(intel_dp);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1509,6 +1600,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 | 
			
		|||
			      pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp);
 | 
			
		||||
		dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	intel_ddi_clock_get(encoder, pipe_config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void intel_ddi_destroy(struct drm_encoder *encoder)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2372,7 +2372,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 | 
			
		|||
	 * whether the platform allows pfit disable with pipe active, and only
 | 
			
		||||
	 * then update the pipesrc and pfit state, even on the flip path.
 | 
			
		||||
	 */
 | 
			
		||||
	if (i915_fastboot) {
 | 
			
		||||
	if (i915.fastboot) {
 | 
			
		||||
		const struct drm_display_mode *adjusted_mode =
 | 
			
		||||
			&intel_crtc->config.adjusted_mode;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4088,9 +4088,8 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
 | 
			
		|||
	/* Looks like the 200MHz CDclk freq doesn't work on some configs */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
 | 
			
		||||
				 unsigned modeset_pipes,
 | 
			
		||||
				 struct intel_crtc_config *pipe_config)
 | 
			
		||||
/* compute the max pixel clock for new configuration */
 | 
			
		||||
static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = dev_priv->dev;
 | 
			
		||||
	struct intel_crtc *intel_crtc;
 | 
			
		||||
| 
						 | 
				
			
			@ -4098,31 +4097,26 @@ static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
 | 
			
		|||
 | 
			
		||||
	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		if (modeset_pipes & (1 << intel_crtc->pipe))
 | 
			
		||||
		if (intel_crtc->new_enabled)
 | 
			
		||||
			max_pixclk = max(max_pixclk,
 | 
			
		||||
					 pipe_config->adjusted_mode.crtc_clock);
 | 
			
		||||
		else if (intel_crtc->base.enabled)
 | 
			
		||||
			max_pixclk = max(max_pixclk,
 | 
			
		||||
					 intel_crtc->config.adjusted_mode.crtc_clock);
 | 
			
		||||
					 intel_crtc->new_config->adjusted_mode.crtc_clock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return max_pixclk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void valleyview_modeset_global_pipes(struct drm_device *dev,
 | 
			
		||||
					    unsigned *prepare_pipes,
 | 
			
		||||
					    unsigned modeset_pipes,
 | 
			
		||||
					    struct intel_crtc_config *pipe_config)
 | 
			
		||||
					    unsigned *prepare_pipes)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_crtc *intel_crtc;
 | 
			
		||||
	int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes,
 | 
			
		||||
					       pipe_config);
 | 
			
		||||
	int max_pixclk = intel_mode_max_pixclk(dev_priv);
 | 
			
		||||
	int cur_cdclk = valleyview_cur_cdclk(dev_priv);
 | 
			
		||||
 | 
			
		||||
	if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* disable/enable all currently active pipes while we change cdclk */
 | 
			
		||||
	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head)
 | 
			
		||||
		if (intel_crtc->base.enabled)
 | 
			
		||||
| 
						 | 
				
			
			@ -4132,7 +4126,7 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev,
 | 
			
		|||
static void valleyview_modeset_global_resources(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL);
 | 
			
		||||
	int max_pixclk = intel_mode_max_pixclk(dev_priv);
 | 
			
		||||
	int cur_cdclk = valleyview_cur_cdclk(dev_priv);
 | 
			
		||||
	int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4176,6 +4170,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 | 
			
		|||
 | 
			
		||||
	intel_update_watermarks(crtc);
 | 
			
		||||
	intel_enable_pipe(dev_priv, pipe, false, is_dsi);
 | 
			
		||||
	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 | 
			
		||||
	intel_enable_primary_plane(dev_priv, plane, pipe);
 | 
			
		||||
	intel_enable_planes(crtc);
 | 
			
		||||
	intel_crtc_update_cursor(crtc, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -4214,6 +4209,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 | 
			
		|||
 | 
			
		||||
	intel_update_watermarks(crtc);
 | 
			
		||||
	intel_enable_pipe(dev_priv, pipe, false, false);
 | 
			
		||||
	intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
 | 
			
		||||
	intel_enable_primary_plane(dev_priv, plane, pipe);
 | 
			
		||||
	intel_enable_planes(crtc);
 | 
			
		||||
	/* The fixup needs to happen before cursor is enabled */
 | 
			
		||||
| 
						 | 
				
			
			@ -4272,6 +4268,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 | 
			
		|||
	intel_disable_planes(crtc);
 | 
			
		||||
	intel_disable_primary_plane(dev_priv, plane, pipe);
 | 
			
		||||
 | 
			
		||||
	intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
 | 
			
		||||
	intel_disable_pipe(dev_priv, pipe);
 | 
			
		||||
 | 
			
		||||
	i9xx_pfit_disable(intel_crtc);
 | 
			
		||||
| 
						 | 
				
			
			@ -4583,7 +4580,7 @@ retry:
 | 
			
		|||
static void hsw_compute_ips_config(struct intel_crtc *crtc,
 | 
			
		||||
				   struct intel_crtc_config *pipe_config)
 | 
			
		||||
{
 | 
			
		||||
	pipe_config->ips_enabled = i915_enable_ips &&
 | 
			
		||||
	pipe_config->ips_enabled = i915.enable_ips &&
 | 
			
		||||
				   hsw_crtc_supports_ips(crtc) &&
 | 
			
		||||
				   pipe_config->pipe_bpp <= 24;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4784,8 +4781,8 @@ intel_link_compute_m_n(int bits_per_pixel, int nlanes,
 | 
			
		|||
 | 
			
		||||
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	if (i915_panel_use_ssc >= 0)
 | 
			
		||||
		return i915_panel_use_ssc != 0;
 | 
			
		||||
	if (i915.panel_use_ssc >= 0)
 | 
			
		||||
		return i915.panel_use_ssc != 0;
 | 
			
		||||
	return dev_priv->vbt.lvds_use_ssc
 | 
			
		||||
		&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4844,7 +4841,7 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
 | 
			
		|||
 | 
			
		||||
	crtc->lowfreq_avail = false;
 | 
			
		||||
	if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
 | 
			
		||||
	    reduced_clock && i915_powersave) {
 | 
			
		||||
	    reduced_clock && i915.powersave) {
 | 
			
		||||
		I915_WRITE(FP1(pipe), fp2);
 | 
			
		||||
		crtc->config.dpll_hw_state.fp1 = fp2;
 | 
			
		||||
		crtc->lowfreq_avail = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -6348,7 +6345,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 | 
			
		|||
	if (intel_crtc->config.has_dp_encoder)
 | 
			
		||||
		intel_dp_set_m_n(intel_crtc);
 | 
			
		||||
 | 
			
		||||
	if (is_lvds && has_reduced_clock && i915_powersave)
 | 
			
		||||
	if (is_lvds && has_reduced_clock && i915.powersave)
 | 
			
		||||
		intel_crtc->lowfreq_avail = true;
 | 
			
		||||
	else
 | 
			
		||||
		intel_crtc->lowfreq_avail = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -6716,7 +6713,7 @@ static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	schedule_delayed_work(&dev_priv->pc8.enable_work,
 | 
			
		||||
			      msecs_to_jiffies(i915_pc8_timeout));
 | 
			
		||||
			      msecs_to_jiffies(i915.pc8_timeout));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
 | 
			
		||||
| 
						 | 
				
			
			@ -6815,7 +6812,7 @@ static void hsw_update_package_c8(struct drm_device *dev)
 | 
			
		|||
	if (!HAS_PC8(dev_priv->dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!i915_enable_pc8)
 | 
			
		||||
	if (!i915.enable_pc8)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev_priv->pc8.lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -7855,6 +7852,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 | 
			
		|||
	to_intel_connector(connector)->new_encoder = intel_encoder;
 | 
			
		||||
 | 
			
		||||
	intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	intel_crtc->new_enabled = true;
 | 
			
		||||
	intel_crtc->new_config = &intel_crtc->config;
 | 
			
		||||
	old->dpms_mode = connector->dpms;
 | 
			
		||||
	old->load_detect_temp = true;
 | 
			
		||||
	old->release_fb = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -7878,21 +7877,28 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 | 
			
		|||
		DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
 | 
			
		||||
	if (IS_ERR(fb)) {
 | 
			
		||||
		DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
 | 
			
		||||
		mutex_unlock(&crtc->mutex);
 | 
			
		||||
		return false;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (intel_set_mode(crtc, mode, 0, 0, fb)) {
 | 
			
		||||
		DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
 | 
			
		||||
		if (old->release_fb)
 | 
			
		||||
			old->release_fb->funcs->destroy(old->release_fb);
 | 
			
		||||
		mutex_unlock(&crtc->mutex);
 | 
			
		||||
		return false;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* let the connector get through one full cycle before testing */
 | 
			
		||||
	intel_wait_for_vblank(dev, intel_crtc->pipe);
 | 
			
		||||
	return true;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
	intel_crtc->new_enabled = crtc->enabled;
 | 
			
		||||
	if (intel_crtc->new_enabled)
 | 
			
		||||
		intel_crtc->new_config = &intel_crtc->config;
 | 
			
		||||
	else
 | 
			
		||||
		intel_crtc->new_config = NULL;
 | 
			
		||||
	mutex_unlock(&crtc->mutex);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void intel_release_load_detect_pipe(struct drm_connector *connector,
 | 
			
		||||
| 
						 | 
				
			
			@ -7902,6 +7908,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 | 
			
		|||
		intel_attached_encoder(connector);
 | 
			
		||||
	struct drm_encoder *encoder = &intel_encoder->base;
 | 
			
		||||
	struct drm_crtc *crtc = encoder->crtc;
 | 
			
		||||
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
 | 
			
		||||
		      connector->base.id, drm_get_connector_name(connector),
 | 
			
		||||
| 
						 | 
				
			
			@ -7910,6 +7917,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 | 
			
		|||
	if (old->load_detect_temp) {
 | 
			
		||||
		to_intel_connector(connector)->new_encoder = NULL;
 | 
			
		||||
		intel_encoder->new_crtc = NULL;
 | 
			
		||||
		intel_crtc->new_enabled = false;
 | 
			
		||||
		intel_crtc->new_config = NULL;
 | 
			
		||||
		intel_set_mode(crtc, NULL, 0, 0, NULL);
 | 
			
		||||
 | 
			
		||||
		if (old->release_fb) {
 | 
			
		||||
| 
						 | 
				
			
			@ -8201,7 +8210,7 @@ void intel_mark_idle(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	hsw_package_c8_gpu_idle(dev_priv);
 | 
			
		||||
 | 
			
		||||
	if (!i915_powersave)
 | 
			
		||||
	if (!i915.powersave)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 | 
			
		||||
| 
						 | 
				
			
			@ -8221,7 +8230,7 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
 | 
			
		|||
	struct drm_device *dev = obj->base.dev;
 | 
			
		||||
	struct drm_crtc *crtc;
 | 
			
		||||
 | 
			
		||||
	if (!i915_powersave)
 | 
			
		||||
	if (!i915.powersave)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 | 
			
		||||
| 
						 | 
				
			
			@ -8766,6 +8775,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
 | 
			
		|||
 */
 | 
			
		||||
static void intel_modeset_update_staged_output_state(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_crtc *crtc;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8780,6 +8790,16 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
 | 
			
		|||
		encoder->new_crtc =
 | 
			
		||||
			to_intel_crtc(encoder->base.crtc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		crtc->new_enabled = crtc->base.enabled;
 | 
			
		||||
 | 
			
		||||
		if (crtc->new_enabled)
 | 
			
		||||
			crtc->new_config = &crtc->config;
 | 
			
		||||
		else
 | 
			
		||||
			crtc->new_config = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -8789,6 +8809,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
 | 
			
		|||
 */
 | 
			
		||||
static void intel_modeset_commit_output_state(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_crtc *crtc;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8801,6 +8822,11 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
 | 
			
		|||
			    base.head) {
 | 
			
		||||
		encoder->base.crtc = &encoder->new_crtc->base;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		crtc->base.enabled = crtc->new_enabled;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -9127,29 +9153,22 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
 | 
			
		|||
			*prepare_pipes |= 1 << encoder->new_crtc->pipe;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check for any pipes that will be fully disabled ... */
 | 
			
		||||
	/* Check for pipes that will be enabled/disabled ... */
 | 
			
		||||
	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		bool used = false;
 | 
			
		||||
 | 
			
		||||
		/* Don't try to disable disabled crtcs. */
 | 
			
		||||
		if (!intel_crtc->base.enabled)
 | 
			
		||||
		if (intel_crtc->base.enabled == intel_crtc->new_enabled)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(encoder, &dev->mode_config.encoder_list,
 | 
			
		||||
				    base.head) {
 | 
			
		||||
			if (encoder->new_crtc == intel_crtc)
 | 
			
		||||
				used = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!used)
 | 
			
		||||
		if (!intel_crtc->new_enabled)
 | 
			
		||||
			*disable_pipes |= 1 << intel_crtc->pipe;
 | 
			
		||||
		else
 | 
			
		||||
			*prepare_pipes |= 1 << intel_crtc->pipe;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* set_mode is also used to update properties on life display pipes. */
 | 
			
		||||
	intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	if (crtc->enabled)
 | 
			
		||||
	if (intel_crtc->new_enabled)
 | 
			
		||||
		*prepare_pipes |= 1 << intel_crtc->pipe;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -9208,10 +9227,13 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 | 
			
		|||
 | 
			
		||||
	intel_modeset_commit_output_state(dev);
 | 
			
		||||
 | 
			
		||||
	/* Update computed state. */
 | 
			
		||||
	/* Double check state. */
 | 
			
		||||
	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base);
 | 
			
		||||
		WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base));
 | 
			
		||||
		WARN_ON(intel_crtc->new_config &&
 | 
			
		||||
			intel_crtc->new_config != &intel_crtc->config);
 | 
			
		||||
		WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 | 
			
		||||
| 
						 | 
				
			
			@ -9380,10 +9402,8 @@ intel_pipe_config_compare(struct drm_device *dev,
 | 
			
		|||
	if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
 | 
			
		||||
		PIPE_CONF_CHECK_I(pipe_bpp);
 | 
			
		||||
 | 
			
		||||
	if (!HAS_DDI(dev)) {
 | 
			
		||||
	PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock);
 | 
			
		||||
	PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#undef PIPE_CONF_CHECK_X
 | 
			
		||||
#undef PIPE_CONF_CHECK_I
 | 
			
		||||
| 
						 | 
				
			
			@ -9643,6 +9663,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 | 
			
		|||
		}
 | 
			
		||||
		intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
 | 
			
		||||
				       "[modeset]");
 | 
			
		||||
		to_intel_crtc(crtc)->new_config = pipe_config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -9653,8 +9674,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 | 
			
		|||
	 * adjusted_mode bits in the crtc directly.
 | 
			
		||||
	 */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev)) {
 | 
			
		||||
		valleyview_modeset_global_pipes(dev, &prepare_pipes,
 | 
			
		||||
						modeset_pipes, pipe_config);
 | 
			
		||||
		valleyview_modeset_global_pipes(dev, &prepare_pipes);
 | 
			
		||||
 | 
			
		||||
		/* may have added more to prepare_pipes than we should */
 | 
			
		||||
		prepare_pipes &= ~disable_pipes;
 | 
			
		||||
| 
						 | 
				
			
			@ -9676,6 +9696,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 | 
			
		|||
		/* mode_set/enable/disable functions rely on a correct pipe
 | 
			
		||||
		 * config. */
 | 
			
		||||
		to_intel_crtc(crtc)->config = *pipe_config;
 | 
			
		||||
		to_intel_crtc(crtc)->new_config = &to_intel_crtc(crtc)->config;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Calculate and store various constants which
 | 
			
		||||
| 
						 | 
				
			
			@ -9746,16 +9767,24 @@ static void intel_set_config_free(struct intel_set_config *config)
 | 
			
		|||
 | 
			
		||||
	kfree(config->save_connector_encoders);
 | 
			
		||||
	kfree(config->save_encoder_crtcs);
 | 
			
		||||
	kfree(config->save_crtc_enabled);
 | 
			
		||||
	kfree(config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_set_config_save_state(struct drm_device *dev,
 | 
			
		||||
				       struct intel_set_config *config)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_crtc *crtc;
 | 
			
		||||
	struct drm_encoder *encoder;
 | 
			
		||||
	struct drm_connector *connector;
 | 
			
		||||
	int count;
 | 
			
		||||
 | 
			
		||||
	config->save_crtc_enabled =
 | 
			
		||||
		kcalloc(dev->mode_config.num_crtc,
 | 
			
		||||
			sizeof(bool), GFP_KERNEL);
 | 
			
		||||
	if (!config->save_crtc_enabled)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	config->save_encoder_crtcs =
 | 
			
		||||
		kcalloc(dev->mode_config.num_encoder,
 | 
			
		||||
			sizeof(struct drm_crtc *), GFP_KERNEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -9772,6 +9801,11 @@ static int intel_set_config_save_state(struct drm_device *dev,
 | 
			
		|||
	 * Should anything bad happen only the expected state is
 | 
			
		||||
	 * restored, not the drivers personal bookkeeping.
 | 
			
		||||
	 */
 | 
			
		||||
	count = 0;
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 | 
			
		||||
		config->save_crtc_enabled[count++] = crtc->enabled;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	count = 0;
 | 
			
		||||
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 | 
			
		||||
		config->save_encoder_crtcs[count++] = encoder->crtc;
 | 
			
		||||
| 
						 | 
				
			
			@ -9788,10 +9822,21 @@ static int intel_set_config_save_state(struct drm_device *dev,
 | 
			
		|||
static void intel_set_config_restore_state(struct drm_device *dev,
 | 
			
		||||
					   struct intel_set_config *config)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_crtc *crtc;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
	int count;
 | 
			
		||||
 | 
			
		||||
	count = 0;
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
 | 
			
		||||
		crtc->new_enabled = config->save_crtc_enabled[count++];
 | 
			
		||||
 | 
			
		||||
		if (crtc->new_enabled)
 | 
			
		||||
			crtc->new_config = &crtc->config;
 | 
			
		||||
		else
 | 
			
		||||
			crtc->new_config = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	count = 0;
 | 
			
		||||
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
 | 
			
		||||
		encoder->new_crtc =
 | 
			
		||||
| 
						 | 
				
			
			@ -9840,7 +9885,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 | 
			
		|||
			struct intel_crtc *intel_crtc =
 | 
			
		||||
				to_intel_crtc(set->crtc);
 | 
			
		||||
 | 
			
		||||
			if (intel_crtc->active && i915_fastboot) {
 | 
			
		||||
			if (intel_crtc->active && i915.fastboot) {
 | 
			
		||||
				DRM_DEBUG_KMS("crtc has no fb, will flip\n");
 | 
			
		||||
				config->fb_changed = true;
 | 
			
		||||
			} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -9876,9 +9921,9 @@ intel_modeset_stage_output_state(struct drm_device *dev,
 | 
			
		|||
				 struct drm_mode_set *set,
 | 
			
		||||
				 struct intel_set_config *config)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_crtc *new_crtc;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_crtc *crtc;
 | 
			
		||||
	int ro;
 | 
			
		||||
 | 
			
		||||
	/* The upper layers ensure that we either disable a crtc or have a list
 | 
			
		||||
| 
						 | 
				
			
			@ -9921,6 +9966,8 @@ intel_modeset_stage_output_state(struct drm_device *dev,
 | 
			
		|||
	/* Update crtc of enabled connectors. */
 | 
			
		||||
	list_for_each_entry(connector, &dev->mode_config.connector_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		struct drm_crtc *new_crtc;
 | 
			
		||||
 | 
			
		||||
		if (!connector->new_encoder)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9971,9 +10018,58 @@ intel_modeset_stage_output_state(struct drm_device *dev,
 | 
			
		|||
	}
 | 
			
		||||
	/* Now we've also updated encoder->new_crtc for all encoders. */
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		crtc->new_enabled = false;
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(encoder,
 | 
			
		||||
				    &dev->mode_config.encoder_list,
 | 
			
		||||
				    base.head) {
 | 
			
		||||
			if (encoder->new_crtc == crtc) {
 | 
			
		||||
				crtc->new_enabled = true;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (crtc->new_enabled != crtc->base.enabled) {
 | 
			
		||||
			DRM_DEBUG_KMS("crtc %sabled, full mode switch\n",
 | 
			
		||||
				      crtc->new_enabled ? "en" : "dis");
 | 
			
		||||
			config->mode_changed = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (crtc->new_enabled)
 | 
			
		||||
			crtc->new_config = &crtc->config;
 | 
			
		||||
		else
 | 
			
		||||
			crtc->new_config = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void disable_crtc_nofb(struct intel_crtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = crtc->base.dev;
 | 
			
		||||
	struct intel_encoder *encoder;
 | 
			
		||||
	struct intel_connector *connector;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n",
 | 
			
		||||
		      pipe_name(crtc->pipe));
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
 | 
			
		||||
		if (connector->new_encoder &&
 | 
			
		||||
		    connector->new_encoder->new_crtc == crtc)
 | 
			
		||||
			connector->new_encoder = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
 | 
			
		||||
		if (encoder->new_crtc == crtc)
 | 
			
		||||
			encoder->new_crtc = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	crtc->new_enabled = false;
 | 
			
		||||
	crtc->new_config = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_crtc_set_config(struct drm_mode_set *set)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -10040,7 +10136,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 | 
			
		|||
		 * flipping, so increasing its cost here shouldn't be a big
 | 
			
		||||
		 * deal).
 | 
			
		||||
		 */
 | 
			
		||||
		if (i915_fastboot && ret == 0)
 | 
			
		||||
		if (i915.fastboot && ret == 0)
 | 
			
		||||
			intel_modeset_check_state(set->crtc->dev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10050,6 +10146,15 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 | 
			
		|||
fail:
 | 
			
		||||
		intel_set_config_restore_state(dev, config);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * HACK: if the pipe was on, but we didn't have a framebuffer,
 | 
			
		||||
		 * force the pipe off to avoid oopsing in the modeset code
 | 
			
		||||
		 * due to fb==NULL. This should only happen during boot since
 | 
			
		||||
		 * we don't yet reconstruct the FB from the hardware state.
 | 
			
		||||
		 */
 | 
			
		||||
		if (to_intel_crtc(save_set.crtc)->new_enabled && !save_set.fb)
 | 
			
		||||
			disable_crtc_nofb(to_intel_crtc(save_set.crtc));
 | 
			
		||||
 | 
			
		||||
		/* Try to restore the config */
 | 
			
		||||
		if (config->mode_changed &&
 | 
			
		||||
		    intel_set_mode(save_set.crtc, save_set.mode,
 | 
			
		||||
| 
						 | 
				
			
			@ -10839,6 +10944,9 @@ static struct intel_quirk intel_quirks[] = {
 | 
			
		|||
 | 
			
		||||
	/* Acer Aspire 4736Z */
 | 
			
		||||
	{ 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
 | 
			
		||||
 | 
			
		||||
	/* Acer Aspire 5336 */
 | 
			
		||||
	{ 0x2a42, 0x1025, 0x048a, quirk_invert_brightness },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void intel_init_quirks(struct drm_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -10869,6 +10977,7 @@ static void i915_disable_vga(struct drm_device *dev)
 | 
			
		|||
	u8 sr1;
 | 
			
		||||
	u32 vga_reg = i915_vgacntrl_reg(dev);
 | 
			
		||||
 | 
			
		||||
	/* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
 | 
			
		||||
	vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
 | 
			
		||||
	outb(SR01, VGA_SR_INDEX);
 | 
			
		||||
	sr1 = inb(VGA_SR_DATA);
 | 
			
		||||
| 
						 | 
				
			
			@ -11265,7 +11374,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 | 
			
		|||
	 */
 | 
			
		||||
	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
 | 
			
		||||
			    base.head) {
 | 
			
		||||
		if (crtc->active && i915_fastboot) {
 | 
			
		||||
		if (crtc->active && i915.fastboot) {
 | 
			
		||||
			intel_crtc_mode_from_pipe_config(crtc, &crtc->config);
 | 
			
		||||
 | 
			
		||||
			DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
 | 
			
		||||
| 
						 | 
				
			
			@ -11329,7 +11438,6 @@ void intel_modeset_gem_init(struct drm_device *dev)
 | 
			
		|||
	intel_setup_overlay(dev);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->mode_config.mutex);
 | 
			
		||||
	drm_mode_config_reset(dev);
 | 
			
		||||
	intel_modeset_setup_hw_state(dev, false);
 | 
			
		||||
	mutex_unlock(&dev->mode_config.mutex);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,17 +91,24 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void intel_dp_link_down(struct intel_dp *intel_dp);
 | 
			
		||||
static void edp_panel_vdd_on(struct intel_dp *intel_dp);
 | 
			
		||||
static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
intel_dp_max_link_bw(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
 | 
			
		||||
	struct drm_device *dev = intel_dp->attached_connector->base.dev;
 | 
			
		||||
 | 
			
		||||
	switch (max_link_bw) {
 | 
			
		||||
	case DP_LINK_BW_1_62:
 | 
			
		||||
	case DP_LINK_BW_2_7:
 | 
			
		||||
		break;
 | 
			
		||||
	case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */
 | 
			
		||||
		if ((IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) &&
 | 
			
		||||
		    intel_dp->dpcd[DP_DPCD_REV] >= 0x12)
 | 
			
		||||
			max_link_bw = DP_LINK_BW_5_4;
 | 
			
		||||
		else
 | 
			
		||||
			max_link_bw = DP_LINK_BW_2_7;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +301,7 @@ static u32 _pp_stat_reg(struct intel_dp *intel_dp)
 | 
			
		|||
		return VLV_PIPE_PP_STATUS(vlv_power_sequencer_pipe(intel_dp));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
 | 
			
		||||
static bool edp_have_panel_power(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -302,7 +309,7 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
 | 
			
		|||
	return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp)
 | 
			
		||||
static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +326,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
 | 
			
		|||
	if (!is_edp(intel_dp))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) {
 | 
			
		||||
	if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
 | 
			
		||||
		WARN(1, "eDP powered off while attempting aux channel communication.\n");
 | 
			
		||||
		DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
 | 
			
		||||
			      I915_READ(_pp_stat_reg(intel_dp)),
 | 
			
		||||
| 
						 | 
				
			
			@ -351,31 +358,46 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
 | 
			
		|||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp,
 | 
			
		||||
				      int index)
 | 
			
		||||
static uint32_t i9xx_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The clock divider is based off the hrawclk, and would like to run at
 | 
			
		||||
	 * 2MHz.  So, take the hrawclk value and divide by 2 and use that
 | 
			
		||||
	 */
 | 
			
		||||
	return index ? 0 : intel_hrawclk(dev) / 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
 | 
			
		||||
	if (index)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (intel_dig_port->port == PORT_A) {
 | 
			
		||||
		if (IS_GEN6(dev) || IS_GEN7(dev))
 | 
			
		||||
			return 200; /* SNB & IVB eDP input clock at 400Mhz */
 | 
			
		||||
		else
 | 
			
		||||
			return 225; /* eDP input clock at 450Mhz */
 | 
			
		||||
	} else {
 | 
			
		||||
		return DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	/* The clock divider is based off the hrawclk,
 | 
			
		||||
	 * and would like to run at 2MHz. So, take the
 | 
			
		||||
	 * hrawclk value and divide by 2 and use that
 | 
			
		||||
	 *
 | 
			
		||||
	 * Note that PCH attached eDP panels should use a 125MHz input
 | 
			
		||||
	 * clock divider.
 | 
			
		||||
	 */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev)) {
 | 
			
		||||
		return index ? 0 : 100;
 | 
			
		||||
	} else if (intel_dig_port->port == PORT_A) {
 | 
			
		||||
	if (intel_dig_port->port == PORT_A) {
 | 
			
		||||
		if (index)
 | 
			
		||||
			return 0;
 | 
			
		||||
		if (HAS_DDI(dev))
 | 
			
		||||
		return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000);
 | 
			
		||||
		else if (IS_GEN6(dev) || IS_GEN7(dev))
 | 
			
		||||
			return 200; /* SNB & IVB eDP input clock at 400Mhz */
 | 
			
		||||
		else
 | 
			
		||||
			return 225; /* eDP input clock at 450Mhz */
 | 
			
		||||
	} else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
 | 
			
		||||
		/* Workaround for non-ULT HSW */
 | 
			
		||||
		switch (index) {
 | 
			
		||||
| 
						 | 
				
			
			@ -383,13 +405,46 @@ static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp,
 | 
			
		|||
		case 1: return 72;
 | 
			
		||||
		default: return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (HAS_PCH_SPLIT(dev)) {
 | 
			
		||||
		return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
 | 
			
		||||
	} else  {
 | 
			
		||||
		return index ? 0 :intel_hrawclk(dev) / 2;
 | 
			
		||||
		return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 | 
			
		||||
{
 | 
			
		||||
	return index ? 0 : 100;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
 | 
			
		||||
				      bool has_aux_irq,
 | 
			
		||||
				      int send_bytes,
 | 
			
		||||
				      uint32_t aux_clock_divider)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
	uint32_t precharge, timeout;
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN6(dev))
 | 
			
		||||
		precharge = 3;
 | 
			
		||||
	else
 | 
			
		||||
		precharge = 5;
 | 
			
		||||
 | 
			
		||||
	if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL)
 | 
			
		||||
		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
 | 
			
		||||
	else
 | 
			
		||||
		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
 | 
			
		||||
 | 
			
		||||
	return DP_AUX_CH_CTL_SEND_BUSY |
 | 
			
		||||
	       DP_AUX_CH_CTL_DONE |
 | 
			
		||||
	       (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
 | 
			
		||||
	       DP_AUX_CH_CTL_TIME_OUT_ERROR |
 | 
			
		||||
	       timeout |
 | 
			
		||||
	       DP_AUX_CH_CTL_RECEIVE_ERROR |
 | 
			
		||||
	       (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
 | 
			
		||||
	       (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
 | 
			
		||||
	       (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
intel_dp_aux_ch(struct intel_dp *intel_dp,
 | 
			
		||||
		uint8_t *send, int send_bytes,
 | 
			
		||||
| 
						 | 
				
			
			@ -403,9 +458,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 | 
			
		|||
	uint32_t aux_clock_divider;
 | 
			
		||||
	int i, ret, recv_bytes;
 | 
			
		||||
	uint32_t status;
 | 
			
		||||
	int try, precharge, clock = 0;
 | 
			
		||||
	int try, clock = 0;
 | 
			
		||||
	bool has_aux_irq = HAS_AUX_IRQ(dev);
 | 
			
		||||
	uint32_t timeout;
 | 
			
		||||
 | 
			
		||||
	/* dp aux is extremely sensitive to irq latency, hence request the
 | 
			
		||||
	 * lowest possible wakeup latency and so prevent the cpu from going into
 | 
			
		||||
| 
						 | 
				
			
			@ -415,16 +469,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 | 
			
		|||
 | 
			
		||||
	intel_dp_check_edp(intel_dp);
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN6(dev))
 | 
			
		||||
		precharge = 3;
 | 
			
		||||
	else
 | 
			
		||||
		precharge = 5;
 | 
			
		||||
 | 
			
		||||
	if (IS_BROADWELL(dev) && ch_ctl == DPA_AUX_CH_CTL)
 | 
			
		||||
		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
 | 
			
		||||
	else
 | 
			
		||||
		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
 | 
			
		||||
 | 
			
		||||
	intel_aux_display_runtime_get(dev_priv);
 | 
			
		||||
 | 
			
		||||
	/* Try to wait for any previous AUX channel activity */
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +492,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((aux_clock_divider = get_aux_clock_divider(intel_dp, clock++))) {
 | 
			
		||||
	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
 | 
			
		||||
		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
 | 
			
		||||
							  has_aux_irq,
 | 
			
		||||
							  send_bytes,
 | 
			
		||||
							  aux_clock_divider);
 | 
			
		||||
 | 
			
		||||
		/* Must try at least 3 times according to DP spec */
 | 
			
		||||
		for (try = 0; try < 5; try++) {
 | 
			
		||||
			/* Load the send data into the aux channel data registers */
 | 
			
		||||
| 
						 | 
				
			
			@ -457,16 +506,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 | 
			
		|||
					   pack_aux(send + i, send_bytes - i));
 | 
			
		||||
 | 
			
		||||
			/* Send the command and wait for it to complete */
 | 
			
		||||
			I915_WRITE(ch_ctl,
 | 
			
		||||
				   DP_AUX_CH_CTL_SEND_BUSY |
 | 
			
		||||
				   (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
 | 
			
		||||
				   timeout |
 | 
			
		||||
				   (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
 | 
			
		||||
				   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
 | 
			
		||||
				   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
 | 
			
		||||
				   DP_AUX_CH_CTL_DONE |
 | 
			
		||||
				   DP_AUX_CH_CTL_TIME_OUT_ERROR |
 | 
			
		||||
				   DP_AUX_CH_CTL_RECEIVE_ERROR);
 | 
			
		||||
			I915_WRITE(ch_ctl, send_ctl);
 | 
			
		||||
 | 
			
		||||
			status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -637,7 +677,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 | 
			
		|||
	int reply_bytes;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ironlake_edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	intel_dp_check_edp(intel_dp);
 | 
			
		||||
	/* Set up the command byte */
 | 
			
		||||
	if (mode & MODE_I2C_READ)
 | 
			
		||||
| 
						 | 
				
			
			@ -740,7 +780,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 | 
			
		|||
	ret = -EREMOTEIO;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	ironlake_edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
	edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -812,9 +852,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 | 
			
		|||
	struct intel_connector *intel_connector = intel_dp->attached_connector;
 | 
			
		||||
	int lane_count, clock;
 | 
			
		||||
	int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
 | 
			
		||||
	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
 | 
			
		||||
	/* Conveniently, the link BW constants become indices with a shift...*/
 | 
			
		||||
	int max_clock = intel_dp_max_link_bw(intel_dp) >> 3;
 | 
			
		||||
	int bpp, mode_rate;
 | 
			
		||||
	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
 | 
			
		||||
	static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 };
 | 
			
		||||
	int link_avail, link_clock;
 | 
			
		||||
 | 
			
		||||
	if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
 | 
			
		||||
| 
						 | 
				
			
			@ -1015,16 +1056,16 @@ static void intel_dp_mode_set(struct intel_encoder *encoder)
 | 
			
		|||
		ironlake_set_pll_cpu_edp(intel_dp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define IDLE_ON_MASK		(PP_ON | 0 	  | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
 | 
			
		||||
#define IDLE_ON_VALUE   	(PP_ON | 0 	  | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
 | 
			
		||||
#define IDLE_ON_MASK		(PP_ON | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
 | 
			
		||||
#define IDLE_ON_VALUE   	(PP_ON | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
 | 
			
		||||
 | 
			
		||||
#define IDLE_OFF_MASK		(PP_ON | 0        | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
 | 
			
		||||
#define IDLE_OFF_VALUE		(0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
 | 
			
		||||
#define IDLE_OFF_MASK		(PP_ON | PP_SEQUENCE_MASK | 0                     | 0)
 | 
			
		||||
#define IDLE_OFF_VALUE		(0     | PP_SEQUENCE_NONE | 0                     | 0)
 | 
			
		||||
 | 
			
		||||
#define IDLE_CYCLE_MASK		(PP_ON | 0        | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
 | 
			
		||||
#define IDLE_CYCLE_VALUE	(0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
 | 
			
		||||
#define IDLE_CYCLE_MASK		(PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
 | 
			
		||||
#define IDLE_CYCLE_VALUE	(0     | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
 | 
			
		||||
 | 
			
		||||
static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
 | 
			
		||||
static void wait_panel_status(struct intel_dp *intel_dp,
 | 
			
		||||
				       u32 mask,
 | 
			
		||||
				       u32 value)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1049,24 +1090,41 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
 | 
			
		|||
	DRM_DEBUG_KMS("Wait complete\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_wait_panel_on(struct intel_dp *intel_dp)
 | 
			
		||||
static void wait_panel_on(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	DRM_DEBUG_KMS("Wait for panel power on\n");
 | 
			
		||||
	ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
 | 
			
		||||
	wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
 | 
			
		||||
static void wait_panel_off(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	DRM_DEBUG_KMS("Wait for panel power off time\n");
 | 
			
		||||
	ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
 | 
			
		||||
	wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
 | 
			
		||||
static void wait_panel_power_cycle(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	DRM_DEBUG_KMS("Wait for panel power cycle\n");
 | 
			
		||||
	ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
 | 
			
		||||
 | 
			
		||||
	/* When we disable the VDD override bit last we have to do the manual
 | 
			
		||||
	 * wait. */
 | 
			
		||||
	wait_remaining_ms_from_jiffies(intel_dp->last_power_cycle,
 | 
			
		||||
				       intel_dp->panel_power_cycle_delay);
 | 
			
		||||
 | 
			
		||||
	wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wait_backlight_on(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	wait_remaining_ms_from_jiffies(intel_dp->last_power_on,
 | 
			
		||||
				       intel_dp->backlight_on_delay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void edp_wait_backlight_off(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off,
 | 
			
		||||
				       intel_dp->backlight_off_delay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read the current pp_control value, unlocking the register if it
 | 
			
		||||
 * is locked
 | 
			
		||||
| 
						 | 
				
			
			@ -1084,7 +1142,7 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
 | 
			
		|||
	return control;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
 | 
			
		||||
static void edp_panel_vdd_on(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1099,15 +1157,15 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
 | 
			
		|||
 | 
			
		||||
	intel_dp->want_panel_vdd = true;
 | 
			
		||||
 | 
			
		||||
	if (ironlake_edp_have_panel_vdd(intel_dp))
 | 
			
		||||
	if (edp_have_panel_vdd(intel_dp))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	intel_runtime_pm_get(dev_priv);
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("Turning eDP VDD on\n");
 | 
			
		||||
 | 
			
		||||
	if (!ironlake_edp_have_panel_power(intel_dp))
 | 
			
		||||
		ironlake_wait_panel_power_cycle(intel_dp);
 | 
			
		||||
	if (!edp_have_panel_power(intel_dp))
 | 
			
		||||
		wait_panel_power_cycle(intel_dp);
 | 
			
		||||
 | 
			
		||||
	pp = ironlake_get_pp_control(intel_dp);
 | 
			
		||||
	pp |= EDP_FORCE_VDD;
 | 
			
		||||
| 
						 | 
				
			
			@ -1122,13 +1180,13 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
 | 
			
		|||
	/*
 | 
			
		||||
	 * If the panel wasn't on, delay before accessing aux channel
 | 
			
		||||
	 */
 | 
			
		||||
	if (!ironlake_edp_have_panel_power(intel_dp)) {
 | 
			
		||||
	if (!edp_have_panel_power(intel_dp)) {
 | 
			
		||||
		DRM_DEBUG_KMS("eDP was not running\n");
 | 
			
		||||
		msleep(intel_dp->panel_power_up_delay);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 | 
			
		||||
static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1137,7 +1195,7 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 | 
			
		|||
 | 
			
		||||
	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 | 
			
		||||
 | 
			
		||||
	if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
 | 
			
		||||
	if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
 | 
			
		||||
		DRM_DEBUG_KMS("Turning eDP VDD off\n");
 | 
			
		||||
 | 
			
		||||
		pp = ironlake_get_pp_control(intel_dp);
 | 
			
		||||
| 
						 | 
				
			
			@ -1154,24 +1212,24 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 | 
			
		|||
		I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
 | 
			
		||||
 | 
			
		||||
		if ((pp & POWER_TARGET_ON) == 0)
 | 
			
		||||
			msleep(intel_dp->panel_power_cycle_delay);
 | 
			
		||||
			intel_dp->last_power_cycle = jiffies;
 | 
			
		||||
 | 
			
		||||
		intel_runtime_pm_put(dev_priv);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_panel_vdd_work(struct work_struct *__work)
 | 
			
		||||
static void edp_panel_vdd_work(struct work_struct *__work)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
 | 
			
		||||
						 struct intel_dp, panel_vdd_work);
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->mode_config.mutex);
 | 
			
		||||
	ironlake_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
	edp_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
	mutex_unlock(&dev->mode_config.mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 | 
			
		||||
static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 | 
			
		||||
{
 | 
			
		||||
	if (!is_edp(intel_dp))
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1181,7 +1239,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 | 
			
		|||
	intel_dp->want_panel_vdd = false;
 | 
			
		||||
 | 
			
		||||
	if (sync) {
 | 
			
		||||
		ironlake_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
		edp_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Queue the timer to fire a long
 | 
			
		||||
| 
						 | 
				
			
			@ -1193,7 +1251,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_panel_on(struct intel_dp *intel_dp)
 | 
			
		||||
void intel_edp_panel_on(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1205,12 +1263,12 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
 | 
			
		|||
 | 
			
		||||
	DRM_DEBUG_KMS("Turn eDP power on\n");
 | 
			
		||||
 | 
			
		||||
	if (ironlake_edp_have_panel_power(intel_dp)) {
 | 
			
		||||
	if (edp_have_panel_power(intel_dp)) {
 | 
			
		||||
		DRM_DEBUG_KMS("eDP power already on\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ironlake_wait_panel_power_cycle(intel_dp);
 | 
			
		||||
	wait_panel_power_cycle(intel_dp);
 | 
			
		||||
 | 
			
		||||
	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 | 
			
		||||
	pp = ironlake_get_pp_control(intel_dp);
 | 
			
		||||
| 
						 | 
				
			
			@ -1228,7 +1286,8 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
 | 
			
		|||
	I915_WRITE(pp_ctrl_reg, pp);
 | 
			
		||||
	POSTING_READ(pp_ctrl_reg);
 | 
			
		||||
 | 
			
		||||
	ironlake_wait_panel_on(intel_dp);
 | 
			
		||||
	wait_panel_on(intel_dp);
 | 
			
		||||
	intel_dp->last_power_on = jiffies;
 | 
			
		||||
 | 
			
		||||
	if (IS_GEN5(dev)) {
 | 
			
		||||
		pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 | 
			
		||||
| 
						 | 
				
			
			@ -1237,7 +1296,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 | 
			
		||||
void intel_edp_panel_off(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1249,6 +1308,8 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 | 
			
		|||
 | 
			
		||||
	DRM_DEBUG_KMS("Turn eDP power off\n");
 | 
			
		||||
 | 
			
		||||
	edp_wait_backlight_off(intel_dp);
 | 
			
		||||
 | 
			
		||||
	pp = ironlake_get_pp_control(intel_dp);
 | 
			
		||||
	/* We need to switch off panel power _and_ force vdd, for otherwise some
 | 
			
		||||
	 * panels get very unhappy and cease to work. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1259,10 +1320,11 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 | 
			
		|||
	I915_WRITE(pp_ctrl_reg, pp);
 | 
			
		||||
	POSTING_READ(pp_ctrl_reg);
 | 
			
		||||
 | 
			
		||||
	ironlake_wait_panel_off(intel_dp);
 | 
			
		||||
	intel_dp->last_power_cycle = jiffies;
 | 
			
		||||
	wait_panel_off(intel_dp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
 | 
			
		||||
void intel_edp_backlight_on(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,7 +1342,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
 | 
			
		|||
	 * link.  So delay a bit to make sure the image is solid before
 | 
			
		||||
	 * allowing it to appear.
 | 
			
		||||
	 */
 | 
			
		||||
	msleep(intel_dp->backlight_on_delay);
 | 
			
		||||
	wait_backlight_on(intel_dp);
 | 
			
		||||
	pp = ironlake_get_pp_control(intel_dp);
 | 
			
		||||
	pp |= EDP_BLC_ENABLE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1292,7 +1354,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
 | 
			
		|||
	intel_panel_enable_backlight(intel_dp->attached_connector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
 | 
			
		||||
void intel_edp_backlight_off(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,7 +1374,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
 | 
			
		|||
 | 
			
		||||
	I915_WRITE(pp_ctrl_reg, pp);
 | 
			
		||||
	POSTING_READ(pp_ctrl_reg);
 | 
			
		||||
	msleep(intel_dp->backlight_off_delay);
 | 
			
		||||
	intel_dp->last_backlight_off = jiffies;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 | 
			
		||||
| 
						 | 
				
			
			@ -1597,10 +1659,12 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp, 0);
 | 
			
		||||
	uint32_t aux_clock_divider;
 | 
			
		||||
	int precharge = 0x3;
 | 
			
		||||
	int msg_size = 5;       /* Header(4) + Message(1) */
 | 
			
		||||
 | 
			
		||||
	aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
 | 
			
		||||
 | 
			
		||||
	/* Enable PSR in sink */
 | 
			
		||||
	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
 | 
			
		||||
		intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
 | 
			
		||||
| 
						 | 
				
			
			@ -1668,7 +1732,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!i915_enable_psr) {
 | 
			
		||||
	if (!i915.enable_psr) {
 | 
			
		||||
		DRM_DEBUG_KMS("PSR disable by flag\n");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1784,9 +1848,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 | 
			
		|||
 | 
			
		||||
	/* Make sure the panel is off before trying to change the mode. But also
 | 
			
		||||
	 * ensure that we have vdd while we switch off the panel. */
 | 
			
		||||
	ironlake_edp_backlight_off(intel_dp);
 | 
			
		||||
	intel_edp_backlight_off(intel_dp);
 | 
			
		||||
	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 | 
			
		||||
	ironlake_edp_panel_off(intel_dp);
 | 
			
		||||
	intel_edp_panel_off(intel_dp);
 | 
			
		||||
 | 
			
		||||
	/* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
 | 
			
		||||
	if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
 | 
			
		||||
| 
						 | 
				
			
			@ -1816,11 +1880,11 @@ static void intel_enable_dp(struct intel_encoder *encoder)
 | 
			
		|||
	if (WARN_ON(dp_reg & DP_PORT_EN))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ironlake_edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 | 
			
		||||
	intel_dp_start_link_train(intel_dp);
 | 
			
		||||
	ironlake_edp_panel_on(intel_dp);
 | 
			
		||||
	ironlake_edp_panel_vdd_off(intel_dp, true);
 | 
			
		||||
	intel_edp_panel_on(intel_dp);
 | 
			
		||||
	edp_panel_vdd_off(intel_dp, true);
 | 
			
		||||
	intel_dp_complete_link_train(intel_dp);
 | 
			
		||||
	intel_dp_stop_link_train(intel_dp);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1830,14 +1894,14 @@ static void g4x_enable_dp(struct intel_encoder *encoder)
 | 
			
		|||
	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 | 
			
		||||
 | 
			
		||||
	intel_enable_dp(encoder);
 | 
			
		||||
	ironlake_edp_backlight_on(intel_dp);
 | 
			
		||||
	intel_edp_backlight_on(intel_dp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void vlv_enable_dp(struct intel_encoder *encoder)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 | 
			
		||||
 | 
			
		||||
	ironlake_edp_backlight_on(intel_dp);
 | 
			
		||||
	intel_edp_backlight_on(intel_dp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void g4x_pre_enable_dp(struct intel_encoder *encoder)
 | 
			
		||||
| 
						 | 
				
			
			@ -2630,10 +2694,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 | 
			
		|||
	bool channel_eq = false;
 | 
			
		||||
	int tries, cr_tries;
 | 
			
		||||
	uint32_t DP = intel_dp->DP;
 | 
			
		||||
	uint32_t training_pattern = DP_TRAINING_PATTERN_2;
 | 
			
		||||
 | 
			
		||||
	/* Training Pattern 3 for HBR2 ot 1.2 devices that support it*/
 | 
			
		||||
	if (intel_dp->link_bw == DP_LINK_BW_5_4 || intel_dp->use_tps3)
 | 
			
		||||
		training_pattern = DP_TRAINING_PATTERN_3;
 | 
			
		||||
 | 
			
		||||
	/* channel equalization */
 | 
			
		||||
	if (!intel_dp_set_link_train(intel_dp, &DP,
 | 
			
		||||
				     DP_TRAINING_PATTERN_2 |
 | 
			
		||||
				     training_pattern |
 | 
			
		||||
				     DP_LINK_SCRAMBLING_DISABLE)) {
 | 
			
		||||
		DRM_ERROR("failed to start channel equalization\n");
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -2660,7 +2729,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 | 
			
		|||
		if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
 | 
			
		||||
			intel_dp_start_link_train(intel_dp);
 | 
			
		||||
			intel_dp_set_link_train(intel_dp, &DP,
 | 
			
		||||
						DP_TRAINING_PATTERN_2 |
 | 
			
		||||
						training_pattern |
 | 
			
		||||
						DP_LINK_SCRAMBLING_DISABLE);
 | 
			
		||||
			cr_tries++;
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -2676,7 +2745,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 | 
			
		|||
			intel_dp_link_down(intel_dp);
 | 
			
		||||
			intel_dp_start_link_train(intel_dp);
 | 
			
		||||
			intel_dp_set_link_train(intel_dp, &DP,
 | 
			
		||||
						DP_TRAINING_PATTERN_2 |
 | 
			
		||||
						training_pattern |
 | 
			
		||||
						DP_LINK_SCRAMBLING_DISABLE);
 | 
			
		||||
			tries = 0;
 | 
			
		||||
			cr_tries++;
 | 
			
		||||
| 
						 | 
				
			
			@ -2818,6 +2887,14 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Training Pattern 3 support */
 | 
			
		||||
	if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
 | 
			
		||||
	    intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) {
 | 
			
		||||
		intel_dp->use_tps3 = true;
 | 
			
		||||
		DRM_DEBUG_KMS("Displayport TPS3 supported");
 | 
			
		||||
	} else
 | 
			
		||||
		intel_dp->use_tps3 = false;
 | 
			
		||||
 | 
			
		||||
	if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
 | 
			
		||||
	      DP_DWN_STRM_PORT_PRESENT))
 | 
			
		||||
		return true; /* native DP sink */
 | 
			
		||||
| 
						 | 
				
			
			@ -2841,7 +2918,7 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
 | 
			
		|||
	if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ironlake_edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	edp_panel_vdd_on(intel_dp);
 | 
			
		||||
 | 
			
		||||
	if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3))
 | 
			
		||||
		DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
 | 
			
		||||
| 
						 | 
				
			
			@ -2851,7 +2928,36 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
 | 
			
		|||
		DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
 | 
			
		||||
			      buf[0], buf[1], buf[2]);
 | 
			
		||||
 | 
			
		||||
	ironlake_edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
	edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
 | 
			
		||||
{
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
	struct intel_crtc *intel_crtc =
 | 
			
		||||
		to_intel_crtc(intel_dig_port->base.base.crtc);
 | 
			
		||||
	u8 buf[1];
 | 
			
		||||
 | 
			
		||||
	if (!intel_dp_aux_native_read(intel_dp, DP_TEST_SINK_MISC, buf, 1))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	if (!(buf[0] & DP_TEST_CRC_SUPPORTED))
 | 
			
		||||
		return -ENOTTY;
 | 
			
		||||
 | 
			
		||||
	if (!intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK,
 | 
			
		||||
					 DP_TEST_SINK_START))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	/* Wait 2 vblanks to be sure we will have the correct CRC value */
 | 
			
		||||
	intel_wait_for_vblank(dev, intel_crtc->pipe);
 | 
			
		||||
	intel_wait_for_vblank(dev, intel_crtc->pipe);
 | 
			
		||||
 | 
			
		||||
	if (!intel_dp_aux_native_read(intel_dp, DP_TEST_CRC_R_CR, crc, 6))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
| 
						 | 
				
			
			@ -3295,7 +3401,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 | 
			
		|||
	if (is_edp(intel_dp)) {
 | 
			
		||||
		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
 | 
			
		||||
		mutex_lock(&dev->mode_config.mutex);
 | 
			
		||||
		ironlake_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
		edp_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
		mutex_unlock(&dev->mode_config.mutex);
 | 
			
		||||
	}
 | 
			
		||||
	kfree(intel_dig_port);
 | 
			
		||||
| 
						 | 
				
			
			@ -3394,6 +3500,13 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp)
 | 
			
		||||
{
 | 
			
		||||
	intel_dp->last_power_cycle = jiffies;
 | 
			
		||||
	intel_dp->last_power_on = jiffies;
 | 
			
		||||
	intel_dp->last_backlight_off = jiffies;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
intel_dp_init_panel_power_sequencer(struct drm_device *dev,
 | 
			
		||||
				    struct intel_dp *intel_dp,
 | 
			
		||||
| 
						 | 
				
			
			@ -3516,10 +3629,17 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 | 
			
		|||
		pp_div_reg = VLV_PIPE_PP_DIVISOR(pipe);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* And finally store the new values in the power sequencer. */
 | 
			
		||||
	/*
 | 
			
		||||
	 * And finally store the new values in the power sequencer. The
 | 
			
		||||
	 * backlight delays are set to 1 because we do manual waits on them. For
 | 
			
		||||
	 * T8, even BSpec recommends doing it. For T9, if we don't do this,
 | 
			
		||||
	 * we'll end up waiting for the backlight off delay twice: once when we
 | 
			
		||||
	 * do the manual sleep, and once when we disable the panel and wait for
 | 
			
		||||
	 * the PP_STATUS bit to become zero.
 | 
			
		||||
	 */
 | 
			
		||||
	pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
 | 
			
		||||
		(seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
 | 
			
		||||
	pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
 | 
			
		||||
		(1 << PANEL_LIGHT_ON_DELAY_SHIFT);
 | 
			
		||||
	pp_off = (1 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
 | 
			
		||||
		 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
 | 
			
		||||
	/* Compute the divisor for the pp clock, simply match the Bspec
 | 
			
		||||
	 * formula. */
 | 
			
		||||
| 
						 | 
				
			
			@ -3554,14 +3674,14 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 | 
			
		||||
				     struct intel_connector *intel_connector)
 | 
			
		||||
				     struct intel_connector *intel_connector,
 | 
			
		||||
				     struct edp_power_seq *power_seq)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_connector *connector = &intel_connector->base;
 | 
			
		||||
	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 | 
			
		||||
	struct drm_device *dev = intel_dig_port->base.base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_display_mode *fixed_mode = NULL;
 | 
			
		||||
	struct edp_power_seq power_seq = { 0 };
 | 
			
		||||
	bool has_dpcd;
 | 
			
		||||
	struct drm_display_mode *scan;
 | 
			
		||||
	struct edid *edid;
 | 
			
		||||
| 
						 | 
				
			
			@ -3569,12 +3689,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 | 
			
		|||
	if (!is_edp(intel_dp))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
 | 
			
		||||
 | 
			
		||||
	/* Cache DPCD and EDID for edp. */
 | 
			
		||||
	ironlake_edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	edp_panel_vdd_on(intel_dp);
 | 
			
		||||
	has_dpcd = intel_dp_get_dpcd(intel_dp);
 | 
			
		||||
	ironlake_edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
	edp_panel_vdd_off(intel_dp, false);
 | 
			
		||||
 | 
			
		||||
	if (has_dpcd) {
 | 
			
		||||
		if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
 | 
			
		||||
| 
						 | 
				
			
			@ -3588,8 +3706,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* We now know it's not a ghost, init power sequence regs. */
 | 
			
		||||
	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
 | 
			
		||||
						      &power_seq);
 | 
			
		||||
	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
 | 
			
		||||
 | 
			
		||||
	edid = drm_get_edid(connector, &intel_dp->adapter);
 | 
			
		||||
	if (edid) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3638,9 +3755,22 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 | 
			
		|||
	struct drm_device *dev = intel_encoder->base.dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	enum port port = intel_dig_port->port;
 | 
			
		||||
	struct edp_power_seq power_seq = { 0 };
 | 
			
		||||
	const char *name = NULL;
 | 
			
		||||
	int type, error;
 | 
			
		||||
 | 
			
		||||
	/* intel_dp vfuncs */
 | 
			
		||||
	if (IS_VALLEYVIEW(dev))
 | 
			
		||||
		intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
 | 
			
		||||
	else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 | 
			
		||||
		intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
 | 
			
		||||
	else if (HAS_PCH_SPLIT(dev))
 | 
			
		||||
		intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
 | 
			
		||||
	else
 | 
			
		||||
		intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider;
 | 
			
		||||
 | 
			
		||||
	intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
 | 
			
		||||
 | 
			
		||||
	/* Preserve the current hw state. */
 | 
			
		||||
	intel_dp->DP = I915_READ(intel_dp->output_reg);
 | 
			
		||||
	intel_dp->attached_connector = intel_connector;
 | 
			
		||||
| 
						 | 
				
			
			@ -3669,7 +3799,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 | 
			
		|||
	connector->doublescan_allowed = 0;
 | 
			
		||||
 | 
			
		||||
	INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
 | 
			
		||||
			  ironlake_panel_vdd_work);
 | 
			
		||||
			  edp_panel_vdd_work);
 | 
			
		||||
 | 
			
		||||
	intel_connector_attach_encoder(intel_connector, intel_encoder);
 | 
			
		||||
	drm_sysfs_connector_add(connector);
 | 
			
		||||
| 
						 | 
				
			
			@ -3721,18 +3851,23 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 | 
			
		|||
		BUG();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (is_edp(intel_dp)) {
 | 
			
		||||
		intel_dp_init_panel_power_timestamps(intel_dp);
 | 
			
		||||
		intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = intel_dp_i2c_init(intel_dp, intel_connector, name);
 | 
			
		||||
	WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
 | 
			
		||||
	     error, port_name(port));
 | 
			
		||||
 | 
			
		||||
	intel_dp->psr_setup_done = false;
 | 
			
		||||
 | 
			
		||||
	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
 | 
			
		||||
	if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
 | 
			
		||||
		i2c_del_adapter(&intel_dp->adapter);
 | 
			
		||||
		if (is_edp(intel_dp)) {
 | 
			
		||||
			cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
 | 
			
		||||
			mutex_lock(&dev->mode_config.mutex);
 | 
			
		||||
			ironlake_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
			edp_panel_vdd_off_sync(intel_dp);
 | 
			
		||||
			mutex_unlock(&dev->mode_config.mutex);
 | 
			
		||||
		}
 | 
			
		||||
		drm_sysfs_connector_remove(connector);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -359,6 +359,8 @@ struct intel_crtc {
 | 
			
		|||
	bool cursor_visible;
 | 
			
		||||
 | 
			
		||||
	struct intel_crtc_config config;
 | 
			
		||||
	struct intel_crtc_config *new_config;
 | 
			
		||||
	bool new_enabled;
 | 
			
		||||
 | 
			
		||||
	uint32_t ddi_pll_sel;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -485,8 +487,22 @@ struct intel_dp {
 | 
			
		|||
	int backlight_off_delay;
 | 
			
		||||
	struct delayed_work panel_vdd_work;
 | 
			
		||||
	bool want_panel_vdd;
 | 
			
		||||
	unsigned long last_power_cycle;
 | 
			
		||||
	unsigned long last_power_on;
 | 
			
		||||
	unsigned long last_backlight_off;
 | 
			
		||||
	bool psr_setup_done;
 | 
			
		||||
	bool use_tps3;
 | 
			
		||||
	struct intel_connector *attached_connector;
 | 
			
		||||
 | 
			
		||||
	uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index);
 | 
			
		||||
	/*
 | 
			
		||||
	 * This function returns the value we have to program the AUX_CTL
 | 
			
		||||
	 * register with to kick off an AUX transaction.
 | 
			
		||||
	 */
 | 
			
		||||
	uint32_t (*get_aux_send_ctl)(struct intel_dp *dp,
 | 
			
		||||
				     bool has_aux_irq,
 | 
			
		||||
				     int send_bytes,
 | 
			
		||||
				     uint32_t aux_clock_divider);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct intel_digital_port {
 | 
			
		||||
| 
						 | 
				
			
			@ -540,6 +556,7 @@ struct intel_unpin_work {
 | 
			
		|||
struct intel_set_config {
 | 
			
		||||
	struct drm_encoder **save_connector_encoders;
 | 
			
		||||
	struct drm_crtc **save_encoder_crtcs;
 | 
			
		||||
	bool *save_crtc_enabled;
 | 
			
		||||
 | 
			
		||||
	bool fb_changed;
 | 
			
		||||
	bool mode_changed;
 | 
			
		||||
| 
						 | 
				
			
			@ -721,15 +738,14 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 | 
			
		|||
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 | 
			
		||||
void intel_dp_encoder_destroy(struct drm_encoder *encoder);
 | 
			
		||||
void intel_dp_check_link_status(struct intel_dp *intel_dp);
 | 
			
		||||
int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 | 
			
		||||
bool intel_dp_compute_config(struct intel_encoder *encoder,
 | 
			
		||||
			     struct intel_crtc_config *pipe_config);
 | 
			
		||||
bool intel_dp_is_edp(struct drm_device *dev, enum port port);
 | 
			
		||||
void ironlake_edp_backlight_on(struct intel_dp *intel_dp);
 | 
			
		||||
void ironlake_edp_backlight_off(struct intel_dp *intel_dp);
 | 
			
		||||
void ironlake_edp_panel_on(struct intel_dp *intel_dp);
 | 
			
		||||
void ironlake_edp_panel_off(struct intel_dp *intel_dp);
 | 
			
		||||
void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
 | 
			
		||||
void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 | 
			
		||||
void intel_edp_backlight_on(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_backlight_off(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_panel_on(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_panel_off(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_psr_enable(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_psr_disable(struct intel_dp *intel_dp);
 | 
			
		||||
void intel_edp_psr_update(struct drm_device *dev);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
out_unref:
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
out:
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +208,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
out_unlock:
 | 
			
		||||
	mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,7 +113,8 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type,
 | 
			
		||||
				  enum transcoder cpu_transcoder)
 | 
			
		||||
				  enum transcoder cpu_transcoder,
 | 
			
		||||
				  struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case HDMI_INFOFRAME_TYPE_AVI:
 | 
			
		||||
| 
						 | 
				
			
			@ -296,7 +297,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
 | 
			
		|||
	u32 val = I915_READ(ctl_reg);
 | 
			
		||||
 | 
			
		||||
	data_reg = hsw_infoframe_data_reg(type,
 | 
			
		||||
					  intel_crtc->config.cpu_transcoder);
 | 
			
		||||
					  intel_crtc->config.cpu_transcoder,
 | 
			
		||||
					  dev_priv);
 | 
			
		||||
	if (data_reg == 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -848,8 +848,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	/* use the module option value if specified */
 | 
			
		||||
	if (i915_lvds_channel_mode > 0)
 | 
			
		||||
		return i915_lvds_channel_mode == 2;
 | 
			
		||||
	if (i915.lvds_channel_mode > 0)
 | 
			
		||||
		return i915.lvds_channel_mode == 2;
 | 
			
		||||
 | 
			
		||||
	if (dmi_check_system(intel_dual_link_lvds))
 | 
			
		||||
		return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -1036,7 +1036,7 @@ void intel_lvds_init(struct drm_device *dev)
 | 
			
		|||
					intel_find_panel_downclock(dev,
 | 
			
		||||
					fixed_mode, connector);
 | 
			
		||||
				if (intel_connector->panel.downclock_mode !=
 | 
			
		||||
					NULL &&	i915_lvds_downclock) {
 | 
			
		||||
					NULL &&	i915.lvds_downclock) {
 | 
			
		||||
					/* We found the downclock for LVDS. */
 | 
			
		||||
					dev_priv->lvds_downclock_avail = true;
 | 
			
		||||
					dev_priv->lvds_downclock =
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -293,7 +293,7 @@ static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_gem_object *obj = overlay->old_vid_bo;
 | 
			
		||||
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
 | 
			
		||||
	overlay->old_vid_bo = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +306,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay)
 | 
			
		|||
	/* never have the overlay hw on without showing a frame */
 | 
			
		||||
	BUG_ON(!overlay->vid_bo);
 | 
			
		||||
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
	overlay->vid_bo = NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -782,7 +782,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_unpin:
 | 
			
		||||
	i915_gem_object_unpin(new_bo);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(new_bo);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1386,7 +1386,7 @@ void intel_setup_overlay(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
out_unpin_bo:
 | 
			
		||||
	if (!OVERLAY_NEEDS_PHYSICAL(dev))
 | 
			
		||||
		i915_gem_object_unpin(reg_bo);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(reg_bo);
 | 
			
		||||
out_free_bo:
 | 
			
		||||
	drm_gem_object_unreference(®_bo->base);
 | 
			
		||||
out_free:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,6 @@
 | 
			
		|||
#include <linux/moduleparam.h>
 | 
			
		||||
#include "intel_drv.h"
 | 
			
		||||
 | 
			
		||||
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
 | 
			
		||||
		       struct drm_display_mode *adjusted_mode)
 | 
			
		||||
| 
						 | 
				
			
			@ -325,13 +323,6 @@ out:
 | 
			
		|||
	pipe_config->gmch_pfit.lvds_border_bits = border;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int i915_panel_invert_brightness;
 | 
			
		||||
MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
 | 
			
		||||
	"(-1 force normal, 0 machine defaults, 1 force inversion), please "
 | 
			
		||||
	"report PCI device ID, subsystem vendor and subsystem device ID "
 | 
			
		||||
	"to dri-devel@lists.freedesktop.org, if your machine needs it. "
 | 
			
		||||
	"It will then be included in an upcoming module version.");
 | 
			
		||||
module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
 | 
			
		||||
static u32 intel_panel_compute_brightness(struct intel_connector *connector,
 | 
			
		||||
					  u32 val)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -341,10 +332,10 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector,
 | 
			
		|||
 | 
			
		||||
	WARN_ON(panel->backlight.max == 0);
 | 
			
		||||
 | 
			
		||||
	if (i915_panel_invert_brightness < 0)
 | 
			
		||||
	if (i915.invert_brightness < 0)
 | 
			
		||||
		return val;
 | 
			
		||||
 | 
			
		||||
	if (i915_panel_invert_brightness > 0 ||
 | 
			
		||||
	if (i915.invert_brightness > 0 ||
 | 
			
		||||
	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
 | 
			
		||||
		return panel->backlight.max - val;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -810,13 +801,13 @@ intel_panel_detect(struct drm_device *dev)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	/* Assume that the BIOS does not lie through the OpRegion... */
 | 
			
		||||
	if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
 | 
			
		||||
	if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
 | 
			
		||||
		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
 | 
			
		||||
			connector_status_connected :
 | 
			
		||||
			connector_status_disconnected;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (i915_panel_ignore_lid) {
 | 
			
		||||
	switch (i915.panel_ignore_lid) {
 | 
			
		||||
	case -2:
 | 
			
		||||
		return connector_status_connected;
 | 
			
		||||
	case -1:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
	struct drm_i915_gem_object *obj = intel_fb->obj;
 | 
			
		||||
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	int cfb_pitch;
 | 
			
		||||
	int plane, i;
 | 
			
		||||
	int i;
 | 
			
		||||
	u32 fbc_ctl;
 | 
			
		||||
 | 
			
		||||
	cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +109,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
		cfb_pitch = (cfb_pitch / 32) - 1;
 | 
			
		||||
	else
 | 
			
		||||
		cfb_pitch = (cfb_pitch / 64) - 1;
 | 
			
		||||
	plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
 | 
			
		||||
 | 
			
		||||
	/* Clear old tags */
 | 
			
		||||
	for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +119,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
 | 
			
		||||
		/* Set it up... */
 | 
			
		||||
		fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
 | 
			
		||||
		fbc_ctl2 |= plane;
 | 
			
		||||
		fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
 | 
			
		||||
		I915_WRITE(FBC_CONTROL2, fbc_ctl2);
 | 
			
		||||
		I915_WRITE(FBC_FENCE_OFF, crtc->y);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +134,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
	fbc_ctl |= obj->fence_reg;
 | 
			
		||||
	I915_WRITE(FBC_CONTROL, fbc_ctl);
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c, ",
 | 
			
		||||
	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
 | 
			
		||||
		      cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,17 +153,19 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 | 
			
		||||
	struct drm_i915_gem_object *obj = intel_fb->obj;
 | 
			
		||||
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 | 
			
		||||
	u32 dpfc_ctl;
 | 
			
		||||
 | 
			
		||||
	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
 | 
			
		||||
	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
 | 
			
		||||
	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 | 
			
		||||
	else
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 | 
			
		||||
	dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
 | 
			
		||||
	I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
 | 
			
		||||
 | 
			
		||||
	/* enable it... */
 | 
			
		||||
	I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
 | 
			
		||||
	I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -224,18 +225,16 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 | 
			
		||||
	struct drm_i915_gem_object *obj = intel_fb->obj;
 | 
			
		||||
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 | 
			
		||||
	u32 dpfc_ctl;
 | 
			
		||||
 | 
			
		||||
	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
 | 
			
		||||
	dpfc_ctl &= DPFC_RESERVED;
 | 
			
		||||
	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
 | 
			
		||||
	/* Set persistent mode for front-buffer rendering, ala X. */
 | 
			
		||||
	dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
 | 
			
		||||
	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
 | 
			
		||||
	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 | 
			
		||||
	else
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 | 
			
		||||
	dpfc_ctl |= DPFC_CTL_FENCE_EN;
 | 
			
		||||
	if (IS_GEN5(dev))
 | 
			
		||||
		dpfc_ctl |= obj->fence_reg;
 | 
			
		||||
	I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
 | 
			
		||||
	I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
 | 
			
		||||
| 
						 | 
				
			
			@ -282,12 +281,16 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
 | 
			
		|||
	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 | 
			
		||||
	struct drm_i915_gem_object *obj = intel_fb->obj;
 | 
			
		||||
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 | 
			
		||||
	u32 dpfc_ctl;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(IVB_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj));
 | 
			
		||||
	dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
 | 
			
		||||
	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 | 
			
		||||
	else
 | 
			
		||||
		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 | 
			
		||||
	dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X |
 | 
			
		||||
		   IVB_DPFC_CTL_FENCE_EN |
 | 
			
		||||
		   intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT);
 | 
			
		||||
	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 | 
			
		||||
 | 
			
		||||
	if (IS_IVYBRIDGE(dev)) {
 | 
			
		||||
		/* WaFbcAsynchFlipDisableFbcQueue:ivb */
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +469,7 @@ void intel_update_fbc(struct drm_device *dev)
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!i915_powersave) {
 | 
			
		||||
	if (!i915.powersave) {
 | 
			
		||||
		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
 | 
			
		||||
			DRM_DEBUG_KMS("fbc disabled per module param\n");
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -505,13 +508,13 @@ void intel_update_fbc(struct drm_device *dev)
 | 
			
		|||
	obj = intel_fb->obj;
 | 
			
		||||
	adjusted_mode = &intel_crtc->config.adjusted_mode;
 | 
			
		||||
 | 
			
		||||
	if (i915_enable_fbc < 0 &&
 | 
			
		||||
	if (i915.enable_fbc < 0 &&
 | 
			
		||||
	    INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) {
 | 
			
		||||
		if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
 | 
			
		||||
			DRM_DEBUG_KMS("disabled per chip default\n");
 | 
			
		||||
		goto out_disable;
 | 
			
		||||
	}
 | 
			
		||||
	if (!i915_enable_fbc) {
 | 
			
		||||
	if (!i915.enable_fbc) {
 | 
			
		||||
		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
 | 
			
		||||
			DRM_DEBUG_KMS("fbc disabled per module param\n");
 | 
			
		||||
		goto out_disable;
 | 
			
		||||
| 
						 | 
				
			
			@ -1886,7 +1889,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Calculate the maximum FBC watermark */
 | 
			
		||||
static unsigned int ilk_fbc_wm_max(struct drm_device *dev)
 | 
			
		||||
static unsigned int ilk_fbc_wm_max(const struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	/* max that registers can hold */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 8)
 | 
			
		||||
| 
						 | 
				
			
			@ -1895,7 +1898,7 @@ static unsigned int ilk_fbc_wm_max(struct drm_device *dev)
 | 
			
		|||
		return 15;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ilk_compute_wm_maximums(struct drm_device *dev,
 | 
			
		||||
static void ilk_compute_wm_maximums(const struct drm_device *dev,
 | 
			
		||||
				    int level,
 | 
			
		||||
				    const struct intel_wm_config *config,
 | 
			
		||||
				    enum intel_ddb_partitioning ddb_partitioning,
 | 
			
		||||
| 
						 | 
				
			
			@ -1948,7 +1951,7 @@ static bool ilk_validate_wm_level(int level,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
 | 
			
		||||
static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
 | 
			
		||||
				 int level,
 | 
			
		||||
				 const struct ilk_pipe_wm_parameters *p,
 | 
			
		||||
				 struct intel_wm_level *result)
 | 
			
		||||
| 
						 | 
				
			
			@ -2140,7 +2143,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
 | 
			
		|||
				  struct intel_pipe_wm *pipe_wm)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = crtc->dev;
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	const struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	int level, max_level = ilk_wm_max_level(dev);
 | 
			
		||||
	/* LP0 watermark maximums depend on this pipe alone */
 | 
			
		||||
	struct intel_wm_config config = {
 | 
			
		||||
| 
						 | 
				
			
			@ -2753,7 +2756,7 @@ intel_alloc_context_page(struct drm_device *dev)
 | 
			
		|||
	return ctx;
 | 
			
		||||
 | 
			
		||||
err_unpin:
 | 
			
		||||
	i915_gem_object_unpin(ctx);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(ctx);
 | 
			
		||||
err_unref:
 | 
			
		||||
	drm_gem_object_unreference(&ctx->base);
 | 
			
		||||
	return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -3000,6 +3003,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
 | 
			
		|||
	dev_priv->rps.last_adj = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* gen6_set_rps is called to update the frequency request, but should also be
 | 
			
		||||
 * called when the range (min_delay and max_delay) is modified so that we can
 | 
			
		||||
 * update the GEN6_RP_INTERRUPT_LIMITS register accordingly. */
 | 
			
		||||
void gen6_set_rps(struct drm_device *dev, u8 val)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -3008,8 +3014,14 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
 | 
			
		|||
	WARN_ON(val > dev_priv->rps.max_delay);
 | 
			
		||||
	WARN_ON(val < dev_priv->rps.min_delay);
 | 
			
		||||
 | 
			
		||||
	if (val == dev_priv->rps.cur_delay)
 | 
			
		||||
	if (val == dev_priv->rps.cur_delay) {
 | 
			
		||||
		/* min/max delay may still have been modified so be sure to
 | 
			
		||||
		 * write the limits value */
 | 
			
		||||
		I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
 | 
			
		||||
			   gen6_rps_limits(dev_priv, val));
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gen6_set_rps_thresholds(dev_priv, val);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3035,6 +3047,58 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
 | 
			
		|||
	trace_intel_gpu_freq_change(val * 50);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* vlv_set_rps_idle: Set the frequency to Rpn if Gfx clocks are down
 | 
			
		||||
 *
 | 
			
		||||
 * * If Gfx is Idle, then
 | 
			
		||||
 * 1. Mask Turbo interrupts
 | 
			
		||||
 * 2. Bring up Gfx clock
 | 
			
		||||
 * 3. Change the freq to Rpn and wait till P-Unit updates freq
 | 
			
		||||
 * 4. Clear the Force GFX CLK ON bit so that Gfx can down
 | 
			
		||||
 * 5. Unmask Turbo interrupts
 | 
			
		||||
*/
 | 
			
		||||
static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * When we are idle.  Drop to min voltage state.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->rps.cur_delay <= dev_priv->rps.min_delay)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Mask turbo interrupt so that they will not come in between */
 | 
			
		||||
	I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
	/* Bring up the Gfx clock */
 | 
			
		||||
	I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
 | 
			
		||||
		I915_READ(VLV_GTLC_SURVIVABILITY_REG) |
 | 
			
		||||
				VLV_GFX_CLK_FORCE_ON_BIT);
 | 
			
		||||
 | 
			
		||||
	if (wait_for(((VLV_GFX_CLK_STATUS_BIT &
 | 
			
		||||
		I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), 5)) {
 | 
			
		||||
			DRM_ERROR("GFX_CLK_ON request timed out\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.cur_delay = dev_priv->rps.min_delay;
 | 
			
		||||
 | 
			
		||||
	vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
 | 
			
		||||
					dev_priv->rps.min_delay);
 | 
			
		||||
 | 
			
		||||
	if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
 | 
			
		||||
				& GENFREQSTATUS) == 0, 5))
 | 
			
		||||
		DRM_ERROR("timed out waiting for Punit\n");
 | 
			
		||||
 | 
			
		||||
	/* Release the Gfx clock */
 | 
			
		||||
	I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
 | 
			
		||||
		I915_READ(VLV_GTLC_SURVIVABILITY_REG) &
 | 
			
		||||
				~VLV_GFX_CLK_FORCE_ON_BIT);
 | 
			
		||||
 | 
			
		||||
	/* Unmask Up interrupts */
 | 
			
		||||
	dev_priv->rps.rp_up_masked = true;
 | 
			
		||||
	gen6_set_pm_mask(dev_priv, GEN6_PM_RP_DOWN_THRESHOLD,
 | 
			
		||||
						dev_priv->rps.min_delay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gen6_rps_idle(struct drm_i915_private *dev_priv)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_device *dev = dev_priv->dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -3042,7 +3106,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
 | 
			
		|||
	mutex_lock(&dev_priv->rps.hw_lock);
 | 
			
		||||
	if (dev_priv->rps.enabled) {
 | 
			
		||||
		if (IS_VALLEYVIEW(dev))
 | 
			
		||||
			valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
 | 
			
		||||
			vlv_set_rps_idle(dev_priv);
 | 
			
		||||
		else
 | 
			
		||||
			gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
 | 
			
		||||
		dev_priv->rps.last_adj = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3151,8 +3215,8 @@ int intel_enable_rc6(const struct drm_device *dev)
 | 
			
		|||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Respect the kernel parameter if it is set */
 | 
			
		||||
	if (i915_enable_rc6 >= 0)
 | 
			
		||||
		return i915_enable_rc6;
 | 
			
		||||
	if (i915.enable_rc6 >= 0)
 | 
			
		||||
		return i915.enable_rc6;
 | 
			
		||||
 | 
			
		||||
	/* Disable RC6 on Ironlake */
 | 
			
		||||
	if (INTEL_INFO(dev)->gen == 5)
 | 
			
		||||
| 
						 | 
				
			
			@ -3267,7 +3331,7 @@ static void gen6_enable_rps(struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	u32 rp_state_cap;
 | 
			
		||||
	u32 rp_state_cap, hw_max, hw_min;
 | 
			
		||||
	u32 gt_perf_status;
 | 
			
		||||
	u32 rc6vids, pcu_mbox, rc6_mask = 0;
 | 
			
		||||
	u32 gtfifodbg;
 | 
			
		||||
| 
						 | 
				
			
			@ -3296,13 +3360,20 @@ static void gen6_enable_rps(struct drm_device *dev)
 | 
			
		|||
	gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 | 
			
		||||
 | 
			
		||||
	/* In units of 50MHz */
 | 
			
		||||
	dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff;
 | 
			
		||||
	dev_priv->rps.min_delay = (rp_state_cap >> 16) & 0xff;
 | 
			
		||||
	dev_priv->rps.hw_max = hw_max = rp_state_cap & 0xff;
 | 
			
		||||
	hw_min = (rp_state_cap >> 16) & 0xff;
 | 
			
		||||
	dev_priv->rps.rp1_delay = (rp_state_cap >>  8) & 0xff;
 | 
			
		||||
	dev_priv->rps.rp0_delay = (rp_state_cap >>  0) & 0xff;
 | 
			
		||||
	dev_priv->rps.rpe_delay = dev_priv->rps.rp1_delay;
 | 
			
		||||
	dev_priv->rps.cur_delay = 0;
 | 
			
		||||
 | 
			
		||||
	/* Preserve min/max settings in case of re-init */
 | 
			
		||||
	if (dev_priv->rps.max_delay == 0)
 | 
			
		||||
		dev_priv->rps.max_delay = hw_max;
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->rps.min_delay == 0)
 | 
			
		||||
		dev_priv->rps.min_delay = hw_min;
 | 
			
		||||
 | 
			
		||||
	/* disable the counters and set deterministic thresholds */
 | 
			
		||||
	I915_WRITE(GEN6_RC_CONTROL, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3531,7 +3602,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct intel_ring_buffer *ring;
 | 
			
		||||
	u32 gtfifodbg, val, rc6_mode = 0;
 | 
			
		||||
	u32 gtfifodbg, val, hw_max, hw_min, rc6_mode = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 | 
			
		||||
| 
						 | 
				
			
			@ -3593,21 +3664,27 @@ static void valleyview_enable_rps(struct drm_device *dev)
 | 
			
		|||
			 vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
 | 
			
		||||
			 dev_priv->rps.cur_delay);
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
 | 
			
		||||
	dev_priv->rps.hw_max = dev_priv->rps.max_delay;
 | 
			
		||||
	dev_priv->rps.hw_max = hw_max = valleyview_rps_max_freq(dev_priv);
 | 
			
		||||
	DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay),
 | 
			
		||||
			 dev_priv->rps.max_delay);
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, hw_max),
 | 
			
		||||
			 hw_max);
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
 | 
			
		||||
	DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
 | 
			
		||||
			 dev_priv->rps.rpe_delay);
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv);
 | 
			
		||||
	hw_min = valleyview_rps_min_freq(dev_priv);
 | 
			
		||||
	DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay),
 | 
			
		||||
			 dev_priv->rps.min_delay);
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, hw_min),
 | 
			
		||||
			 hw_min);
 | 
			
		||||
 | 
			
		||||
	/* Preserve min/max settings in case of re-init */
 | 
			
		||||
	if (dev_priv->rps.max_delay == 0)
 | 
			
		||||
		dev_priv->rps.max_delay = hw_max;
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->rps.min_delay == 0)
 | 
			
		||||
		dev_priv->rps.min_delay = hw_min;
 | 
			
		||||
 | 
			
		||||
	DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
 | 
			
		||||
			 vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
 | 
			
		||||
| 
						 | 
				
			
			@ -3615,6 +3692,9 @@ static void valleyview_enable_rps(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
 | 
			
		||||
 | 
			
		||||
	dev_priv->rps.rp_up_masked = false;
 | 
			
		||||
	dev_priv->rps.rp_down_masked = false;
 | 
			
		||||
 | 
			
		||||
	gen6_enable_rps_interrupts(dev);
 | 
			
		||||
 | 
			
		||||
	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 | 
			
		||||
| 
						 | 
				
			
			@ -3625,13 +3705,13 @@ void ironlake_teardown_rc6(struct drm_device *dev)
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->ips.renderctx) {
 | 
			
		||||
		i915_gem_object_unpin(dev_priv->ips.renderctx);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(dev_priv->ips.renderctx);
 | 
			
		||||
		drm_gem_object_unreference(&dev_priv->ips.renderctx->base);
 | 
			
		||||
		dev_priv->ips.renderctx = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dev_priv->ips.pwrctx) {
 | 
			
		||||
		i915_gem_object_unpin(dev_priv->ips.pwrctx);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(dev_priv->ips.pwrctx);
 | 
			
		||||
		drm_gem_object_unreference(&dev_priv->ips.pwrctx->base);
 | 
			
		||||
		dev_priv->ips.pwrctx = NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4270,6 +4350,7 @@ void intel_gpu_ips_teardown(void)
 | 
			
		|||
	i915_mch_dev = NULL;
 | 
			
		||||
	spin_unlock_irq(&mchdev_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void intel_init_emon(struct drm_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
| 
						 | 
				
			
			@ -4605,11 +4686,10 @@ static void gen6_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
	 * According to the spec, bit 11 (RCCUNIT) must also be set,
 | 
			
		||||
	 * but we didn't debug actual testcases to find it out.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Also apply WaDisableVDSUnitClockGating:snb and
 | 
			
		||||
	 * WaDisableRCPBUnitClockGating:snb.
 | 
			
		||||
	 * WaDisableRCCUnitClockGating:snb
 | 
			
		||||
	 * WaDisableRCPBUnitClockGating:snb
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(GEN6_UCGCTL2,
 | 
			
		||||
		   GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4655,14 +4735,17 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
 | 
			
		|||
{
 | 
			
		||||
	uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * WaVSThreadDispatchOverride:ivb,vlv
 | 
			
		||||
	 *
 | 
			
		||||
	 * This actually overrides the dispatch
 | 
			
		||||
	 * mode for all thread types.
 | 
			
		||||
	 */
 | 
			
		||||
	reg &= ~GEN7_FF_SCHED_MASK;
 | 
			
		||||
	reg |= GEN7_FF_TS_SCHED_HW;
 | 
			
		||||
	reg |= GEN7_FF_VS_SCHED_HW;
 | 
			
		||||
	reg |= GEN7_FF_DS_SCHED_HW;
 | 
			
		||||
 | 
			
		||||
	if (IS_HASWELL(dev_priv->dev))
 | 
			
		||||
		reg &= ~GEN7_FF_VS_REF_CNT_FFME;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(GEN7_FF_THREAD_MODE, reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4709,8 +4792,10 @@ static void gen8_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
	/* FIXME(BDW): Check all the w/a, some might only apply to
 | 
			
		||||
	 * pre-production hw. */
 | 
			
		||||
 | 
			
		||||
	WARN(!i915_preliminary_hw_support,
 | 
			
		||||
	     "GEN8_CENTROID_PIXEL_OPT_DIS not be needed for production\n");
 | 
			
		||||
	/*
 | 
			
		||||
	 * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for
 | 
			
		||||
	 * pre-production hardware
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(HALF_SLICE_CHICKEN3,
 | 
			
		||||
		   _MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS));
 | 
			
		||||
	I915_WRITE(HALF_SLICE_CHICKEN3,
 | 
			
		||||
| 
						 | 
				
			
			@ -4761,21 +4846,6 @@ static void haswell_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	ilk_init_lp_watermarks(dev);
 | 
			
		||||
 | 
			
		||||
	/* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
 | 
			
		||||
	 * This implements the WaDisableRCZUnitClockGating:hsw workaround.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/* Apply the WaDisableRHWOOptimizationForRenderHang:hsw workaround. */
 | 
			
		||||
	I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
 | 
			
		||||
		   GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
 | 
			
		||||
 | 
			
		||||
	/* WaApplyL3ControlAndL3ChickenMode:hsw */
 | 
			
		||||
	I915_WRITE(GEN7_L3CNTLREG1,
 | 
			
		||||
			GEN7_WA_FOR_GEN7_L3_CONTROL);
 | 
			
		||||
	I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
 | 
			
		||||
			GEN7_WA_L3_CHICKEN_MODE);
 | 
			
		||||
 | 
			
		||||
	/* L3 caching of data atomics doesn't work -- disable it. */
 | 
			
		||||
	I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE);
 | 
			
		||||
	I915_WRITE(HSW_ROW_CHICKEN3,
 | 
			
		||||
| 
						 | 
				
			
			@ -4787,7 +4857,12 @@ static void haswell_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
			GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 | 
			
		||||
 | 
			
		||||
	/* WaVSRefCountFullforceMissDisable:hsw */
 | 
			
		||||
	gen7_setup_fixed_func_scheduler(dev_priv);
 | 
			
		||||
	I915_WRITE(GEN7_FF_THREAD_MODE,
 | 
			
		||||
		   I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME);
 | 
			
		||||
 | 
			
		||||
	/* enable HiZ Raw Stall Optimization */
 | 
			
		||||
	I915_WRITE(CACHE_MODE_0_GEN7,
 | 
			
		||||
		   _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE));
 | 
			
		||||
 | 
			
		||||
	/* WaDisable4x2SubspanOptimization:hsw */
 | 
			
		||||
	I915_WRITE(CACHE_MODE_1,
 | 
			
		||||
| 
						 | 
				
			
			@ -4825,9 +4900,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
	if (IS_IVB_GT1(dev))
 | 
			
		||||
		I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
 | 
			
		||||
			   _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 | 
			
		||||
	else
 | 
			
		||||
		I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2,
 | 
			
		||||
			   _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 | 
			
		||||
 | 
			
		||||
	/* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */
 | 
			
		||||
	I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
 | 
			
		||||
| 
						 | 
				
			
			@ -4841,31 +4913,24 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
	if (IS_IVB_GT1(dev))
 | 
			
		||||
		I915_WRITE(GEN7_ROW_CHICKEN2,
 | 
			
		||||
			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
 | 
			
		||||
	else
 | 
			
		||||
	else {
 | 
			
		||||
		/* must write both registers */
 | 
			
		||||
		I915_WRITE(GEN7_ROW_CHICKEN2,
 | 
			
		||||
			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
 | 
			
		||||
		I915_WRITE(GEN7_ROW_CHICKEN2_GT2,
 | 
			
		||||
			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* WaForceL3Serialization:ivb */
 | 
			
		||||
	I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
 | 
			
		||||
		   ~L3SQ_URB_READ_CAM_MATCH_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
 | 
			
		||||
	 * gating disable must be set.  Failure to set it results in
 | 
			
		||||
	 * flickering pixels due to Z write ordering failures after
 | 
			
		||||
	 * some amount of runtime in the Mesa "fire" demo, and Unigine
 | 
			
		||||
	 * Sanctuary and Tropics, and apparently anything else with
 | 
			
		||||
	 * alpha test or pixel discard.
 | 
			
		||||
	 *
 | 
			
		||||
	 * According to the spec, bit 11 (RCCUNIT) must also be set,
 | 
			
		||||
	 * but we didn't debug actual testcases to find it out.
 | 
			
		||||
	 *
 | 
			
		||||
	/*
 | 
			
		||||
	 * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
 | 
			
		||||
	 * This implements the WaDisableRCZUnitClockGating:ivb workaround.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(GEN6_UCGCTL2,
 | 
			
		||||
		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/* This is required by WaCatErrorRejectionIssue:ivb */
 | 
			
		||||
	I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
 | 
			
		||||
| 
						 | 
				
			
			@ -4874,9 +4939,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
 | 
			
		||||
	g4x_disable_trickle_feed(dev);
 | 
			
		||||
 | 
			
		||||
	/* WaVSRefCountFullforceMissDisable:ivb */
 | 
			
		||||
	gen7_setup_fixed_func_scheduler(dev_priv);
 | 
			
		||||
 | 
			
		||||
	/* enable HiZ Raw Stall Optimization */
 | 
			
		||||
	I915_WRITE(CACHE_MODE_0_GEN7,
 | 
			
		||||
		   _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE));
 | 
			
		||||
 | 
			
		||||
	/* WaDisable4x2SubspanOptimization:ivb */
 | 
			
		||||
	I915_WRITE(CACHE_MODE_1,
 | 
			
		||||
		   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 | 
			
		||||
| 
						 | 
				
			
			@ -4927,18 +4995,14 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
		   CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
 | 
			
		||||
		   CHICKEN3_DGMG_DONE_FIX_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/* WaPsdDispatchEnable:vlv */
 | 
			
		||||
	/* WaDisablePSDDualDispatchEnable:vlv */
 | 
			
		||||
	I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
 | 
			
		||||
		   _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP |
 | 
			
		||||
				      GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 | 
			
		||||
 | 
			
		||||
	/* Apply the WaDisableRHWOOptimizationForRenderHang:vlv workaround. */
 | 
			
		||||
	I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
 | 
			
		||||
		   GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
 | 
			
		||||
 | 
			
		||||
	/* WaApplyL3ControlAndL3ChickenMode:vlv */
 | 
			
		||||
	/* WaDisableL3CacheAging:vlv */
 | 
			
		||||
	I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS);
 | 
			
		||||
	I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
 | 
			
		||||
 | 
			
		||||
	/* WaForceL3Serialization:vlv */
 | 
			
		||||
	I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
 | 
			
		||||
| 
						 | 
				
			
			@ -4953,51 +5017,39 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
 | 
			
		|||
		   I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
 | 
			
		||||
		   GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 | 
			
		||||
 | 
			
		||||
	/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
 | 
			
		||||
	 * gating disable must be set.  Failure to set it results in
 | 
			
		||||
	 * flickering pixels due to Z write ordering failures after
 | 
			
		||||
	 * some amount of runtime in the Mesa "fire" demo, and Unigine
 | 
			
		||||
	 * Sanctuary and Tropics, and apparently anything else with
 | 
			
		||||
	 * alpha test or pixel discard.
 | 
			
		||||
	 *
 | 
			
		||||
	 * According to the spec, bit 11 (RCCUNIT) must also be set,
 | 
			
		||||
	 * but we didn't debug actual testcases to find it out.
 | 
			
		||||
	 *
 | 
			
		||||
	gen7_setup_fixed_func_scheduler(dev_priv);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
 | 
			
		||||
	 * This implements the WaDisableRCZUnitClockGating:vlv workaround.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Also apply WaDisableVDSUnitClockGating:vlv and
 | 
			
		||||
	 * WaDisableRCPBUnitClockGating:vlv.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(GEN6_UCGCTL2,
 | 
			
		||||
		   GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN7_TDLUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
 | 
			
		||||
		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/* WaDisableL3Bank2xClockGate:vlv */
 | 
			
		||||
	I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * BSpec says this must be set, even though
 | 
			
		||||
	 * WaDisable4x2SubspanOptimization isn't listed for VLV.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(CACHE_MODE_1,
 | 
			
		||||
		   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * WaIncreaseL3CreditsForVLVB0:vlv
 | 
			
		||||
	 * This is the hardware default actually.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(GEN7_L3SQCREG1, VLV_B0_WA_L3SQCREG1_VALUE);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * WaDisableVLVClockGating_VBIIssue:vlv
 | 
			
		||||
	 * Disable clock gating on th GCFG unit to prevent a delay
 | 
			
		||||
	 * in the reporting of vblank events.
 | 
			
		||||
	 */
 | 
			
		||||
	I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff);
 | 
			
		||||
 | 
			
		||||
	/* Conservative clock gating settings for now */
 | 
			
		||||
	I915_WRITE(0x9400, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x9404, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x9408, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x940c, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x9410, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x9414, 0xffffffff);
 | 
			
		||||
	I915_WRITE(0x9418, 0xffffffff);
 | 
			
		||||
	I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void g4x_init_clock_gating(struct drm_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -5272,7 +5324,7 @@ static void __intel_power_well_put(struct drm_device *dev,
 | 
			
		|||
	WARN_ON(!power_well->count);
 | 
			
		||||
 | 
			
		||||
	if (!--power_well->count && power_well->set &&
 | 
			
		||||
	    i915_disable_power_well) {
 | 
			
		||||
	    i915.disable_power_well) {
 | 
			
		||||
		power_well->set(dev, power_well, false);
 | 
			
		||||
		hsw_enable_package_c8(dev_priv);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -549,7 +549,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unpin:
 | 
			
		||||
	i915_gem_object_unpin(ring->scratch.obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(ring->scratch.obj);
 | 
			
		||||
err_unref:
 | 
			
		||||
	drm_gem_object_unreference(&ring->scratch.obj->base);
 | 
			
		||||
err:
 | 
			
		||||
| 
						 | 
				
			
			@ -625,7 +625,7 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring)
 | 
			
		|||
 | 
			
		||||
	if (INTEL_INFO(dev)->gen >= 5) {
 | 
			
		||||
		kunmap(sg_page(ring->scratch.obj->pages->sgl));
 | 
			
		||||
		i915_gem_object_unpin(ring->scratch.obj);
 | 
			
		||||
		i915_gem_object_ggtt_unpin(ring->scratch.obj);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drm_gem_object_unreference(&ring->scratch.obj->base);
 | 
			
		||||
| 
						 | 
				
			
			@ -1253,7 +1253,7 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	kunmap(sg_page(obj->pages->sgl));
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
	ring->status_page.obj = NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1293,7 +1293,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
 | 
			
		|||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
err_unref:
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
err:
 | 
			
		||||
| 
						 | 
				
			
			@ -1390,7 +1390,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 | 
			
		|||
err_unmap:
 | 
			
		||||
	iounmap(ring->virtual_start);
 | 
			
		||||
err_unpin:
 | 
			
		||||
	i915_gem_object_unpin(obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(obj);
 | 
			
		||||
err_unref:
 | 
			
		||||
	drm_gem_object_unreference(&obj->base);
 | 
			
		||||
	ring->obj = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1418,7 +1418,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 | 
			
		|||
 | 
			
		||||
	iounmap(ring->virtual_start);
 | 
			
		||||
 | 
			
		||||
	i915_gem_object_unpin(ring->obj);
 | 
			
		||||
	i915_gem_object_ggtt_unpin(ring->obj);
 | 
			
		||||
	drm_gem_object_unreference(&ring->obj->base);
 | 
			
		||||
	ring->obj = NULL;
 | 
			
		||||
	ring->preallocated_lazy_request = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1430,28 +1430,16 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 | 
			
		|||
	cleanup_status_page(ring);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = i915_wait_seqno(ring, seqno);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		i915_gem_retire_requests_ring(ring);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
 | 
			
		||||
{
 | 
			
		||||
	struct drm_i915_gem_request *request;
 | 
			
		||||
	u32 seqno = 0;
 | 
			
		||||
	u32 seqno = 0, tail;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	i915_gem_retire_requests_ring(ring);
 | 
			
		||||
 | 
			
		||||
	if (ring->last_retired_head != -1) {
 | 
			
		||||
		ring->head = ring->last_retired_head;
 | 
			
		||||
		ring->last_retired_head = -1;
 | 
			
		||||
 | 
			
		||||
		ring->space = ring_space(ring);
 | 
			
		||||
		if (ring->space >= n)
 | 
			
		||||
			return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1468,6 +1456,7 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
 | 
			
		|||
			space += ring->size;
 | 
			
		||||
		if (space >= n) {
 | 
			
		||||
			seqno = request->seqno;
 | 
			
		||||
			tail = request->tail;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1482,15 +1471,11 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
 | 
			
		|||
	if (seqno == 0)
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
 | 
			
		||||
	ret = intel_ring_wait_seqno(ring, seqno);
 | 
			
		||||
	ret = i915_wait_seqno(ring, seqno);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(ring->last_retired_head == -1))
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
 | 
			
		||||
	ring->head = ring->last_retired_head;
 | 
			
		||||
	ring->last_retired_head = -1;
 | 
			
		||||
	ring->head = tail;
 | 
			
		||||
	ring->space = ring_space(ring);
 | 
			
		||||
	if (WARN_ON(ring->space < n))
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,8 @@ enum intel_ring_hangcheck_action {
 | 
			
		|||
	HANGCHECK_HUNG,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define HANGCHECK_SCORE_RING_HUNG 31
 | 
			
		||||
 | 
			
		||||
struct intel_ring_hangcheck {
 | 
			
		||||
	bool deadlock;
 | 
			
		||||
	u32 seqno;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,9 +124,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 | 
			
		|||
	crtc_w--;
 | 
			
		||||
	crtc_h--;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	linear_offset = y * fb->pitches[0] + x * pixel_size;
 | 
			
		||||
	sprsurf_offset = intel_gen4_compute_page_offset(&x, &y,
 | 
			
		||||
							obj->tiling_mode,
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +131,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 | 
			
		|||
							fb->pitches[0]);
 | 
			
		||||
	linear_offset -= sprsurf_offset;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	if (obj->tiling_mode != I915_TILING_NONE)
 | 
			
		||||
		I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			@ -293,15 +293,15 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 | 
			
		|||
	if (crtc_w != src_w || crtc_h != src_h)
 | 
			
		||||
		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	linear_offset = y * fb->pitches[0] + x * pixel_size;
 | 
			
		||||
	sprsurf_offset =
 | 
			
		||||
		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
 | 
			
		||||
					       pixel_size, fb->pitches[0]);
 | 
			
		||||
	linear_offset -= sprsurf_offset;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
 | 
			
		||||
	 * register */
 | 
			
		||||
	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 | 
			
		||||
| 
						 | 
				
			
			@ -472,15 +472,15 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 | 
			
		|||
	if (crtc_w != src_w || crtc_h != src_h)
 | 
			
		||||
		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	linear_offset = y * fb->pitches[0] + x * pixel_size;
 | 
			
		||||
	dvssurf_offset =
 | 
			
		||||
		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
 | 
			
		||||
					       pixel_size, fb->pitches[0]);
 | 
			
		||||
	linear_offset -= dvssurf_offset;
 | 
			
		||||
 | 
			
		||||
	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
 | 
			
		||||
	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 | 
			
		||||
 | 
			
		||||
	if (obj->tiling_mode != I915_TILING_NONE)
 | 
			
		||||
		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -852,6 +852,7 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev,
 | 
			
		|||
	struct drm_i915_private *dev_priv = dev->dev_private;
 | 
			
		||||
	struct drm_i915_reset_stats *args = data;
 | 
			
		||||
	struct i915_ctx_hang_stats *hs;
 | 
			
		||||
	struct i915_hw_context *ctx;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (args->flags || args->pad)
 | 
			
		||||
| 
						 | 
				
			
			@ -864,11 +865,12 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev,
 | 
			
		|||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id);
 | 
			
		||||
	if (IS_ERR(hs)) {
 | 
			
		||||
	ctx = i915_gem_context_get(file->driver_priv, args->ctx_id);
 | 
			
		||||
	if (IS_ERR(ctx)) {
 | 
			
		||||
		mutex_unlock(&dev->struct_mutex);
 | 
			
		||||
		return PTR_ERR(hs);
 | 
			
		||||
		return PTR_ERR(ctx);
 | 
			
		||||
	}
 | 
			
		||||
	hs = &ctx->hang_stats;
 | 
			
		||||
 | 
			
		||||
	if (capable(CAP_SYS_ADMIN))
 | 
			
		||||
		args->reset_count = i915_reset_count(&dev_priv->gpu_error);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,11 +279,21 @@
 | 
			
		|||
 | 
			
		||||
#define DP_TEST_PATTERN			    0x221
 | 
			
		||||
 | 
			
		||||
#define DP_TEST_CRC_R_CR		    0x240
 | 
			
		||||
#define DP_TEST_CRC_G_Y			    0x242
 | 
			
		||||
#define DP_TEST_CRC_B_CB		    0x244
 | 
			
		||||
 | 
			
		||||
#define DP_TEST_SINK_MISC		    0x246
 | 
			
		||||
#define DP_TEST_CRC_SUPPORTED		    (1 << 5)
 | 
			
		||||
 | 
			
		||||
#define DP_TEST_RESPONSE		    0x260
 | 
			
		||||
# define DP_TEST_ACK			    (1 << 0)
 | 
			
		||||
# define DP_TEST_NAK			    (1 << 1)
 | 
			
		||||
# define DP_TEST_EDID_CHECKSUM_WRITE	    (1 << 2)
 | 
			
		||||
 | 
			
		||||
#define DP_TEST_SINK			    0x270
 | 
			
		||||
#define DP_TEST_SINK_START	    (1 << 0)
 | 
			
		||||
 | 
			
		||||
#define DP_SOURCE_OUI			    0x300
 | 
			
		||||
#define DP_SINK_OUI			    0x400
 | 
			
		||||
#define DP_BRANCH_OUI			    0x500
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue