blob: 6930a47e0317a5818d935946e8bb8e3dd8d9196d [file] [log] [blame]
kz15163460405de2006-09-28 01:41:18 -07001/*
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +08002 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
kz15163460405de2006-09-28 01:41:18 -07003 * Use is subject to license terms.
4 */
5
6/*
7 * lock.c -- IOCTLs for locking -*- linux-c -*-
8 * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
9 */
10/*
11 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13 * All Rights Reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 * OTHER DEALINGS IN THE SOFTWARE.
33 *
34 * Authors:
35 * Rickard E. (Rik) Faith <faith@valinux.com>
36 * Gareth Hughes <gareth@valinux.com>
37 *
38 */
39
kz15163460405de2006-09-28 01:41:18 -070040#include "drmP.h"
41
42int
cg149915d0538f62008-01-09 19:45:15 -080043drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
kz15163460405de2006-09-28 01:41:18 -070044{
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080045 unsigned int old, new;
cg149915d0538f62008-01-09 19:45:15 -080046 volatile unsigned int *lock = &lock_data->hw_lock->lock;
kz15163460405de2006-09-28 01:41:18 -070047
48 do {
49 old = *lock;
cg149915d0538f62008-01-09 19:45:15 -080050 if (old & _DRM_LOCK_HELD)
51 new = old | _DRM_LOCK_CONT;
52 else
53 new = context | _DRM_LOCK_HELD;
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080054 } while (!atomic_cmpset_int(lock, old, new));
kz15163460405de2006-09-28 01:41:18 -070055
56 if (_DRM_LOCKING_CONTEXT(old) == context) {
57 if (old & _DRM_LOCK_HELD) {
58 if (context != DRM_KERNEL_CONTEXT) {
59 DRM_ERROR("%d holds heavyweight lock\n",
60 context);
61 }
62 return (0);
63 }
64 }
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080065 if (new == (context | _DRM_LOCK_HELD)) {
66 /* Have lock */
kz15163460405de2006-09-28 01:41:18 -070067 return (1);
68 }
69 return (0);
70}
71
72/*
73 * This takes a lock forcibly and hands it to context. Should ONLY be used
74 * inside *_unlock to give lock to kernel before calling *_dma_schedule.
75 */
76int
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080077drm_lock_transfer(drm_device_t *dev, drm_lock_data_t *lock_data,
78 unsigned int context)
kz15163460405de2006-09-28 01:41:18 -070079{
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080080 unsigned int old, new;
81 volatile unsigned int *lock = &lock_data->hw_lock->lock;
kz15163460405de2006-09-28 01:41:18 -070082
83 dev->lock.filp = NULL;
84 do {
85 old = *lock;
86 new = context | _DRM_LOCK_HELD;
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080087 } while (!atomic_cmpset_int(lock, old, new));
kz15163460405de2006-09-28 01:41:18 -070088
89 return (1);
90}
91
92int
cg149915d0538f62008-01-09 19:45:15 -080093drm_lock_free(drm_device_t *dev, volatile unsigned int *lock,
kz15163460405de2006-09-28 01:41:18 -070094 unsigned int context)
95{
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +080096 unsigned int old, new;
kz15163460405de2006-09-28 01:41:18 -070097
98 mutex_enter(&(dev->lock.lock_mutex));
99 dev->lock.filp = NULL;
100 do {
101 old = *lock;
cg149915d0538f62008-01-09 19:45:15 -0800102 new = 0;
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +0800103 } while (!atomic_cmpset_int(lock, old, new));
kz15163460405de2006-09-28 01:41:18 -0700104
cg149915d0538f62008-01-09 19:45:15 -0800105 if (_DRM_LOCK_IS_HELD(old) &&
106 (_DRM_LOCKING_CONTEXT(old) != context)) {
kz15163460405de2006-09-28 01:41:18 -0700107 DRM_ERROR("%d freed heavyweight lock held by %d\n",
108 context, _DRM_LOCKING_CONTEXT(old));
cg149915d0538f62008-01-09 19:45:15 -0800109 mutex_exit(&(dev->lock.lock_mutex));
kz15163460405de2006-09-28 01:41:18 -0700110 return (1);
111 }
112 cv_broadcast(&(dev->lock.lock_cv));
113 mutex_exit(&(dev->lock.lock_mutex));
114 return (0);
115}
116
117/*ARGSUSED*/
118int
119drm_lock(DRM_IOCTL_ARGS)
120{
121 DRM_DEVICE;
122 drm_lock_t lock;
123 int ret = 0;
124
cg149915d0538f62008-01-09 19:45:15 -0800125 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
kz15163460405de2006-09-28 01:41:18 -0700126
127 if (lock.context == DRM_KERNEL_CONTEXT) {
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +0800128 DRM_ERROR("Process %d using kernel context %d\n",
129 DRM_CURRENTPID, lock.context);
cg149915d0538f62008-01-09 19:45:15 -0800130 return (EINVAL);
kz15163460405de2006-09-28 01:41:18 -0700131 }
132
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +0800133 DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
134 lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
135 lock.flags);
cg149915d0538f62008-01-09 19:45:15 -0800136 if (dev->driver->use_dma_queue && lock.context < 0)
137 return (EINVAL);
kz15163460405de2006-09-28 01:41:18 -0700138
139 mutex_enter(&(dev->lock.lock_mutex));
kz15163460405de2006-09-28 01:41:18 -0700140 for (;;) {
cg149915d0538f62008-01-09 19:45:15 -0800141 if (drm_lock_take(&dev->lock, lock.context)) {
142 dev->lock.filp = fpriv;
Rafael Vanonid3d50732009-11-13 01:32:32 -0800143 dev->lock.lock_time = ddi_get_lbolt();
kz15163460405de2006-09-28 01:41:18 -0700144 break; /* Got lock */
145 }
kz15163460405de2006-09-28 01:41:18 -0700146 ret = cv_wait_sig(&(dev->lock.lock_cv),
147 &(dev->lock.lock_mutex));
148
149 if (ret == 0) {
150 mutex_exit(&(dev->lock.lock_mutex));
cg149915d0538f62008-01-09 19:45:15 -0800151 return (EINTR);
kz15163460405de2006-09-28 01:41:18 -0700152 }
153 }
kz15163460405de2006-09-28 01:41:18 -0700154 mutex_exit(&(dev->lock.lock_mutex));
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +0800155 DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
kz15163460405de2006-09-28 01:41:18 -0700156
cg149915d0538f62008-01-09 19:45:15 -0800157 if (dev->driver->dma_quiescent != NULL &&
kz15163460405de2006-09-28 01:41:18 -0700158 (lock.flags & _DRM_LOCK_QUIESCENT))
cg149915d0538f62008-01-09 19:45:15 -0800159 dev->driver->dma_quiescent(dev);
kz15163460405de2006-09-28 01:41:18 -0700160
161 return (0);
162}
163
164/*ARGSUSED*/
165int
166drm_unlock(DRM_IOCTL_ARGS)
167{
168 DRM_DEVICE;
169 drm_lock_t lock;
170
cg149915d0538f62008-01-09 19:45:15 -0800171 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
kz15163460405de2006-09-28 01:41:18 -0700172
miao chen - Sun Microsystems - Beijing Chinad0231072009-02-17 16:22:10 +0800173 DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
174 lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
175 lock.flags);
176
kz15163460405de2006-09-28 01:41:18 -0700177 if (lock.context == DRM_KERNEL_CONTEXT) {
178 DRM_ERROR("Process %d using kernel context %d\n",
179 DRM_CURRENTPID, lock.context);
cg149915d0538f62008-01-09 19:45:15 -0800180 return (EINVAL);
kz15163460405de2006-09-28 01:41:18 -0700181 }
kz15163460405de2006-09-28 01:41:18 -0700182 atomic_inc_32(&dev->counts[_DRM_STAT_UNLOCKS]);
183
184 DRM_LOCK();
cg149915d0538f62008-01-09 19:45:15 -0800185 if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) {
kz15163460405de2006-09-28 01:41:18 -0700186 DRM_ERROR("drm_unlock\n");
187 }
188 DRM_UNLOCK();
kz15163460405de2006-09-28 01:41:18 -0700189 return (0);
190}