Commit 49f89764 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/drm-misc-2015-05-06' of git://anongit.freedesktop.org/drm-intel into drm-next

misc drm core patches.

* tag 'topic/drm-misc-2015-05-06' of git://anongit.freedesktop.org/drm-intel:
  drm: simplify master cleanup
  drm: simplify authentication management
  drm: drop unused 'magicfree' list
  drm: fix a memleak on mutex failure path
  drm/atomic-helper: Really recover pre-atomic plane/cursor behavior
  drm/qxl: Fix qxl_noop_get_vblank_counter()
  drm: Zero out invalid vblank timestamp in drm_update_vblank_count. (v2)
  drm: Prevent invalid use of vblank_disable_immediate. (v2)
  drm/vblank: Fixup and document timestamp update/read barriers
  DRM: Don't re-poll connector for disconnect
  drm: Fix for DP CTS test 4.2.2.5 - I2C DEFER handling
  drm: Fix the 'native defer' message in drm_dp_i2c_do_msg()
  drm/atomic-helper: Don't call atomic_update_plane when it stays off
parents 5ebe6afa 4a324d33
...@@ -1138,7 +1138,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, ...@@ -1138,7 +1138,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
if (drm_atomic_plane_disabling(plane, old_plane_state) && if (drm_atomic_plane_disabling(plane, old_plane_state) &&
funcs->atomic_disable) funcs->atomic_disable)
funcs->atomic_disable(plane, old_plane_state); funcs->atomic_disable(plane, old_plane_state);
else else if (plane->state->crtc ||
drm_atomic_plane_disabling(plane, old_plane_state))
funcs->atomic_update(plane, old_plane_state); funcs->atomic_update(plane, old_plane_state);
} }
...@@ -1309,13 +1310,13 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, ...@@ -1309,13 +1310,13 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
plane_state->src_h = src_h; plane_state->src_h = src_h;
plane_state->src_w = src_w; plane_state->src_w = src_w;
if (plane == crtc->cursor)
state->legacy_cursor_update = true;
ret = drm_atomic_commit(state); ret = drm_atomic_commit(state);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
if (plane == crtc->cursor)
state->legacy_cursor_update = true;
/* Driver takes ownership of state on successful commit. */ /* Driver takes ownership of state on successful commit. */
return 0; return 0;
fail: fail:
......
/**
* \file drm_auth.c
* IOCTLs for authentication
*
* \author Rickard E. (Rik) Faith <faith@valinux.com>
* \author Gareth Hughes <gareth@valinux.com>
*/
/* /*
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
* *
...@@ -13,6 +5,9 @@ ...@@ -13,6 +5,9 @@
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved. * All Rights Reserved.
* *
* Author Rickard E. (Rik) Faith <faith@valinux.com>
* Author Gareth Hughes <gareth@valinux.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
...@@ -36,154 +31,47 @@ ...@@ -36,154 +31,47 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include "drm_internal.h" #include "drm_internal.h"
struct drm_magic_entry {
struct list_head head;
struct drm_hash_item hash_item;
struct drm_file *priv;
};
/**
* Find the file with the given magic number.
*
* \param dev DRM device.
* \param magic magic number.
*
* Searches in drm_device::magiclist within all files with the same hash key
* the one with matching magic number, while holding the drm_device::struct_mutex
* lock.
*/
static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic)
{
struct drm_file *retval = NULL;
struct drm_magic_entry *pt;
struct drm_hash_item *hash;
struct drm_device *dev = master->minor->dev;
mutex_lock(&dev->struct_mutex);
if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
retval = pt->priv;
}
mutex_unlock(&dev->struct_mutex);
return retval;
}
/** /**
* Adds a magic number. * drm_getmagic - Get unique magic of a client
* @dev: DRM device to operate on
* @data: ioctl data containing the drm_auth object
* @file_priv: DRM file that performs the operation
* *
* \param dev DRM device. * This looks up the unique magic of the passed client and returns it. If the
* \param priv file private data. * client did not have a magic assigned, yet, a new one is registered. The magic
* \param magic magic number. * is stored in the passed drm_auth object.
* *
* Creates a drm_magic_entry structure and appends to the linked list * Returns: 0 on success, negative error code on failure.
* associated the magic number hash key in drm_device::magiclist, while holding
* the drm_device::struct_mutex lock.
*/
static int drm_add_magic(struct drm_master *master, struct drm_file *priv,
drm_magic_t magic)
{
struct drm_magic_entry *entry;
struct drm_device *dev = master->minor->dev;
DRM_DEBUG("%d\n", magic);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->priv = priv;
entry->hash_item.key = (unsigned long)magic;
mutex_lock(&dev->struct_mutex);
drm_ht_insert_item(&master->magiclist, &entry->hash_item);
list_add_tail(&entry->head, &master->magicfree);
mutex_unlock(&dev->struct_mutex);
return 0;
}
/**
* Remove a magic number.
*
* \param dev DRM device.
* \param magic magic number.
*
* Searches and unlinks the entry in drm_device::magiclist with the magic
* number hash key, while holding the drm_device::struct_mutex lock.
*/
int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
{
struct drm_magic_entry *pt;
struct drm_hash_item *hash;
struct drm_device *dev = master->minor->dev;
DRM_DEBUG("%d\n", magic);
mutex_lock(&dev->struct_mutex);
if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
drm_ht_remove_item(&master->magiclist, hash);
list_del(&pt->head);
mutex_unlock(&dev->struct_mutex);
kfree(pt);
return 0;
}
/**
* Get a unique magic number (ioctl).
*
* \param inode device inode.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a resulting drm_auth structure.
* \return zero on success, or a negative number on failure.
*
* If there is a magic number in drm_file::magic then use it, otherwise
* searches an unique non-zero magic number and add it associating it with \p
* file_priv.
* This ioctl needs protection by the drm_global_mutex, which protects
* struct drm_file::magic and struct drm_magic_entry::priv.
*/ */
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ {
static drm_magic_t sequence = 0;
static DEFINE_SPINLOCK(lock);
struct drm_auth *auth = data; struct drm_auth *auth = data;
int ret = 0;
/* Find unique magic */ mutex_lock(&dev->struct_mutex);
if (file_priv->magic) { if (!file_priv->magic) {
auth->magic = file_priv->magic; ret = idr_alloc(&file_priv->master->magic_map, file_priv,
} else { 1, 0, GFP_KERNEL);
do { if (ret >= 0)
spin_lock(&lock); file_priv->magic = ret;
if (!sequence)
++sequence; /* reserve 0 */
auth->magic = sequence++;
spin_unlock(&lock);
} while (drm_find_file(file_priv->master, auth->magic));
file_priv->magic = auth->magic;
drm_add_magic(file_priv->master, file_priv, auth->magic);
} }
auth->magic = file_priv->magic;
mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("%u\n", auth->magic); DRM_DEBUG("%u\n", auth->magic);
return 0; return ret < 0 ? ret : 0;
} }
/** /**
* Authenticate with a magic. * drm_authmagic - Authenticate client with a magic
* @dev: DRM device to operate on
* @data: ioctl data containing the drm_auth object
* @file_priv: DRM file that performs the operation
* *
* \param inode device inode. * This looks up a DRM client by the passed magic and authenticates it.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_auth structure.
* \return zero if authentication successed, or a negative number otherwise.
* *
* Checks if \p file_priv is associated with the magic number passed in \arg. * Returns: 0 on success, negative error code on failure.
* This ioctl needs protection by the drm_global_mutex, which protects
* struct drm_file::magic and struct drm_magic_entry::priv.
*/ */
int drm_authmagic(struct drm_device *dev, void *data, int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
...@@ -192,10 +80,14 @@ int drm_authmagic(struct drm_device *dev, void *data, ...@@ -192,10 +80,14 @@ int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file; struct drm_file *file;
DRM_DEBUG("%u\n", auth->magic); DRM_DEBUG("%u\n", auth->magic);
if ((file = drm_find_file(file_priv->master, auth->magic))) {
mutex_lock(&dev->struct_mutex);
file = idr_find(&file_priv->master->magic_map, auth->magic);
if (file) {
file->authenticated = 1; file->authenticated = 1;
drm_remove_magic(file_priv->master, auth->magic); idr_replace(&file_priv->master->magic_map, NULL, auth->magic);
return 0;
} }
return -EINVAL; mutex_unlock(&dev->struct_mutex);
return file ? 0 : -EINVAL;
} }
...@@ -432,7 +432,7 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) ...@@ -432,7 +432,7 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
*/ */
static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{ {
unsigned int retry; unsigned int retry, defer_i2c;
int ret; int ret;
/* /*
...@@ -440,7 +440,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -440,7 +440,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
* is required to retry at least seven times upon receiving AUX_DEFER * is required to retry at least seven times upon receiving AUX_DEFER
* before giving up the AUX transaction. * before giving up the AUX transaction.
*/ */
for (retry = 0; retry < 7; retry++) { for (retry = 0, defer_i2c = 0; retry < (7 + defer_i2c); retry++) {
mutex_lock(&aux->hw_mutex); mutex_lock(&aux->hw_mutex);
ret = aux->transfer(aux, msg); ret = aux->transfer(aux, msg);
mutex_unlock(&aux->hw_mutex); mutex_unlock(&aux->hw_mutex);
...@@ -466,7 +466,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -466,7 +466,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
return -EREMOTEIO; return -EREMOTEIO;
case DP_AUX_NATIVE_REPLY_DEFER: case DP_AUX_NATIVE_REPLY_DEFER:
DRM_DEBUG_KMS("native defer"); DRM_DEBUG_KMS("native defer\n");
/* /*
* We could check for I2C bit rate capabilities and if * We could check for I2C bit rate capabilities and if
* available adjust this interval. We could also be * available adjust this interval. We could also be
...@@ -499,7 +499,13 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -499,7 +499,13 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
case DP_AUX_I2C_REPLY_DEFER: case DP_AUX_I2C_REPLY_DEFER:
DRM_DEBUG_KMS("I2C defer\n"); DRM_DEBUG_KMS("I2C defer\n");
/* DP Compliance Test 4.2.2.5 Requirement:
* Must have at least 7 retries for I2C defers on the
* transaction to pass this test
*/
aux->i2c_defer_count++; aux->i2c_defer_count++;
if (defer_i2c < 7)
defer_i2c++;
usleep_range(400, 500); usleep_range(400, 500);
continue; continue;
......
...@@ -92,8 +92,6 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...) ...@@ -92,8 +92,6 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...)
} }
EXPORT_SYMBOL(drm_ut_debug_printk); EXPORT_SYMBOL(drm_ut_debug_printk);
#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */
struct drm_master *drm_master_create(struct drm_minor *minor) struct drm_master *drm_master_create(struct drm_minor *minor)
{ {
struct drm_master *master; struct drm_master *master;
...@@ -105,11 +103,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor) ...@@ -105,11 +103,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor)
kref_init(&master->refcount); kref_init(&master->refcount);
spin_lock_init(&master->lock.spinlock); spin_lock_init(&master->lock.spinlock);
init_waitqueue_head(&master->lock.lock_queue); init_waitqueue_head(&master->lock.lock_queue);
if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) { idr_init(&master->magic_map);
kfree(master);
return NULL;
}
INIT_LIST_HEAD(&master->magicfree);
master->minor = minor; master->minor = minor;
return master; return master;
...@@ -138,16 +132,10 @@ static void drm_master_destroy(struct kref *kref) ...@@ -138,16 +132,10 @@ static void drm_master_destroy(struct kref *kref)
r_list = NULL; r_list = NULL;
} }
} }
mutex_unlock(&dev->struct_mutex);
if (master->unique) { idr_destroy(&master->magic_map);
kfree(master->unique); kfree(master->unique);
master->unique = NULL;
master->unique_len = 0;
}
drm_ht_remove(&master->magiclist);
mutex_unlock(&dev->struct_mutex);
kfree(master); kfree(master);
} }
......
...@@ -380,6 +380,8 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -380,6 +380,8 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_del(&file_priv->lhead); list_del(&file_priv->lhead);
if (file_priv->magic)
idr_remove(&file_priv->master->magic_map, file_priv->magic);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
if (dev->driver->preclose) if (dev->driver->preclose)
...@@ -394,11 +396,6 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -394,11 +396,6 @@ int drm_release(struct inode *inode, struct file *filp)
(long)old_encode_dev(file_priv->minor->kdev->devt), (long)old_encode_dev(file_priv->minor->kdev->devt),
dev->open_count); dev->open_count);
/* Release any auth tokens that might point to this file_priv,
(do that under the drm_global_mutex) */
if (file_priv->magic)
(void) drm_remove_magic(file_priv->master, file_priv->magic);
/* if the master has gone away we can't do anything with the lock */ /* if the master has gone away we can't do anything with the lock */
if (file_priv->minor->master) if (file_priv->minor->master)
drm_master_release(dev, filp); drm_master_release(dev, filp);
......
...@@ -69,7 +69,6 @@ int drm_getmagic(struct drm_device *dev, void *data, ...@@ -69,7 +69,6 @@ int drm_getmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int drm_authmagic(struct drm_device *dev, void *data, int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
/* drm_sysfs.c */ /* drm_sysfs.c */
extern struct class *drm_class; extern struct class *drm_class;
......
...@@ -74,6 +74,36 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); ...@@ -74,6 +74,36 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
static void store_vblank(struct drm_device *dev, int crtc,
unsigned vblank_count_inc,
struct timeval *t_vblank)
{
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
u32 tslot;
assert_spin_locked(&dev->vblank_time_lock);
if (t_vblank) {
/* All writers hold the spinlock, but readers are serialized by
* the latching of vblank->count below.
*/
tslot = vblank->count + vblank_count_inc;
vblanktimestamp(dev, crtc, tslot) = *t_vblank;
}
/*
* vblank timestamp updates are protected on the write side with
* vblank_time_lock, but on the read side done locklessly using a
* sequence-lock on the vblank counter. Ensure correct ordering using
* memory barrriers. We need the barrier both before and also after the
* counter update to synchronize with the next timestamp write.
* The read-side barriers for this are in drm_vblank_count_and_time.
*/
smp_wmb();
vblank->count += vblank_count_inc;
smp_wmb();
}
/** /**
* drm_update_vblank_count - update the master vblank counter * drm_update_vblank_count - update the master vblank counter
* @dev: DRM device * @dev: DRM device
...@@ -93,7 +123,7 @@ module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); ...@@ -93,7 +123,7 @@ module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
static void drm_update_vblank_count(struct drm_device *dev, int crtc) static void drm_update_vblank_count(struct drm_device *dev, int crtc)
{ {
struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
u32 cur_vblank, diff, tslot; u32 cur_vblank, diff;
bool rc; bool rc;
struct timeval t_vblank; struct timeval t_vblank;
...@@ -129,18 +159,15 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) ...@@ -129,18 +159,15 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
if (diff == 0) if (diff == 0)
return; return;
/* Reinitialize corresponding vblank timestamp if high-precision query /*
* available. Skip this step if query unsupported or failed. Will * Only reinitialize corresponding vblank timestamp if high-precision query
* reinitialize delayed at next vblank interrupt in that case. * available and didn't fail. Otherwise reinitialize delayed at next vblank
* interrupt and assign 0 for now, to mark the vblanktimestamp as invalid.
*/ */
if (rc) { if (!rc)
tslot = atomic_read(&vblank->count) + diff; t_vblank = (struct timeval) {0, 0};
vblanktimestamp(dev, crtc, tslot) = t_vblank;
}
smp_mb__before_atomic(); store_vblank(dev, crtc, diff, &t_vblank);
atomic_add(diff, &vblank->count);
smp_mb__after_atomic();
} }
/* /*
...@@ -218,7 +245,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) ...@@ -218,7 +245,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
/* Compute time difference to stored timestamp of last vblank /* Compute time difference to stored timestamp of last vblank
* as updated by last invocation of drm_handle_vblank() in vblank irq. * as updated by last invocation of drm_handle_vblank() in vblank irq.
*/ */
vblcount = atomic_read(&vblank->count); vblcount = vblank->count;
diff_ns = timeval_to_ns(&tvblank) - diff_ns = timeval_to_ns(&tvblank) -
timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
...@@ -234,17 +261,8 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) ...@@ -234,17 +261,8 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
* available. In that case we can't account for this and just * available. In that case we can't account for this and just
* hope for the best. * hope for the best.
*/ */
if (vblrc && (abs64(diff_ns) > 1000000)) { if (vblrc && (abs64(diff_ns) > 1000000))
/* Store new timestamp in ringbuffer. */ store_vblank(dev, crtc, 1, &tvblank);
vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
/* Increment cooked vblank count. This also atomically commits
* the timestamp computed above.
*/
smp_mb__before_atomic();
atomic_inc(&vblank->count);
smp_mb__after_atomic();
}
spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
} }
...@@ -337,6 +355,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) ...@@ -337,6 +355,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
else else
DRM_INFO("No driver support for vblank timestamp query.\n"); DRM_INFO("No driver support for vblank timestamp query.\n");
/* Must have precise timestamping for reliable vblank instant disable */
if (dev->vblank_disable_immediate && !dev->driver->get_vblank_timestamp) {
dev->vblank_disable_immediate = false;
DRM_INFO("Setting vblank_disable_immediate to false because "
"get_vblank_timestamp == NULL\n");
}
dev->vblank_disable_allowed = false; dev->vblank_disable_allowed = false;
return 0; return 0;
...@@ -852,7 +877,7 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) ...@@ -852,7 +877,7 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
if (WARN_ON(crtc >= dev->num_crtcs)) if (WARN_ON(crtc >= dev->num_crtcs))
return 0; return 0;
return atomic_read(&vblank->count); return vblank->count;
} }
EXPORT_SYMBOL(drm_vblank_count); EXPORT_SYMBOL(drm_vblank_count);
...@@ -897,16 +922,17 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, ...@@ -897,16 +922,17 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
if (WARN_ON(crtc >= dev->num_crtcs)) if (WARN_ON(crtc >= dev->num_crtcs))
return 0; return 0;
/* Read timestamp from slot of _vblank_time ringbuffer /*
* that corresponds to current vblank count. Retry if * Vblank timestamps are read lockless. To ensure consistency the vblank
* count has incremented during readout. This works like * counter is rechecked and ordering is ensured using memory barriers.
* a seqlock. * This works like a seqlock. The write-side barriers are in store_vblank.
*/ */
do { do {
cur_vblank = atomic_read(&vblank->count); cur_vblank = vblank->count;
smp_rmb();
*vblanktime = vblanktimestamp(dev, crtc, cur_vblank); *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
smp_rmb(); smp_rmb();
} while (cur_vblank != atomic_read(&vblank->count)); } while (cur_vblank != vblank->count);
return cur_vblank; return cur_vblank;
} }
...@@ -1715,7 +1741,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) ...@@ -1715,7 +1741,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
*/ */
/* Get current timestamp and count. */ /* Get current timestamp and count. */
vblcount = atomic_read(&vblank->count); vblcount = vblank->count;
drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
/* Compute time difference to timestamp of last vblank */ /* Compute time difference to timestamp of last vblank */
...@@ -1731,20 +1757,11 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) ...@@ -1731,20 +1757,11 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
* e.g., due to spurious vblank interrupts. We need to * e.g., due to spurious vblank interrupts. We need to
* ignore those for accounting. * ignore those for accounting.
*/ */
if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS)
/* Store new timestamp in ringbuffer. */ store_vblank(dev, crtc, 1, &tvblank);
vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; else
/* Increment cooked vblank count. This also atomically commits
* the timestamp computed above.
*/
smp_mb__before_atomic();
atomic_inc(&vblank->count);
smp_mb__after_atomic();
} else {
DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
crtc, (int) diff_ns); crtc, (int) diff_ns);
}
spin_unlock(&dev->vblank_time_lock); spin_unlock(&dev->vblank_time_lock);
......
...@@ -80,8 +80,10 @@ int __drm_modeset_lock_all(struct drm_device *dev, ...@@ -80,8 +80,10 @@ int __drm_modeset_lock_all(struct drm_device *dev,
return -ENOMEM; return -ENOMEM;
if (trylock) { if (trylock) {
if (!mutex_trylock(&config->mutex)) if (!mutex_trylock(&config->mutex)) {
return -EBUSY; ret = -EBUSY;
goto out;
}
} else { } else {
mutex_lock(&config->mutex); mutex_lock(&config->mutex);
} }
...@@ -114,6 +116,8 @@ int __drm_modeset_lock_all(struct drm_device *dev, ...@@ -114,6 +116,8 @@ int __drm_modeset_lock_all(struct drm_device *dev,
goto retry; goto retry;
} }
out:
kfree(ctx);
return ret; return ret;
} }
EXPORT_SYMBOL(__drm_modeset_lock_all); EXPORT_SYMBOL(__drm_modeset_lock_all);
......
...@@ -323,8 +323,6 @@ static void output_poll_execute(struct work_struct *work) ...@@ -323,8 +323,6 @@ static void output_poll_execute(struct work_struct *work)
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
continue; continue;
repoll = true;
old_status = connector->status; old_status = connector->status;
/* if we are connected and don't want to poll for disconnect /* if we are connected and don't want to poll for disconnect
skip it */ skip it */
...@@ -332,6 +330,8 @@ static void output_poll_execute(struct work_struct *work) ...@@ -332,6 +330,8 @@ static void output_poll_execute(struct work_struct *work)
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
continue; continue;
repoll = true;
connector->status = connector->funcs->detect(connector, false); connector->status = connector->funcs->detect(connector, false);
if (old_status != connector->status) { if (old_status != connector->status) {
const char *old, *new; const char *old, *new;
......
...@@ -172,10 +172,6 @@ static void intel_plane_atomic_update(struct drm_plane *plane, ...@@ -172,10 +172,6 @@ static void intel_plane_atomic_update(struct drm_plane *plane,
struct intel_plane_state *intel_state = struct intel_plane_state *intel_state =
to_intel_plane_state(plane->state); to_intel_plane_state(plane->state);
/* Don't disable an already disabled plane */
if (!plane->state->fb && !old_state->fb)
return;
intel_plane->commit_plane(plane, intel_state); intel_plane->commit_plane(plane, intel_state);
} }
......
...@@ -198,7 +198,7 @@ static int qxl_pm_restore(struct device *dev) ...@@ -198,7 +198,7 @@ static int qxl_pm_restore(struct device *dev)
static u32 qxl_noop_get_vblank_counter(struct drm_device *dev, int crtc) static u32 qxl_noop_get_vblank_counter(struct drm_device *dev, int crtc)
{ {
return dev->vblank[crtc].count.counter; return 0;
} }
static int qxl_noop_enable_vblank(struct drm_device *dev, int crtc) static int qxl_noop_enable_vblank(struct drm_device *dev, int crtc)
......
...@@ -355,8 +355,7 @@ struct drm_lock_data { ...@@ -355,8 +355,7 @@ struct drm_lock_data {
* @minor: Link back to minor char device we are master for. Immutable. * @minor: Link back to minor char device we are master for. Immutable.
* @unique: Unique identifier: e.g. busid. Protected by drm_global_mutex. * @unique: Unique identifier: e.g. busid. Protected by drm_global_mutex.
* @unique_len: Length of unique field. Protected by drm_global_mutex. * @unique_len: Length of unique field. Protected by drm_global_mutex.
* @magiclist: Hash of used authentication tokens. Protected by struct_mutex. * @magic_map: Map of used authentication tokens. Protected by struct_mutex.
* @magicfree: List of used authentication tokens. Protected by struct_mutex.
* @lock: DRI lock information. * @lock: DRI lock information.
* @driver_priv: Pointer to driver-private information. * @driver_priv: Pointer to driver-private information.
*/ */
...@@ -365,8 +364,7 @@ struct drm_master { ...@@ -365,8 +364,7 @@ struct drm_master {
struct drm_minor *minor; struct drm_minor *minor;
char *unique; char *unique;
int unique_len; int unique_len;
struct drm_open_hash magiclist; struct idr magic_map;
struct list_head magicfree;
struct drm_lock_data lock; struct drm_lock_data lock;
void *driver_priv; void *driver_priv;
}; };
...@@ -686,9 +684,13 @@ struct drm_pending_vblank_event { ...@@ -686,9 +684,13 @@ struct drm_pending_vblank_event {
struct drm_vblank_crtc { struct drm_vblank_crtc {
struct drm_device *dev; /* pointer to the drm_device */ struct drm_device *dev; /* pointer to the drm_device */
wait_queue_head_t queue; /**< VBLANK wait queue */ wait_queue_head_t queue; /**< VBLANK wait queue */
struct timeval time[DRM_VBLANKTIME_RBSIZE]; /**< timestamp of current count */
struct timer_list disable_timer; /* delayed disable timer */ struct timer_list disable_timer; /* delayed disable timer */
atomic_t count; /**< number of VBLANK interrupts */
/* vblank counter, protected by dev->vblank_time_lock for writes */
unsigned long count;
/* vblank timestamps, protected by dev->vblank_time_lock for writes */
struct timeval time[DRM_VBLANKTIME_RBSIZE];
atomic_t refcount; /* number of users of vblank interruptsper crtc */ atomic_t refcount; /* number of users of vblank interruptsper crtc */
u32 last; /* protected by dev->vbl_lock, used */ u32 last; /* protected by dev->vbl_lock, used */
/* for wraparound handling */ /* for wraparound handling */
......
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