xref: /onnv-gate/usr/src/uts/common/avs/ns/nsctl/nsc_mem.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/cmn_err.h>
287836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
297836SJohn.Forte@Sun.COM #include <sys/kmem.h>
307836SJohn.Forte@Sun.COM #include <sys/map.h>
317836SJohn.Forte@Sun.COM #include <sys/errno.h>
327836SJohn.Forte@Sun.COM #include <sys/ddi.h>
337836SJohn.Forte@Sun.COM 
347836SJohn.Forte@Sun.COM 
357836SJohn.Forte@Sun.COM #define	__NSC_GEN__
367836SJohn.Forte@Sun.COM #include "nsc_dev.h"
377836SJohn.Forte@Sun.COM #include "nsc_gen.h"
387836SJohn.Forte@Sun.COM #include "nsc_mem.h"
397836SJohn.Forte@Sun.COM #include "../nsctl.h"
407836SJohn.Forte@Sun.COM #ifdef DS_DDICT
417836SJohn.Forte@Sun.COM #include "../contract.h"
427836SJohn.Forte@Sun.COM #endif
437836SJohn.Forte@Sun.COM 
447836SJohn.Forte@Sun.COM 
457836SJohn.Forte@Sun.COM static size_t _nsc_rm_size;
467836SJohn.Forte@Sun.COM caddr_t _nsc_rm_base;
477836SJohn.Forte@Sun.COM caddr_t _nsc_rm_nvmem_base;
487836SJohn.Forte@Sun.COM size_t	_nsc_rmhdr_size;
497836SJohn.Forte@Sun.COM 
507836SJohn.Forte@Sun.COM static kmutex_t _nsc_mem_lock;
517836SJohn.Forte@Sun.COM static nsc_mem_t *_nsc_anon_mem;
527836SJohn.Forte@Sun.COM static nsc_mem_t *_nsc_rmhdr_mem;
537836SJohn.Forte@Sun.COM 
547836SJohn.Forte@Sun.COM nsc_mem_t *_nsc_mem_top;
557836SJohn.Forte@Sun.COM 
567836SJohn.Forte@Sun.COM nsc_rmhdr_t *_nsc_rmhdr_ptr;
577836SJohn.Forte@Sun.COM nsc_rmmap_t *_nsc_global_map;
587836SJohn.Forte@Sun.COM nsc_mem_t *_nsc_local_mem;
597836SJohn.Forte@Sun.COM 
607836SJohn.Forte@Sun.COM static void *_nsc_mem_alloc(size_t *, int, nsc_mem_t *);
617836SJohn.Forte@Sun.COM static void *_nsc_rm_alloc(size_t *, nsc_mem_t *);
627836SJohn.Forte@Sun.COM static int _nsc_mem_free(void *, size_t);
637836SJohn.Forte@Sun.COM static int _nsc_rm_free(void *, size_t);
647836SJohn.Forte@Sun.COM static size_t _nsc_rm_avail(nsc_mem_t *);
657836SJohn.Forte@Sun.COM 
667836SJohn.Forte@Sun.COM extern void nscsetup(void);
677836SJohn.Forte@Sun.COM extern void _nsc_mark_pages(caddr_t, size_t, int);
687836SJohn.Forte@Sun.COM extern int  _nsc_lock_all_rm(void);
697836SJohn.Forte@Sun.COM extern void _nsc_unlock_all_rm(void);
707836SJohn.Forte@Sun.COM extern void _nsc_set_max_devices(int);
717836SJohn.Forte@Sun.COM 
727836SJohn.Forte@Sun.COM /*
737836SJohn.Forte@Sun.COM  * void
747836SJohn.Forte@Sun.COM  * _nsc_init_mem (void)
757836SJohn.Forte@Sun.COM  *	Initialise memory allocation system.
767836SJohn.Forte@Sun.COM  *
777836SJohn.Forte@Sun.COM  * Calling/Exit State:
787836SJohn.Forte@Sun.COM  *	Called at driver initialisation time to allocate necessary
797836SJohn.Forte@Sun.COM  *	data structures.
807836SJohn.Forte@Sun.COM  */
817836SJohn.Forte@Sun.COM void
_nsc_init_mem()827836SJohn.Forte@Sun.COM _nsc_init_mem()
837836SJohn.Forte@Sun.COM {
847836SJohn.Forte@Sun.COM 	mutex_init(&_nsc_mem_lock, NULL, MUTEX_DRIVER, NULL);
857836SJohn.Forte@Sun.COM 
867836SJohn.Forte@Sun.COM 	_nsc_anon_mem = nsc_register_mem("anon:kmem", NSC_MEM_LOCAL, 0);
877836SJohn.Forte@Sun.COM 	_nsc_local_mem = nsc_register_mem("nsctl:kmem", NSC_MEM_LOCAL, 0);
887836SJohn.Forte@Sun.COM 
897836SJohn.Forte@Sun.COM 	if (!_nsc_anon_mem)
907836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "nsctl: nsc_init_mem");
917836SJohn.Forte@Sun.COM }
927836SJohn.Forte@Sun.COM 
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM /*
957836SJohn.Forte@Sun.COM  * void
967836SJohn.Forte@Sun.COM  * _nsc_deinit_mem (void)
977836SJohn.Forte@Sun.COM  *	De-initialise memory alloation system.
987836SJohn.Forte@Sun.COM  *
997836SJohn.Forte@Sun.COM  * Calling/Exit State:
1007836SJohn.Forte@Sun.COM  *	Called at driver unload time to de-allocate
1017836SJohn.Forte@Sun.COM  *	resources.
1027836SJohn.Forte@Sun.COM  */
1037836SJohn.Forte@Sun.COM 
1047836SJohn.Forte@Sun.COM 
1057836SJohn.Forte@Sun.COM void
_nsc_deinit_mem()1067836SJohn.Forte@Sun.COM _nsc_deinit_mem()
1077836SJohn.Forte@Sun.COM {
1087836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base)
1097836SJohn.Forte@Sun.COM 		nsc_kmem_free(_nsc_rm_base, _nsc_rmhdr_size);
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM 	_nsc_rm_nvmem_base = NULL;
1127836SJohn.Forte@Sun.COM 	_nsc_rm_base = NULL;
1137836SJohn.Forte@Sun.COM }
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM /*
1167836SJohn.Forte@Sun.COM  * int
1177836SJohn.Forte@Sun.COM  * _nsc_clear_dirty(int force)
1187836SJohn.Forte@Sun.COM  *	mark the global area clean by clearing the header dirty bit number.
1197836SJohn.Forte@Sun.COM  *
1207836SJohn.Forte@Sun.COM  *	returns 0 if successfully cleared, valid errno otherwise
1217836SJohn.Forte@Sun.COM  *
1227836SJohn.Forte@Sun.COM  *	this function should only be called at system shutdown.
1237836SJohn.Forte@Sun.COM  */
1247836SJohn.Forte@Sun.COM /*ARGSUSED*/
1257836SJohn.Forte@Sun.COM int
_nsc_clear_dirty(int force)1267836SJohn.Forte@Sun.COM _nsc_clear_dirty(int force)
1277836SJohn.Forte@Sun.COM {
1287836SJohn.Forte@Sun.COM 	int rc = 0;
1297836SJohn.Forte@Sun.COM 
1307836SJohn.Forte@Sun.COM #ifdef DEBUG
1317836SJohn.Forte@Sun.COM 	ulong_t longzeros = 0;
1327836SJohn.Forte@Sun.COM 	if (force) {
1337836SJohn.Forte@Sun.COM 		if (_nsc_rm_nvmem_base) {
1347836SJohn.Forte@Sun.COM 			if (nsc_commit_mem((void *)&longzeros,
1357836SJohn.Forte@Sun.COM 			    (void *)&((nsc_rmhdr_t *)
1367836SJohn.Forte@Sun.COM 			    _nsc_rm_nvmem_base)->rh_dirty,
1377836SJohn.Forte@Sun.COM 			    sizeof (ulong_t), nsc_cm_errhdlr) < 0) {
1387836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
139*9093SRamana.Srikanth@Sun.COM 				    "!nsctl: _nsc_clear_magic: "
1407836SJohn.Forte@Sun.COM 				    "hdr force clear failed 0x%p",
1417836SJohn.Forte@Sun.COM 				    (void *)_nsc_rm_nvmem_base);
1427836SJohn.Forte@Sun.COM 			} else {
1437836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
144*9093SRamana.Srikanth@Sun.COM 				    "!nsctl: _nsc_clear_magic: "
1457836SJohn.Forte@Sun.COM 				    "hdr force cleared 0x%p",
1467836SJohn.Forte@Sun.COM 				    (void *)_nsc_rm_nvmem_base);
1477836SJohn.Forte@Sun.COM 				_nsc_rmhdr_ptr->rh_dirty = 0;
1487836SJohn.Forte@Sun.COM 			}
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM 			return (0);
1517836SJohn.Forte@Sun.COM 		} else
1527836SJohn.Forte@Sun.COM 			return (EINVAL);
1537836SJohn.Forte@Sun.COM 	}
1547836SJohn.Forte@Sun.COM 
1557836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base) {
1567836SJohn.Forte@Sun.COM 		if (_nsc_global_lock_init) {
1577836SJohn.Forte@Sun.COM 			mutex_enter(&_nsc_global_lock);
1587836SJohn.Forte@Sun.COM 			if (!_nsc_check_mapinuse()) {
1597836SJohn.Forte@Sun.COM 				if (nsc_commit_mem((void *)&longzeros,
1607836SJohn.Forte@Sun.COM 				    (void *)&((nsc_rmhdr_t *)
1617836SJohn.Forte@Sun.COM 				    _nsc_rm_nvmem_base)->rh_dirty,
1627836SJohn.Forte@Sun.COM 				    sizeof (ulong_t), nsc_cm_errhdlr) < 0) {
1637836SJohn.Forte@Sun.COM 					cmn_err(CE_WARN,
164*9093SRamana.Srikanth@Sun.COM 					    "!nsctl: _nsc_clear_magic: "
1657836SJohn.Forte@Sun.COM 					    "hdr clear failed 0x%p",
1667836SJohn.Forte@Sun.COM 					    (void *)_nsc_rm_nvmem_base);
1677836SJohn.Forte@Sun.COM 				} else {
1687836SJohn.Forte@Sun.COM 					cmn_err(CE_WARN,
169*9093SRamana.Srikanth@Sun.COM 					    "!nsctl: _nsc_clear_magic: "
1707836SJohn.Forte@Sun.COM 					    "hdr cleared 0x%p",
1717836SJohn.Forte@Sun.COM 					    (void *)_nsc_rm_nvmem_base);
1727836SJohn.Forte@Sun.COM 					_nsc_rmhdr_ptr->rh_dirty = 0;
1737836SJohn.Forte@Sun.COM 				}
1747836SJohn.Forte@Sun.COM 				rc = 0;
1757836SJohn.Forte@Sun.COM 			} else {
1767836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
177*9093SRamana.Srikanth@Sun.COM 				    "!nsctl: _nsc_clear_magic: "
178*9093SRamana.Srikanth@Sun.COM 				    "global area in use. cannot clear magic");
1797836SJohn.Forte@Sun.COM 				rc = EBUSY;
1807836SJohn.Forte@Sun.COM 			}
1817836SJohn.Forte@Sun.COM 			mutex_exit(&_nsc_global_lock);
1827836SJohn.Forte@Sun.COM 		} else {
1837836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN,
184*9093SRamana.Srikanth@Sun.COM 			    "!nsctl: _nsc_clear_magic: cannot clear magic");
1857836SJohn.Forte@Sun.COM 			rc = EINVAL;
1867836SJohn.Forte@Sun.COM 		}
1877836SJohn.Forte@Sun.COM 	} else
1887836SJohn.Forte@Sun.COM 		rc = EINVAL;
1897836SJohn.Forte@Sun.COM #else
1907836SJohn.Forte@Sun.COM 
1917836SJohn.Forte@Sun.COM 	rc = ENOTTY;
1927836SJohn.Forte@Sun.COM 
1937836SJohn.Forte@Sun.COM #endif /* DEBUG */
1947836SJohn.Forte@Sun.COM 
1957836SJohn.Forte@Sun.COM 	return (rc);
1967836SJohn.Forte@Sun.COM }
1977836SJohn.Forte@Sun.COM 
1987836SJohn.Forte@Sun.COM /*
1997836SJohn.Forte@Sun.COM  * int
2007836SJohn.Forte@Sun.COM  * _nsc_check_mapinuse()
2017836SJohn.Forte@Sun.COM  *	check if any global maps are still inuse;
2027836SJohn.Forte@Sun.COM  *
2037836SJohn.Forte@Sun.COM  *	return 1 if any non-nsctl map is in use, 0 otherwise
2047836SJohn.Forte@Sun.COM  *	should be called with _nsc_global_lock held
2057836SJohn.Forte@Sun.COM  *
2067836SJohn.Forte@Sun.COM  * 	for nvmem support.  if a client of nsctl is still
2077836SJohn.Forte@Sun.COM  * 	using the global maps then the global area will not
2087836SJohn.Forte@Sun.COM  *	be marked clean.
2097836SJohn.Forte@Sun.COM  */
2107836SJohn.Forte@Sun.COM int
_nsc_check_mapinuse(void)2117836SJohn.Forte@Sun.COM _nsc_check_mapinuse(void)
2127836SJohn.Forte@Sun.COM {
2137836SJohn.Forte@Sun.COM 	nsc_rmmap_t *rmap = _nsc_rmhdr_ptr->map;
2147836SJohn.Forte@Sun.COM 	nsc_rmmap_t *rmapend;
2157836SJohn.Forte@Sun.COM 
2167836SJohn.Forte@Sun.COM 	rmapend = (nsc_rmmap_t *)
2177836SJohn.Forte@Sun.COM 	    ((char *)_nsc_rmhdr_ptr + _nsc_rmhdr_ptr->size);
2187836SJohn.Forte@Sun.COM 
2197836SJohn.Forte@Sun.COM 	for (; rmap < rmapend; ++rmap)
2207836SJohn.Forte@Sun.COM 		if ((rmap->inuse) && !(_nsc_is_nsctl_map(rmap->name)))
2217836SJohn.Forte@Sun.COM 			return (1);
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM 	return (0);
2247836SJohn.Forte@Sun.COM 
2257836SJohn.Forte@Sun.COM }
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM /* names of maps in the global area that belong to nsctl */
2287836SJohn.Forte@Sun.COM static char *nsctl_mapnames[] = {
2297836SJohn.Forte@Sun.COM 	"nsc_global",
2307836SJohn.Forte@Sun.COM 	"nsc_lock"
2317836SJohn.Forte@Sun.COM };
2327836SJohn.Forte@Sun.COM 
2337836SJohn.Forte@Sun.COM int
_nsc_is_nsctl_map(char * mapname)2347836SJohn.Forte@Sun.COM _nsc_is_nsctl_map(char *mapname)
2357836SJohn.Forte@Sun.COM {
2367836SJohn.Forte@Sun.COM 	int i;
2377836SJohn.Forte@Sun.COM 
2387836SJohn.Forte@Sun.COM 	for (i = 0; i < sizeof (nsctl_mapnames)/sizeof (char *); ++i)
2397836SJohn.Forte@Sun.COM 		if (strncmp(mapname, nsctl_mapnames[i], _NSC_MAXNAME) == 0)
2407836SJohn.Forte@Sun.COM 			return (1);
2417836SJohn.Forte@Sun.COM 
2427836SJohn.Forte@Sun.COM 	return (0);
2437836SJohn.Forte@Sun.COM }
2447836SJohn.Forte@Sun.COM 
2457836SJohn.Forte@Sun.COM 
2467836SJohn.Forte@Sun.COM /*
2477836SJohn.Forte@Sun.COM  * nsc_mem_t *
2487836SJohn.Forte@Sun.COM  * nsc_register_mem(char *name, int type, int flag)
2497836SJohn.Forte@Sun.COM  *	Register a category of memory usage.
2507836SJohn.Forte@Sun.COM  *
2517836SJohn.Forte@Sun.COM  * Calling/Exit State:
2527836SJohn.Forte@Sun.COM  *	Returns a token for use in future calls to nsc_kmem_alloc.
2537836SJohn.Forte@Sun.COM  *		type is NSC_MEM_LOCAL, or NSC_MEM_GLOBAL.
2547836SJohn.Forte@Sun.COM  *		flag is passed through to kmem_alloc on allocate.
2557836SJohn.Forte@Sun.COM  *
2567836SJohn.Forte@Sun.COM  * Description:
2577836SJohn.Forte@Sun.COM  *	The parameters associated with a category can be changed
2587836SJohn.Forte@Sun.COM  *	by making a subsequent call to nsc_register_mem.
2597836SJohn.Forte@Sun.COM  */
2607836SJohn.Forte@Sun.COM nsc_mem_t *
nsc_register_mem(char * name,int type,int flag)2617836SJohn.Forte@Sun.COM nsc_register_mem(char *name, int type, int flag)
2627836SJohn.Forte@Sun.COM {
2637836SJohn.Forte@Sun.COM 	nsc_mem_t *mp, *new;
2647836SJohn.Forte@Sun.COM 
2657836SJohn.Forte@Sun.COM 	new = kmem_zalloc(sizeof (*new), KM_NOSLEEP);
2667836SJohn.Forte@Sun.COM 
2677836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
2687836SJohn.Forte@Sun.COM 
2697836SJohn.Forte@Sun.COM 	for (mp = _nsc_mem_top; mp; mp = mp->next)
2707836SJohn.Forte@Sun.COM 		if (strcmp(mp->name, name) == 0)
2717836SJohn.Forte@Sun.COM 			break;
2727836SJohn.Forte@Sun.COM 
2737836SJohn.Forte@Sun.COM 	if (!mp && !(mp = new)) {
2747836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_mem_lock);
2757836SJohn.Forte@Sun.COM 		return (NULL);
2767836SJohn.Forte@Sun.COM 	}
2777836SJohn.Forte@Sun.COM 
2787836SJohn.Forte@Sun.COM 	mp->type = type;
2797836SJohn.Forte@Sun.COM 	mp->flag = flag;
2807836SJohn.Forte@Sun.COM 
2817836SJohn.Forte@Sun.COM 	mp->hwm = mp->used;
2827836SJohn.Forte@Sun.COM 	mp->pagehwm = mp->pages;
2837836SJohn.Forte@Sun.COM 	mp->nalloc -= mp->nfree;
2847836SJohn.Forte@Sun.COM 	mp->nfree = 0;
2857836SJohn.Forte@Sun.COM 
2867836SJohn.Forte@Sun.COM 	if (!mp->name) {
2877836SJohn.Forte@Sun.COM 		mp->name = name;
2887836SJohn.Forte@Sun.COM 		mp->next = _nsc_mem_top;
2897836SJohn.Forte@Sun.COM 		_nsc_mem_top = mp;
2907836SJohn.Forte@Sun.COM 	}
2917836SJohn.Forte@Sun.COM 
2927836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
2937836SJohn.Forte@Sun.COM 
2947836SJohn.Forte@Sun.COM 	if (new && mp != new)
2957836SJohn.Forte@Sun.COM 		kmem_free(new, sizeof (*new));
2967836SJohn.Forte@Sun.COM 
2977836SJohn.Forte@Sun.COM 	return (mp);
2987836SJohn.Forte@Sun.COM }
2997836SJohn.Forte@Sun.COM 
3007836SJohn.Forte@Sun.COM 
3017836SJohn.Forte@Sun.COM /*
3027836SJohn.Forte@Sun.COM  * void
3037836SJohn.Forte@Sun.COM  * nsc_unregister_mem(nsc_mem_t *)
3047836SJohn.Forte@Sun.COM  *	Un-register a category of memory usage.
3057836SJohn.Forte@Sun.COM  *
3067836SJohn.Forte@Sun.COM  * Description:
3077836SJohn.Forte@Sun.COM  *	The specified category is un-registered. For correct
3087836SJohn.Forte@Sun.COM  *	operation this should only be called when all memory
3097836SJohn.Forte@Sun.COM  *	associated with the category has been free'd.
3107836SJohn.Forte@Sun.COM  */
3117836SJohn.Forte@Sun.COM void
nsc_unregister_mem(nsc_mem_t * mp)3127836SJohn.Forte@Sun.COM nsc_unregister_mem(nsc_mem_t *mp)
3137836SJohn.Forte@Sun.COM {
3147836SJohn.Forte@Sun.COM 	nsc_mem_t **mpp;
3157836SJohn.Forte@Sun.COM 
3167836SJohn.Forte@Sun.COM 	if (!mp)
3177836SJohn.Forte@Sun.COM 		return;
3187836SJohn.Forte@Sun.COM 
3197836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
3207836SJohn.Forte@Sun.COM 
3217836SJohn.Forte@Sun.COM 	for (mpp = &_nsc_mem_top; *mpp; mpp = &(*mpp)->next)
3227836SJohn.Forte@Sun.COM 		if (*mpp == mp)
3237836SJohn.Forte@Sun.COM 			break;
3247836SJohn.Forte@Sun.COM 
3257836SJohn.Forte@Sun.COM 	if (*mpp != NULL) {
3267836SJohn.Forte@Sun.COM 		*mpp = mp->next;
3277836SJohn.Forte@Sun.COM 		kmem_free(mp, sizeof (*mp));
3287836SJohn.Forte@Sun.COM 	}
3297836SJohn.Forte@Sun.COM 
3307836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
3317836SJohn.Forte@Sun.COM }
3327836SJohn.Forte@Sun.COM 
3337836SJohn.Forte@Sun.COM /*
3347836SJohn.Forte@Sun.COM  * void
3357836SJohn.Forte@Sun.COM  * _nsc_global_setup
3367836SJohn.Forte@Sun.COM  *	Setup global variables.
3377836SJohn.Forte@Sun.COM  *
3387836SJohn.Forte@Sun.COM  * Calling/Exit State:
3397836SJohn.Forte@Sun.COM  *	Called to setup the global header.
3407836SJohn.Forte@Sun.COM  */
3417836SJohn.Forte@Sun.COM void
_nsc_global_setup()3427836SJohn.Forte@Sun.COM _nsc_global_setup()
3437836SJohn.Forte@Sun.COM {
3447836SJohn.Forte@Sun.COM 	nsc_rmhdr_t *hdr = (void *)_nsc_rm_base;
3457836SJohn.Forte@Sun.COM 	size_t size;
3467836SJohn.Forte@Sun.COM 
3477836SJohn.Forte@Sun.COM 	if (!hdr || !_nsc_global_lock_init || _nsc_rmhdr_ptr)
3487836SJohn.Forte@Sun.COM 		return;
3497836SJohn.Forte@Sun.COM 
3507836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_global_lock);
3517836SJohn.Forte@Sun.COM 
3527836SJohn.Forte@Sun.COM 	if (!hdr->magic || (_nsc_rm_nvmem_base && !hdr->rh_dirty)) {
3537836SJohn.Forte@Sun.COM 		size = sizeof (nsc_rmhdr_t) +
3547836SJohn.Forte@Sun.COM 		    (sizeof (nsc_rmmap_t) * (_NSC_GLSLOT - 1));
3557836SJohn.Forte@Sun.COM 
3567836SJohn.Forte@Sun.COM 		size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN;
3577836SJohn.Forte@Sun.COM 		bzero(_nsc_rm_base, size);
3587836SJohn.Forte@Sun.COM 
3597836SJohn.Forte@Sun.COM 		hdr->magic = _NSCTL_HDRMAGIC;
3607836SJohn.Forte@Sun.COM 		hdr->ver = _NSCTL_HDRVER3;
3617836SJohn.Forte@Sun.COM 		hdr->size = size;
3627836SJohn.Forte@Sun.COM 		hdr->maxdev = nsc_max_devices();
3637836SJohn.Forte@Sun.COM 
3647836SJohn.Forte@Sun.COM 		hdr->map[0].inuse = _NSC_GLSLOT;
3657836SJohn.Forte@Sun.COM 		if (_nsc_rm_nvmem_base) {
3667836SJohn.Forte@Sun.COM 			if (hdr->rh_dirty) { /* corrupted */
3677836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN,
368*9093SRamana.Srikanth@Sun.COM 				    "!nsctl: _nsc_global_setup: nv bad header");
3697836SJohn.Forte@Sun.COM 				mutex_exit(&_nsc_global_lock);
3707836SJohn.Forte@Sun.COM 				return;
3717836SJohn.Forte@Sun.COM 			}
3727836SJohn.Forte@Sun.COM 			if (nsc_commit_mem((void *)_nsc_rm_base,
3737836SJohn.Forte@Sun.COM 			    (void *)_nsc_rm_nvmem_base,
3747836SJohn.Forte@Sun.COM 			    size, nsc_cm_errhdlr) < 0)
375*9093SRamana.Srikanth@Sun.COM 				cmn_err(CE_WARN, "!_nsc_global_setup: "
3767836SJohn.Forte@Sun.COM 				    "nvmem header not updated");
3777836SJohn.Forte@Sun.COM 		}
3787836SJohn.Forte@Sun.COM 	}
3797836SJohn.Forte@Sun.COM 
3807836SJohn.Forte@Sun.COM 	_nsc_rmhdr_ptr = hdr;
3817836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_global_lock);
3827836SJohn.Forte@Sun.COM 
3837836SJohn.Forte@Sun.COM 	if (hdr->magic != _NSCTL_HDRMAGIC || (hdr->ver != _NSCTL_HDRVER &&
3847836SJohn.Forte@Sun.COM 	    hdr->ver != _NSCTL_HDRVER3)) {
385*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nsctl: _nsc_global_setup: bad header");
3867836SJohn.Forte@Sun.COM 		return;
3877836SJohn.Forte@Sun.COM 	}
3887836SJohn.Forte@Sun.COM 
3897836SJohn.Forte@Sun.COM 	if (hdr->ver == _NSCTL_HDRVER3 && hdr->maxdev != nsc_max_devices()) {
3907836SJohn.Forte@Sun.COM 		_nsc_set_max_devices(hdr->maxdev);
3917836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
392*9093SRamana.Srikanth@Sun.COM 		    "!nsctl: _nsc_global_setup: setting nsc_max_devices to %d",
3937836SJohn.Forte@Sun.COM 		    hdr->maxdev);
3947836SJohn.Forte@Sun.COM 	}
3957836SJohn.Forte@Sun.COM 
3967836SJohn.Forte@Sun.COM 	if (!_nsc_rmmap_init(hdr->map, "nsc_global", _NSC_GLSLOT,
3977836SJohn.Forte@Sun.COM 	    _nsc_rm_size - hdr->size, hdr->size)) {
3987836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
399*9093SRamana.Srikanth@Sun.COM 		    "!nsctl: _nsc_global_setup: global map init failed");
4007836SJohn.Forte@Sun.COM 		return;
4017836SJohn.Forte@Sun.COM 	}
4027836SJohn.Forte@Sun.COM 
4037836SJohn.Forte@Sun.COM 	_nsc_global_map = hdr->map;
4047836SJohn.Forte@Sun.COM 
4057836SJohn.Forte@Sun.COM 	(void) nsc_kmem_alloc(hdr->size, 0, _nsc_rmhdr_mem);
4067836SJohn.Forte@Sun.COM }
4077836SJohn.Forte@Sun.COM 
4087836SJohn.Forte@Sun.COM /*
4097836SJohn.Forte@Sun.COM  * int
4107836SJohn.Forte@Sun.COM  * _nsc_need_global_mem ()
4117836SJohn.Forte@Sun.COM  *	Expected global memory usage.
4127836SJohn.Forte@Sun.COM  *
4137836SJohn.Forte@Sun.COM  * Calling/Exit State:
4147836SJohn.Forte@Sun.COM  *	Returns the amount of global memory expected to be
4157836SJohn.Forte@Sun.COM  *	used by internal data structures.
4167836SJohn.Forte@Sun.COM  *
4177836SJohn.Forte@Sun.COM  * Remarks:
4187836SJohn.Forte@Sun.COM  *	This is provided purely as a configuration aid to
4197836SJohn.Forte@Sun.COM  *	systems without global memory and as such is not
4207836SJohn.Forte@Sun.COM  *	declared in nsctl.h.
4217836SJohn.Forte@Sun.COM  */
4227836SJohn.Forte@Sun.COM int
_nsc_need_global_mem()4237836SJohn.Forte@Sun.COM _nsc_need_global_mem()
4247836SJohn.Forte@Sun.COM {
4257836SJohn.Forte@Sun.COM 	int size = sizeof (nsc_rmhdr_t) +
4267836SJohn.Forte@Sun.COM 	    (sizeof (nsc_rmmap_t) * (_NSC_GLSLOT - 1));
4277836SJohn.Forte@Sun.COM 
4287836SJohn.Forte@Sun.COM 	size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN;
4297836SJohn.Forte@Sun.COM 	return (size);
4307836SJohn.Forte@Sun.COM }
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM 
4337836SJohn.Forte@Sun.COM /*
4347836SJohn.Forte@Sun.COM  * void *
4357836SJohn.Forte@Sun.COM  * nsc_kmem_alloc (size_t size, int flag, nsc_mem_t *mem)
4367836SJohn.Forte@Sun.COM  *	Allocate memory of the specified type.
4377836SJohn.Forte@Sun.COM  *
4387836SJohn.Forte@Sun.COM  * Calling/Exit State:
4397836SJohn.Forte@Sun.COM  *	Returns a pointer to a word aligned area of memory.
4407836SJohn.Forte@Sun.COM  *	If mem is zero then an anonymous category is used.
4417836SJohn.Forte@Sun.COM  *
4427836SJohn.Forte@Sun.COM  * Description:
4437836SJohn.Forte@Sun.COM  *	Allocates the required memory and updates the usage
4447836SJohn.Forte@Sun.COM  *	statistics stored in mem.
4457836SJohn.Forte@Sun.COM  *
4467836SJohn.Forte@Sun.COM  * Remarks:
4477836SJohn.Forte@Sun.COM  *	VME memory is guaranteed to be eight byte aligned.
4487836SJohn.Forte@Sun.COM  */
4497836SJohn.Forte@Sun.COM void *
nsc_kmem_alloc(size_t size,int flag,nsc_mem_t * mem)4507836SJohn.Forte@Sun.COM nsc_kmem_alloc(size_t size, int flag, nsc_mem_t *mem)
4517836SJohn.Forte@Sun.COM {
4527836SJohn.Forte@Sun.COM 	void *vp;
4537836SJohn.Forte@Sun.COM 
4547836SJohn.Forte@Sun.COM 	if (!mem)
4557836SJohn.Forte@Sun.COM 		mem = _nsc_anon_mem;
4567836SJohn.Forte@Sun.COM 
4577836SJohn.Forte@Sun.COM 	if ((vp = _nsc_mem_alloc(&size, flag, mem)) == NULL)
4587836SJohn.Forte@Sun.COM 		return (NULL);
4597836SJohn.Forte@Sun.COM 
4607836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
4617836SJohn.Forte@Sun.COM 
4627836SJohn.Forte@Sun.COM 	mem->nalloc++;
4637836SJohn.Forte@Sun.COM 	mem->used += size;
4647836SJohn.Forte@Sun.COM 	mem->pages += btopr(size);
4657836SJohn.Forte@Sun.COM 
4667836SJohn.Forte@Sun.COM 	if (mem->used > mem->hwm)
4677836SJohn.Forte@Sun.COM 		mem->hwm = mem->used;
4687836SJohn.Forte@Sun.COM 	if (mem->pages > mem->pagehwm)
4697836SJohn.Forte@Sun.COM 		mem->pagehwm = mem->pages;
4707836SJohn.Forte@Sun.COM 
4717836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
4727836SJohn.Forte@Sun.COM 	return (vp);
4737836SJohn.Forte@Sun.COM }
4747836SJohn.Forte@Sun.COM 
4757836SJohn.Forte@Sun.COM 
4767836SJohn.Forte@Sun.COM /*
4777836SJohn.Forte@Sun.COM  * void *
4787836SJohn.Forte@Sun.COM  * _nsc_mem_alloc (size_t *sizep, int flag, nsc_mem_t *mem)
4797836SJohn.Forte@Sun.COM  *	Allocate memory of the specified type.
4807836SJohn.Forte@Sun.COM  *
4817836SJohn.Forte@Sun.COM  * Calling/Exit State:
4827836SJohn.Forte@Sun.COM  *	Returns a pointer to a word aligned area of memory.
4837836SJohn.Forte@Sun.COM  *
4847836SJohn.Forte@Sun.COM  * Description:
4857836SJohn.Forte@Sun.COM  *	Uses the type field to determine whether to allocate RM,
4867836SJohn.Forte@Sun.COM  *	VME or kernel memory. For types other then RM a copy of
4877836SJohn.Forte@Sun.COM  *	mem is stored immediately prior to the returned area.
4887836SJohn.Forte@Sun.COM  *	size is updated to reflect the header.
4897836SJohn.Forte@Sun.COM  *
4907836SJohn.Forte@Sun.COM  * Remarks:
4917836SJohn.Forte@Sun.COM  *	A two word header is user for VME memory to ensure
4927836SJohn.Forte@Sun.COM  *	eight byte alignment.
4937836SJohn.Forte@Sun.COM  */
4947836SJohn.Forte@Sun.COM static void *
_nsc_mem_alloc(size_t * sizep,int flag,nsc_mem_t * mem)4957836SJohn.Forte@Sun.COM _nsc_mem_alloc(size_t *sizep, int flag, nsc_mem_t *mem)
4967836SJohn.Forte@Sun.COM {
4977836SJohn.Forte@Sun.COM 	size_t size = *sizep;
4987836SJohn.Forte@Sun.COM 	void *vp;
4997836SJohn.Forte@Sun.COM 
5007836SJohn.Forte@Sun.COM 	if (mem->type & NSC_MEM_GLOBAL)
5017836SJohn.Forte@Sun.COM 		return (_nsc_rm_alloc(sizep, mem));
5027836SJohn.Forte@Sun.COM 
5037836SJohn.Forte@Sun.COM 	flag |= mem->flag;
5047836SJohn.Forte@Sun.COM 	size += sizeof (nsc_mem_t *);
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 	if (flag & KM_NOSLEEP)
5077836SJohn.Forte@Sun.COM 		flag &= ~KM_SLEEP;
5087836SJohn.Forte@Sun.COM 
5097836SJohn.Forte@Sun.COM 	vp = kmem_alloc(size, flag);
5107836SJohn.Forte@Sun.COM 	if (!vp)
5117836SJohn.Forte@Sun.COM 		return (NULL);
5127836SJohn.Forte@Sun.COM 
5137836SJohn.Forte@Sun.COM 	*sizep = size;
5147836SJohn.Forte@Sun.COM 
5157836SJohn.Forte@Sun.COM 	*(nsc_mem_t **)vp = mem;
5167836SJohn.Forte@Sun.COM 
5177836SJohn.Forte@Sun.COM 	return (void *)((nsc_mem_t **)vp + 1);
5187836SJohn.Forte@Sun.COM }
5197836SJohn.Forte@Sun.COM 
5207836SJohn.Forte@Sun.COM 
5217836SJohn.Forte@Sun.COM /*
5227836SJohn.Forte@Sun.COM  * void
5237836SJohn.Forte@Sun.COM  * nsc_kmem_free (void *addr, size_t size)
5247836SJohn.Forte@Sun.COM  *	Free a previously allocated area of memory.
5257836SJohn.Forte@Sun.COM  *
5267836SJohn.Forte@Sun.COM  * Calling/Exit State:
5277836SJohn.Forte@Sun.COM  *	The memory specified by addr is returned to the free pool.
5287836SJohn.Forte@Sun.COM  *
5297836SJohn.Forte@Sun.COM  * Description:
5307836SJohn.Forte@Sun.COM  *	Updates the usage statistics appropriately.
5317836SJohn.Forte@Sun.COM  */
5327836SJohn.Forte@Sun.COM void
nsc_kmem_free(void * addr,size_t size)5337836SJohn.Forte@Sun.COM nsc_kmem_free(void *addr, size_t size)
5347836SJohn.Forte@Sun.COM {
5357836SJohn.Forte@Sun.COM 	caddr_t caddr = (caddr_t)addr;
5367836SJohn.Forte@Sun.COM 	caddr_t rm_base;
5377836SJohn.Forte@Sun.COM 	int rc;
5387836SJohn.Forte@Sun.COM 
5397836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base)
5407836SJohn.Forte@Sun.COM 		rm_base = _nsc_rm_nvmem_base;
5417836SJohn.Forte@Sun.COM 	else
5427836SJohn.Forte@Sun.COM 		rm_base = _nsc_rm_base;
5437836SJohn.Forte@Sun.COM 
5447836SJohn.Forte@Sun.COM 	if (rm_base <= caddr && caddr < rm_base + _nsc_rm_size)
5457836SJohn.Forte@Sun.COM 		rc = _nsc_rm_free(addr, size);
5467836SJohn.Forte@Sun.COM 	else
5477836SJohn.Forte@Sun.COM 		rc = _nsc_mem_free(addr, size);
5487836SJohn.Forte@Sun.COM 
5497836SJohn.Forte@Sun.COM 	if (rc < 0)
5507836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "nsctl: nsc_kmem_free: invalid free");
5517836SJohn.Forte@Sun.COM }
5527836SJohn.Forte@Sun.COM 
5537836SJohn.Forte@Sun.COM 
5547836SJohn.Forte@Sun.COM /*
5557836SJohn.Forte@Sun.COM  * nsc_mem_t *
5567836SJohn.Forte@Sun.COM  * _nsc_mem_free (void *addr, size_t size)
5577836SJohn.Forte@Sun.COM  *	Free a previously allocated area of memory.
5587836SJohn.Forte@Sun.COM  *
5597836SJohn.Forte@Sun.COM  * Calling/Exit State:
5607836SJohn.Forte@Sun.COM  *	Frees the VME or kernel memory at addr and updates
5617836SJohn.Forte@Sun.COM  *	the associated mem structure.
5627836SJohn.Forte@Sun.COM  */
5637836SJohn.Forte@Sun.COM static int
_nsc_mem_free(void * addr,size_t size)5647836SJohn.Forte@Sun.COM _nsc_mem_free(void *addr, size_t size)
5657836SJohn.Forte@Sun.COM {
5667836SJohn.Forte@Sun.COM 	nsc_mem_t *mp, *tp;
5677836SJohn.Forte@Sun.COM 
5687836SJohn.Forte@Sun.COM 	addr = (void *)((nsc_mem_t **)addr - 1);
5697836SJohn.Forte@Sun.COM 	size += sizeof (nsc_mem_t *);
5707836SJohn.Forte@Sun.COM 
5717836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
5727836SJohn.Forte@Sun.COM 
5737836SJohn.Forte@Sun.COM 	mp = *(nsc_mem_t **)addr;
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM 	for (tp = _nsc_mem_top; tp; tp = tp->next)
5767836SJohn.Forte@Sun.COM 		if (tp == mp)
5777836SJohn.Forte@Sun.COM 			break;
5787836SJohn.Forte@Sun.COM 
5797836SJohn.Forte@Sun.COM 	if (tp == NULL) {
5807836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_mem_lock);
5817836SJohn.Forte@Sun.COM 		return (-1);
5827836SJohn.Forte@Sun.COM 	}
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 	mp->nfree++;
5857836SJohn.Forte@Sun.COM 	mp->used -= size;
5867836SJohn.Forte@Sun.COM 	mp->pages -= btopr(size);
5877836SJohn.Forte@Sun.COM 
5887836SJohn.Forte@Sun.COM 	*(nsc_mem_t **)addr = NULL;
5897836SJohn.Forte@Sun.COM 
5907836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
5917836SJohn.Forte@Sun.COM 
5927836SJohn.Forte@Sun.COM 	kmem_free(addr, size);
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 	return (0);
5957836SJohn.Forte@Sun.COM }
5967836SJohn.Forte@Sun.COM 
5977836SJohn.Forte@Sun.COM 
5987836SJohn.Forte@Sun.COM /*
5997836SJohn.Forte@Sun.COM  * void *
6007836SJohn.Forte@Sun.COM  * nsc_kmem_zalloc(size_t size, int flags, nsc_mem_t *mem)
6017836SJohn.Forte@Sun.COM  *	Allocate and zero memory.
6027836SJohn.Forte@Sun.COM  *
6037836SJohn.Forte@Sun.COM  * Calling/Exit State:
6047836SJohn.Forte@Sun.COM  *	Same as nsc_kmem_alloc(), except that the memory is zeroed.
6057836SJohn.Forte@Sun.COM  */
6067836SJohn.Forte@Sun.COM void *
nsc_kmem_zalloc(size_t size,int flag,nsc_mem_t * mem)6077836SJohn.Forte@Sun.COM nsc_kmem_zalloc(size_t size, int flag, nsc_mem_t *mem)
6087836SJohn.Forte@Sun.COM {
6097836SJohn.Forte@Sun.COM 	void *vp = nsc_kmem_alloc(size, flag, mem);
6107836SJohn.Forte@Sun.COM 
6117836SJohn.Forte@Sun.COM 	if (vp)
6127836SJohn.Forte@Sun.COM 		bzero((char *)vp, size);
6137836SJohn.Forte@Sun.COM 
6147836SJohn.Forte@Sun.COM 	return (vp);
6157836SJohn.Forte@Sun.COM }
6167836SJohn.Forte@Sun.COM 
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM /*
6197836SJohn.Forte@Sun.COM  * void
6207836SJohn.Forte@Sun.COM  * nsc_mem_sizes (nsc_mem_t *mem, size_t *usedp, size_t *hwmp, size_t *reqp)
6217836SJohn.Forte@Sun.COM  *	Access size information for category.
6227836SJohn.Forte@Sun.COM  *
6237836SJohn.Forte@Sun.COM  * Calling/Exit State:
6247836SJohn.Forte@Sun.COM  *	If the corresponding pointer is non-zero returns
6257836SJohn.Forte@Sun.COM  *	respectively, the number of bytes currently allocated, the
6267836SJohn.Forte@Sun.COM  *	high water mark in bytes and an estimate of the number of
6277836SJohn.Forte@Sun.COM  *	bytes needed for the category assuming that each request
6287836SJohn.Forte@Sun.COM  *	is satisfied from a different page.
6297836SJohn.Forte@Sun.COM  *
6307836SJohn.Forte@Sun.COM  * Remarks:
6317836SJohn.Forte@Sun.COM  *	The reqp parameter is used to estimate the amount of special
6327836SJohn.Forte@Sun.COM  *	purpose memory needed to support the category.
6337836SJohn.Forte@Sun.COM  */
6347836SJohn.Forte@Sun.COM void
nsc_mem_sizes(nsc_mem_t * mem,size_t * usedp,size_t * hwmp,size_t * reqp)6357836SJohn.Forte@Sun.COM nsc_mem_sizes(nsc_mem_t *mem, size_t *usedp, size_t *hwmp, size_t *reqp)
6367836SJohn.Forte@Sun.COM {
6377836SJohn.Forte@Sun.COM 	if (!mem)
6387836SJohn.Forte@Sun.COM 		mem = _nsc_anon_mem;
6397836SJohn.Forte@Sun.COM 
6407836SJohn.Forte@Sun.COM 	if (usedp)
6417836SJohn.Forte@Sun.COM 		*usedp = mem->used;
6427836SJohn.Forte@Sun.COM 	if (hwmp)
6437836SJohn.Forte@Sun.COM 		*hwmp = mem->hwm;
6447836SJohn.Forte@Sun.COM 	if (reqp)
6457836SJohn.Forte@Sun.COM 		*reqp = (size_t)ptob(mem->pagehwm);
6467836SJohn.Forte@Sun.COM }
6477836SJohn.Forte@Sun.COM 
6487836SJohn.Forte@Sun.COM 
6497836SJohn.Forte@Sun.COM /*
6507836SJohn.Forte@Sun.COM  * size_t
6517836SJohn.Forte@Sun.COM  * nsc_mem_avail (nsc_mem_t *mem)
6527836SJohn.Forte@Sun.COM  *	Memory available for use by category.
6537836SJohn.Forte@Sun.COM  *
6547836SJohn.Forte@Sun.COM  * Calling/Exit State:
6557836SJohn.Forte@Sun.COM  *	Returns the number of bytes of memory currently
6567836SJohn.Forte@Sun.COM  *	available for use by the category.
6577836SJohn.Forte@Sun.COM  *
6587836SJohn.Forte@Sun.COM  * Remarks:
6597836SJohn.Forte@Sun.COM  *	Reduces the memory available to allow for one unit
6607836SJohn.Forte@Sun.COM  *	of allocation overhead.
6617836SJohn.Forte@Sun.COM  *
6627836SJohn.Forte@Sun.COM  *	Only implemented for NSC_MEM_GLOBAL.
6637836SJohn.Forte@Sun.COM  */
6647836SJohn.Forte@Sun.COM size_t
nsc_mem_avail(nsc_mem_t * mem)6657836SJohn.Forte@Sun.COM nsc_mem_avail(nsc_mem_t *mem)
6667836SJohn.Forte@Sun.COM {
6677836SJohn.Forte@Sun.COM 	if (!mem)
6687836SJohn.Forte@Sun.COM 		mem = _nsc_anon_mem;
6697836SJohn.Forte@Sun.COM 
6707836SJohn.Forte@Sun.COM 	if (mem->type & NSC_MEM_GLOBAL)
6717836SJohn.Forte@Sun.COM 		return (_nsc_rm_avail(mem));
6727836SJohn.Forte@Sun.COM 
6737836SJohn.Forte@Sun.COM #ifdef DEBUG
674*9093SRamana.Srikanth@Sun.COM 	cmn_err(CE_WARN, "!nsc_mem_avail: called for non-global memory!");
6757836SJohn.Forte@Sun.COM #endif
6767836SJohn.Forte@Sun.COM 
6777836SJohn.Forte@Sun.COM 	return (0);
6787836SJohn.Forte@Sun.COM }
6797836SJohn.Forte@Sun.COM 
6807836SJohn.Forte@Sun.COM 
6817836SJohn.Forte@Sun.COM /*
6827836SJohn.Forte@Sun.COM  * void
6837836SJohn.Forte@Sun.COM  * _nsc_global_zero (ulong_t offset, size_t size)
6847836SJohn.Forte@Sun.COM  *	Zero global memory.
6857836SJohn.Forte@Sun.COM  *
6867836SJohn.Forte@Sun.COM  * Description:
6877836SJohn.Forte@Sun.COM  *	Zeroes an area of global memory at the specified offset.
6887836SJohn.Forte@Sun.COM  */
6897836SJohn.Forte@Sun.COM 
6907836SJohn.Forte@Sun.COM #define	ZSIZE 4096
6917836SJohn.Forte@Sun.COM static char _nsc_nvmem_zeroes[ZSIZE];
6927836SJohn.Forte@Sun.COM 
6937836SJohn.Forte@Sun.COM static void
_nsc_global_zero(ulong_t offset,size_t size)6947836SJohn.Forte@Sun.COM _nsc_global_zero(ulong_t offset, size_t size)
6957836SJohn.Forte@Sun.COM {
6967836SJohn.Forte@Sun.COM 	int i;
6977836SJohn.Forte@Sun.COM 	int rc;
6987836SJohn.Forte@Sun.COM 	int failed = 0;
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base) {
7017836SJohn.Forte@Sun.COM 		for (i = 0; i < (int)(size / ZSIZE); ++i) {
7027836SJohn.Forte@Sun.COM 			rc = nsc_commit_mem((void *)_nsc_nvmem_zeroes,
7037836SJohn.Forte@Sun.COM 			    (void *)(_nsc_rm_nvmem_base + offset +
7047836SJohn.Forte@Sun.COM 			    i * ZSIZE),
7057836SJohn.Forte@Sun.COM 			    ZSIZE, nsc_cm_errhdlr);
7067836SJohn.Forte@Sun.COM 
7077836SJohn.Forte@Sun.COM 			if (rc < 0)
7087836SJohn.Forte@Sun.COM 				++failed;
7097836SJohn.Forte@Sun.COM 
7107836SJohn.Forte@Sun.COM 		}
7117836SJohn.Forte@Sun.COM 		rc = nsc_commit_mem((void *)_nsc_nvmem_zeroes,
7127836SJohn.Forte@Sun.COM 		    (void *)(_nsc_rm_nvmem_base + offset + i * ZSIZE),
7137836SJohn.Forte@Sun.COM 		    size % ZSIZE,
7147836SJohn.Forte@Sun.COM 		    nsc_cm_errhdlr);
7157836SJohn.Forte@Sun.COM 		if ((rc <  0) || failed)
716*9093SRamana.Srikanth@Sun.COM 			cmn_err(CE_WARN, "!_nsc_global_zero: clear mem failed");
7177836SJohn.Forte@Sun.COM 		return;
7187836SJohn.Forte@Sun.COM 	}
7197836SJohn.Forte@Sun.COM 
7207836SJohn.Forte@Sun.COM 	if (_nsc_rm_base)
7217836SJohn.Forte@Sun.COM 		bzero(_nsc_rm_base + offset, size);
7227836SJohn.Forte@Sun.COM }
7237836SJohn.Forte@Sun.COM 
7247836SJohn.Forte@Sun.COM 
7257836SJohn.Forte@Sun.COM /*
7267836SJohn.Forte@Sun.COM  * void *
7277836SJohn.Forte@Sun.COM  * _nsc_rm_alloc (size_t *sizep, nsc_mem_t *mem)
7287836SJohn.Forte@Sun.COM  *	Allocate next available section of RM.
7297836SJohn.Forte@Sun.COM  *
7307836SJohn.Forte@Sun.COM  * Calling/Exit State:
7317836SJohn.Forte@Sun.COM  *	Returns a pointer to an area of global memory.
7327836SJohn.Forte@Sun.COM  *
7337836SJohn.Forte@Sun.COM  * Description:
7347836SJohn.Forte@Sun.COM  *	Only one allocation request is allowed for each
7357836SJohn.Forte@Sun.COM  *	category of global memory.
7367836SJohn.Forte@Sun.COM  */
7377836SJohn.Forte@Sun.COM static void *
_nsc_rm_alloc(size_t * sizep,nsc_mem_t * mem)7387836SJohn.Forte@Sun.COM _nsc_rm_alloc(size_t *sizep, nsc_mem_t *mem)
7397836SJohn.Forte@Sun.COM {
7407836SJohn.Forte@Sun.COM 	size_t avail, size = (*sizep);
7417836SJohn.Forte@Sun.COM 	ulong_t offset = 0;
7427836SJohn.Forte@Sun.COM 	caddr_t	retaddr;
7437836SJohn.Forte@Sun.COM 
7447836SJohn.Forte@Sun.COM 	if (!_nsc_global_map) {
745*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!_nsc_rm_alloc: no map");
7467836SJohn.Forte@Sun.COM 		return (NULL);
7477836SJohn.Forte@Sun.COM 	}
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
7507836SJohn.Forte@Sun.COM 
7517836SJohn.Forte@Sun.COM 	if (mem->base || mem->pend) {
7527836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_mem_lock);
753*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!_nsc_rm_alloc: invalid alloc");
7547836SJohn.Forte@Sun.COM 		return (NULL);
7557836SJohn.Forte@Sun.COM 	}
7567836SJohn.Forte@Sun.COM 
7577836SJohn.Forte@Sun.COM 	mem->pend = 1;
7587836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
7597836SJohn.Forte@Sun.COM 
7607836SJohn.Forte@Sun.COM 	size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN;
7617836SJohn.Forte@Sun.COM 
7627836SJohn.Forte@Sun.COM 	/* CONSTCOND */
7637836SJohn.Forte@Sun.COM 
7647836SJohn.Forte@Sun.COM 	while (1) {
7657836SJohn.Forte@Sun.COM 		if (strcmp(mem->name, "nsctl:rmhdr") == 0)
7667836SJohn.Forte@Sun.COM 			break;
7677836SJohn.Forte@Sun.COM 
7687836SJohn.Forte@Sun.COM 		offset = _nsc_rmmap_alloc(_nsc_global_map,
7697836SJohn.Forte@Sun.COM 		    mem->name, size, _nsc_global_zero);
7707836SJohn.Forte@Sun.COM 
7717836SJohn.Forte@Sun.COM 		if (offset)
7727836SJohn.Forte@Sun.COM 			break;
7737836SJohn.Forte@Sun.COM 
7747836SJohn.Forte@Sun.COM 		if (mem->type & NSC_MEM_RESIZE) {
7757836SJohn.Forte@Sun.COM 			avail = _nsc_rmmap_size(_nsc_global_map, mem->name);
7767836SJohn.Forte@Sun.COM 
7777836SJohn.Forte@Sun.COM 			if (avail && avail != size) {
7787836SJohn.Forte@Sun.COM 				size = avail;
7797836SJohn.Forte@Sun.COM 				continue;
7807836SJohn.Forte@Sun.COM 			}
7817836SJohn.Forte@Sun.COM 		}
7827836SJohn.Forte@Sun.COM 
7837836SJohn.Forte@Sun.COM 		mem->pend = 0;
7847836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
785*9093SRamana.Srikanth@Sun.COM 		    "!_nsc_rm_alloc: alloc %ld bytes - %ld available",
7867836SJohn.Forte@Sun.COM 		    size, _nsc_rm_avail(mem));
7877836SJohn.Forte@Sun.COM 		return (NULL);
7887836SJohn.Forte@Sun.COM 	}
7897836SJohn.Forte@Sun.COM 
7907836SJohn.Forte@Sun.COM 	_nsc_mark_pages(_nsc_rm_base + offset, size, 1);
7917836SJohn.Forte@Sun.COM 
7927836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base)
7937836SJohn.Forte@Sun.COM 		retaddr = _nsc_rm_nvmem_base + offset;
7947836SJohn.Forte@Sun.COM 	else
7957836SJohn.Forte@Sun.COM 		retaddr = _nsc_rm_base + offset;
7967836SJohn.Forte@Sun.COM 
7977836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
7987836SJohn.Forte@Sun.COM 
7997836SJohn.Forte@Sun.COM 	mem->base = retaddr;
8007836SJohn.Forte@Sun.COM 	mem->pend = 0;
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
8037836SJohn.Forte@Sun.COM 
8047836SJohn.Forte@Sun.COM 	(*sizep) = size;
8057836SJohn.Forte@Sun.COM 	return (retaddr);
8067836SJohn.Forte@Sun.COM }
8077836SJohn.Forte@Sun.COM 
8087836SJohn.Forte@Sun.COM 
8097836SJohn.Forte@Sun.COM /*
8107836SJohn.Forte@Sun.COM  * nsc_mem_t *
8117836SJohn.Forte@Sun.COM  * _nsc_rm_free (void *addr, size_t size)
8127836SJohn.Forte@Sun.COM  *	Free an area of RM.
8137836SJohn.Forte@Sun.COM  *
8147836SJohn.Forte@Sun.COM  * Calling/Exit State:
8157836SJohn.Forte@Sun.COM  *	Returns 0 on success, -1 on failure.
8167836SJohn.Forte@Sun.COM  */
8177836SJohn.Forte@Sun.COM static int
_nsc_rm_free(void * addr,size_t size)8187836SJohn.Forte@Sun.COM _nsc_rm_free(void *addr, size_t size)
8197836SJohn.Forte@Sun.COM {
8207836SJohn.Forte@Sun.COM 	caddr_t caddr = (caddr_t)addr;
8217836SJohn.Forte@Sun.COM 	nsc_mem_t *mp;
8227836SJohn.Forte@Sun.COM 
8237836SJohn.Forte@Sun.COM 	mutex_enter(&_nsc_mem_lock);
8247836SJohn.Forte@Sun.COM 
8257836SJohn.Forte@Sun.COM 	for (mp = _nsc_mem_top; mp; mp = mp->next)
8267836SJohn.Forte@Sun.COM 		if (mp->base == caddr)
8277836SJohn.Forte@Sun.COM 			break;
8287836SJohn.Forte@Sun.COM 
8297836SJohn.Forte@Sun.COM 	if (!mp) {
8307836SJohn.Forte@Sun.COM 		mutex_exit(&_nsc_mem_lock);
8317836SJohn.Forte@Sun.COM 		return (-1);
8327836SJohn.Forte@Sun.COM 	}
8337836SJohn.Forte@Sun.COM 
8347836SJohn.Forte@Sun.COM 	mp->nfree++;
8357836SJohn.Forte@Sun.COM 	mp->used -= size;
8367836SJohn.Forte@Sun.COM 	mp->pages -= btopr(size);
8377836SJohn.Forte@Sun.COM 	mp->pend = 1;
8387836SJohn.Forte@Sun.COM 
8397836SJohn.Forte@Sun.COM 	if (!mp->used)
8407836SJohn.Forte@Sun.COM 		mp->base = 0;
8417836SJohn.Forte@Sun.COM 
8427836SJohn.Forte@Sun.COM 	mutex_exit(&_nsc_mem_lock);
8437836SJohn.Forte@Sun.COM 
8447836SJohn.Forte@Sun.COM 	if (_nsc_global_map)
8457836SJohn.Forte@Sun.COM 		_nsc_rmmap_free(_nsc_global_map, mp->name, mp);
8467836SJohn.Forte@Sun.COM 
8477836SJohn.Forte@Sun.COM 	_nsc_mark_pages(addr, size, 0);
8487836SJohn.Forte@Sun.COM 
8497836SJohn.Forte@Sun.COM 	mp->pend = 0;
8507836SJohn.Forte@Sun.COM 	return (0);
8517836SJohn.Forte@Sun.COM }
8527836SJohn.Forte@Sun.COM 
8537836SJohn.Forte@Sun.COM 
8547836SJohn.Forte@Sun.COM /*
8557836SJohn.Forte@Sun.COM  * static size_t
8567836SJohn.Forte@Sun.COM  * _nsc_rm_avail (mem)
8577836SJohn.Forte@Sun.COM  *	Amount of RM available.
8587836SJohn.Forte@Sun.COM  *
8597836SJohn.Forte@Sun.COM  * Calling/Exit State:
8607836SJohn.Forte@Sun.COM  *	Returns 0 if the specified category has already been
8617836SJohn.Forte@Sun.COM  *	allocated. Returns the size of the region if it already
8627836SJohn.Forte@Sun.COM  *	exists, otherwise the number of bytes of global memory
8637836SJohn.Forte@Sun.COM  *	available.
8647836SJohn.Forte@Sun.COM  */
8657836SJohn.Forte@Sun.COM static size_t
_nsc_rm_avail(nsc_mem_t * mem)8667836SJohn.Forte@Sun.COM _nsc_rm_avail(nsc_mem_t *mem)
8677836SJohn.Forte@Sun.COM {
8687836SJohn.Forte@Sun.COM 	size_t size;
8697836SJohn.Forte@Sun.COM 
8707836SJohn.Forte@Sun.COM 	if (!_nsc_global_map || mem->base || mem->pend)
8717836SJohn.Forte@Sun.COM 		return (0);
8727836SJohn.Forte@Sun.COM 
8737836SJohn.Forte@Sun.COM 	if ((size = _nsc_rmmap_size(_nsc_global_map, mem->name)) != 0)
8747836SJohn.Forte@Sun.COM 		return (size);
8757836SJohn.Forte@Sun.COM 
8767836SJohn.Forte@Sun.COM 	return (_nsc_rmmap_avail(_nsc_global_map));
8777836SJohn.Forte@Sun.COM }
8787836SJohn.Forte@Sun.COM 
8797836SJohn.Forte@Sun.COM 
8807836SJohn.Forte@Sun.COM /*
8817836SJohn.Forte@Sun.COM  * nvram support
8827836SJohn.Forte@Sun.COM  * given a map address, return the address of the copy
8837836SJohn.Forte@Sun.COM  * in nvram.
8847836SJohn.Forte@Sun.COM  * Assumes that _nsc_rm_nvmem_base is valid.
8857836SJohn.Forte@Sun.COM  */
8867836SJohn.Forte@Sun.COM nsc_rmmap_t *
_nsc_global_nvmemmap_lookup(nsc_rmmap_t * hp)8877836SJohn.Forte@Sun.COM _nsc_global_nvmemmap_lookup(nsc_rmmap_t *hp)
8887836SJohn.Forte@Sun.COM {
8897836SJohn.Forte@Sun.COM 	size_t offset;
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM 	/* LINTED */
8927836SJohn.Forte@Sun.COM 	offset = (caddr_t)hp - _nsc_rm_base;
8937836SJohn.Forte@Sun.COM 	return ((nsc_rmmap_t *)(_nsc_rm_nvmem_base + offset));
8947836SJohn.Forte@Sun.COM }
8957836SJohn.Forte@Sun.COM 
8967836SJohn.Forte@Sun.COM int
_nsc_get_global_sizes(void * arg,int * rvp)8977836SJohn.Forte@Sun.COM _nsc_get_global_sizes(void *arg, int *rvp)
8987836SJohn.Forte@Sun.COM {
8997836SJohn.Forte@Sun.COM 	if (!_nsc_rmhdr_ptr)
9007836SJohn.Forte@Sun.COM 		return (EINVAL);
9017836SJohn.Forte@Sun.COM 
9027836SJohn.Forte@Sun.COM 	if (copyout(&_nsc_rmhdr_ptr->size, arg,
903*9093SRamana.Srikanth@Sun.COM 	    sizeof (_nsc_rmhdr_ptr->size)) < 0)
9047836SJohn.Forte@Sun.COM 		return (EFAULT);
9057836SJohn.Forte@Sun.COM 
9067836SJohn.Forte@Sun.COM 	*rvp = 0;
9077836SJohn.Forte@Sun.COM 	return (0);
9087836SJohn.Forte@Sun.COM }
9097836SJohn.Forte@Sun.COM 
9107836SJohn.Forte@Sun.COM int
_nsc_get_global_data(void * arg,int * rvp)9117836SJohn.Forte@Sun.COM _nsc_get_global_data(void *arg, int *rvp)
9127836SJohn.Forte@Sun.COM {
9137836SJohn.Forte@Sun.COM 	size_t size;
9147836SJohn.Forte@Sun.COM 
9157836SJohn.Forte@Sun.COM 	if (!_nsc_rmhdr_ptr)
9167836SJohn.Forte@Sun.COM 		return (EINVAL);
9177836SJohn.Forte@Sun.COM 
9187836SJohn.Forte@Sun.COM 	size = _nsc_rmhdr_ptr->size;
9197836SJohn.Forte@Sun.COM 
9207836SJohn.Forte@Sun.COM 	if (copyout(_nsc_rmhdr_ptr, arg, size) < 0)
9217836SJohn.Forte@Sun.COM 		return (EFAULT);
9227836SJohn.Forte@Sun.COM 
9237836SJohn.Forte@Sun.COM 	if (_nsc_rm_nvmem_base) {
9247836SJohn.Forte@Sun.COM 		char *taddr;
9257836SJohn.Forte@Sun.COM 
9267836SJohn.Forte@Sun.COM 		if ((taddr = kmem_alloc(size, KM_NOSLEEP)) == NULL)
9277836SJohn.Forte@Sun.COM 			return (ENOMEM);
9287836SJohn.Forte@Sun.COM 
9297836SJohn.Forte@Sun.COM 		if (copyout(taddr, (char *)arg + size, size) < 0) {
9307836SJohn.Forte@Sun.COM 			kmem_free(taddr, size);
9317836SJohn.Forte@Sun.COM 			return (EFAULT);
9327836SJohn.Forte@Sun.COM 		}
9337836SJohn.Forte@Sun.COM 
9347836SJohn.Forte@Sun.COM 		kmem_free(taddr, size);
9357836SJohn.Forte@Sun.COM 	}
9367836SJohn.Forte@Sun.COM 
9377836SJohn.Forte@Sun.COM 	*rvp = 0;
9387836SJohn.Forte@Sun.COM 	return (0);
9397836SJohn.Forte@Sun.COM }
940