xref: /onnv-gate/usr/src/uts/common/avs/ns/nsctl/nsc_rmspin.c (revision 9093:cd587b0bd19c)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/debug.h>
287836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
297836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
307836SJohn.Forte@Sun.COM #include <sys/kmem.h>
317836SJohn.Forte@Sun.COM #include <sys/ddi.h>
327836SJohn.Forte@Sun.COM 
337836SJohn.Forte@Sun.COM #define	__NSC_GEN__
347836SJohn.Forte@Sun.COM #include "nsc_gen.h"
357836SJohn.Forte@Sun.COM #include "nsc_mem.h"
367836SJohn.Forte@Sun.COM #include "nsc_rmspin.h"
377836SJohn.Forte@Sun.COM #include "../nsctl.h"
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM 
407836SJohn.Forte@Sun.COM static kmutex_t _nsc_rmspin_slp;
417836SJohn.Forte@Sun.COM 
427836SJohn.Forte@Sun.COM nsc_rmlock_t _nsc_lock_top;
437836SJohn.Forte@Sun.COM kmutex_t _nsc_global_lock;
447836SJohn.Forte@Sun.COM int _nsc_global_lock_init;
457836SJohn.Forte@Sun.COM 
467836SJohn.Forte@Sun.COM extern nsc_mem_t *_nsc_local_mem;
477836SJohn.Forte@Sun.COM 
487836SJohn.Forte@Sun.COM /*
497836SJohn.Forte@Sun.COM  * void
507836SJohn.Forte@Sun.COM  * _nsc_init_rmlock (void)
517836SJohn.Forte@Sun.COM  *	Initialise global locks.
527836SJohn.Forte@Sun.COM  *
537836SJohn.Forte@Sun.COM  * Calling/Exit State:
547836SJohn.Forte@Sun.COM  *	Called at driver initialisation time to allocate necessary
557836SJohn.Forte@Sun.COM  *	data structures.
567836SJohn.Forte@Sun.COM  */
577836SJohn.Forte@Sun.COM void
_nsc_init_rmlock()587836SJohn.Forte@Sun.COM _nsc_init_rmlock()
597836SJohn.Forte@Sun.COM {
607836SJohn.Forte@Sun.COM 	mutex_init(&_nsc_rmspin_slp, NULL, MUTEX_DRIVER, NULL);
617836SJohn.Forte@Sun.COM 
627836SJohn.Forte@Sun.COM 	_nsc_lock_top.next = _nsc_lock_top.prev = &_nsc_lock_top;
637836SJohn.Forte@Sun.COM 
647836SJohn.Forte@Sun.COM 	mutex_init(&_nsc_global_lock, NULL, MUTEX_DRIVER, NULL);
657836SJohn.Forte@Sun.COM 	_nsc_global_lock_init = 1;
667836SJohn.Forte@Sun.COM }
677836SJohn.Forte@Sun.COM 
687836SJohn.Forte@Sun.COM 
697836SJohn.Forte@Sun.COM /*
707836SJohn.Forte@Sun.COM  * void
717836SJohn.Forte@Sun.COM  * _nsc_deinit_rmlock (void)
727836SJohn.Forte@Sun.COM  *	De-initialise global locks.
737836SJohn.Forte@Sun.COM  *
747836SJohn.Forte@Sun.COM  * Calling/Exit State:
757836SJohn.Forte@Sun.COM  *	Called at driver unload time to de-allocate
767836SJohn.Forte@Sun.COM  *	resources.
777836SJohn.Forte@Sun.COM  */
787836SJohn.Forte@Sun.COM void
_nsc_deinit_rmlock()797836SJohn.Forte@Sun.COM _nsc_deinit_rmlock()
807836SJohn.Forte@Sun.COM {
817836SJohn.Forte@Sun.COM 	_nsc_global_lock_init = 0;
827836SJohn.Forte@Sun.COM 	mutex_destroy(&_nsc_global_lock);
837836SJohn.Forte@Sun.COM 
847836SJohn.Forte@Sun.COM 	ASSERT(_nsc_lock_top.next == &_nsc_lock_top);
857836SJohn.Forte@Sun.COM 	ASSERT(_nsc_lock_top.prev == &_nsc_lock_top);
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM 	mutex_destroy(&_nsc_rmspin_slp);
887836SJohn.Forte@Sun.COM }
897836SJohn.Forte@Sun.COM 
907836SJohn.Forte@Sun.COM 
917836SJohn.Forte@Sun.COM /*
927836SJohn.Forte@Sun.COM  * int
937836SJohn.Forte@Sun.COM  * _nsc_lock_all_rm (void)
947836SJohn.Forte@Sun.COM  *	Take all global locks in address order.
957836SJohn.Forte@Sun.COM  *
967836SJohn.Forte@Sun.COM  * Calling/Exit State:
977836SJohn.Forte@Sun.COM  *	Returns 0 if _nsc_unlock_all_rm() should be called, or -1.
987836SJohn.Forte@Sun.COM  */
997836SJohn.Forte@Sun.COM int
_nsc_lock_all_rm()1007836SJohn.Forte@Sun.COM _nsc_lock_all_rm()
1017836SJohn.Forte@Sun.COM {
1027836SJohn.Forte@Sun.COM 	nsc_rmlock_t *lp;
1037836SJohn.Forte@Sun.COM 
1047836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_rmspin_slp);
1057836SJohn.Forte@Sun.COM 
1067836SJohn.Forte@Sun.COM 	for (lp = _nsc_lock_top.next; lp != &_nsc_lock_top; lp = lp->next) {
1077836SJohn.Forte@Sun.COM 		(void) nsc_rm_lock(lp);
1087836SJohn.Forte@Sun.COM 	}
1097836SJohn.Forte@Sun.COM 
1107836SJohn.Forte@Sun.COM 	return (0);
1117836SJohn.Forte@Sun.COM }
1127836SJohn.Forte@Sun.COM 
1137836SJohn.Forte@Sun.COM 
1147836SJohn.Forte@Sun.COM /*
1157836SJohn.Forte@Sun.COM  * void
1167836SJohn.Forte@Sun.COM  * _nsc_unlock_all_rm (void)
1177836SJohn.Forte@Sun.COM  *	Release all global locks in reverse address order.
1187836SJohn.Forte@Sun.COM  *
1197836SJohn.Forte@Sun.COM  * Calling/Exit State:
1207836SJohn.Forte@Sun.COM  */
1217836SJohn.Forte@Sun.COM void
_nsc_unlock_all_rm()1227836SJohn.Forte@Sun.COM _nsc_unlock_all_rm()
1237836SJohn.Forte@Sun.COM {
1247836SJohn.Forte@Sun.COM 	nsc_rmlock_t *lp;
1257836SJohn.Forte@Sun.COM 
1267836SJohn.Forte@Sun.COM 	for (lp = _nsc_lock_top.prev; lp != &_nsc_lock_top; lp = lp->prev) {
1277836SJohn.Forte@Sun.COM 		nsc_rm_unlock(lp);
1287836SJohn.Forte@Sun.COM 	}
1297836SJohn.Forte@Sun.COM 
1307836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_rmspin_slp);
1317836SJohn.Forte@Sun.COM }
1327836SJohn.Forte@Sun.COM 
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM /*
1357836SJohn.Forte@Sun.COM  * nsc_rmlock_t *
1367836SJohn.Forte@Sun.COM  * nsc_rm_lock_alloc(char *name, int flag, void *arg)
1377836SJohn.Forte@Sun.COM  *	Allocate and initialise a global lock.
1387836SJohn.Forte@Sun.COM  *
1397836SJohn.Forte@Sun.COM  * Calling/Exit State:
1407836SJohn.Forte@Sun.COM  *	The 'flag' parameter should be either KM_SLEEP or KM_NOSLEEP,
1417836SJohn.Forte@Sun.COM  *	depending on whether the caller is willing to sleep while memory
1427836SJohn.Forte@Sun.COM  *	is allocated or not.
1437836SJohn.Forte@Sun.COM  *
1447836SJohn.Forte@Sun.COM  *	The 'arg' parameter is passed directly to the underlying
1457836SJohn.Forte@Sun.COM  *	mutex_init(9f) function call.
1467836SJohn.Forte@Sun.COM  *
1477836SJohn.Forte@Sun.COM  *	Returns NULL if lock cannot be allocated.
1487836SJohn.Forte@Sun.COM  */
1497836SJohn.Forte@Sun.COM nsc_rmlock_t *
nsc_rm_lock_alloc(char * name,int flag,void * arg)1507836SJohn.Forte@Sun.COM nsc_rm_lock_alloc(char *name, int flag, void *arg)
1517836SJohn.Forte@Sun.COM {
1527836SJohn.Forte@Sun.COM 	nsc_rmlock_t *lp, *lk;
1537836SJohn.Forte@Sun.COM 
1547836SJohn.Forte@Sun.COM 	if ((lk = (nsc_rmlock_t *)nsc_kmem_zalloc(sizeof (*lk),
1557836SJohn.Forte@Sun.COM 	    flag, _nsc_local_mem)) == NULL)
1567836SJohn.Forte@Sun.COM 		return (NULL);
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM 	mutex_init(&lk->lockp, NULL, MUTEX_DRIVER, arg);
1597836SJohn.Forte@Sun.COM 
1607836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_rmspin_slp);
1617836SJohn.Forte@Sun.COM 
1627836SJohn.Forte@Sun.COM 	for (lp = _nsc_lock_top.next; lp != &_nsc_lock_top; lp = lp->next)
1637836SJohn.Forte@Sun.COM 		if (strcmp(lp->name, name) == 0)
1647836SJohn.Forte@Sun.COM 			break;
1657836SJohn.Forte@Sun.COM 
1667836SJohn.Forte@Sun.COM 	if (lp != &_nsc_lock_top) {
1677836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_rmspin_slp);
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM 		mutex_destroy(&lk->lockp);
1707836SJohn.Forte@Sun.COM 		nsc_kmem_free(lk, sizeof (*lk));
1717836SJohn.Forte@Sun.COM 
172*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nsctl: rmlock double allocation (%s)", name);
1737836SJohn.Forte@Sun.COM 		return (NULL);
1747836SJohn.Forte@Sun.COM 	}
1757836SJohn.Forte@Sun.COM 
1767836SJohn.Forte@Sun.COM 	lk->name = name;
1777836SJohn.Forte@Sun.COM 
1787836SJohn.Forte@Sun.COM 	lk->next = _nsc_lock_top.next;
1797836SJohn.Forte@Sun.COM 	lk->prev = &_nsc_lock_top;
1807836SJohn.Forte@Sun.COM 	_nsc_lock_top.next = lk;
1817836SJohn.Forte@Sun.COM 	lk->next->prev = lk;
1827836SJohn.Forte@Sun.COM 
1837836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_rmspin_slp);
1847836SJohn.Forte@Sun.COM 
1857836SJohn.Forte@Sun.COM 	return (lk);
1867836SJohn.Forte@Sun.COM }
1877836SJohn.Forte@Sun.COM 
1887836SJohn.Forte@Sun.COM 
1897836SJohn.Forte@Sun.COM /*
1907836SJohn.Forte@Sun.COM  * void
1917836SJohn.Forte@Sun.COM  * nsc_rm_lock_destroy(nsc_rmlock_t *rmlockp)
1927836SJohn.Forte@Sun.COM  *	Release the global lock.
1937836SJohn.Forte@Sun.COM  *
1947836SJohn.Forte@Sun.COM  * Remarks:
1957836SJohn.Forte@Sun.COM  *	The specified global lock is released and made
1967836SJohn.Forte@Sun.COM  *	available for reallocation.
1977836SJohn.Forte@Sun.COM  */
1987836SJohn.Forte@Sun.COM void
nsc_rm_lock_dealloc(rmlockp)1997836SJohn.Forte@Sun.COM nsc_rm_lock_dealloc(rmlockp)
2007836SJohn.Forte@Sun.COM nsc_rmlock_t *rmlockp;
2017836SJohn.Forte@Sun.COM {
2027836SJohn.Forte@Sun.COM 	if (!rmlockp)
2037836SJohn.Forte@Sun.COM 		return;
2047836SJohn.Forte@Sun.COM 
2057836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_rmspin_slp);
2067836SJohn.Forte@Sun.COM 
2077836SJohn.Forte@Sun.COM 	rmlockp->next->prev = rmlockp->prev;
2087836SJohn.Forte@Sun.COM 	rmlockp->prev->next = rmlockp->next;
2097836SJohn.Forte@Sun.COM 
2107836SJohn.Forte@Sun.COM 	if (rmlockp->child) {
211*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nsctl: rmlock destroyed when locked (%s)",
2127836SJohn.Forte@Sun.COM 		    rmlockp->name);
2137836SJohn.Forte@Sun.COM 		nsc_do_unlock(rmlockp->child);
2147836SJohn.Forte@Sun.COM 		rmlockp->child = NULL;
2157836SJohn.Forte@Sun.COM 	}
2167836SJohn.Forte@Sun.COM 
2177836SJohn.Forte@Sun.COM 	mutex_destroy(&rmlockp->lockp);
2187836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_rmspin_slp);
2197836SJohn.Forte@Sun.COM 
2207836SJohn.Forte@Sun.COM 	nsc_kmem_free(rmlockp, sizeof (*rmlockp));
2217836SJohn.Forte@Sun.COM }
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM 
2247836SJohn.Forte@Sun.COM /*
2257836SJohn.Forte@Sun.COM  * void
2267836SJohn.Forte@Sun.COM  * nsc_rm_lock(nsc_rmlock_t *rmlockp)
2277836SJohn.Forte@Sun.COM  * 	Acquire a global lock.
2287836SJohn.Forte@Sun.COM  *
2297836SJohn.Forte@Sun.COM  * Calling/Exit State:
2307836SJohn.Forte@Sun.COM  *	rmlockp is the lock to be acquired.
2317836SJohn.Forte@Sun.COM  *	Returns 0 (success) or errno. Lock is not acquired if rc != 0.
2327836SJohn.Forte@Sun.COM  */
2337836SJohn.Forte@Sun.COM int
nsc_rm_lock(nsc_rmlock_t * rmlockp)2347836SJohn.Forte@Sun.COM nsc_rm_lock(nsc_rmlock_t *rmlockp)
2357836SJohn.Forte@Sun.COM {
2367836SJohn.Forte@Sun.COM 	int rc;
2377836SJohn.Forte@Sun.COM 
2387836SJohn.Forte@Sun.COM 	mutex_enter(&rmlockp->lockp);
2397836SJohn.Forte@Sun.COM 
2407836SJohn.Forte@Sun.COM 	ASSERT(! rmlockp->child);
2417836SJohn.Forte@Sun.COM 
2427836SJohn.Forte@Sun.COM 	/* always use a write-lock */
2437836SJohn.Forte@Sun.COM 	rc = nsc_do_lock(1, &rmlockp->child);
2447836SJohn.Forte@Sun.COM 	if (rc) {
2457836SJohn.Forte@Sun.COM 		rmlockp->child = NULL;
2467836SJohn.Forte@Sun.COM 		mutex_exit(&rmlockp->lockp);
2477836SJohn.Forte@Sun.COM 	}
2487836SJohn.Forte@Sun.COM 
2497836SJohn.Forte@Sun.COM 	return (rc);
2507836SJohn.Forte@Sun.COM }
2517836SJohn.Forte@Sun.COM 
2527836SJohn.Forte@Sun.COM 
2537836SJohn.Forte@Sun.COM /*
2547836SJohn.Forte@Sun.COM  * static void
2557836SJohn.Forte@Sun.COM  * nsc_rm_unlock(nsc_rmlock_t *rmlockp)
2567836SJohn.Forte@Sun.COM  * 	Unlock a global lock.
2577836SJohn.Forte@Sun.COM  *
2587836SJohn.Forte@Sun.COM  * Calling/Exit State:
2597836SJohn.Forte@Sun.COM  *	rmlockp is the lock to be released.
2607836SJohn.Forte@Sun.COM  */
2617836SJohn.Forte@Sun.COM void
nsc_rm_unlock(nsc_rmlock_t * rmlockp)2627836SJohn.Forte@Sun.COM nsc_rm_unlock(nsc_rmlock_t *rmlockp)
2637836SJohn.Forte@Sun.COM {
2647836SJohn.Forte@Sun.COM 	if (rmlockp->child) {
2657836SJohn.Forte@Sun.COM 		ASSERT(MUTEX_HELD(&rmlockp->lockp));
2667836SJohn.Forte@Sun.COM 		nsc_do_unlock(rmlockp->child);
2677836SJohn.Forte@Sun.COM 		rmlockp->child = NULL;
2687836SJohn.Forte@Sun.COM 		mutex_exit(&rmlockp->lockp);
2697836SJohn.Forte@Sun.COM 	}
2707836SJohn.Forte@Sun.COM }
271