Commit 26b23ace authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel

* '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
...@@ -735,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, ...@@ -735,8 +735,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
if (cmdbuf->num_cliprects) { if (cmdbuf->num_cliprects) {
cliprects = kcalloc(cmdbuf->num_cliprects, cliprects = kcalloc(cmdbuf->num_cliprects,
sizeof(struct drm_clip_rect), GFP_KERNEL); sizeof(struct drm_clip_rect), GFP_KERNEL);
if (cliprects == NULL) if (cliprects == NULL) {
ret = -ENOMEM;
goto fail_batch_free; goto fail_batch_free;
}
ret = copy_from_user(cliprects, cmdbuf->cliprects, ret = copy_from_user(cliprects, cmdbuf->cliprects,
cmdbuf->num_cliprects * cmdbuf->num_cliprects *
......
...@@ -174,78 +174,100 @@ const static struct pci_device_id pciidlist[] = { ...@@ -174,78 +174,100 @@ const static struct pci_device_id pciidlist[] = {
MODULE_DEVICE_TABLE(pci, pciidlist); MODULE_DEVICE_TABLE(pci, pciidlist);
#endif #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); pci_save_state(dev->pdev);
/* If KMS is active, we do the leavevt stuff here */ /* If KMS is active, we do the leavevt stuff here */
if (drm_core_check_feature(dev, DRIVER_MODESET)) { 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, 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); drm_irq_uninstall(dev);
} }
i915_save_state(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); 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) { if (state.event == PM_EVENT_SUSPEND) {
/* Shut down the device */ /* Shut down the device */
pci_disable_device(dev->pdev); pci_disable_device(dev->pdev);
pci_set_power_state(dev->pdev, PCI_D3hot); pci_set_power_state(dev->pdev, PCI_D3hot);
} }
/* Modeset on resume, not lid events */
dev_priv->modeset_on_lid = 0;
return 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; struct drm_i915_private *dev_priv = dev->dev_private;
int ret = 0; int error = 0;
if (pci_enable_device(dev->pdev))
return -1;
pci_set_master(dev->pdev);
i915_restore_state(dev);
intel_opregion_init(dev, 1);
/* KMS EnterVT equivalent */ /* KMS EnterVT equivalent */
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
dev_priv->mm.suspended = 0; dev_priv->mm.suspended = 0;
ret = i915_gem_init_ringbuffer(dev); error = i915_gem_init_ringbuffer(dev);
if (ret != 0)
ret = -1;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
drm_irq_install(dev); drm_irq_install(dev);
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
/* Resume the modeset for every activated CRTC */ /* Resume the modeset for every activated CRTC */
drm_helper_resume_force_mode(dev); drm_helper_resume_force_mode(dev);
} }
dev_priv->modeset_on_lid = 0; 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) ...@@ -386,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev); drm_put_dev(dev);
} }
static int static int i915_pm_suspend(struct device *dev)
i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{ {
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 error = i915_drm_freeze(drm_dev);
i915_pci_resume(struct pci_dev *pdev) if (error)
{ return error;
struct drm_device *dev = pci_get_drvdata(pdev);
return i915_resume(dev); i915_drm_suspend(drm_dev);
}
static int pci_disable_device(pdev);
i915_pm_suspend(struct device *dev) pci_set_power_state(pdev, PCI_D3hot);
{
return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND);
}
static int return 0;
i915_pm_resume(struct device *dev)
{
return i915_pci_resume(to_pci_dev(dev));
} }
static int static int i915_pm_resume(struct device *dev)
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);
return i915_resume(drm_dev);
} }
static int static int i915_pm_freeze(struct device *dev)
i915_pm_thaw(struct device *dev)
{ {
/* thaw during hibernate, do nothing! */ struct pci_dev *pdev = to_pci_dev(dev);
return 0; 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;
}
return i915_drm_freeze(drm_dev);
} }
static int static int i915_pm_thaw(struct device *dev)
i915_pm_poweroff(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 static int i915_pm_poweroff(struct device *dev)
i915_pm_restore(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 = { const struct dev_pm_ops i915_pm_ops = {
...@@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = { ...@@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = {
.freeze = i915_pm_freeze, .freeze = i915_pm_freeze,
.thaw = i915_pm_thaw, .thaw = i915_pm_thaw,
.poweroff = i915_pm_poweroff, .poweroff = i915_pm_poweroff,
.restore = i915_pm_restore, .restore = i915_pm_resume,
}; };
static struct vm_operations_struct i915_gem_vm_ops = { static struct vm_operations_struct i915_gem_vm_ops = {
......
...@@ -492,6 +492,15 @@ typedef struct drm_i915_private { ...@@ -492,6 +492,15 @@ typedef struct drm_i915_private {
*/ */
struct list_head flushing_list; 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 * LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT. * are ready to unbind, but are still in the GTT.
...@@ -592,6 +601,8 @@ struct drm_i915_gem_object { ...@@ -592,6 +601,8 @@ struct drm_i915_gem_object {
/** This object's place on the active/flushing/inactive lists */ /** This object's place on the active/flushing/inactive lists */
struct list_head list; 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 */ /** This object's place on the fenced object LRU */
struct list_head fence_list; struct list_head fence_list;
......
...@@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) ...@@ -1552,6 +1552,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
else else
list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); 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; obj_priv->last_rendering_seqno = 0;
if (obj_priv->active) { if (obj_priv->active) {
obj_priv->active = 0; obj_priv->active = 0;
...@@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, ...@@ -1622,7 +1624,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
struct drm_i915_gem_object *obj_priv, *next; struct drm_i915_gem_object *obj_priv, *next;
list_for_each_entry_safe(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; struct drm_gem_object *obj = obj_priv->obj;
if ((obj->write_domain & flush_domains) == if ((obj->write_domain & flush_domains) ==
...@@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, ...@@ -1630,6 +1633,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
uint32_t old_write_domain = obj->write_domain; uint32_t old_write_domain = obj->write_domain;
obj->write_domain = 0; obj->write_domain = 0;
list_del_init(&obj_priv->gpu_write_list);
i915_gem_object_move_to_active(obj, seqno); i915_gem_object_move_to_active(obj, seqno);
trace_i915_gem_object_change_domain(obj, trace_i915_gem_object_change_domain(obj,
...@@ -2084,8 +2088,8 @@ static int ...@@ -2084,8 +2088,8 @@ static int
i915_gem_evict_everything(struct drm_device *dev) i915_gem_evict_everything(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
int ret; int ret;
uint32_t seqno;
bool lists_empty; bool lists_empty;
spin_lock(&dev_priv->mm.active_list_lock); spin_lock(&dev_priv->mm.active_list_lock);
...@@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev) ...@@ -2107,6 +2111,8 @@ i915_gem_evict_everything(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
ret = i915_gem_evict_from_inactive_list(dev); ret = i915_gem_evict_from_inactive_list(dev);
if (ret) if (ret)
return ret; return ret;
...@@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) ...@@ -2701,7 +2707,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
old_write_domain = obj->write_domain; old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain); i915_gem_flush(dev, 0, obj->write_domain);
seqno = i915_add_request(dev, NULL, 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); i915_gem_object_move_to_active(obj, seqno);
trace_i915_gem_object_change_domain(obj, trace_i915_gem_object_change_domain(obj,
...@@ -3682,8 +3688,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ...@@ -3682,8 +3688,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (args->num_cliprects != 0) { if (args->num_cliprects != 0) {
cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects),
GFP_KERNEL); GFP_KERNEL);
if (cliprects == NULL) if (cliprects == NULL) {
ret = -ENOMEM;
goto pre_mutex_err; goto pre_mutex_err;
}
ret = copy_from_user(cliprects, ret = copy_from_user(cliprects,
(struct drm_clip_rect __user *) (struct drm_clip_rect __user *)
...@@ -3850,16 +3858,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ...@@ -3850,16 +3858,23 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
i915_gem_flush(dev, i915_gem_flush(dev,
dev->invalidate_domains, dev->invalidate_domains,
dev->flush_domains); dev->flush_domains);
if (dev->flush_domains) if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
(void)i915_add_request(dev, file_priv, (void)i915_add_request(dev, file_priv,
dev->flush_domains); dev->flush_domains);
} }
for (i = 0; i < args->buffer_count; i++) { for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[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; uint32_t old_write_domain = obj->write_domain;
obj->write_domain = obj->pending_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, trace_i915_gem_object_change_domain(obj,
obj->read_domains, obj->read_domains,
old_write_domain); old_write_domain);
...@@ -4370,6 +4385,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) ...@@ -4370,6 +4385,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
obj_priv->obj = obj; obj_priv->obj = obj;
obj_priv->fence_reg = I915_FENCE_REG_NONE; obj_priv->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj_priv->list); INIT_LIST_HEAD(&obj_priv->list);
INIT_LIST_HEAD(&obj_priv->gpu_write_list);
INIT_LIST_HEAD(&obj_priv->fence_list); INIT_LIST_HEAD(&obj_priv->fence_list);
obj_priv->madv = I915_MADV_WILLNEED; obj_priv->madv = I915_MADV_WILLNEED;
...@@ -4821,6 +4837,7 @@ i915_gem_load(struct drm_device *dev) ...@@ -4821,6 +4837,7 @@ i915_gem_load(struct drm_device *dev)
spin_lock_init(&dev_priv->mm.active_list_lock); spin_lock_init(&dev_priv->mm.active_list_lock);
INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.active_list);
INIT_LIST_HEAD(&dev_priv->mm.flushing_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.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_LIST_HEAD(&dev_priv->mm.request_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list);
......
...@@ -309,21 +309,21 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) ...@@ -309,21 +309,21 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
if (de_iir & DE_GSE) if (de_iir & DE_GSE)
ironlake_opregion_gse_intr(dev); 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_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_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); 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); drm_handle_vblank(dev, 1);
intel_finish_page_flip(dev, 1);
}
/* check event from PCH */ /* check event from PCH */
if ((de_iir & DE_PCH_EVENT) && if ((de_iir & DE_PCH_EVENT) &&
......
...@@ -338,6 +338,7 @@ ...@@ -338,6 +338,7 @@
#define FBC_CTL_PERIODIC (1<<30) #define FBC_CTL_PERIODIC (1<<30)
#define FBC_CTL_INTERVAL_SHIFT (16) #define FBC_CTL_INTERVAL_SHIFT (16)
#define FBC_CTL_UNCOMPRESSIBLE (1<<14) #define FBC_CTL_UNCOMPRESSIBLE (1<<14)
#define FBC_C3_IDLE (1<<13)
#define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_STRIDE_SHIFT (5)
#define FBC_CTL_FENCENO (1<<0) #define FBC_CTL_FENCENO (1<<0)
#define FBC_COMMAND 0x0320c #define FBC_COMMAND 0x0320c
......
This diff is collapsed.
...@@ -148,7 +148,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -148,7 +148,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
ret = i915_gem_object_pin(fbo, PAGE_SIZE); ret = i915_gem_object_pin(fbo, 64*1024);
if (ret) { if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret); DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref; goto out_unref;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment