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
This commit is contained in:
@ -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 @@ retry:
|
|||||||
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:
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
/**
|
|
||||||
* \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 @@
|
|||||||
* 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 @@
|
|||||||
#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.
|
* 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 magic magic number.
|
* client did not have a magic assigned, yet, a new one is registered. The magic
|
||||||
|
* is stored in the passed drm_auth object.
|
||||||
*
|
*
|
||||||
* Searches in drm_device::magiclist within all files with the same hash key
|
* Returns: 0 on success, negative error code on failure.
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* \param dev DRM device.
|
|
||||||
* \param priv file private data.
|
|
||||||
* \param magic magic number.
|
|
||||||
*
|
|
||||||
* Creates a drm_magic_entry structure and appends to the linked list
|
|
||||||
* 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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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, ...)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
r_list = NULL;
|
r_list = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (master->unique) {
|
|
||||||
kfree(master->unique);
|
|
||||||
master->unique = NULL;
|
|
||||||
master->unique_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
drm_ht_remove(&master->magiclist);
|
|
||||||
|
|
||||||
mutex_unlock(&dev->struct_mutex);
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
|
||||||
|
idr_destroy(&master->magic_map);
|
||||||
|
kfree(master->unique);
|
||||||
kfree(master);
|
kfree(master);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|||||||
(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,
|
|||||||
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);
|
|||||||
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);
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* 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)
|
|||||||
* 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,
|
|||||||
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 @@ fail:
|
|||||||
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)
|
|||||||
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)
|
|||||||
!(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,
|
|||||||
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)
|
|||||||
|
|
||||||
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 {
|
|||||||
* @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 {
|
|||||||
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 {
|
|||||||
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 */
|
||||||
|
Reference in New Issue
Block a user