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

Commit 26b23ace 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:
  drm/i915: hold ref on flip object until it completes
  drm/i915: Fix crash while aborting hibernation
  drm/i915: Correctly return -ENOMEM on allocation failure in cmdbuf ioctls.
  drm/i915: fix pipe source image setting in flip command
  drm/i915: fix flip done interrupt on Ironlake
  drm/i915: untangle page flip completion
  drm/i915: handle FBC and self-refresh better
  drm/i915: Increase fb alignment to 64k
  drm/i915: Update write_domains on active list after flush.
  drm/i915: Rework DPLL calculation parameters for Ironlake
parents 22a8cdd6 75dfca80
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -735,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
	if (cmdbuf->num_cliprects) {
		cliprects = kcalloc(cmdbuf->num_cliprects,
				    sizeof(struct drm_clip_rect), GFP_KERNEL);
		if (cliprects == NULL)
		if (cliprects == NULL) {
			ret = -ENOMEM;
			goto fail_batch_free;
		}

		ret = copy_from_user(cliprects, cmdbuf->cliprects,
				     cmdbuf->num_cliprects *
+101 −67
Original line number Diff line number Diff line
@@ -174,78 +174,100 @@ const static struct pci_device_id pciidlist[] = {
MODULE_DEVICE_TABLE(pci, pciidlist);
#endif

static int i915_suspend(struct drm_device *dev, pm_message_t state)
static int i915_drm_freeze(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	if (!dev || !dev_priv) {
		DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
		DRM_ERROR("DRM not initialized, aborting suspend.\n");
		return -ENODEV;
	}

	if (state.event == PM_EVENT_PRETHAW)
		return 0;

	pci_save_state(dev->pdev);

	/* If KMS is active, we do the leavevt stuff here */
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		if (i915_gem_idle(dev))
		int error = i915_gem_idle(dev);
		if (error) {
			dev_err(&dev->pdev->dev,
				"GEM idle failed, resume may fail\n");
				"GEM idle failed, resume might fail\n");
			return error;
		}
		drm_irq_uninstall(dev);
	}

	i915_save_state(dev);

	return 0;
}

static void i915_drm_suspend(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	intel_opregion_free(dev, 1);

	/* Modeset on resume, not lid events */
	dev_priv->modeset_on_lid = 0;
}

static int i915_suspend(struct drm_device *dev, pm_message_t state)
{
	int error;

	if (!dev || !dev->dev_private) {
		DRM_ERROR("dev: %p\n", dev);
		DRM_ERROR("DRM not initialized, aborting suspend.\n");
		return -ENODEV;
	}

	if (state.event == PM_EVENT_PRETHAW)
		return 0;

	error = i915_drm_freeze(dev);
	if (error)
		return error;

	i915_drm_suspend(dev);

	if (state.event == PM_EVENT_SUSPEND) {
		/* Shut down the device */
		pci_disable_device(dev->pdev);
		pci_set_power_state(dev->pdev, PCI_D3hot);
	}

	/* Modeset on resume, not lid events */
	dev_priv->modeset_on_lid = 0;

	return 0;
}

static int i915_resume(struct drm_device *dev)
static int i915_drm_thaw(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	int ret = 0;

	if (pci_enable_device(dev->pdev))
		return -1;
	pci_set_master(dev->pdev);

	i915_restore_state(dev);

	intel_opregion_init(dev, 1);
	int error = 0;

	/* KMS EnterVT equivalent */
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		mutex_lock(&dev->struct_mutex);
		dev_priv->mm.suspended = 0;

		ret = i915_gem_init_ringbuffer(dev);
		if (ret != 0)
			ret = -1;
		error = i915_gem_init_ringbuffer(dev);
		mutex_unlock(&dev->struct_mutex);

		drm_irq_install(dev);
	}
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {

		/* Resume the modeset for every activated CRTC */
		drm_helper_resume_force_mode(dev);
	}

	dev_priv->modeset_on_lid = 0;

	return ret;
	return error;
}

static int i915_resume(struct drm_device *dev)
{
	if (pci_enable_device(dev->pdev))
		return -EIO;

	pci_set_master(dev->pdev);

	i915_restore_state(dev);

	intel_opregion_init(dev, 1);

	return i915_drm_thaw(dev);
}

/**
@@ -386,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev)
	drm_put_dev(dev);
}

static int
i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int i915_pm_suspend(struct device *dev)
{
	struct drm_device *dev = pci_get_drvdata(pdev);
	struct pci_dev *pdev = to_pci_dev(dev);
	struct drm_device *drm_dev = pci_get_drvdata(pdev);
	int error;

	return i915_suspend(dev, state);
	if (!drm_dev || !drm_dev->dev_private) {
		dev_err(dev, "DRM not initialized, aborting suspend.\n");
		return -ENODEV;
	}

static int
i915_pci_resume(struct pci_dev *pdev)
{
	struct drm_device *dev = pci_get_drvdata(pdev);
	error = i915_drm_freeze(drm_dev);
	if (error)
		return error;

	return i915_resume(dev);
}
	i915_drm_suspend(drm_dev);

static int
i915_pm_suspend(struct device *dev)
{
	return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND);
	pci_disable_device(pdev);
	pci_set_power_state(pdev, PCI_D3hot);

	return 0;
}

static int
i915_pm_resume(struct device *dev)
static int i915_pm_resume(struct device *dev)
{
	return i915_pci_resume(to_pci_dev(dev));
	struct pci_dev *pdev = to_pci_dev(dev);
	struct drm_device *drm_dev = pci_get_drvdata(pdev);

	return i915_resume(drm_dev);
}

static int
i915_pm_freeze(struct device *dev)
static int i915_pm_freeze(struct device *dev)
{
	return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE);
	struct pci_dev *pdev = to_pci_dev(dev);
	struct drm_device *drm_dev = pci_get_drvdata(pdev);

	if (!drm_dev || !drm_dev->dev_private) {
		dev_err(dev, "DRM not initialized, aborting suspend.\n");
		return -ENODEV;
	}

static int
i915_pm_thaw(struct device *dev)
{
	/* thaw during hibernate, do nothing! */
	return 0;
	return i915_drm_freeze(drm_dev);
}

static int
i915_pm_poweroff(struct device *dev)
static int i915_pm_thaw(struct device *dev)
{
	return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE);
	struct pci_dev *pdev = to_pci_dev(dev);
	struct drm_device *drm_dev = pci_get_drvdata(pdev);

	return i915_drm_thaw(drm_dev);
}

static int
i915_pm_restore(struct device *dev)
static int i915_pm_poweroff(struct device *dev)
{
	return i915_pci_resume(to_pci_dev(dev));
	struct pci_dev *pdev = to_pci_dev(dev);
	struct drm_device *drm_dev = pci_get_drvdata(pdev);
	int error;

	error = i915_drm_freeze(drm_dev);
	if (!error)
		i915_drm_suspend(drm_dev);

	return error;
}

const struct dev_pm_ops i915_pm_ops = {
@@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = {
     .freeze = i915_pm_freeze,
     .thaw = i915_pm_thaw,
     .poweroff = i915_pm_poweroff,
     .restore = i915_pm_restore,
     .restore = i915_pm_resume,
};

static struct vm_operations_struct i915_gem_vm_ops = {
+11 −0
Original line number Diff line number Diff line
@@ -492,6 +492,15 @@ typedef struct drm_i915_private {
		 */
		struct list_head flushing_list;

		/**
		 * List of objects currently pending a GPU write flush.
		 *
		 * All elements on this list will belong to either the
		 * active_list or flushing_list, last_rendering_seqno can
		 * be used to differentiate between the two elements.
		 */
		struct list_head gpu_write_list;

		/**
		 * LRU list of objects which are not in the ringbuffer and
		 * are ready to unbind, but are still in the GTT.
@@ -592,6 +601,8 @@ struct drm_i915_gem_object {

	/** This object's place on the active/flushing/inactive lists */
	struct list_head list;
	/** This object's place on GPU write list */
	struct list_head gpu_write_list;

	/** This object's place on the fenced object LRU */
	struct list_head fence_list;
+22 −5
Original line number Diff line number Diff line
@@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
	else
		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);

	BUG_ON(!list_empty(&obj_priv->gpu_write_list));

	obj_priv->last_rendering_seqno = 0;
	if (obj_priv->active) {
		obj_priv->active = 0;
@@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
		struct drm_i915_gem_object *obj_priv, *next;

		list_for_each_entry_safe(obj_priv, next,
					 &dev_priv->mm.flushing_list, list) {
					 &dev_priv->mm.gpu_write_list,
					 gpu_write_list) {
			struct drm_gem_object *obj = obj_priv->obj;

			if ((obj->write_domain & flush_domains) ==
@@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
				uint32_t old_write_domain = obj->write_domain;

				obj->write_domain = 0;
				list_del_init(&obj_priv->gpu_write_list);
				i915_gem_object_move_to_active(obj, seqno);

				trace_i915_gem_object_change_domain(obj,
@@ -2084,8 +2088,8 @@ static int
i915_gem_evict_everything(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	uint32_t seqno;
	int ret;
	uint32_t seqno;
	bool lists_empty;

	spin_lock(&dev_priv->mm.active_list_lock);
@@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev)
	if (ret)
		return ret;

	BUG_ON(!list_empty(&dev_priv->mm.flushing_list));

	ret = i915_gem_evict_from_inactive_list(dev);
	if (ret)
		return ret;
@@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
	old_write_domain = obj->write_domain;
	i915_gem_flush(dev, 0, obj->write_domain);
	seqno = i915_add_request(dev, NULL, obj->write_domain);
	obj->write_domain = 0;
	BUG_ON(obj->write_domain);
	i915_gem_object_move_to_active(obj, seqno);

	trace_i915_gem_object_change_domain(obj,
@@ -3682,8 +3688,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
	if (args->num_cliprects != 0) {
		cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects),
				    GFP_KERNEL);
		if (cliprects == NULL)
		if (cliprects == NULL) {
			ret = -ENOMEM;
			goto pre_mutex_err;
		}

		ret = copy_from_user(cliprects,
				     (struct drm_clip_rect __user *)
@@ -3850,16 +3858,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
		i915_gem_flush(dev,
			       dev->invalidate_domains,
			       dev->flush_domains);
		if (dev->flush_domains)
		if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
			(void)i915_add_request(dev, file_priv,
					       dev->flush_domains);
	}

	for (i = 0; i < args->buffer_count; i++) {
		struct drm_gem_object *obj = object_list[i];
		struct drm_i915_gem_object *obj_priv = obj->driver_private;
		uint32_t old_write_domain = obj->write_domain;

		obj->write_domain = obj->pending_write_domain;
		if (obj->write_domain)
			list_move_tail(&obj_priv->gpu_write_list,
				       &dev_priv->mm.gpu_write_list);
		else
			list_del_init(&obj_priv->gpu_write_list);

		trace_i915_gem_object_change_domain(obj,
						    obj->read_domains,
						    old_write_domain);
@@ -4370,6 +4385,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
	obj_priv->obj = obj;
	obj_priv->fence_reg = I915_FENCE_REG_NONE;
	INIT_LIST_HEAD(&obj_priv->list);
	INIT_LIST_HEAD(&obj_priv->gpu_write_list);
	INIT_LIST_HEAD(&obj_priv->fence_list);
	obj_priv->madv = I915_MADV_WILLNEED;

@@ -4821,6 +4837,7 @@ i915_gem_load(struct drm_device *dev)
	spin_lock_init(&dev_priv->mm.active_list_lock);
	INIT_LIST_HEAD(&dev_priv->mm.active_list);
	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
	INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
	INIT_LIST_HEAD(&dev_priv->mm.request_list);
	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+8 −8
Original line number Diff line number Diff line
@@ -309,21 +309,21 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
	if (de_iir & DE_GSE)
		ironlake_opregion_gse_intr(dev);

	if (de_iir & DE_PLANEA_FLIP_DONE)
	if (de_iir & DE_PLANEA_FLIP_DONE) {
		intel_prepare_page_flip(dev, 0);
		intel_finish_page_flip(dev, 0);
	}

	if (de_iir & DE_PLANEB_FLIP_DONE)
	if (de_iir & DE_PLANEB_FLIP_DONE) {
		intel_prepare_page_flip(dev, 1);
		intel_finish_page_flip(dev, 1);
	}

	if (de_iir & DE_PIPEA_VBLANK) {
	if (de_iir & DE_PIPEA_VBLANK)
		drm_handle_vblank(dev, 0);
		intel_finish_page_flip(dev, 0);
	}

	if (de_iir & DE_PIPEB_VBLANK) {
	if (de_iir & DE_PIPEB_VBLANK)
		drm_handle_vblank(dev, 1);
		intel_finish_page_flip(dev, 1);
	}

	/* check event from PCH */
	if ((de_iir & DE_PCH_EVENT) &&
Loading