160405de4Skz151634 /*
2d0231070Smiao chen - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
360405de4Skz151634 * Use is subject to license terms.
460405de4Skz151634 */
560405de4Skz151634
660405de4Skz151634 /*
760405de4Skz151634 * lock.c -- IOCTLs for locking -*- linux-c -*-
860405de4Skz151634 * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
960405de4Skz151634 */
1060405de4Skz151634 /*
1160405de4Skz151634 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
1260405de4Skz151634 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
1360405de4Skz151634 * All Rights Reserved.
1460405de4Skz151634 *
1560405de4Skz151634 * Permission is hereby granted, free of charge, to any person obtaining a
1660405de4Skz151634 * copy of this software and associated documentation files (the "Software"),
1760405de4Skz151634 * to deal in the Software without restriction, including without limitation
1860405de4Skz151634 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1960405de4Skz151634 * and/or sell copies of the Software, and to permit persons to whom the
2060405de4Skz151634 * Software is furnished to do so, subject to the following conditions:
2160405de4Skz151634 *
2260405de4Skz151634 * The above copyright notice and this permission notice (including the next
2360405de4Skz151634 * paragraph) shall be included in all copies or substantial portions of the
2460405de4Skz151634 * Software.
2560405de4Skz151634 *
2660405de4Skz151634 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2760405de4Skz151634 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2860405de4Skz151634 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2960405de4Skz151634 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
3060405de4Skz151634 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3160405de4Skz151634 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
3260405de4Skz151634 * OTHER DEALINGS IN THE SOFTWARE.
3360405de4Skz151634 *
3460405de4Skz151634 * Authors:
3560405de4Skz151634 * Rickard E. (Rik) Faith <faith@valinux.com>
3660405de4Skz151634 * Gareth Hughes <gareth@valinux.com>
3760405de4Skz151634 *
3860405de4Skz151634 */
3960405de4Skz151634
4060405de4Skz151634 #include "drmP.h"
4160405de4Skz151634
4260405de4Skz151634 int
drm_lock_take(drm_lock_data_t * lock_data,unsigned int context)43d0538f66Scg149915 drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
4460405de4Skz151634 {
45d0231070Smiao chen - Sun Microsystems - Beijing China unsigned int old, new;
46d0538f66Scg149915 volatile unsigned int *lock = &lock_data->hw_lock->lock;
4760405de4Skz151634
4860405de4Skz151634 do {
4960405de4Skz151634 old = *lock;
50d0538f66Scg149915 if (old & _DRM_LOCK_HELD)
51d0538f66Scg149915 new = old | _DRM_LOCK_CONT;
52d0538f66Scg149915 else
53d0538f66Scg149915 new = context | _DRM_LOCK_HELD;
54d0231070Smiao chen - Sun Microsystems - Beijing China } while (!atomic_cmpset_int(lock, old, new));
5560405de4Skz151634
5660405de4Skz151634 if (_DRM_LOCKING_CONTEXT(old) == context) {
5760405de4Skz151634 if (old & _DRM_LOCK_HELD) {
5860405de4Skz151634 if (context != DRM_KERNEL_CONTEXT) {
5960405de4Skz151634 DRM_ERROR("%d holds heavyweight lock\n",
6060405de4Skz151634 context);
6160405de4Skz151634 }
6260405de4Skz151634 return (0);
6360405de4Skz151634 }
6460405de4Skz151634 }
65d0231070Smiao chen - Sun Microsystems - Beijing China if (new == (context | _DRM_LOCK_HELD)) {
6660405de4Skz151634 /* Have lock */
6760405de4Skz151634 return (1);
6860405de4Skz151634 }
6960405de4Skz151634 return (0);
7060405de4Skz151634 }
7160405de4Skz151634
7260405de4Skz151634 /*
7360405de4Skz151634 * This takes a lock forcibly and hands it to context. Should ONLY be used
7460405de4Skz151634 * inside *_unlock to give lock to kernel before calling *_dma_schedule.
7560405de4Skz151634 */
7660405de4Skz151634 int
drm_lock_transfer(drm_device_t * dev,drm_lock_data_t * lock_data,unsigned int context)77d0231070Smiao chen - Sun Microsystems - Beijing China drm_lock_transfer(drm_device_t *dev, drm_lock_data_t *lock_data,
7860405de4Skz151634 unsigned int context)
7960405de4Skz151634 {
80d0231070Smiao chen - Sun Microsystems - Beijing China unsigned int old, new;
81d0231070Smiao chen - Sun Microsystems - Beijing China volatile unsigned int *lock = &lock_data->hw_lock->lock;
8260405de4Skz151634
8360405de4Skz151634 dev->lock.filp = NULL;
8460405de4Skz151634 do {
8560405de4Skz151634 old = *lock;
8660405de4Skz151634 new = context | _DRM_LOCK_HELD;
87d0231070Smiao chen - Sun Microsystems - Beijing China } while (!atomic_cmpset_int(lock, old, new));
8860405de4Skz151634
8960405de4Skz151634 return (1);
9060405de4Skz151634 }
9160405de4Skz151634
9260405de4Skz151634 int
drm_lock_free(drm_device_t * dev,volatile unsigned int * lock,unsigned int context)93d0538f66Scg149915 drm_lock_free(drm_device_t *dev, volatile unsigned int *lock,
9460405de4Skz151634 unsigned int context)
9560405de4Skz151634 {
96d0231070Smiao chen - Sun Microsystems - Beijing China unsigned int old, new;
9760405de4Skz151634
9860405de4Skz151634 mutex_enter(&(dev->lock.lock_mutex));
9960405de4Skz151634 dev->lock.filp = NULL;
10060405de4Skz151634 do {
10160405de4Skz151634 old = *lock;
10260405de4Skz151634 new = 0;
103d0231070Smiao chen - Sun Microsystems - Beijing China } while (!atomic_cmpset_int(lock, old, new));
10460405de4Skz151634
105d0538f66Scg149915 if (_DRM_LOCK_IS_HELD(old) &&
106d0538f66Scg149915 (_DRM_LOCKING_CONTEXT(old) != context)) {
10760405de4Skz151634 DRM_ERROR("%d freed heavyweight lock held by %d\n",
10860405de4Skz151634 context, _DRM_LOCKING_CONTEXT(old));
109d0538f66Scg149915 mutex_exit(&(dev->lock.lock_mutex));
11060405de4Skz151634 return (1);
11160405de4Skz151634 }
11260405de4Skz151634 cv_broadcast(&(dev->lock.lock_cv));
11360405de4Skz151634 mutex_exit(&(dev->lock.lock_mutex));
11460405de4Skz151634 return (0);
11560405de4Skz151634 }
11660405de4Skz151634
11760405de4Skz151634 /*ARGSUSED*/
11860405de4Skz151634 int
drm_lock(DRM_IOCTL_ARGS)11960405de4Skz151634 drm_lock(DRM_IOCTL_ARGS)
12060405de4Skz151634 {
12160405de4Skz151634 DRM_DEVICE;
12260405de4Skz151634 drm_lock_t lock;
12360405de4Skz151634 int ret = 0;
12460405de4Skz151634
125d0538f66Scg149915 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
12660405de4Skz151634
12760405de4Skz151634 if (lock.context == DRM_KERNEL_CONTEXT) {
128d0231070Smiao chen - Sun Microsystems - Beijing China DRM_ERROR("Process %d using kernel context %d\n",
129d0231070Smiao chen - Sun Microsystems - Beijing China DRM_CURRENTPID, lock.context);
130d0538f66Scg149915 return (EINVAL);
13160405de4Skz151634 }
13260405de4Skz151634
133d0231070Smiao chen - Sun Microsystems - Beijing China DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
134d0231070Smiao chen - Sun Microsystems - Beijing China lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
135d0231070Smiao chen - Sun Microsystems - Beijing China lock.flags);
136d0538f66Scg149915 if (dev->driver->use_dma_queue && lock.context < 0)
137d0538f66Scg149915 return (EINVAL);
13860405de4Skz151634
13960405de4Skz151634 mutex_enter(&(dev->lock.lock_mutex));
14060405de4Skz151634 for (;;) {
141d0538f66Scg149915 if (drm_lock_take(&dev->lock, lock.context)) {
142d0538f66Scg149915 dev->lock.filp = fpriv;
143*d3d50737SRafael Vanoni dev->lock.lock_time = ddi_get_lbolt();
14460405de4Skz151634 break; /* Got lock */
14560405de4Skz151634 }
14660405de4Skz151634 ret = cv_wait_sig(&(dev->lock.lock_cv),
14760405de4Skz151634 &(dev->lock.lock_mutex));
14860405de4Skz151634
14960405de4Skz151634 if (ret == 0) {
15060405de4Skz151634 mutex_exit(&(dev->lock.lock_mutex));
151d0538f66Scg149915 return (EINTR);
15260405de4Skz151634 }
15360405de4Skz151634 }
15460405de4Skz151634 mutex_exit(&(dev->lock.lock_mutex));
155d0231070Smiao chen - Sun Microsystems - Beijing China DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
15660405de4Skz151634
157d0538f66Scg149915 if (dev->driver->dma_quiescent != NULL &&
15860405de4Skz151634 (lock.flags & _DRM_LOCK_QUIESCENT))
159d0538f66Scg149915 dev->driver->dma_quiescent(dev);
16060405de4Skz151634
16160405de4Skz151634 return (0);
16260405de4Skz151634 }
16360405de4Skz151634
16460405de4Skz151634 /*ARGSUSED*/
16560405de4Skz151634 int
drm_unlock(DRM_IOCTL_ARGS)16660405de4Skz151634 drm_unlock(DRM_IOCTL_ARGS)
16760405de4Skz151634 {
16860405de4Skz151634 DRM_DEVICE;
16960405de4Skz151634 drm_lock_t lock;
17060405de4Skz151634
171d0538f66Scg149915 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
17260405de4Skz151634
173d0231070Smiao chen - Sun Microsystems - Beijing China DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
174d0231070Smiao chen - Sun Microsystems - Beijing China lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
175d0231070Smiao chen - Sun Microsystems - Beijing China lock.flags);
176d0231070Smiao chen - Sun Microsystems - Beijing China
17760405de4Skz151634 if (lock.context == DRM_KERNEL_CONTEXT) {
17860405de4Skz151634 DRM_ERROR("Process %d using kernel context %d\n",
17960405de4Skz151634 DRM_CURRENTPID, lock.context);
180d0538f66Scg149915 return (EINVAL);
18160405de4Skz151634 }
18260405de4Skz151634 atomic_inc_32(&dev->counts[_DRM_STAT_UNLOCKS]);
18360405de4Skz151634
18460405de4Skz151634 DRM_LOCK();
185d0538f66Scg149915 if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) {
18660405de4Skz151634 DRM_ERROR("drm_unlock\n");
18760405de4Skz151634 }
18860405de4Skz151634 DRM_UNLOCK();
18960405de4Skz151634 return (0);
19060405de4Skz151634 }
191