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 }