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/cmn_err.h> 28 #include <sys/ksynch.h> 29 #include <sys/kmem.h> 30 #include <sys/map.h> 31 #include <sys/errno.h> 32 #include <sys/ddi.h> 33 34 35 #define __NSC_GEN__ 36 #include "nsc_dev.h" 37 #include "nsc_gen.h" 38 #include "nsc_mem.h" 39 #include "../nsctl.h" 40 #ifdef DS_DDICT 41 #include "../contract.h" 42 #endif 43 44 45 static size_t _nsc_rm_size; 46 caddr_t _nsc_rm_base; 47 caddr_t _nsc_rm_nvmem_base; 48 size_t _nsc_rmhdr_size; 49 50 static kmutex_t _nsc_mem_lock; 51 static nsc_mem_t *_nsc_anon_mem; 52 static nsc_mem_t *_nsc_rmhdr_mem; 53 54 nsc_mem_t *_nsc_mem_top; 55 56 nsc_rmhdr_t *_nsc_rmhdr_ptr; 57 nsc_rmmap_t *_nsc_global_map; 58 nsc_mem_t *_nsc_local_mem; 59 60 static void *_nsc_mem_alloc(size_t *, int, nsc_mem_t *); 61 static void *_nsc_rm_alloc(size_t *, nsc_mem_t *); 62 static int _nsc_mem_free(void *, size_t); 63 static int _nsc_rm_free(void *, size_t); 64 static size_t _nsc_rm_avail(nsc_mem_t *); 65 66 extern void nscsetup(void); 67 extern void _nsc_mark_pages(caddr_t, size_t, int); 68 extern int _nsc_lock_all_rm(void); 69 extern void _nsc_unlock_all_rm(void); 70 extern void _nsc_set_max_devices(int); 71 72 /* 73 * void 74 * _nsc_init_mem (void) 75 * Initialise memory allocation system. 76 * 77 * Calling/Exit State: 78 * Called at driver initialisation time to allocate necessary 79 * data structures. 80 */ 81 void 82 _nsc_init_mem() 83 { 84 mutex_init(&_nsc_mem_lock, NULL, MUTEX_DRIVER, NULL); 85 86 _nsc_anon_mem = nsc_register_mem("anon:kmem", NSC_MEM_LOCAL, 0); 87 _nsc_local_mem = nsc_register_mem("nsctl:kmem", NSC_MEM_LOCAL, 0); 88 89 if (!_nsc_anon_mem) 90 cmn_err(CE_PANIC, "nsctl: nsc_init_mem"); 91 } 92 93 94 /* 95 * void 96 * _nsc_deinit_mem (void) 97 * De-initialise memory alloation system. 98 * 99 * Calling/Exit State: 100 * Called at driver unload time to de-allocate 101 * resources. 102 */ 103 104 105 void 106 _nsc_deinit_mem() 107 { 108 if (_nsc_rm_nvmem_base) 109 nsc_kmem_free(_nsc_rm_base, _nsc_rmhdr_size); 110 111 _nsc_rm_nvmem_base = NULL; 112 _nsc_rm_base = NULL; 113 } 114 115 /* 116 * int 117 * _nsc_clear_dirty(int force) 118 * mark the global area clean by clearing the header dirty bit number. 119 * 120 * returns 0 if successfully cleared, valid errno otherwise 121 * 122 * this function should only be called at system shutdown. 123 */ 124 /*ARGSUSED*/ 125 int 126 _nsc_clear_dirty(int force) 127 { 128 int rc = 0; 129 130 #ifdef DEBUG 131 ulong_t longzeros = 0; 132 if (force) { 133 if (_nsc_rm_nvmem_base) { 134 if (nsc_commit_mem((void *)&longzeros, 135 (void *)&((nsc_rmhdr_t *) 136 _nsc_rm_nvmem_base)->rh_dirty, 137 sizeof (ulong_t), nsc_cm_errhdlr) < 0) { 138 cmn_err(CE_WARN, 139 "!nsctl: _nsc_clear_magic: " 140 "hdr force clear failed 0x%p", 141 (void *)_nsc_rm_nvmem_base); 142 } else { 143 cmn_err(CE_WARN, 144 "!nsctl: _nsc_clear_magic: " 145 "hdr force cleared 0x%p", 146 (void *)_nsc_rm_nvmem_base); 147 _nsc_rmhdr_ptr->rh_dirty = 0; 148 } 149 150 return (0); 151 } else 152 return (EINVAL); 153 } 154 155 if (_nsc_rm_nvmem_base) { 156 if (_nsc_global_lock_init) { 157 mutex_enter(&_nsc_global_lock); 158 if (!_nsc_check_mapinuse()) { 159 if (nsc_commit_mem((void *)&longzeros, 160 (void *)&((nsc_rmhdr_t *) 161 _nsc_rm_nvmem_base)->rh_dirty, 162 sizeof (ulong_t), nsc_cm_errhdlr) < 0) { 163 cmn_err(CE_WARN, 164 "!nsctl: _nsc_clear_magic: " 165 "hdr clear failed 0x%p", 166 (void *)_nsc_rm_nvmem_base); 167 } else { 168 cmn_err(CE_WARN, 169 "!nsctl: _nsc_clear_magic: " 170 "hdr cleared 0x%p", 171 (void *)_nsc_rm_nvmem_base); 172 _nsc_rmhdr_ptr->rh_dirty = 0; 173 } 174 rc = 0; 175 } else { 176 cmn_err(CE_WARN, 177 "!nsctl: _nsc_clear_magic: " 178 "global area in use. cannot clear magic"); 179 rc = EBUSY; 180 } 181 mutex_exit(&_nsc_global_lock); 182 } else { 183 cmn_err(CE_WARN, 184 "!nsctl: _nsc_clear_magic: cannot clear magic"); 185 rc = EINVAL; 186 } 187 } else 188 rc = EINVAL; 189 #else 190 191 rc = ENOTTY; 192 193 #endif /* DEBUG */ 194 195 return (rc); 196 } 197 198 /* 199 * int 200 * _nsc_check_mapinuse() 201 * check if any global maps are still inuse; 202 * 203 * return 1 if any non-nsctl map is in use, 0 otherwise 204 * should be called with _nsc_global_lock held 205 * 206 * for nvmem support. if a client of nsctl is still 207 * using the global maps then the global area will not 208 * be marked clean. 209 */ 210 int 211 _nsc_check_mapinuse(void) 212 { 213 nsc_rmmap_t *rmap = _nsc_rmhdr_ptr->map; 214 nsc_rmmap_t *rmapend; 215 216 rmapend = (nsc_rmmap_t *) 217 ((char *)_nsc_rmhdr_ptr + _nsc_rmhdr_ptr->size); 218 219 for (; rmap < rmapend; ++rmap) 220 if ((rmap->inuse) && !(_nsc_is_nsctl_map(rmap->name))) 221 return (1); 222 223 return (0); 224 225 } 226 227 /* names of maps in the global area that belong to nsctl */ 228 static char *nsctl_mapnames[] = { 229 "nsc_global", 230 "nsc_lock" 231 }; 232 233 int 234 _nsc_is_nsctl_map(char *mapname) 235 { 236 int i; 237 238 for (i = 0; i < sizeof (nsctl_mapnames)/sizeof (char *); ++i) 239 if (strncmp(mapname, nsctl_mapnames[i], _NSC_MAXNAME) == 0) 240 return (1); 241 242 return (0); 243 } 244 245 246 /* 247 * nsc_mem_t * 248 * nsc_register_mem(char *name, int type, int flag) 249 * Register a category of memory usage. 250 * 251 * Calling/Exit State: 252 * Returns a token for use in future calls to nsc_kmem_alloc. 253 * type is NSC_MEM_LOCAL, or NSC_MEM_GLOBAL. 254 * flag is passed through to kmem_alloc on allocate. 255 * 256 * Description: 257 * The parameters associated with a category can be changed 258 * by making a subsequent call to nsc_register_mem. 259 */ 260 nsc_mem_t * 261 nsc_register_mem(char *name, int type, int flag) 262 { 263 nsc_mem_t *mp, *new; 264 265 new = kmem_zalloc(sizeof (*new), KM_NOSLEEP); 266 267 mutex_enter(&_nsc_mem_lock); 268 269 for (mp = _nsc_mem_top; mp; mp = mp->next) 270 if (strcmp(mp->name, name) == 0) 271 break; 272 273 if (!mp && !(mp = new)) { 274 mutex_exit(&_nsc_mem_lock); 275 return (NULL); 276 } 277 278 mp->type = type; 279 mp->flag = flag; 280 281 mp->hwm = mp->used; 282 mp->pagehwm = mp->pages; 283 mp->nalloc -= mp->nfree; 284 mp->nfree = 0; 285 286 if (!mp->name) { 287 mp->name = name; 288 mp->next = _nsc_mem_top; 289 _nsc_mem_top = mp; 290 } 291 292 mutex_exit(&_nsc_mem_lock); 293 294 if (new && mp != new) 295 kmem_free(new, sizeof (*new)); 296 297 return (mp); 298 } 299 300 301 /* 302 * void 303 * nsc_unregister_mem(nsc_mem_t *) 304 * Un-register a category of memory usage. 305 * 306 * Description: 307 * The specified category is un-registered. For correct 308 * operation this should only be called when all memory 309 * associated with the category has been free'd. 310 */ 311 void 312 nsc_unregister_mem(nsc_mem_t *mp) 313 { 314 nsc_mem_t **mpp; 315 316 if (!mp) 317 return; 318 319 mutex_enter(&_nsc_mem_lock); 320 321 for (mpp = &_nsc_mem_top; *mpp; mpp = &(*mpp)->next) 322 if (*mpp == mp) 323 break; 324 325 if (*mpp != NULL) { 326 *mpp = mp->next; 327 kmem_free(mp, sizeof (*mp)); 328 } 329 330 mutex_exit(&_nsc_mem_lock); 331 } 332 333 /* 334 * void 335 * _nsc_global_setup 336 * Setup global variables. 337 * 338 * Calling/Exit State: 339 * Called to setup the global header. 340 */ 341 void 342 _nsc_global_setup() 343 { 344 nsc_rmhdr_t *hdr = (void *)_nsc_rm_base; 345 size_t size; 346 347 if (!hdr || !_nsc_global_lock_init || _nsc_rmhdr_ptr) 348 return; 349 350 mutex_enter(&_nsc_global_lock); 351 352 if (!hdr->magic || (_nsc_rm_nvmem_base && !hdr->rh_dirty)) { 353 size = sizeof (nsc_rmhdr_t) + 354 (sizeof (nsc_rmmap_t) * (_NSC_GLSLOT - 1)); 355 356 size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN; 357 bzero(_nsc_rm_base, size); 358 359 hdr->magic = _NSCTL_HDRMAGIC; 360 hdr->ver = _NSCTL_HDRVER3; 361 hdr->size = size; 362 hdr->maxdev = nsc_max_devices(); 363 364 hdr->map[0].inuse = _NSC_GLSLOT; 365 if (_nsc_rm_nvmem_base) { 366 if (hdr->rh_dirty) { /* corrupted */ 367 cmn_err(CE_WARN, 368 "!nsctl: _nsc_global_setup: nv bad header"); 369 mutex_exit(&_nsc_global_lock); 370 return; 371 } 372 if (nsc_commit_mem((void *)_nsc_rm_base, 373 (void *)_nsc_rm_nvmem_base, 374 size, nsc_cm_errhdlr) < 0) 375 cmn_err(CE_WARN, "!_nsc_global_setup: " 376 "nvmem header not updated"); 377 } 378 } 379 380 _nsc_rmhdr_ptr = hdr; 381 mutex_exit(&_nsc_global_lock); 382 383 if (hdr->magic != _NSCTL_HDRMAGIC || (hdr->ver != _NSCTL_HDRVER && 384 hdr->ver != _NSCTL_HDRVER3)) { 385 cmn_err(CE_WARN, "!nsctl: _nsc_global_setup: bad header"); 386 return; 387 } 388 389 if (hdr->ver == _NSCTL_HDRVER3 && hdr->maxdev != nsc_max_devices()) { 390 _nsc_set_max_devices(hdr->maxdev); 391 cmn_err(CE_WARN, 392 "!nsctl: _nsc_global_setup: setting nsc_max_devices to %d", 393 hdr->maxdev); 394 } 395 396 if (!_nsc_rmmap_init(hdr->map, "nsc_global", _NSC_GLSLOT, 397 _nsc_rm_size - hdr->size, hdr->size)) { 398 cmn_err(CE_WARN, 399 "!nsctl: _nsc_global_setup: global map init failed"); 400 return; 401 } 402 403 _nsc_global_map = hdr->map; 404 405 (void) nsc_kmem_alloc(hdr->size, 0, _nsc_rmhdr_mem); 406 } 407 408 /* 409 * int 410 * _nsc_need_global_mem () 411 * Expected global memory usage. 412 * 413 * Calling/Exit State: 414 * Returns the amount of global memory expected to be 415 * used by internal data structures. 416 * 417 * Remarks: 418 * This is provided purely as a configuration aid to 419 * systems without global memory and as such is not 420 * declared in nsctl.h. 421 */ 422 int 423 _nsc_need_global_mem() 424 { 425 int size = sizeof (nsc_rmhdr_t) + 426 (sizeof (nsc_rmmap_t) * (_NSC_GLSLOT - 1)); 427 428 size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN; 429 return (size); 430 } 431 432 433 /* 434 * void * 435 * nsc_kmem_alloc (size_t size, int flag, nsc_mem_t *mem) 436 * Allocate memory of the specified type. 437 * 438 * Calling/Exit State: 439 * Returns a pointer to a word aligned area of memory. 440 * If mem is zero then an anonymous category is used. 441 * 442 * Description: 443 * Allocates the required memory and updates the usage 444 * statistics stored in mem. 445 * 446 * Remarks: 447 * VME memory is guaranteed to be eight byte aligned. 448 */ 449 void * 450 nsc_kmem_alloc(size_t size, int flag, nsc_mem_t *mem) 451 { 452 void *vp; 453 454 if (!mem) 455 mem = _nsc_anon_mem; 456 457 if ((vp = _nsc_mem_alloc(&size, flag, mem)) == NULL) 458 return (NULL); 459 460 mutex_enter(&_nsc_mem_lock); 461 462 mem->nalloc++; 463 mem->used += size; 464 mem->pages += btopr(size); 465 466 if (mem->used > mem->hwm) 467 mem->hwm = mem->used; 468 if (mem->pages > mem->pagehwm) 469 mem->pagehwm = mem->pages; 470 471 mutex_exit(&_nsc_mem_lock); 472 return (vp); 473 } 474 475 476 /* 477 * void * 478 * _nsc_mem_alloc (size_t *sizep, int flag, nsc_mem_t *mem) 479 * Allocate memory of the specified type. 480 * 481 * Calling/Exit State: 482 * Returns a pointer to a word aligned area of memory. 483 * 484 * Description: 485 * Uses the type field to determine whether to allocate RM, 486 * VME or kernel memory. For types other then RM a copy of 487 * mem is stored immediately prior to the returned area. 488 * size is updated to reflect the header. 489 * 490 * Remarks: 491 * A two word header is user for VME memory to ensure 492 * eight byte alignment. 493 */ 494 static void * 495 _nsc_mem_alloc(size_t *sizep, int flag, nsc_mem_t *mem) 496 { 497 size_t size = *sizep; 498 void *vp; 499 500 if (mem->type & NSC_MEM_GLOBAL) 501 return (_nsc_rm_alloc(sizep, mem)); 502 503 flag |= mem->flag; 504 size += sizeof (nsc_mem_t *); 505 506 if (flag & KM_NOSLEEP) 507 flag &= ~KM_SLEEP; 508 509 vp = kmem_alloc(size, flag); 510 if (!vp) 511 return (NULL); 512 513 *sizep = size; 514 515 *(nsc_mem_t **)vp = mem; 516 517 return (void *)((nsc_mem_t **)vp + 1); 518 } 519 520 521 /* 522 * void 523 * nsc_kmem_free (void *addr, size_t size) 524 * Free a previously allocated area of memory. 525 * 526 * Calling/Exit State: 527 * The memory specified by addr is returned to the free pool. 528 * 529 * Description: 530 * Updates the usage statistics appropriately. 531 */ 532 void 533 nsc_kmem_free(void *addr, size_t size) 534 { 535 caddr_t caddr = (caddr_t)addr; 536 caddr_t rm_base; 537 int rc; 538 539 if (_nsc_rm_nvmem_base) 540 rm_base = _nsc_rm_nvmem_base; 541 else 542 rm_base = _nsc_rm_base; 543 544 if (rm_base <= caddr && caddr < rm_base + _nsc_rm_size) 545 rc = _nsc_rm_free(addr, size); 546 else 547 rc = _nsc_mem_free(addr, size); 548 549 if (rc < 0) 550 cmn_err(CE_PANIC, "nsctl: nsc_kmem_free: invalid free"); 551 } 552 553 554 /* 555 * nsc_mem_t * 556 * _nsc_mem_free (void *addr, size_t size) 557 * Free a previously allocated area of memory. 558 * 559 * Calling/Exit State: 560 * Frees the VME or kernel memory at addr and updates 561 * the associated mem structure. 562 */ 563 static int 564 _nsc_mem_free(void *addr, size_t size) 565 { 566 nsc_mem_t *mp, *tp; 567 568 addr = (void *)((nsc_mem_t **)addr - 1); 569 size += sizeof (nsc_mem_t *); 570 571 mutex_enter(&_nsc_mem_lock); 572 573 mp = *(nsc_mem_t **)addr; 574 575 for (tp = _nsc_mem_top; tp; tp = tp->next) 576 if (tp == mp) 577 break; 578 579 if (tp == NULL) { 580 mutex_exit(&_nsc_mem_lock); 581 return (-1); 582 } 583 584 mp->nfree++; 585 mp->used -= size; 586 mp->pages -= btopr(size); 587 588 *(nsc_mem_t **)addr = NULL; 589 590 mutex_exit(&_nsc_mem_lock); 591 592 kmem_free(addr, size); 593 594 return (0); 595 } 596 597 598 /* 599 * void * 600 * nsc_kmem_zalloc(size_t size, int flags, nsc_mem_t *mem) 601 * Allocate and zero memory. 602 * 603 * Calling/Exit State: 604 * Same as nsc_kmem_alloc(), except that the memory is zeroed. 605 */ 606 void * 607 nsc_kmem_zalloc(size_t size, int flag, nsc_mem_t *mem) 608 { 609 void *vp = nsc_kmem_alloc(size, flag, mem); 610 611 if (vp) 612 bzero((char *)vp, size); 613 614 return (vp); 615 } 616 617 618 /* 619 * void 620 * nsc_mem_sizes (nsc_mem_t *mem, size_t *usedp, size_t *hwmp, size_t *reqp) 621 * Access size information for category. 622 * 623 * Calling/Exit State: 624 * If the corresponding pointer is non-zero returns 625 * respectively, the number of bytes currently allocated, the 626 * high water mark in bytes and an estimate of the number of 627 * bytes needed for the category assuming that each request 628 * is satisfied from a different page. 629 * 630 * Remarks: 631 * The reqp parameter is used to estimate the amount of special 632 * purpose memory needed to support the category. 633 */ 634 void 635 nsc_mem_sizes(nsc_mem_t *mem, size_t *usedp, size_t *hwmp, size_t *reqp) 636 { 637 if (!mem) 638 mem = _nsc_anon_mem; 639 640 if (usedp) 641 *usedp = mem->used; 642 if (hwmp) 643 *hwmp = mem->hwm; 644 if (reqp) 645 *reqp = (size_t)ptob(mem->pagehwm); 646 } 647 648 649 /* 650 * size_t 651 * nsc_mem_avail (nsc_mem_t *mem) 652 * Memory available for use by category. 653 * 654 * Calling/Exit State: 655 * Returns the number of bytes of memory currently 656 * available for use by the category. 657 * 658 * Remarks: 659 * Reduces the memory available to allow for one unit 660 * of allocation overhead. 661 * 662 * Only implemented for NSC_MEM_GLOBAL. 663 */ 664 size_t 665 nsc_mem_avail(nsc_mem_t *mem) 666 { 667 if (!mem) 668 mem = _nsc_anon_mem; 669 670 if (mem->type & NSC_MEM_GLOBAL) 671 return (_nsc_rm_avail(mem)); 672 673 #ifdef DEBUG 674 cmn_err(CE_WARN, "!nsc_mem_avail: called for non-global memory!"); 675 #endif 676 677 return (0); 678 } 679 680 681 /* 682 * void 683 * _nsc_global_zero (ulong_t offset, size_t size) 684 * Zero global memory. 685 * 686 * Description: 687 * Zeroes an area of global memory at the specified offset. 688 */ 689 690 #define ZSIZE 4096 691 static char _nsc_nvmem_zeroes[ZSIZE]; 692 693 static void 694 _nsc_global_zero(ulong_t offset, size_t size) 695 { 696 int i; 697 int rc; 698 int failed = 0; 699 700 if (_nsc_rm_nvmem_base) { 701 for (i = 0; i < (int)(size / ZSIZE); ++i) { 702 rc = nsc_commit_mem((void *)_nsc_nvmem_zeroes, 703 (void *)(_nsc_rm_nvmem_base + offset + 704 i * ZSIZE), 705 ZSIZE, nsc_cm_errhdlr); 706 707 if (rc < 0) 708 ++failed; 709 710 } 711 rc = nsc_commit_mem((void *)_nsc_nvmem_zeroes, 712 (void *)(_nsc_rm_nvmem_base + offset + i * ZSIZE), 713 size % ZSIZE, 714 nsc_cm_errhdlr); 715 if ((rc < 0) || failed) 716 cmn_err(CE_WARN, "!_nsc_global_zero: clear mem failed"); 717 return; 718 } 719 720 if (_nsc_rm_base) 721 bzero(_nsc_rm_base + offset, size); 722 } 723 724 725 /* 726 * void * 727 * _nsc_rm_alloc (size_t *sizep, nsc_mem_t *mem) 728 * Allocate next available section of RM. 729 * 730 * Calling/Exit State: 731 * Returns a pointer to an area of global memory. 732 * 733 * Description: 734 * Only one allocation request is allowed for each 735 * category of global memory. 736 */ 737 static void * 738 _nsc_rm_alloc(size_t *sizep, nsc_mem_t *mem) 739 { 740 size_t avail, size = (*sizep); 741 ulong_t offset = 0; 742 caddr_t retaddr; 743 744 if (!_nsc_global_map) { 745 cmn_err(CE_WARN, "!_nsc_rm_alloc: no map"); 746 return (NULL); 747 } 748 749 mutex_enter(&_nsc_mem_lock); 750 751 if (mem->base || mem->pend) { 752 mutex_exit(&_nsc_mem_lock); 753 cmn_err(CE_WARN, "!_nsc_rm_alloc: invalid alloc"); 754 return (NULL); 755 } 756 757 mem->pend = 1; 758 mutex_exit(&_nsc_mem_lock); 759 760 size = (size + _NSC_GLALIGN) & ~_NSC_GLALIGN; 761 762 /* CONSTCOND */ 763 764 while (1) { 765 if (strcmp(mem->name, "nsctl:rmhdr") == 0) 766 break; 767 768 offset = _nsc_rmmap_alloc(_nsc_global_map, 769 mem->name, size, _nsc_global_zero); 770 771 if (offset) 772 break; 773 774 if (mem->type & NSC_MEM_RESIZE) { 775 avail = _nsc_rmmap_size(_nsc_global_map, mem->name); 776 777 if (avail && avail != size) { 778 size = avail; 779 continue; 780 } 781 } 782 783 mem->pend = 0; 784 cmn_err(CE_WARN, 785 "!_nsc_rm_alloc: alloc %ld bytes - %ld available", 786 size, _nsc_rm_avail(mem)); 787 return (NULL); 788 } 789 790 _nsc_mark_pages(_nsc_rm_base + offset, size, 1); 791 792 if (_nsc_rm_nvmem_base) 793 retaddr = _nsc_rm_nvmem_base + offset; 794 else 795 retaddr = _nsc_rm_base + offset; 796 797 mutex_enter(&_nsc_mem_lock); 798 799 mem->base = retaddr; 800 mem->pend = 0; 801 802 mutex_exit(&_nsc_mem_lock); 803 804 (*sizep) = size; 805 return (retaddr); 806 } 807 808 809 /* 810 * nsc_mem_t * 811 * _nsc_rm_free (void *addr, size_t size) 812 * Free an area of RM. 813 * 814 * Calling/Exit State: 815 * Returns 0 on success, -1 on failure. 816 */ 817 static int 818 _nsc_rm_free(void *addr, size_t size) 819 { 820 caddr_t caddr = (caddr_t)addr; 821 nsc_mem_t *mp; 822 823 mutex_enter(&_nsc_mem_lock); 824 825 for (mp = _nsc_mem_top; mp; mp = mp->next) 826 if (mp->base == caddr) 827 break; 828 829 if (!mp) { 830 mutex_exit(&_nsc_mem_lock); 831 return (-1); 832 } 833 834 mp->nfree++; 835 mp->used -= size; 836 mp->pages -= btopr(size); 837 mp->pend = 1; 838 839 if (!mp->used) 840 mp->base = 0; 841 842 mutex_exit(&_nsc_mem_lock); 843 844 if (_nsc_global_map) 845 _nsc_rmmap_free(_nsc_global_map, mp->name, mp); 846 847 _nsc_mark_pages(addr, size, 0); 848 849 mp->pend = 0; 850 return (0); 851 } 852 853 854 /* 855 * static size_t 856 * _nsc_rm_avail (mem) 857 * Amount of RM available. 858 * 859 * Calling/Exit State: 860 * Returns 0 if the specified category has already been 861 * allocated. Returns the size of the region if it already 862 * exists, otherwise the number of bytes of global memory 863 * available. 864 */ 865 static size_t 866 _nsc_rm_avail(nsc_mem_t *mem) 867 { 868 size_t size; 869 870 if (!_nsc_global_map || mem->base || mem->pend) 871 return (0); 872 873 if ((size = _nsc_rmmap_size(_nsc_global_map, mem->name)) != 0) 874 return (size); 875 876 return (_nsc_rmmap_avail(_nsc_global_map)); 877 } 878 879 880 /* 881 * nvram support 882 * given a map address, return the address of the copy 883 * in nvram. 884 * Assumes that _nsc_rm_nvmem_base is valid. 885 */ 886 nsc_rmmap_t * 887 _nsc_global_nvmemmap_lookup(nsc_rmmap_t *hp) 888 { 889 size_t offset; 890 891 /* LINTED */ 892 offset = (caddr_t)hp - _nsc_rm_base; 893 return ((nsc_rmmap_t *)(_nsc_rm_nvmem_base + offset)); 894 } 895 896 int 897 _nsc_get_global_sizes(void *arg, int *rvp) 898 { 899 if (!_nsc_rmhdr_ptr) 900 return (EINVAL); 901 902 if (copyout(&_nsc_rmhdr_ptr->size, arg, 903 sizeof (_nsc_rmhdr_ptr->size)) < 0) 904 return (EFAULT); 905 906 *rvp = 0; 907 return (0); 908 } 909 910 int 911 _nsc_get_global_data(void *arg, int *rvp) 912 { 913 size_t size; 914 915 if (!_nsc_rmhdr_ptr) 916 return (EINVAL); 917 918 size = _nsc_rmhdr_ptr->size; 919 920 if (copyout(_nsc_rmhdr_ptr, arg, size) < 0) 921 return (EFAULT); 922 923 if (_nsc_rm_nvmem_base) { 924 char *taddr; 925 926 if ((taddr = kmem_alloc(size, KM_NOSLEEP)) == NULL) 927 return (ENOMEM); 928 929 if (copyout(taddr, (char *)arg + size, size) < 0) { 930 kmem_free(taddr, size); 931 return (EFAULT); 932 } 933 934 kmem_free(taddr, size); 935 } 936 937 *rvp = 0; 938 return (0); 939 }