summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h28
-rw-r--r--linux-core/drm_bo.c70
-rw-r--r--linux-core/drm_bo_move.c3
-rw-r--r--linux-core/drm_bufs.c12
-rw-r--r--linux-core/drm_crtc.c15
-rw-r--r--linux-core/drm_drv.c4
-rw-r--r--linux-core/drm_fence.c4
-rw-r--r--linux-core/drm_fops.c106
-rw-r--r--linux-core/drm_irq.c166
-rw-r--r--linux-core/drm_memory.c51
-rw-r--r--linux-core/drm_proc.c14
-rw-r--r--linux-core/drm_stub.c23
-rw-r--r--linux-core/drm_ttm.c12
-rw-r--r--linux-core/i915_fence.c4
-rw-r--r--linux-core/intel_crt.c15
-rw-r--r--linux-core/intel_display.c18
-rw-r--r--linux-core/intel_drv.h2
-rw-r--r--linux-core/intel_fb.c2
-rw-r--r--linux-core/intel_sdvo.c14
19 files changed, 407 insertions, 156 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 47974856..c2c3cdde 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -591,6 +591,13 @@ struct drm_vbl_sig {
struct task_struct *task;
};
+struct drm_hotplug_sig {
+ struct list_head head;
+ unsigned int counter;
+ struct siginfo info;
+ struct task_struct *task;
+};
+
/* location of GART table */
#define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2
@@ -867,6 +874,15 @@ struct drm_device {
struct work_struct work;
+ /** \name HOTPLUG IRQ support */
+ /*@{ */
+ wait_queue_head_t hotplug_queue; /**< HOTPLUG wait queue */
+ spinlock_t hotplug_lock;
+ struct list_head *hotplug_sigs; /**< signal list to send on HOTPLUG */
+ atomic_t hotplug_signal_pending; /* number of signals pending on all crtcs*/
+
+ /*@} */
+
/** \name VBLANK IRQ support */
/*@{ */
@@ -1060,8 +1076,10 @@ extern int drm_unbind_agp(DRM_AGP_MEM * handle);
extern void drm_free_memctl(size_t size);
extern int drm_alloc_memctl(size_t size);
extern void drm_query_memctl(uint64_t *cur_used,
+ uint64_t *emer_used,
uint64_t *low_threshold,
- uint64_t *high_threshold);
+ uint64_t *high_threshold,
+ uint64_t *emer_threshold);
extern void drm_init_memctl(size_t low_threshold,
size_t high_threshold,
size_t unit_size);
@@ -1193,13 +1211,17 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev);
+extern int drm_hotplug_init(struct drm_device *dev);
+extern int drm_wait_hotplug(struct drm_device *dev, void *data, struct drm_file *filp);
extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp);
+extern int drm_wait_hotplug(struct drm_device *dev, void *data, struct drm_file *filp);
extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq);
extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
extern void drm_update_vblank_count(struct drm_device *dev, int crtc);
extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern void drm_handle_hotplug(struct drm_device *dev);
extern int drm_vblank_get(struct drm_device *dev, int crtc);
extern void drm_vblank_put(struct drm_device *dev, int crtc);
@@ -1244,6 +1266,10 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev);
extern void drm_agp_chipset_flush(struct drm_device *dev);
/* Stub support (drm_stub.h) */
+extern int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern struct drm_master *drm_get_master(struct drm_minor *minor);
extern void drm_put_master(struct drm_master *master);
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 1d3f87e5..7e82080b 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -208,36 +208,35 @@ static int drm_bo_handle_move_mem(struct drm_buffer_object *bo,
if (ret)
goto out_err;
}
- }
-
- if ((bo->mem.mem_type == DRM_BO_MEM_LOCAL) && bo->ttm == NULL) {
-
- struct drm_bo_mem_reg *old_mem = &bo->mem;
- uint64_t save_flags = old_mem->flags;
- uint64_t save_proposed_flags = old_mem->proposed_flags;
- *old_mem = *mem;
- mem->mm_node = NULL;
- old_mem->proposed_flags = save_proposed_flags;
- DRM_FLAG_MASKED(save_flags, mem->flags, DRM_BO_MASK_MEMTYPE);
-
- } else if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) &&
- !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) {
+ if (bo->mem.mem_type == DRM_BO_MEM_LOCAL) {
+
+ struct drm_bo_mem_reg *old_mem = &bo->mem;
+ uint64_t save_flags = old_mem->flags;
+ uint64_t save_proposed_flags = old_mem->proposed_flags;
+
+ *old_mem = *mem;
+ mem->mm_node = NULL;
+ old_mem->proposed_flags = save_proposed_flags;
+ DRM_FLAG_MASKED(save_flags, mem->flags,
+ DRM_BO_MASK_MEMTYPE);
+ goto moved;
+ }
+
+ }
+ if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) &&
+ !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED))
ret = drm_bo_move_ttm(bo, evict, no_wait, mem);
-
- } else if (dev->driver->bo_driver->move) {
+ else if (dev->driver->bo_driver->move)
ret = dev->driver->bo_driver->move(bo, evict, no_wait, mem);
-
- } else {
-
+ else
ret = drm_bo_move_memcpy(bo, evict, no_wait, mem);
- }
-
if (ret)
goto out_err;
+moved:
if (old_is_pci || new_is_pci)
drm_bo_vm_post_move(bo);
@@ -789,6 +788,11 @@ static int drm_bo_mem_force_space(struct drm_device *dev,
}
node = drm_mm_get_block(node, num_pages, mem->page_alignment);
+ if (unlikely(!node)) {
+ mutex_unlock(&dev->struct_mutex);
+ return -ENOMEM;
+ }
+
mutex_unlock(&dev->struct_mutex);
mem->mm_node = node;
mem->mem_type = mem_type;
@@ -974,6 +978,20 @@ static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo,
return -EPERM;
}
+ if (likely(new_mask & DRM_BO_MASK_MEM) &&
+ (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) &&
+ !DRM_SUSER(DRM_CURPROC)) {
+ if (likely(bo->mem.flags & new_flags & new_mask &
+ DRM_BO_MASK_MEM))
+ new_flags = (new_flags & ~DRM_BO_MASK_MEM) |
+ (bo->mem.flags & DRM_BO_MASK_MEM);
+ else {
+ DRM_ERROR("Incompatible memory type specification "
+ "for NO_EVICT buffer.\n");
+ return -EPERM;
+ }
+ }
+
if ((new_flags & DRM_BO_FLAG_NO_MOVE)) {
DRM_ERROR("DRM_BO_FLAG_NO_MOVE is not properly implemented yet.\n");
return -EPERM;
@@ -1482,6 +1500,9 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo,
if (ret) {
if (ret != -EAGAIN)
DRM_ERROR("Failed moving buffer.\n");
+ if (ret == -ENOMEM)
+ DRM_ERROR("Out of aperture space or "
+ "DRM memory quota.\n");
return ret;
}
}
@@ -2748,7 +2769,7 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo)
list->file_offset_node = drm_mm_search_free(&dev->offset_manager,
bo->mem.num_pages, 0, 0);
- if (!list->file_offset_node) {
+ if (unlikely(!list->file_offset_node)) {
drm_bo_takedown_vm_locked(bo);
return -ENOMEM;
}
@@ -2756,6 +2777,11 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo)
list->file_offset_node = drm_mm_get_block(list->file_offset_node,
bo->mem.num_pages, 0);
+ if (unlikely(!list->file_offset_node)) {
+ drm_bo_takedown_vm_locked(bo);
+ return -ENOMEM;
+ }
+
list->hash.key = list->file_offset_node->start;
if (drm_ht_insert_item(&dev->map_hash, &list->hash)) {
drm_bo_takedown_vm_locked(bo);
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c
index 536ff5d3..f10549ab 100644
--- a/linux-core/drm_bo_move.c
+++ b/linux-core/drm_bo_move.c
@@ -42,7 +42,6 @@ static void drm_bo_free_old_node(struct drm_buffer_object *bo)
if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) {
mutex_lock(&bo->dev->struct_mutex);
drm_mm_put_block(old_mem->mm_node);
- old_mem->mm_node = NULL;
mutex_unlock(&bo->dev->struct_mutex);
}
old_mem->mm_node = NULL;
@@ -57,7 +56,7 @@ int drm_bo_move_ttm(struct drm_buffer_object *bo,
uint64_t save_proposed_flags = old_mem->proposed_flags;
int ret;
- if (old_mem->mem_type == DRM_BO_MEM_TT) {
+ if (old_mem->mem_type != DRM_BO_MEM_LOCAL) {
if (evict)
drm_ttm_evict(ttm);
else
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
index 031f8ba0..f6ff75ab 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -380,10 +380,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
struct drm_map_list *r_list = NULL, *list_t;
drm_dma_handle_t dmah;
int found = 0;
+ struct drm_master *master;
/* Find the list entry for the map and remove it */
list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
if (r_list->map == map) {
+ master = r_list->master;
list_del(&r_list->head);
drm_ht_remove_key(&dev->map_hash,
r_list->user_token >> PAGE_SHIFT);
@@ -413,9 +415,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
break;
case _DRM_SHM:
vfree(map->handle);
- dev->sigdata.lock = dev->primary->master->lock.hw_lock = NULL; /* SHM removed */
- dev->primary->master->lock.file_priv = NULL;
- wake_up_interruptible(&dev->primary->master->lock.lock_queue);
+ if (master) {
+ if (dev->sigdata.lock == master->lock.hw_lock)
+ dev->sigdata.lock = NULL;
+ master->lock.hw_lock = NULL; /* SHM removed */
+ master->lock.file_priv = NULL;
+ wake_up_interruptible(&master->lock.lock_queue);
+ }
break;
case _DRM_AGP:
case _DRM_SCATTER_GATHER:
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index e0c85cef..0cd0ebd0 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -947,6 +947,7 @@ static void drm_pick_crtcs (struct drm_device *dev)
if (drm_mode_equal (modes, modes_equal)) {
if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) {
printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones);
+ des_mode = modes;
assigned = 0;
goto clone;
}
@@ -1180,7 +1181,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info,
* @output hotpluged output
*
* LOCKING.
- * Caller must hold mode config lock, function might grap struct lock.
+ * Caller must hold mode config lock, function might grab struct lock.
*
* Stage two of a hotplug.
*
@@ -1192,10 +1193,11 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,
{
int has_config = 0;
+ dev->mode_config.hotplug_counter++;
+
/* We might want to do something more here */
if (!connected) {
DRM_DEBUG("not connected\n");
- dev->mode_config.hotplug_counter++;
return 0;
}
@@ -1211,10 +1213,10 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,
if (!output->crtc || !output->crtc->desired_mode) {
DRM_DEBUG("could not find a desired mode or crtc for output\n");
- goto out_err;
+ return 1;
}
- /* We should realy check if there is a fb using this crtc */
+ /* We should really check if there is a fb using this crtc */
if (!has_config)
dev->driver->fb_probe(dev, output->crtc);
else {
@@ -1226,12 +1228,7 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,
drm_disable_unused_functions(dev);
- dev->mode_config.hotplug_counter++;
return 0;
-
-out_err:
- dev->mode_config.hotplug_counter++;
- return 1;
}
EXPORT_SYMBOL(drm_hotplug_stage_two);
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 434789dd..649d4cae 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -76,6 +76,9 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+
DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -136,6 +139,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0),
DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c
index 9d80327f..0ca0c408 100644
--- a/linux-core/drm_fence.c
+++ b/linux-core/drm_fence.c
@@ -520,8 +520,10 @@ int drm_fence_object_create(struct drm_device *dev, uint32_t fence_class,
struct drm_fence_manager *fm = &dev->fm;
fence = drm_ctl_calloc(1, sizeof(*fence), DRM_MEM_FENCE);
- if (!fence)
+ if (!fence) {
+ DRM_ERROR("Out of memory creating fence object\n");
return -ENOMEM;
+ }
ret = drm_fence_object_init(dev, fence_class, type, flags, fence);
if (ret) {
drm_fence_usage_deref_unlocked(&fence);
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
index fcadc544..d5c59b19 100644
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -402,59 +402,63 @@ int drm_release(struct inode *inode, struct file *filp)
current->pid, (long)old_encode_dev(file_priv->minor->device),
dev->open_count);
- if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) {
- if (drm_i_have_hw_lock(dev, file_priv)) {
- dev->driver->reclaim_buffers_locked(dev, file_priv);
- } else {
- unsigned long _end=jiffies + 3*DRM_HZ;
- int locked = 0;
-
- drm_idlelock_take(&file_priv->master->lock);
-
- /*
- * Wait for a while.
- */
-
- do{
- spin_lock(&file_priv->master->lock.spinlock);
- locked = file_priv->master->lock.idle_has_lock;
- spin_unlock(&file_priv->master->lock.spinlock);
- if (locked)
- break;
- schedule();
- } while (!time_after_eq(jiffies, _end));
-
- if (!locked) {
- DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
- "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
- "\tI will go on reclaiming the buffers anyway.\n");
+ /* if the master has gone away we can't do anything with the lock */
+ if (file_priv->minor->master) {
+ if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) {
+ if (drm_i_have_hw_lock(dev, file_priv)) {
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
+ } else {
+ unsigned long _end=jiffies + 3*DRM_HZ;
+ int locked = 0;
+
+ drm_idlelock_take(&file_priv->master->lock);
+
+ /*
+ * Wait for a while.
+ */
+
+ do{
+ spin_lock(&file_priv->master->lock.spinlock);
+ locked = file_priv->master->lock.idle_has_lock;
+ spin_unlock(&file_priv->master->lock.spinlock);
+ if (locked)
+ break;
+ schedule();
+ } while (!time_after_eq(jiffies, _end));
+
+ if (!locked) {
+ DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
+ "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
+ "\tI will go on reclaiming the buffers anyway.\n");
+ }
+
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
+ drm_idlelock_release(&file_priv->master->lock);
}
+ }
- dev->driver->reclaim_buffers_locked(dev, file_priv);
+ if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) {
+
+ drm_idlelock_take(&file_priv->master->lock);
+ dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
drm_idlelock_release(&file_priv->master->lock);
+
}
- }
-
- if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) {
-
- drm_idlelock_take(&file_priv->master->lock);
- dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
- drm_idlelock_release(&file_priv->master->lock);
-
- }
-
- if (drm_i_have_hw_lock(dev, file_priv)) {
- DRM_DEBUG("File %p released, freeing lock for context %d\n",
- filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
- drm_lock_free(&file_priv->master->lock,
- _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
- }
+ if (drm_i_have_hw_lock(dev, file_priv)) {
+ DRM_DEBUG("File %p released, freeing lock for context %d\n",
+ filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+
+ drm_lock_free(&file_priv->master->lock,
+ _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+ }
+
- if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
- !dev->driver->reclaim_buffers_locked) {
- dev->driver->reclaim_buffers(dev, file_priv);
+ if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
+ !dev->driver->reclaim_buffers_locked) {
+ dev->driver->reclaim_buffers(dev, file_priv);
+ }
}
drm_fasync(-1, filp, 0);
@@ -484,13 +488,15 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_fb_release(filp);
- file_priv->master = NULL;
-
if (file_priv->is_master) {
- drm_put_master(file_priv->minor->master);
- file_priv->minor->master = NULL;
+ if (file_priv->minor->master == file_priv->master)
+ file_priv->minor->master = NULL;
+ drm_put_master(file_priv->master);
}
+ file_priv->master = NULL;
+ file_priv->is_master = 0;
+
mutex_lock(&dev->struct_mutex);
drm_object_release(filp);
if (file_priv->remove_auth_on_close == 1) {
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 6b740b18..230ef3cc 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -90,32 +90,41 @@ static void vblank_disable_fn(unsigned long arg)
static void drm_vblank_cleanup(struct drm_device *dev)
{
- /* Bail if the driver didn't call drm_vblank_init() */
- if (dev->num_crtcs == 0)
- return;
-
del_timer(&dev->vblank_disable_timer);
vblank_disable_fn((unsigned long)dev);
- drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
+ if (dev->vbl_queue)
+ drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
DRM_MEM_DRIVER);
- drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
+
+ if (dev->vbl_sigs)
+ drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
DRM_MEM_DRIVER);
- drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
+
+ if (dev->_vblank_count)
+ drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
+
+ if (dev->vblank_refcount)
+ drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
+
+ if (dev->vblank_enabled)
+ drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
+
+ if (dev->last_vblank)
+ drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
DRM_MEM_DRIVER);
- drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
+
+ if (dev->vblank_premodeset)
+ drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs,
- DRM_MEM_DRIVER);
- dev->num_crtcs = 0;
+ if (dev->vblank_offset)
+ drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
}
int drm_vblank_init(struct drm_device *dev, int num_crtcs)
@@ -182,6 +191,82 @@ err:
}
EXPORT_SYMBOL(drm_vblank_init);
+int drm_wait_hotplug(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ union drm_wait_hotplug *hotplugwait = data;
+ struct timeval now;
+ int ret = 0;
+ unsigned int flags;
+
+ if ((!dev->irq) || (!dev->irq_enabled))
+ return -EINVAL;
+
+ flags = hotplugwait->request.type;
+
+ if (flags & _DRM_HOTPLUG_SIGNAL) {
+ unsigned long irqflags;
+ struct list_head *hotplug_sigs = dev->hotplug_sigs;
+ struct drm_hotplug_sig *hotplug_sig;
+
+ hotplug_sig = drm_calloc(1, sizeof(struct drm_hotplug_sig),
+ DRM_MEM_DRIVER);
+ if (!hotplug_sig)
+ return -ENOMEM;
+
+ atomic_inc(&dev->hotplug_signal_pending);
+
+ hotplug_sig->info.si_signo = hotplugwait->request.signal;
+ hotplug_sig->task = current;
+ hotplug_sig->counter =
+ hotplugwait->reply.counter =
+ dev->mode_config.hotplug_counter;
+
+ spin_lock_irqsave(&dev->hotplug_lock, irqflags);
+
+ list_add_tail(&hotplug_sig->head, hotplug_sigs);
+
+ spin_unlock_irqrestore(&dev->hotplug_lock, irqflags);
+ } else {
+ int cur_hotplug = dev->mode_config.hotplug_counter;
+
+ DRM_WAIT_ON(ret, dev->hotplug_queue, 3 * DRM_HZ,
+ dev->mode_config.hotplug_counter > cur_hotplug);
+
+ do_gettimeofday(&now);
+
+ hotplugwait->reply.tval_sec = now.tv_sec;
+ hotplugwait->reply.tval_usec = now.tv_usec;
+ hotplugwait->reply.counter = dev->mode_config.hotplug_counter;
+ }
+
+ return ret;
+}
+
+static void drm_hotplug_cleanup(struct drm_device *dev)
+{
+ if (dev->hotplug_sigs)
+ drm_free(dev->hotplug_sigs, sizeof(*dev->hotplug_sigs),
+ DRM_MEM_DRIVER);
+}
+EXPORT_SYMBOL(drm_hotplug_cleanup);
+
+int drm_hotplug_init(struct drm_device *dev)
+{
+ spin_lock_init(&dev->hotplug_lock);
+ atomic_set(&dev->hotplug_signal_pending, 0);
+
+ dev->hotplug_sigs = drm_alloc(sizeof(struct list_head), DRM_MEM_DRIVER);
+ if (!dev->hotplug_sigs)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(dev->hotplug_sigs);
+ init_waitqueue_head(&dev->hotplug_queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_hotplug_init);
+
/**
* Install IRQ handler.
*
@@ -277,6 +362,8 @@ int drm_irq_uninstall(struct drm_device * dev)
drm_vblank_cleanup(dev);
+ drm_hotplug_cleanup(dev);
+
dev->locked_tasklet_func = NULL;
return 0;
@@ -530,7 +617,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
- struct drm_vbl_sig *vbl_sig;
+ struct drm_vbl_sig *vbl_sig, *tmp;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -538,7 +625,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
* for the same vblank sequence number; nothing to be done in
* that case
*/
- list_for_each_entry(vbl_sig, vbl_sigs, head) {
+ list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
if (vbl_sig->sequence == vblwait->request.sequence
&& vbl_sig->info.si_signo ==
vblwait->request.signal
@@ -660,6 +747,53 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
EXPORT_SYMBOL(drm_handle_vblank);
/**
+ * Send the HOTPLUG signals.
+ *
+ * \param dev DRM device.
+ *
+ * Sends a signal for each task in drm_device::hotplug_sigs and empties the list.
+ */
+static void drm_hotplug_send_signals(struct drm_device * dev)
+{
+ struct drm_hotplug_sig *hotplug_sig, *tmp;
+ struct list_head *hotplug_sigs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hotplug_lock, flags);
+
+ hotplug_sigs = dev->hotplug_sigs;
+
+ list_for_each_entry_safe(hotplug_sig, tmp, hotplug_sigs, head) {
+ hotplug_sig->info.si_code = hotplug_sig->counter;
+
+ send_sig_info(hotplug_sig->info.si_signo,
+ &hotplug_sig->info, hotplug_sig->task);
+
+ list_del(&hotplug_sig->head);
+
+ drm_free(hotplug_sig, sizeof(*hotplug_sig),
+ DRM_MEM_DRIVER);
+ atomic_dec(&dev->hotplug_signal_pending);
+ }
+
+ spin_unlock_irqrestore(&dev->hotplug_lock, flags);
+}
+
+/**
+ * drm_handle_hotplug - handle a hotplug event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their hotplug interrupt handlers.
+ */
+void drm_handle_hotplug(struct drm_device *dev)
+{
+ DRM_WAKEUP(&dev->hotplug_queue);
+ drm_hotplug_send_signals(dev);
+}
+EXPORT_SYMBOL(drm_handle_hotplug);
+
+/**
* Tasklet wrapper function.
*
* \param data DRM device in disguise.
diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c
index 402a680f..12e01414 100644
--- a/linux-core/drm_memory.c
+++ b/linux-core/drm_memory.c
@@ -39,8 +39,10 @@
static struct {
spinlock_t lock;
uint64_t cur_used;
+ uint64_t emer_used;
uint64_t low_threshold;
uint64_t high_threshold;
+ uint64_t emer_threshold;
} drm_memctl = {
.lock = SPIN_LOCK_UNLOCKED
};
@@ -59,14 +61,30 @@ static inline size_t drm_size_align(size_t size)
int drm_alloc_memctl(size_t size)
{
- int ret;
+ int ret = 0;
unsigned long a_size = drm_size_align(size);
+ unsigned long new_used = drm_memctl.cur_used + a_size;
spin_lock(&drm_memctl.lock);
- ret = ((drm_memctl.cur_used + a_size) > drm_memctl.high_threshold) ?
- -ENOMEM : 0;
- if (!ret)
- drm_memctl.cur_used += a_size;
+ if (unlikely(new_used > drm_memctl.high_threshold)) {
+ if (!DRM_SUSER(DRM_CURPROC) ||
+ (new_used + drm_memctl.emer_used > drm_memctl.emer_threshold) ||
+ (a_size > 2*PAGE_SIZE)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Allow small root-only allocations, even if the
+ * high threshold is exceeded.
+ */
+
+ new_used -= drm_memctl.high_threshold;
+ drm_memctl.emer_used += new_used;
+ a_size -= new_used;
+ }
+ drm_memctl.cur_used += a_size;
+out:
spin_unlock(&drm_memctl.lock);
return ret;
}
@@ -77,19 +95,30 @@ void drm_free_memctl(size_t size)
unsigned long a_size = drm_size_align(size);
spin_lock(&drm_memctl.lock);
+ if (likely(a_size >= drm_memctl.emer_used)) {
+ a_size -= drm_memctl.emer_used;
+ drm_memctl.emer_used = 0;
+ } else {
+ drm_memctl.emer_used -= a_size;
+ a_size = 0;
+ }
drm_memctl.cur_used -= a_size;
spin_unlock(&drm_memctl.lock);
}
EXPORT_SYMBOL(drm_free_memctl);
void drm_query_memctl(uint64_t *cur_used,
+ uint64_t *emer_used,
uint64_t *low_threshold,
- uint64_t *high_threshold)
+ uint64_t *high_threshold,
+ uint64_t *emer_threshold)
{
spin_lock(&drm_memctl.lock);
*cur_used = drm_memctl.cur_used;
+ *emer_used = drm_memctl.emer_used;
*low_threshold = drm_memctl.low_threshold;
*high_threshold = drm_memctl.high_threshold;
+ *emer_threshold = drm_memctl.emer_threshold;
spin_unlock(&drm_memctl.lock);
}
EXPORT_SYMBOL(drm_query_memctl);
@@ -99,9 +128,12 @@ void drm_init_memctl(size_t p_low_threshold,
size_t unit_size)
{
spin_lock(&drm_memctl.lock);
+ drm_memctl.emer_used = 0;
drm_memctl.cur_used = 0;
drm_memctl.low_threshold = p_low_threshold * unit_size;
drm_memctl.high_threshold = p_high_threshold * unit_size;
+ drm_memctl.emer_threshold = (drm_memctl.high_threshold >> 4) +
+ drm_memctl.high_threshold;
spin_unlock(&drm_memctl.lock);
}
@@ -294,7 +326,12 @@ static void *agp_remap(unsigned long offset, unsigned long size,
return NULL;
}
#endif /* agp */
-
+#else
+static void *agp_remap(unsigned long offset, unsigned long size,
+ struct drm_device * dev)
+{
+ return NULL;
+}
#endif /* debug_memory */
void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c
index e10501f2..b6748b9b 100644
--- a/linux-core/drm_proc.c
+++ b/linux-core/drm_proc.c
@@ -446,9 +446,10 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
struct drm_buffer_manager *bm = &dev->bm;
struct drm_fence_manager *fm = &dev->fm;
uint64_t used_mem;
+ uint64_t used_emer;
uint64_t low_mem;
uint64_t high_mem;
-
+ uint64_t emer_mem;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
@@ -477,7 +478,7 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n");
}
- drm_query_memctl(&used_mem, &low_mem, &high_mem);
+ drm_query_memctl(&used_mem, &used_emer, &low_mem, &high_mem, &emer_mem);
if (used_mem > 16*PAGE_SIZE) {
DRM_PROC_PRINT("Used object memory is %lu pages.\n",
@@ -486,10 +487,19 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("Used object memory is %lu bytes.\n",
(unsigned long) used_mem);
}
+ if (used_emer > 16*PAGE_SIZE) {
+ DRM_PROC_PRINT("Used emergency memory is %lu pages.\n",
+ (unsigned long) (used_emer >> PAGE_SHIFT));
+ } else {
+ DRM_PROC_PRINT("Used emergency memory is %lu bytes.\n\n",
+ (unsigned long) used_emer);
+ }
DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n",
(unsigned long) (low_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n",
(unsigned long) (high_mem >> PAGE_SHIFT));
+ DRM_PROC_PRINT("Emergency root only memory usage threshold is %lu pages.\n",
+ (unsigned long) (emer_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("\n");
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 6856075b..f66dec07 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -88,6 +88,29 @@ again:
return new_id;
}
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
+ return -EINVAL;
+
+ if (!file_priv->master)
+ return -EINVAL;
+
+ if (!file_priv->minor->master && file_priv->minor->master != file_priv->master)
+ file_priv->minor->master = file_priv->master;
+ return 0;
+}
+
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ if (!file_priv->master)
+ return -EINVAL;
+ file_priv->minor->master = NULL;
+ return 0;
+}
+
struct drm_master *drm_get_master(struct drm_minor *minor)
{
struct drm_master *master;
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index cc80b132..e991254f 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -299,13 +299,13 @@ int drm_ttm_populate(struct drm_ttm *ttm)
return 0;
be = ttm->be;
- if (ttm->page_flags & DRM_TTM_PAGE_WRITE) {
- for (i = 0; i < ttm->num_pages; ++i) {
- page = drm_ttm_get_page(ttm, i);
- if (!page)
- return -ENOMEM;
- }
+
+ for (i = 0; i < ttm->num_pages; ++i) {
+ page = drm_ttm_get_page(ttm, i);
+ if (!page)
+ return -ENOMEM;
}
+
be->func->populate(be, ttm->num_pages, ttm->pages, ttm->dummy_read_page);
ttm->state = ttm_unbound;
return 0;
diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c
index 0f6cdeef..f392e8e6 100644
--- a/linux-core/i915_fence.c
+++ b/linux-core/i915_fence.c
@@ -120,11 +120,11 @@ static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class,
if (dev_priv->fence_irq_on &&
!(fc->waiting_types & DRM_FENCE_TYPE_EXE)) {
- i915_user_irq_off(dev_priv);
+ i915_user_irq_off(dev);
dev_priv->fence_irq_on = 0;
} else if (!dev_priv->fence_irq_on &&
(fc->waiting_types & DRM_FENCE_TYPE_EXE)) {
- i915_user_irq_on(dev_priv);
+ i915_user_irq_on(dev);
dev_priv->fence_irq_on = 1;
}
}
diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c
index a9fb50a3..915e430d 100644
--- a/linux-core/intel_crt.c
+++ b/linux-core/intel_crt.c
@@ -132,7 +132,7 @@ static void intel_crt_mode_set(struct drm_output *output,
/**
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
*
- * Only for I945G/GM.
+ * Not for i915G/i915GM
*
* \return TRUE if CRT is connected.
* \return FALSE if CRT is disconnected.
@@ -142,7 +142,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)
struct drm_device *dev = output->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp;
-#if 1
+
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
temp = I915_READ(PORT_HOTPLUG_EN);
@@ -161,15 +161,6 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)
return true;
return false;
-#else
- temp = I915_READ(PORT_HOTPLUG_STAT);
- DRM_DEBUG("HST 0x%08x\n", temp);
-
- if (temp & (1 << 8) && temp & (1 << 9))
- return true;
-
- return false;
-#endif
}
static bool intel_crt_detect_ddc(struct drm_output *output)
@@ -187,7 +178,7 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output)
{
struct drm_device *dev = output->dev;
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) {
+ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
if (intel_crt_detect_hotplug(output))
return output_status_connected;
else
diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c
index 4b48a0b2..fa2b9bea 100644
--- a/linux-core/intel_display.c
+++ b/linux-core/intel_display.c
@@ -1007,7 +1007,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL;
uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE;
uint32_t temp;
- size_t adder;
+ size_t addr;
DRM_DEBUG("\n");
@@ -1039,17 +1039,21 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
return -ENOMEM;
}
- adder = dev_priv->stolen_base + bo->offset;
- intel_crtc->cursor_adder = adder;
+ if (dev_priv->cursor_needs_physical)
+ addr = dev_priv->stolen_base + bo->offset;
+ else
+ addr = bo->offset;
+
+ intel_crtc->cursor_addr = addr;
temp = 0;
/* set the pipe for the cursor */
temp |= (pipe << 28);
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
- DRM_DEBUG("cusror base %x\n", adder);
+ DRM_DEBUG("cusror base %x\n", addr);
I915_WRITE(control, temp);
- I915_WRITE(base, adder);
+ I915_WRITE(base, addr);
return 0;
}
@@ -1075,7 +1079,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
- adder = intel_crtc->cursor_adder;
+ adder = intel_crtc->cursor_addr;
I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp);
I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
@@ -1241,7 +1245,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->lut_b[i] = i;
}
- intel_crtc->cursor_adder = 0;
+ intel_crtc->cursor_addr = 0;
crtc->driver_private = intel_crtc;
}
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
index 72ba01da..a36fd3f1 100644
--- a/linux-core/intel_drv.h
+++ b/linux-core/intel_drv.h
@@ -56,7 +56,7 @@ struct intel_output {
struct intel_crtc {
int pipe;
int plane;
- uint32_t cursor_adder;
+ uint32_t cursor_addr;
u8 lut_r[256], lut_g[256], lut_b[256];
};
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index 52ff3a67..7c4b0632 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -157,7 +157,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
break;
case 16:
var->red.offset = 11;
- var->green.offset = 6;
+ var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c
index 3887df00..a8441d8f 100644
--- a/linux-core/intel_sdvo.c
+++ b/linux-core/intel_sdvo.c
@@ -53,7 +53,6 @@ struct intel_sdvo_priv {
struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
struct intel_sdvo_dtd save_output_dtd[16];
u32 save_SDVOX;
- int hotplug_enabled;
};
/**
@@ -72,14 +71,8 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
if (sdvo_priv->output_device == SDVOB) {
cval = I915_READ(SDVOC);
-
- if (sdvo_priv->hotplug_enabled)
- bval = bval | (1 << 26);
} else {
bval = I915_READ(SDVOB);
-
- if (sdvo_priv->hotplug_enabled)
- cval = cval | (1 << 26);
}
/*
* Write the registers twice for luck. Sometimes,
@@ -933,8 +926,6 @@ int intel_sdvo_supports_hotplug(struct drm_output *output)
void intel_sdvo_set_hotplug(struct drm_output *output, int on)
{
- struct intel_output *intel_output = output->driver_private;
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
u8 response[2];
u8 status;
@@ -942,15 +933,11 @@ void intel_sdvo_set_hotplug(struct drm_output *output, int on)
intel_sdvo_read_response(output, &response, 2);
if (on) {
- sdvo_priv->hotplug_enabled = 1;
-
intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
status = intel_sdvo_read_response(output, &response, 2);
intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
} else {
- sdvo_priv->hotplug_enabled = 0;
-
response[0] = 0;
response[1] = 0;
intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
@@ -1074,7 +1061,6 @@ void intel_sdvo_init(struct drm_device *dev, int output_device)
}
sdvo_priv->output_device = output_device;
- sdvo_priv->hotplug_enabled = 0;
intel_output->i2c_bus = i2cbus;
intel_output->dev_priv = sdvo_priv;