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