162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * \file drm_lock.c
362306a36Sopenharmony_ci * IOCTLs for locking
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * \author Rickard E. (Rik) Faith <faith@valinux.com>
662306a36Sopenharmony_ci * \author Gareth Hughes <gareth@valinux.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
1362306a36Sopenharmony_ci * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
1462306a36Sopenharmony_ci * All Rights Reserved.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
1762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
1862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
1962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
2162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next
2462306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
2562306a36Sopenharmony_ci * Software.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2862306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2962306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3062306a36Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
3162306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3262306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
3362306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/export.h>
3762306a36Sopenharmony_ci#include <linux/sched/signal.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <drm/drm.h>
4062306a36Sopenharmony_ci#include <drm/drm_drv.h>
4162306a36Sopenharmony_ci#include <drm/drm_file.h>
4262306a36Sopenharmony_ci#include <drm/drm_print.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include "drm_internal.h"
4562306a36Sopenharmony_ci#include "drm_legacy.h"
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * Take the heavyweight lock.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * \param lock lock pointer.
5362306a36Sopenharmony_ci * \param context locking context.
5462306a36Sopenharmony_ci * \return one if the lock is held, or zero otherwise.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cistatic
5962306a36Sopenharmony_ciint drm_lock_take(struct drm_lock_data *lock_data,
6062306a36Sopenharmony_ci		  unsigned int context)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	unsigned int old, new, prev;
6362306a36Sopenharmony_ci	volatile unsigned int *lock = &lock_data->hw_lock->lock;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	spin_lock_bh(&lock_data->spinlock);
6662306a36Sopenharmony_ci	do {
6762306a36Sopenharmony_ci		old = *lock;
6862306a36Sopenharmony_ci		if (old & _DRM_LOCK_HELD)
6962306a36Sopenharmony_ci			new = old | _DRM_LOCK_CONT;
7062306a36Sopenharmony_ci		else {
7162306a36Sopenharmony_ci			new = context | _DRM_LOCK_HELD |
7262306a36Sopenharmony_ci				((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
7362306a36Sopenharmony_ci				 _DRM_LOCK_CONT : 0);
7462306a36Sopenharmony_ci		}
7562306a36Sopenharmony_ci		prev = cmpxchg(lock, old, new);
7662306a36Sopenharmony_ci	} while (prev != old);
7762306a36Sopenharmony_ci	spin_unlock_bh(&lock_data->spinlock);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (_DRM_LOCKING_CONTEXT(old) == context) {
8062306a36Sopenharmony_ci		if (old & _DRM_LOCK_HELD) {
8162306a36Sopenharmony_ci			if (context != DRM_KERNEL_CONTEXT) {
8262306a36Sopenharmony_ci				DRM_ERROR("%d holds heavyweight lock\n",
8362306a36Sopenharmony_ci					  context);
8462306a36Sopenharmony_ci			}
8562306a36Sopenharmony_ci			return 0;
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
9062306a36Sopenharmony_ci		/* Have lock */
9162306a36Sopenharmony_ci		return 1;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	return 0;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * This takes a lock forcibly and hands it to context.	Should ONLY be used
9862306a36Sopenharmony_ci * inside *_unlock to give lock to kernel before calling *_dma_schedule.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * \param dev DRM device.
10162306a36Sopenharmony_ci * \param lock lock pointer.
10262306a36Sopenharmony_ci * \param context locking context.
10362306a36Sopenharmony_ci * \return always one.
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * Resets the lock file pointer.
10662306a36Sopenharmony_ci * Marks the lock as held by the given context, via the \p cmpxchg instruction.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic int drm_lock_transfer(struct drm_lock_data *lock_data,
10962306a36Sopenharmony_ci			     unsigned int context)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	unsigned int old, new, prev;
11262306a36Sopenharmony_ci	volatile unsigned int *lock = &lock_data->hw_lock->lock;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	lock_data->file_priv = NULL;
11562306a36Sopenharmony_ci	do {
11662306a36Sopenharmony_ci		old = *lock;
11762306a36Sopenharmony_ci		new = context | _DRM_LOCK_HELD;
11862306a36Sopenharmony_ci		prev = cmpxchg(lock, old, new);
11962306a36Sopenharmony_ci	} while (prev != old);
12062306a36Sopenharmony_ci	return 1;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int drm_legacy_lock_free(struct drm_lock_data *lock_data,
12462306a36Sopenharmony_ci				unsigned int context)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	unsigned int old, new, prev;
12762306a36Sopenharmony_ci	volatile unsigned int *lock = &lock_data->hw_lock->lock;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	spin_lock_bh(&lock_data->spinlock);
13062306a36Sopenharmony_ci	if (lock_data->kernel_waiters != 0) {
13162306a36Sopenharmony_ci		drm_lock_transfer(lock_data, 0);
13262306a36Sopenharmony_ci		lock_data->idle_has_lock = 1;
13362306a36Sopenharmony_ci		spin_unlock_bh(&lock_data->spinlock);
13462306a36Sopenharmony_ci		return 1;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	spin_unlock_bh(&lock_data->spinlock);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	do {
13962306a36Sopenharmony_ci		old = *lock;
14062306a36Sopenharmony_ci		new = _DRM_LOCKING_CONTEXT(old);
14162306a36Sopenharmony_ci		prev = cmpxchg(lock, old, new);
14262306a36Sopenharmony_ci	} while (prev != old);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
14562306a36Sopenharmony_ci		DRM_ERROR("%d freed heavyweight lock held by %d\n",
14662306a36Sopenharmony_ci			  context, _DRM_LOCKING_CONTEXT(old));
14762306a36Sopenharmony_ci		return 1;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci	wake_up_interruptible(&lock_data->lock_queue);
15062306a36Sopenharmony_ci	return 0;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/*
15462306a36Sopenharmony_ci * Lock ioctl.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * \param inode device inode.
15762306a36Sopenharmony_ci * \param file_priv DRM file private.
15862306a36Sopenharmony_ci * \param cmd command.
15962306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_lock structure.
16062306a36Sopenharmony_ci * \return zero on success or negative number on failure.
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * Add the current task to the lock wait queue, and attempt to take to lock.
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_ciint drm_legacy_lock(struct drm_device *dev, void *data,
16562306a36Sopenharmony_ci		    struct drm_file *file_priv)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	DECLARE_WAITQUEUE(entry, current);
16862306a36Sopenharmony_ci	struct drm_lock *lock = data;
16962306a36Sopenharmony_ci	struct drm_master *master = file_priv->master;
17062306a36Sopenharmony_ci	int ret = 0;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
17362306a36Sopenharmony_ci		return -EOPNOTSUPP;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	++file_priv->lock_count;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (lock->context == DRM_KERNEL_CONTEXT) {
17862306a36Sopenharmony_ci		DRM_ERROR("Process %d using kernel context %d\n",
17962306a36Sopenharmony_ci			  task_pid_nr(current), lock->context);
18062306a36Sopenharmony_ci		return -EINVAL;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
18462306a36Sopenharmony_ci		  lock->context, task_pid_nr(current),
18562306a36Sopenharmony_ci		  master->lock.hw_lock ? master->lock.hw_lock->lock : -1,
18662306a36Sopenharmony_ci		  lock->flags);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	add_wait_queue(&master->lock.lock_queue, &entry);
18962306a36Sopenharmony_ci	spin_lock_bh(&master->lock.spinlock);
19062306a36Sopenharmony_ci	master->lock.user_waiters++;
19162306a36Sopenharmony_ci	spin_unlock_bh(&master->lock.spinlock);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	for (;;) {
19462306a36Sopenharmony_ci		__set_current_state(TASK_INTERRUPTIBLE);
19562306a36Sopenharmony_ci		if (!master->lock.hw_lock) {
19662306a36Sopenharmony_ci			/* Device has been unregistered */
19762306a36Sopenharmony_ci			send_sig(SIGTERM, current, 0);
19862306a36Sopenharmony_ci			ret = -EINTR;
19962306a36Sopenharmony_ci			break;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci		if (drm_lock_take(&master->lock, lock->context)) {
20262306a36Sopenharmony_ci			master->lock.file_priv = file_priv;
20362306a36Sopenharmony_ci			master->lock.lock_time = jiffies;
20462306a36Sopenharmony_ci			break;	/* Got lock */
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		/* Contention */
20862306a36Sopenharmony_ci		mutex_unlock(&drm_global_mutex);
20962306a36Sopenharmony_ci		schedule();
21062306a36Sopenharmony_ci		mutex_lock(&drm_global_mutex);
21162306a36Sopenharmony_ci		if (signal_pending(current)) {
21262306a36Sopenharmony_ci			ret = -EINTR;
21362306a36Sopenharmony_ci			break;
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci	spin_lock_bh(&master->lock.spinlock);
21762306a36Sopenharmony_ci	master->lock.user_waiters--;
21862306a36Sopenharmony_ci	spin_unlock_bh(&master->lock.spinlock);
21962306a36Sopenharmony_ci	__set_current_state(TASK_RUNNING);
22062306a36Sopenharmony_ci	remove_wait_queue(&master->lock.lock_queue, &entry);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	DRM_DEBUG("%d %s\n", lock->context,
22362306a36Sopenharmony_ci		  ret ? "interrupted" : "has lock");
22462306a36Sopenharmony_ci	if (ret) return ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* don't set the block all signals on the master process for now
22762306a36Sopenharmony_ci	 * really probably not the correct answer but lets us debug xkb
22862306a36Sopenharmony_ci 	 * xserver for now */
22962306a36Sopenharmony_ci	if (!drm_is_current_master(file_priv)) {
23062306a36Sopenharmony_ci		dev->sigdata.context = lock->context;
23162306a36Sopenharmony_ci		dev->sigdata.lock = master->lock.hw_lock;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
23562306a36Sopenharmony_ci	{
23662306a36Sopenharmony_ci		if (dev->driver->dma_quiescent(dev)) {
23762306a36Sopenharmony_ci			DRM_DEBUG("%d waiting for DMA quiescent\n",
23862306a36Sopenharmony_ci				  lock->context);
23962306a36Sopenharmony_ci			return -EBUSY;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/*
24762306a36Sopenharmony_ci * Unlock ioctl.
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci * \param inode device inode.
25062306a36Sopenharmony_ci * \param file_priv DRM file private.
25162306a36Sopenharmony_ci * \param cmd command.
25262306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_lock structure.
25362306a36Sopenharmony_ci * \return zero on success or negative number on failure.
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * Transfer and free the lock.
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_ciint drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct drm_lock *lock = data;
26062306a36Sopenharmony_ci	struct drm_master *master = file_priv->master;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
26362306a36Sopenharmony_ci		return -EOPNOTSUPP;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (lock->context == DRM_KERNEL_CONTEXT) {
26662306a36Sopenharmony_ci		DRM_ERROR("Process %d using kernel context %d\n",
26762306a36Sopenharmony_ci			  task_pid_nr(current), lock->context);
26862306a36Sopenharmony_ci		return -EINVAL;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (drm_legacy_lock_free(&master->lock, lock->context)) {
27262306a36Sopenharmony_ci		/* FIXME: Should really bail out here. */
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/*
27962306a36Sopenharmony_ci * This function returns immediately and takes the hw lock
28062306a36Sopenharmony_ci * with the kernel context if it is free, otherwise it gets the highest priority when and if
28162306a36Sopenharmony_ci * it is eventually released.
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
28462306a36Sopenharmony_ci * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
28562306a36Sopenharmony_ci * a deadlock, which is why the "idlelock" was invented).
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * This should be sufficient to wait for GPU idle without
28862306a36Sopenharmony_ci * having to worry about starvation.
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_civoid drm_legacy_idlelock_take(struct drm_lock_data *lock_data)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	int ret;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	spin_lock_bh(&lock_data->spinlock);
29562306a36Sopenharmony_ci	lock_data->kernel_waiters++;
29662306a36Sopenharmony_ci	if (!lock_data->idle_has_lock) {
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		spin_unlock_bh(&lock_data->spinlock);
29962306a36Sopenharmony_ci		ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
30062306a36Sopenharmony_ci		spin_lock_bh(&lock_data->spinlock);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		if (ret == 1)
30362306a36Sopenharmony_ci			lock_data->idle_has_lock = 1;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci	spin_unlock_bh(&lock_data->spinlock);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_legacy_idlelock_take);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_civoid drm_legacy_idlelock_release(struct drm_lock_data *lock_data)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	unsigned int old, prev;
31262306a36Sopenharmony_ci	volatile unsigned int *lock = &lock_data->hw_lock->lock;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	spin_lock_bh(&lock_data->spinlock);
31562306a36Sopenharmony_ci	if (--lock_data->kernel_waiters == 0) {
31662306a36Sopenharmony_ci		if (lock_data->idle_has_lock) {
31762306a36Sopenharmony_ci			do {
31862306a36Sopenharmony_ci				old = *lock;
31962306a36Sopenharmony_ci				prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
32062306a36Sopenharmony_ci			} while (prev != old);
32162306a36Sopenharmony_ci			wake_up_interruptible(&lock_data->lock_queue);
32262306a36Sopenharmony_ci			lock_data->idle_has_lock = 0;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci	spin_unlock_bh(&lock_data->spinlock);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_legacy_idlelock_release);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int drm_legacy_i_have_hw_lock(struct drm_device *dev,
33062306a36Sopenharmony_ci				     struct drm_file *file_priv)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct drm_master *master = file_priv->master;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	return (file_priv->lock_count && master->lock.hw_lock &&
33562306a36Sopenharmony_ci		_DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
33662306a36Sopenharmony_ci		master->lock.file_priv == file_priv);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_civoid drm_legacy_lock_release(struct drm_device *dev, struct file *filp)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct drm_file *file_priv = filp->private_data;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* if the master has gone away we can't do anything with the lock */
34462306a36Sopenharmony_ci	if (!dev->master)
34562306a36Sopenharmony_ci		return;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (drm_legacy_i_have_hw_lock(dev, file_priv)) {
34862306a36Sopenharmony_ci		DRM_DEBUG("File %p released, freeing lock for context %d\n",
34962306a36Sopenharmony_ci			  filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
35062306a36Sopenharmony_ci		drm_legacy_lock_free(&file_priv->master->lock,
35162306a36Sopenharmony_ci				     _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
35862306a36Sopenharmony_ci		return;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/*
36162306a36Sopenharmony_ci	 * Since the master is disappearing, so is the
36262306a36Sopenharmony_ci	 * possibility to lock.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	mutex_lock(&dev->struct_mutex);
36562306a36Sopenharmony_ci	if (master->lock.hw_lock) {
36662306a36Sopenharmony_ci		if (dev->sigdata.lock == master->lock.hw_lock)
36762306a36Sopenharmony_ci			dev->sigdata.lock = NULL;
36862306a36Sopenharmony_ci		master->lock.hw_lock = NULL;
36962306a36Sopenharmony_ci		master->lock.file_priv = NULL;
37062306a36Sopenharmony_ci		wake_up_interruptible_all(&master->lock.lock_queue);
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci	mutex_unlock(&dev->struct_mutex);
37362306a36Sopenharmony_ci}
374