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

Commit b32b8e64 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel: (22 commits)
  drm/i915: Fix read outside array bounds in restoring the SWF10 range.
  drm/i915: Use our own workqueue to avoid wedging the system along with the GPU.
  drm/i915: Add support for dual-channel LVDS on 8xx.
  drm/i915: Return disconnected for SDVO DVI when there's no digital EDID.
  drm/i915: Choose real sdvo output according to result from detection
  drm/i915: Set preferred mode for integrated TV according to TV format
  drm/i915: fix 845G FIFO size & burst length
  drm/i915: fix VGA detect on IGDNG
  drm/i915: Add eDP support on IGDNG mobile chip
  drm/i915: enable DisplayPort support on IGDNG
  drm/i915: Fix channel ending action for DP aux transaction
  drm/i915: fix issue in display pipe setup on IGDNG
  drm/i915: disable VGA plane reliably
  drm/I915: Fix offset to DVO timings in LVDS data
  drm/i915: hdmi detection according by reading edid
  drm/i915: correct self-refresh calculation in "everything off" case
  drm/i915: handle FIFO oversubsription correctly
  drm/i915: FIFO watermark calculation fixes
  drm/i915: ignore lvds on AOpen Mini PC MP-915
  drm/i915: Allow frame buffers up to 4096x4096 on 915/945 class hardware
  ...
parents d6a0967c 819e0064
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -1186,6 +1186,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	if (ret)
		goto out_iomapfree;

	dev_priv->wq = create_workqueue("i915");
	if (dev_priv->wq == NULL) {
		DRM_ERROR("Failed to create our workqueue.\n");
		ret = -ENOMEM;
		goto out_iomapfree;
	}

	/* enable GEM by default */
	dev_priv->has_gem = 1;

@@ -1211,7 +1218,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	if (!I915_NEED_GFX_HWS(dev)) {
		ret = i915_init_phys_hws(dev);
		if (ret != 0)
			goto out_iomapfree;
			goto out_workqueue_free;
	}

	i915_get_mem_freq(dev);
@@ -1245,7 +1252,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
		if (ret < 0) {
			DRM_ERROR("failed to init modeset\n");
			goto out_rmmap;
			goto out_workqueue_free;
		}
	}

@@ -1256,6 +1263,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)

	return 0;

out_workqueue_free:
	destroy_workqueue(dev_priv->wq);
out_iomapfree:
	io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap:
@@ -1269,6 +1278,8 @@ int i915_driver_unload(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	destroy_workqueue(dev_priv->wq);

	io_mapping_free(dev_priv->mm.gtt_mapping);
	if (dev_priv->mm.gtt_mtrr >= 0) {
		mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base,
+4 −0
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ typedef struct drm_i915_private {
	unsigned int lvds_vbt:1;
	unsigned int int_crt_support:1;
	unsigned int lvds_use_ssc:1;
	unsigned int edp_support:1;
	int lvds_ssc_freq;

	struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
@@ -229,6 +230,8 @@ typedef struct drm_i915_private {

	spinlock_t error_lock;
	struct drm_i915_error_state *first_error;
	struct work_struct error_work;
	struct workqueue_struct *wq;

	/* Register state */
	u8 saveLBB;
@@ -888,6 +891,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
						      IS_I915GM(dev)))
#define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_INTEGRATED_DP(dev)	(IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_EDP(dev)		(IS_IGDNG_M(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
/* dsparb controlled by hw only */
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
+2 −2
Original line number Diff line number Diff line
@@ -1570,7 +1570,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
	}

	if (was_empty && !dev_priv->mm.suspended)
		schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
	return seqno;
}

@@ -1719,7 +1719,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
	i915_gem_retire_requests(dev);
	if (!dev_priv->mm.suspended &&
	    !list_empty(&dev_priv->mm.request_list))
		schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
	mutex_unlock(&dev->struct_mutex);
}

+2 −0
Original line number Diff line number Diff line
@@ -343,6 +343,8 @@ static int i915_error_state(struct seq_file *m, void *unused)

	error = dev_priv->first_error;

	seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
		   error->time.tv_usec);
	seq_printf(m, "EIR: 0x%08x\n", error->eir);
	seq_printf(m, "  PGTBL_ER: 0x%08x\n", error->pgtbl_er);
	seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm);
+160 −75
Original line number Diff line number Diff line
@@ -290,6 +290,35 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
	return ret;
}

/**
 * i915_error_work_func - do process context error handling work
 * @work: work struct
 *
 * Fire an error uevent so userspace can see that a hang or error
 * was detected.
 */
static void i915_error_work_func(struct work_struct *work)
{
	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
						    error_work);
	struct drm_device *dev = dev_priv->dev;
	char *event_string = "ERROR=1";
	char *envp[] = { event_string, NULL };

	DRM_DEBUG("generating error event\n");

	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
}

/**
 * i915_capture_error_state - capture an error record for later analysis
 * @dev: drm device
 *
 * Should be called when an error is detected (either a hang or an error
 * interrupt) to capture error state from the time of the error.  Fills
 * out a structure which becomes available in debugfs for user level tools
 * to pick up.
 */
static void i915_capture_error_state(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -325,12 +354,137 @@ static void i915_capture_error_state(struct drm_device *dev)
		error->acthd = I915_READ(ACTHD_I965);
	}

	do_gettimeofday(&error->time);

	dev_priv->first_error = error;

out:
	spin_unlock_irqrestore(&dev_priv->error_lock, flags);
}

/**
 * i915_handle_error - handle an error interrupt
 * @dev: drm device
 *
 * Do some basic checking of regsiter state at error interrupt time and
 * dump it to the syslog.  Also call i915_capture_error_state() to make
 * sure we get a record and make it available in debugfs.  Fire a uevent
 * so userspace knows something bad happened (should trigger collection
 * of a ring dump etc.).
 */
static void i915_handle_error(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 eir = I915_READ(EIR);
	u32 pipea_stats = I915_READ(PIPEASTAT);
	u32 pipeb_stats = I915_READ(PIPEBSTAT);

	i915_capture_error_state(dev);

	printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
	       eir);

	if (IS_G4X(dev)) {
		if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
			u32 ipeir = I915_READ(IPEIR_I965);

			printk(KERN_ERR "  IPEIR: 0x%08x\n",
			       I915_READ(IPEIR_I965));
			printk(KERN_ERR "  IPEHR: 0x%08x\n",
			       I915_READ(IPEHR_I965));
			printk(KERN_ERR "  INSTDONE: 0x%08x\n",
			       I915_READ(INSTDONE_I965));
			printk(KERN_ERR "  INSTPS: 0x%08x\n",
			       I915_READ(INSTPS));
			printk(KERN_ERR "  INSTDONE1: 0x%08x\n",
			       I915_READ(INSTDONE1));
			printk(KERN_ERR "  ACTHD: 0x%08x\n",
			       I915_READ(ACTHD_I965));
			I915_WRITE(IPEIR_I965, ipeir);
			(void)I915_READ(IPEIR_I965);
		}
		if (eir & GM45_ERROR_PAGE_TABLE) {
			u32 pgtbl_err = I915_READ(PGTBL_ER);
			printk(KERN_ERR "page table error\n");
			printk(KERN_ERR "  PGTBL_ER: 0x%08x\n",
			       pgtbl_err);
			I915_WRITE(PGTBL_ER, pgtbl_err);
			(void)I915_READ(PGTBL_ER);
		}
	}

	if (IS_I9XX(dev)) {
		if (eir & I915_ERROR_PAGE_TABLE) {
			u32 pgtbl_err = I915_READ(PGTBL_ER);
			printk(KERN_ERR "page table error\n");
			printk(KERN_ERR "  PGTBL_ER: 0x%08x\n",
			       pgtbl_err);
			I915_WRITE(PGTBL_ER, pgtbl_err);
			(void)I915_READ(PGTBL_ER);
		}
	}

	if (eir & I915_ERROR_MEMORY_REFRESH) {
		printk(KERN_ERR "memory refresh error\n");
		printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
		       pipea_stats);
		printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
		       pipeb_stats);
		/* pipestat has already been acked */
	}
	if (eir & I915_ERROR_INSTRUCTION) {
		printk(KERN_ERR "instruction error\n");
		printk(KERN_ERR "  INSTPM: 0x%08x\n",
		       I915_READ(INSTPM));
		if (!IS_I965G(dev)) {
			u32 ipeir = I915_READ(IPEIR);

			printk(KERN_ERR "  IPEIR: 0x%08x\n",
			       I915_READ(IPEIR));
			printk(KERN_ERR "  IPEHR: 0x%08x\n",
			       I915_READ(IPEHR));
			printk(KERN_ERR "  INSTDONE: 0x%08x\n",
			       I915_READ(INSTDONE));
			printk(KERN_ERR "  ACTHD: 0x%08x\n",
			       I915_READ(ACTHD));
			I915_WRITE(IPEIR, ipeir);
			(void)I915_READ(IPEIR);
		} else {
			u32 ipeir = I915_READ(IPEIR_I965);

			printk(KERN_ERR "  IPEIR: 0x%08x\n",
			       I915_READ(IPEIR_I965));
			printk(KERN_ERR "  IPEHR: 0x%08x\n",
			       I915_READ(IPEHR_I965));
			printk(KERN_ERR "  INSTDONE: 0x%08x\n",
			       I915_READ(INSTDONE_I965));
			printk(KERN_ERR "  INSTPS: 0x%08x\n",
			       I915_READ(INSTPS));
			printk(KERN_ERR "  INSTDONE1: 0x%08x\n",
			       I915_READ(INSTDONE1));
			printk(KERN_ERR "  ACTHD: 0x%08x\n",
			       I915_READ(ACTHD_I965));
			I915_WRITE(IPEIR_I965, ipeir);
			(void)I915_READ(IPEIR_I965);
		}
	}

	I915_WRITE(EIR, eir);
	(void)I915_READ(EIR);
	eir = I915_READ(EIR);
	if (eir) {
		/*
		 * some errors might have become stuck,
		 * mask them.
		 */
		DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
		I915_WRITE(EMR, I915_READ(EMR) | eir);
		I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
	}

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

irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
	struct drm_device *dev = (struct drm_device *) arg;
@@ -372,6 +526,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
		pipea_stats = I915_READ(PIPEASTAT);
		pipeb_stats = I915_READ(PIPEBSTAT);

		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
			i915_handle_error(dev);

		/*
		 * Clear the PIPE(A|B)STAT regs before the IIR
		 */
@@ -403,86 +560,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
			DRM_DEBUG("hotplug event received, stat 0x%08x\n",
				  hotplug_status);
			if (hotplug_status & dev_priv->hotplug_supported_mask)
				schedule_work(&dev_priv->hotplug_work);
				queue_work(dev_priv->wq,
					   &dev_priv->hotplug_work);

			I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
			I915_READ(PORT_HOTPLUG_STAT);
		}

		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
			u32 eir = I915_READ(EIR);

			i915_capture_error_state(dev);

			printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
			       eir);
			if (eir & I915_ERROR_PAGE_TABLE) {
				u32 pgtbl_err = I915_READ(PGTBL_ER);
				printk(KERN_ERR "page table error\n");
				printk(KERN_ERR "  PGTBL_ER: 0x%08x\n",
				       pgtbl_err);
				I915_WRITE(PGTBL_ER, pgtbl_err);
				(void)I915_READ(PGTBL_ER);
			}
			if (eir & I915_ERROR_MEMORY_REFRESH) {
				printk(KERN_ERR "memory refresh error\n");
				printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
				       pipea_stats);
				printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
				       pipeb_stats);
				/* pipestat has already been acked */
			}
			if (eir & I915_ERROR_INSTRUCTION) {
				printk(KERN_ERR "instruction error\n");
				printk(KERN_ERR "  INSTPM: 0x%08x\n",
				       I915_READ(INSTPM));
				if (!IS_I965G(dev)) {
					u32 ipeir = I915_READ(IPEIR);

					printk(KERN_ERR "  IPEIR: 0x%08x\n",
					       I915_READ(IPEIR));
					printk(KERN_ERR "  IPEHR: 0x%08x\n",
						   I915_READ(IPEHR));
					printk(KERN_ERR "  INSTDONE: 0x%08x\n",
						   I915_READ(INSTDONE));
					printk(KERN_ERR "  ACTHD: 0x%08x\n",
						   I915_READ(ACTHD));
					I915_WRITE(IPEIR, ipeir);
					(void)I915_READ(IPEIR);
				} else {
					u32 ipeir = I915_READ(IPEIR_I965);

					printk(KERN_ERR "  IPEIR: 0x%08x\n",
					       I915_READ(IPEIR_I965));
					printk(KERN_ERR "  IPEHR: 0x%08x\n",
					       I915_READ(IPEHR_I965));
					printk(KERN_ERR "  INSTDONE: 0x%08x\n",
					       I915_READ(INSTDONE_I965));
					printk(KERN_ERR "  INSTPS: 0x%08x\n",
					       I915_READ(INSTPS));
					printk(KERN_ERR "  INSTDONE1: 0x%08x\n",
					       I915_READ(INSTDONE1));
					printk(KERN_ERR "  ACTHD: 0x%08x\n",
					       I915_READ(ACTHD_I965));
					I915_WRITE(IPEIR_I965, ipeir);
					(void)I915_READ(IPEIR_I965);
				}
			}

			I915_WRITE(EIR, eir);
			(void)I915_READ(EIR);
			eir = I915_READ(EIR);
			if (eir) {
				/*
				 * some errors might have become stuck,
				 * mask them.
				 */
				DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
				I915_WRITE(EMR, I915_READ(EMR) | eir);
				I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
			}
		}

		I915_WRITE(IIR, iir);
		new_iir = I915_READ(IIR); /* Flush posted writes */

@@ -830,6 +914,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
	atomic_set(&dev_priv->irq_received, 0);

	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
	INIT_WORK(&dev_priv->error_work, i915_error_work_func);

	if (IS_IGDNG(dev)) {
		igdng_irq_preinstall(dev);
Loading