xref: /titanic_51/usr/src/uts/common/avs/ns/nsctl/nsc_rmspin.c (revision 3270659f55e0928d6edec3d26217cc29398a8149)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/debug.h>
28 #include <sys/ksynch.h>
29 #include <sys/cmn_err.h>
30 #include <sys/kmem.h>
31 #include <sys/ddi.h>
32 
33 #define	__NSC_GEN__
34 #include "nsc_gen.h"
35 #include "nsc_mem.h"
36 #include "nsc_rmspin.h"
37 #include "../nsctl.h"
38 
39 
40 static kmutex_t _nsc_rmspin_slp;
41 
42 nsc_rmlock_t _nsc_lock_top;
43 kmutex_t _nsc_global_lock;
44 int _nsc_global_lock_init;
45 
46 extern nsc_mem_t *_nsc_local_mem;
47 
48 /*
49  * void
50  * _nsc_init_rmlock (void)
51  *	Initialise global locks.
52  *
53  * Calling/Exit State:
54  *	Called at driver initialisation time to allocate necessary
55  *	data structures.
56  */
57 void
58 _nsc_init_rmlock()
59 {
60 	mutex_init(&_nsc_rmspin_slp, NULL, MUTEX_DRIVER, NULL);
61 
62 	_nsc_lock_top.next = _nsc_lock_top.prev = &_nsc_lock_top;
63 
64 	mutex_init(&_nsc_global_lock, NULL, MUTEX_DRIVER, NULL);
65 	_nsc_global_lock_init = 1;
66 }
67 
68 
69 /*
70  * void
71  * _nsc_deinit_rmlock (void)
72  *	De-initialise global locks.
73  *
74  * Calling/Exit State:
75  *	Called at driver unload time to de-allocate
76  *	resources.
77  */
78 void
79 _nsc_deinit_rmlock()
80 {
81 	_nsc_global_lock_init = 0;
82 	mutex_destroy(&_nsc_global_lock);
83 
84 	ASSERT(_nsc_lock_top.next == &_nsc_lock_top);
85 	ASSERT(_nsc_lock_top.prev == &_nsc_lock_top);
86 
87 	mutex_destroy(&_nsc_rmspin_slp);
88 }
89 
90 
91 /*
92  * int
93  * _nsc_lock_all_rm (void)
94  *	Take all global locks in address order.
95  *
96  * Calling/Exit State:
97  *	Returns 0 if _nsc_unlock_all_rm() should be called, or -1.
98  */
99 int
100 _nsc_lock_all_rm()
101 {
102 	nsc_rmlock_t *lp;
103 
104 	mutex_enter(&_nsc_rmspin_slp);
105 
106 	for (lp = _nsc_lock_top.next; lp != &_nsc_lock_top; lp = lp->next) {
107 		(void) nsc_rm_lock(lp);
108 	}
109 
110 	return (0);
111 }
112 
113 
114 /*
115  * void
116  * _nsc_unlock_all_rm (void)
117  *	Release all global locks in reverse address order.
118  *
119  * Calling/Exit State:
120  */
121 void
122 _nsc_unlock_all_rm()
123 {
124 	nsc_rmlock_t *lp;
125 
126 	for (lp = _nsc_lock_top.prev; lp != &_nsc_lock_top; lp = lp->prev) {
127 		nsc_rm_unlock(lp);
128 	}
129 
130 	mutex_exit(&_nsc_rmspin_slp);
131 }
132 
133 
134 /*
135  * nsc_rmlock_t *
136  * nsc_rm_lock_alloc(char *name, int flag, void *arg)
137  *	Allocate and initialise a global lock.
138  *
139  * Calling/Exit State:
140  *	The 'flag' parameter should be either KM_SLEEP or KM_NOSLEEP,
141  *	depending on whether the caller is willing to sleep while memory
142  *	is allocated or not.
143  *
144  *	The 'arg' parameter is passed directly to the underlying
145  *	mutex_init(9f) function call.
146  *
147  *	Returns NULL if lock cannot be allocated.
148  */
149 nsc_rmlock_t *
150 nsc_rm_lock_alloc(char *name, int flag, void *arg)
151 {
152 	nsc_rmlock_t *lp, *lk;
153 
154 	if ((lk = (nsc_rmlock_t *)nsc_kmem_zalloc(sizeof (*lk),
155 	    flag, _nsc_local_mem)) == NULL)
156 		return (NULL);
157 
158 	mutex_init(&lk->lockp, NULL, MUTEX_DRIVER, arg);
159 
160 	mutex_enter(&_nsc_rmspin_slp);
161 
162 	for (lp = _nsc_lock_top.next; lp != &_nsc_lock_top; lp = lp->next)
163 		if (strcmp(lp->name, name) == 0)
164 			break;
165 
166 	if (lp != &_nsc_lock_top) {
167 		mutex_exit(&_nsc_rmspin_slp);
168 
169 		mutex_destroy(&lk->lockp);
170 		nsc_kmem_free(lk, sizeof (*lk));
171 
172 		cmn_err(CE_WARN, "!nsctl: rmlock double allocation (%s)", name);
173 		return (NULL);
174 	}
175 
176 	lk->name = name;
177 
178 	lk->next = _nsc_lock_top.next;
179 	lk->prev = &_nsc_lock_top;
180 	_nsc_lock_top.next = lk;
181 	lk->next->prev = lk;
182 
183 	mutex_exit(&_nsc_rmspin_slp);
184 
185 	return (lk);
186 }
187 
188 
189 /*
190  * void
191  * nsc_rm_lock_destroy(nsc_rmlock_t *rmlockp)
192  *	Release the global lock.
193  *
194  * Remarks:
195  *	The specified global lock is released and made
196  *	available for reallocation.
197  */
198 void
199 nsc_rm_lock_dealloc(rmlockp)
200 nsc_rmlock_t *rmlockp;
201 {
202 	if (!rmlockp)
203 		return;
204 
205 	mutex_enter(&_nsc_rmspin_slp);
206 
207 	rmlockp->next->prev = rmlockp->prev;
208 	rmlockp->prev->next = rmlockp->next;
209 
210 	if (rmlockp->child) {
211 		cmn_err(CE_WARN, "!nsctl: rmlock destroyed when locked (%s)",
212 		    rmlockp->name);
213 		nsc_do_unlock(rmlockp->child);
214 		rmlockp->child = NULL;
215 	}
216 
217 	mutex_destroy(&rmlockp->lockp);
218 	mutex_exit(&_nsc_rmspin_slp);
219 
220 	nsc_kmem_free(rmlockp, sizeof (*rmlockp));
221 }
222 
223 
224 /*
225  * void
226  * nsc_rm_lock(nsc_rmlock_t *rmlockp)
227  * 	Acquire a global lock.
228  *
229  * Calling/Exit State:
230  *	rmlockp is the lock to be acquired.
231  *	Returns 0 (success) or errno. Lock is not acquired if rc != 0.
232  */
233 int
234 nsc_rm_lock(nsc_rmlock_t *rmlockp)
235 {
236 	int rc;
237 
238 	mutex_enter(&rmlockp->lockp);
239 
240 	ASSERT(! rmlockp->child);
241 
242 	/* always use a write-lock */
243 	rc = nsc_do_lock(1, &rmlockp->child);
244 	if (rc) {
245 		rmlockp->child = NULL;
246 		mutex_exit(&rmlockp->lockp);
247 	}
248 
249 	return (rc);
250 }
251 
252 
253 /*
254  * static void
255  * nsc_rm_unlock(nsc_rmlock_t *rmlockp)
256  * 	Unlock a global lock.
257  *
258  * Calling/Exit State:
259  *	rmlockp is the lock to be released.
260  */
261 void
262 nsc_rm_unlock(nsc_rmlock_t *rmlockp)
263 {
264 	if (rmlockp->child) {
265 		ASSERT(MUTEX_HELD(&rmlockp->lockp));
266 		nsc_do_unlock(rmlockp->child);
267 		rmlockp->child = NULL;
268 		mutex_exit(&rmlockp->lockp);
269 	}
270 }
271