|
|
1.1 ! root 1: /* ! 2: * <ofmem_common.c> ! 3: * ! 4: * OF Memory manager ! 5: * ! 6: * Copyright (C) 1999-2004 Samuel Rydh ([email protected]) ! 7: * Copyright (C) 2004 Stefan Reinauer ! 8: * ! 9: * This program is free software; you can redistribute it and/or ! 10: * modify it under the terms of the GNU General Public License ! 11: * as published by the Free Software Foundation ! 12: * ! 13: */ ! 14: ! 15: #include "config.h" ! 16: #include "libopenbios/bindings.h" ! 17: #include "libopenbios/ofmem.h" ! 18: ! 19: /* Default size of memory allocated for each of the MMU properties (in bytes) */ ! 20: #define OFMEM_DEFAULT_PROP_SIZE 2048 ! 21: ! 22: /* ! 23: * define OFMEM_FILL_RANGE to claim any unclaimed virtual and ! 24: * physical memory in the range for ofmem_map ! 25: * ! 26: * TODO: remove this macro and wrapped code if not needed by implementations ! 27: */ ! 28: //#define OFMEM_FILL_RANGE ! 29: ! 30: ! 31: static inline size_t align_size(size_t x, size_t a) ! 32: { ! 33: return (x + a - 1) & ~(a - 1); ! 34: } ! 35: ! 36: static inline phys_addr_t align_ptr(uintptr_t x, size_t a) ! 37: { ! 38: return (x + a - 1) & ~(a - 1); ! 39: } ! 40: ! 41: static ucell get_ram_size( void ) ! 42: { ! 43: ofmem_t *ofmem = ofmem_arch_get_private(); ! 44: return ofmem->ramsize; ! 45: } ! 46: ! 47: /************************************************************************/ ! 48: /* debug */ ! 49: /************************************************************************/ ! 50: ! 51: #if 0 ! 52: static void ! 53: print_range( range_t *r, char *str ) ! 54: { ! 55: printk("--- Range %s ---\n", str ); ! 56: for( ; r; r=r->next ) ! 57: printk(FMT_plx " - " FMT_plx "\n", r->start, r->start + r->size - 1); ! 58: printk("\n"); ! 59: } ! 60: ! 61: static void ! 62: print_phys_range() ! 63: { ! 64: print_range( ofmem.phys_range, "phys" ); ! 65: } ! 66: ! 67: static void ! 68: print_virt_range() ! 69: { ! 70: print_range( ofmem.virt_range, "virt" ); ! 71: } ! 72: ! 73: static void ! 74: print_trans( void ) ! 75: { ! 76: translation_t *t = ofmem.trans; ! 77: ! 78: printk("--- Translations ---\n"); ! 79: for( ; t; t=t->next ) ! 80: printk("%08lx -> " FMT_plx " [size %lx]\n", t->virt, t->phys, t->size); ! 81: printk("\n"); ! 82: } ! 83: #endif ! 84: ! 85: /************************************************************************/ ! 86: /* OF private allocations */ ! 87: /************************************************************************/ ! 88: ! 89: int ofmem_posix_memalign( void **memptr, size_t alignment, size_t size ) ! 90: { ! 91: ofmem_t *ofmem = ofmem_arch_get_private(); ! 92: alloc_desc_t *d, **pp; ! 93: void *ret; ! 94: ucell top; ! 95: phys_addr_t pa; ! 96: ! 97: if( !size ) ! 98: return ENOMEM; ! 99: ! 100: if( !ofmem->next_malloc ) ! 101: ofmem->next_malloc = (char*)ofmem_arch_get_malloc_base(); ! 102: ! 103: size = align_size(size + sizeof(alloc_desc_t), alignment); ! 104: ! 105: /* look in the freelist */ ! 106: for( pp=&ofmem->mfree; *pp && (**pp).size < size; pp = &(**pp).next ) { ! 107: } ! 108: ! 109: /* waste at most 4K by taking an entry from the freelist */ ! 110: if( *pp && (**pp).size < size + 0x1000 ) { ! 111: /* Alignment should be on physical not virtual address */ ! 112: pa = va2pa((uintptr_t)*pp + sizeof(alloc_desc_t)); ! 113: pa = align_ptr(pa, alignment); ! 114: ret = (void *)pa2va(pa); ! 115: ! 116: memset( ret, 0, (**pp).size - sizeof(alloc_desc_t) ); ! 117: *pp = (**pp).next; ! 118: ! 119: *memptr = ret; ! 120: return 0; ! 121: } ! 122: ! 123: top = ofmem_arch_get_heap_top(); ! 124: ! 125: /* Alignment should be on physical not virtual address */ ! 126: pa = va2pa((uintptr_t)ofmem->next_malloc + sizeof(alloc_desc_t)); ! 127: pa = align_ptr(pa, alignment); ! 128: ret = (void *)pa2va(pa); ! 129: ! 130: if( pointer2cell(ret) + size > top ) { ! 131: printk("out of malloc memory (%x)!\n", size ); ! 132: return ENOMEM; ! 133: } ! 134: ! 135: d = (alloc_desc_t*)((uintptr_t)ret - sizeof(alloc_desc_t)); ! 136: ofmem->next_malloc += size; ! 137: ! 138: d->next = NULL; ! 139: d->size = size; ! 140: ! 141: memset( ret, 0, size - sizeof(alloc_desc_t) ); ! 142: ! 143: *memptr = ret; ! 144: return 0; ! 145: } ! 146: ! 147: void* ofmem_malloc( size_t size ) ! 148: { ! 149: void *memptr; ! 150: int res; ! 151: ! 152: res = ofmem_posix_memalign( &memptr, CONFIG_OFMEM_MALLOC_ALIGN, size ); ! 153: if (!res) { ! 154: /* Success */ ! 155: return memptr; ! 156: } else { ! 157: /* Failure */ ! 158: return NULL; ! 159: } ! 160: } ! 161: ! 162: void ofmem_free( void *ptr ) ! 163: { ! 164: ofmem_t *ofmem = ofmem_arch_get_private(); ! 165: alloc_desc_t **pp, *d; ! 166: ! 167: /* it is legal to free NULL pointers (size zero allocations) */ ! 168: if( !ptr ) ! 169: return; ! 170: ! 171: d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t)); ! 172: d->next = ofmem->mfree; ! 173: ! 174: /* insert in the (sorted) freelist */ ! 175: for( pp=&ofmem->mfree; *pp && (**pp).size < d->size ; pp = &(**pp).next ) { ! 176: } ! 177: ! 178: d->next = *pp; ! 179: *pp = d; ! 180: } ! 181: ! 182: void* ofmem_realloc( void *ptr, size_t size ) ! 183: { ! 184: alloc_desc_t *d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t)); ! 185: char *p; ! 186: ! 187: if( !ptr ) ! 188: return malloc( size ); ! 189: if( !size ) { ! 190: free( ptr ); ! 191: return NULL; ! 192: } ! 193: p = malloc( size ); ! 194: memcpy( p, ptr, MIN(d->size - sizeof(alloc_desc_t),size) ); ! 195: free( ptr ); ! 196: return p; ! 197: } ! 198: ! 199: ! 200: /************************************************************************/ ! 201: /* "translations" and "available" property tracking */ ! 202: /************************************************************************/ ! 203: ! 204: static int trans_prop_size = 0, phys_range_prop_size = 0, virt_range_prop_size = 0; ! 205: static int trans_prop_used = 0, phys_range_prop_used = 0, virt_range_prop_used = 0; ! 206: static ucell *trans_prop, *phys_range_prop, *virt_range_prop; ! 207: ! 208: static void ! 209: ofmem_set_property( phandle_t ph, const char *name, const char *buf, int len ) ! 210: { ! 211: /* This is very similar to set_property() in libopenbios/bindings.c but allows ! 212: us to set the property pointer directly, rather than having to copy it ! 213: into the Forth dictonary every time we update the memory properties */ ! 214: if( !ph ) { ! 215: printk("ofmem_set_property: NULL phandle\n"); ! 216: return; ! 217: } ! 218: PUSH(pointer2cell(buf)); ! 219: PUSH(len); ! 220: push_str(name); ! 221: PUSH_ph(ph); ! 222: fword("encode-property"); ! 223: } ! 224: ! 225: phandle_t s_phandle_memory = 0; ! 226: phandle_t s_phandle_mmu = 0; ! 227: ! 228: static void ofmem_update_mmu_translations( void ) ! 229: { ! 230: ofmem_t *ofmem = ofmem_arch_get_private(); ! 231: translation_t *t; ! 232: int ncells, prop_used, prop_size; ! 233: ! 234: if (s_phandle_mmu == 0) ! 235: return; ! 236: ! 237: for( t = ofmem->trans, ncells = 0; t ; t=t->next, ncells++ ) { ! 238: } ! 239: ! 240: /* Get the current number of bytes required for the MMU translation property */ ! 241: prop_used = ncells * sizeof(ucell) * ofmem_arch_get_translation_entry_size(); ! 242: ! 243: if (prop_used > trans_prop_size) { ! 244: ! 245: /* The property doesn't fit within the existing space, so keep doubling it ! 246: until it does */ ! 247: prop_size = trans_prop_size; ! 248: while (prop_size < prop_used) { ! 249: prop_size *= 2; ! 250: } ! 251: ! 252: /* Allocate the new memory and copy all of the existing information across */ ! 253: trans_prop = realloc(trans_prop, prop_size); ! 254: trans_prop_size = prop_size; ! 255: trans_prop_used = prop_used; ! 256: } ! 257: ! 258: if (trans_prop == NULL) { ! 259: /* out of memory! */ ! 260: printk("Unable to allocate memory for translations property!\n"); ! 261: return; ! 262: } ! 263: ! 264: /* Call architecture-specific routines to generate translation entries */ ! 265: for( t = ofmem->trans, ncells = 0 ; t ; t=t->next ) { ! 266: ofmem_arch_create_translation_entry(&trans_prop[ncells], t); ! 267: ncells += ofmem_arch_get_translation_entry_size(); ! 268: } ! 269: ! 270: ofmem_set_property(s_phandle_mmu, "translations", ! 271: (char*)trans_prop, ncells * sizeof(trans_prop[0])); ! 272: ! 273: } ! 274: ! 275: ! 276: static void ofmem_update_memory_available( phandle_t ph, range_t *range, ! 277: ucell **mem_prop, int *mem_prop_size, int *mem_prop_used, u64 top_address ) ! 278: { ! 279: range_t *r; ! 280: int ncells, prop_used, prop_size; ! 281: phys_addr_t start; ! 282: ucell size, *prop; ! 283: ! 284: if (s_phandle_memory == 0) ! 285: return; ! 286: ! 287: /* count phys_range list entries */ ! 288: for( r = range, ncells = 0; r ; r=r->next, ncells++ ) { ! 289: } ! 290: ! 291: /* inverse of phys_range list could take 2 or more additional cells for the tail ! 292: For /memory, physical addresses may be wider than one ucell. */ ! 293: prop_used = (ncells + 1) * sizeof(ucell) * ofmem_arch_get_available_entry_size(ph) + 1; ! 294: ! 295: if (prop_used > *mem_prop_size) { ! 296: ! 297: /* The property doesn't fit within the existing space, so keep doubling it ! 298: until it does */ ! 299: prop_size = *mem_prop_size; ! 300: while (prop_size < prop_used) { ! 301: prop_size *= 2; ! 302: } ! 303: ! 304: /* Allocate the new memory and copy all of the existing information across */ ! 305: *mem_prop = realloc(*mem_prop, prop_size); ! 306: *mem_prop_size = prop_size; ! 307: *mem_prop_used = prop_used; ! 308: } ! 309: ! 310: if (*mem_prop == NULL) { ! 311: /* out of memory! */ ! 312: printk("Unable to allocate memory for memory range property!\n"); ! 313: return; ! 314: } ! 315: ! 316: start = 0; ! 317: ncells = 0; ! 318: prop = *mem_prop; ! 319: ! 320: for (r = range; r; r=r->next) { ! 321: if (r->start >= top_address) { ! 322: break; ! 323: } ! 324: ! 325: size = r->start - start; ! 326: if (size) { ! 327: ofmem_arch_create_available_entry(ph, &prop[ncells], start, size); ! 328: ncells += ofmem_arch_get_available_entry_size(ph); ! 329: } ! 330: start = r->start + r->size; ! 331: } ! 332: ! 333: /* tail */ ! 334: if (start < top_address) { ! 335: ofmem_arch_create_available_entry(ph, &prop[ncells], start, top_address - start); ! 336: ncells += ofmem_arch_get_available_entry_size(ph); ! 337: } ! 338: ! 339: ofmem_set_property(ph, "available", ! 340: (char*)prop, ncells * sizeof(prop[0])); ! 341: } ! 342: ! 343: static void ofmem_update_translations( void ) ! 344: { ! 345: ofmem_t *ofmem = ofmem_arch_get_private(); ! 346: ! 347: ofmem_update_memory_available(s_phandle_memory, ofmem->phys_range, ! 348: &phys_range_prop, &phys_range_prop_size, &phys_range_prop_used, ofmem_arch_get_phys_top()); ! 349: ofmem_update_memory_available(s_phandle_mmu, ofmem->virt_range, ! 350: &virt_range_prop, &virt_range_prop_size, &virt_range_prop_used, (ucell)-1); ! 351: ofmem_update_mmu_translations(); ! 352: } ! 353: ! 354: ! 355: /************************************************************************/ ! 356: /* client interface */ ! 357: /************************************************************************/ ! 358: ! 359: static int is_free( phys_addr_t ea, ucell size, range_t *r ) ! 360: { ! 361: if( size == 0 ) ! 362: return 1; ! 363: for( ; r ; r=r->next ) { ! 364: if( r->start + r->size - 1 >= ea && r->start <= ea ) ! 365: return 0; ! 366: if( r->start >= ea && r->start <= ea + size - 1 ) ! 367: return 0; ! 368: } ! 369: return 1; ! 370: } ! 371: ! 372: static void add_entry_( phys_addr_t ea, ucell size, range_t **r ) ! 373: { ! 374: range_t *nr; ! 375: ! 376: for( ; *r && (**r).start < ea; r=&(**r).next ) { ! 377: } ! 378: ! 379: nr = (range_t*)malloc( sizeof(range_t) ); ! 380: nr->next = *r; ! 381: nr->start = ea; ! 382: nr->size = size; ! 383: *r = nr; ! 384: } ! 385: ! 386: static int add_entry( phys_addr_t ea, ucell size, range_t **r ) ! 387: { ! 388: if( !is_free( ea, size, *r ) ) { ! 389: OFMEM_TRACE("add_entry: range not free!\n"); ! 390: return -1; ! 391: } ! 392: add_entry_( ea, size, r ); ! 393: return 0; ! 394: } ! 395: ! 396: #if defined(OFMEM_FILL_RANGE) ! 397: static void join_ranges( range_t **rr ) ! 398: { ! 399: range_t *n, *r = *rr; ! 400: while( r ) { ! 401: if( !(n=r->next) ) ! 402: break; ! 403: ! 404: if( r->start + r->size - 1 >= n->start -1 ) { ! 405: int s = n->size + (n->start - r->start - r->size); ! 406: if( s > 0 ) ! 407: r->size += s; ! 408: r->next = n->next; ! 409: free( n ); ! 410: continue; ! 411: } ! 412: r=r->next; ! 413: } ! 414: } ! 415: ! 416: static void fill_range( phys_addr_t ea, ucell size, range_t **rr ) ! 417: { ! 418: add_entry_( ea, size, rr ); ! 419: join_ranges( rr ); ! 420: } ! 421: #endif ! 422: ! 423: static ucell find_area( ucell align, ucell size, range_t *r, ! 424: phys_addr_t min, phys_addr_t max, int reverse ) ! 425: { ! 426: phys_addr_t base = min; ! 427: range_t *r2; ! 428: ! 429: if( (align & (align-1)) ) { ! 430: OFMEM_TRACE("bad alignment " FMT_ucell "\n", align); ! 431: align = 0x1000; ! 432: } ! 433: if( !align ) ! 434: align = 0x1000; ! 435: ! 436: base = reverse ? max - size : min; ! 437: r2 = reverse ? NULL : r; ! 438: ! 439: for( ;; ) { ! 440: if( !reverse ) { ! 441: base = (base + align - 1) & ~(align-1); ! 442: if( base < min ) ! 443: base = min; ! 444: if( base + size - 1 >= max -1 ) ! 445: break; ! 446: } else { ! 447: if( base > max - size ) ! 448: base = max - size; ! 449: base -= base & (align-1); ! 450: } ! 451: if( is_free( base, size, r ) ) ! 452: return base; ! 453: ! 454: if( !reverse ) { ! 455: if( !r2 ) ! 456: break; ! 457: base = r2->start + r2->size; ! 458: r2 = r2->next; ! 459: } else { ! 460: range_t *rp; ! 461: ! 462: for( rp=r; rp && rp->next != r2 ; rp=rp->next ) { ! 463: } ! 464: ! 465: r2 = rp; ! 466: if( !r2 ) ! 467: break; ! 468: base = r2->start - size; ! 469: } ! 470: } ! 471: return -1; ! 472: } ! 473: ! 474: static phys_addr_t ofmem_claim_phys_( phys_addr_t phys, ucell size, ucell align, ! 475: phys_addr_t min, phys_addr_t max, int reverse ) ! 476: { ! 477: ofmem_t *ofmem = ofmem_arch_get_private(); ! 478: if( !align ) { ! 479: if( !is_free( phys, size, ofmem->phys_range ) ) { ! 480: OFMEM_TRACE("Non-free physical memory claimed!\n"); ! 481: return -1; ! 482: } ! 483: add_entry( phys, size, &ofmem->phys_range ); ! 484: ofmem_update_translations(); ! 485: return phys; ! 486: } ! 487: phys = find_area( align, size, ofmem->phys_range, min, max, reverse ); ! 488: if( phys == -1 ) { ! 489: printk("ofmem_claim_phys - out of space (failed request for " FMT_ucellx " bytes)\n", size); ! 490: return -1; ! 491: } ! 492: add_entry( phys, size, &ofmem->phys_range ); ! 493: ! 494: ofmem_update_translations(); ! 495: ! 496: return phys; ! 497: } ! 498: ! 499: /* if align != 0, phys is ignored. Returns -1 on error */ ! 500: phys_addr_t ofmem_claim_phys( phys_addr_t phys, ucell size, ucell align ) ! 501: { ! 502: OFMEM_TRACE("ofmem_claim phys=" FMT_plx " size=" FMT_ucellx ! 503: " align=" FMT_ucellx "\n", ! 504: phys, size, align); ! 505: ! 506: return ofmem_claim_phys_( phys, size, align, 0, ofmem_arch_get_phys_top(), 1 ); ! 507: } ! 508: ! 509: static ucell ofmem_claim_virt_( ucell virt, ucell size, ucell align, ! 510: ucell min, ucell max, int reverse ) ! 511: { ! 512: ofmem_t *ofmem = ofmem_arch_get_private(); ! 513: if( !align ) { ! 514: if( !is_free( virt, size, ofmem->virt_range ) ) { ! 515: OFMEM_TRACE("Non-free virtual memory claimed!\n"); ! 516: return -1; ! 517: } ! 518: add_entry( virt, size, &ofmem->virt_range ); ! 519: ofmem_update_translations(); ! 520: return virt; ! 521: } ! 522: ! 523: virt = find_area( align, size, ofmem->virt_range, min, max, reverse ); ! 524: if( virt == -1 ) { ! 525: printk("ofmem_claim_virt - out of space (failed request for " FMT_ucellx " bytes)\n", size); ! 526: return -1; ! 527: } ! 528: add_entry( virt, size, &ofmem->virt_range ); ! 529: ! 530: ofmem_update_translations(); ! 531: ! 532: return virt; ! 533: } ! 534: ! 535: ucell ofmem_claim_virt( ucell virt, ucell size, ucell align ) ! 536: { ! 537: OFMEM_TRACE("ofmem_claim_virt virt=" FMT_ucellx " size=" FMT_ucellx ! 538: " align=" FMT_ucellx "\n", ! 539: virt, size, align); ! 540: ! 541: /* printk("+ ofmem_claim virt %08lx %lx %ld\n", virt, size, align ); */ ! 542: return ofmem_claim_virt_( virt, size, align, ! 543: get_ram_size(), ofmem_arch_get_virt_top(), 1 ); ! 544: } ! 545: ! 546: static ucell ofmem_claim_io_( ucell virt, ucell size, ucell align, ! 547: ucell min, ucell max, int reverse ) ! 548: { ! 549: ofmem_t *ofmem = ofmem_arch_get_private(); ! 550: if( !align ) { ! 551: if( !is_free( virt, size, ofmem->io_range ) ) { ! 552: OFMEM_TRACE("Non-free I/O memory claimed!\n"); ! 553: return -1; ! 554: } ! 555: add_entry( virt, size, &ofmem->io_range ); ! 556: return virt; ! 557: } ! 558: ! 559: virt = find_area( align, size, ofmem->io_range, min, max, reverse ); ! 560: if( virt == -1 ) { ! 561: printk("ofmem_claim_io - out of space (failed request for " FMT_ucellx " bytes)\n", size); ! 562: return -1; ! 563: } ! 564: add_entry( virt, size, &ofmem->io_range ); ! 565: return virt; ! 566: } ! 567: ! 568: ucell ofmem_claim_io( ucell virt, ucell size, ucell align ) ! 569: { ! 570: /* Claim a section of memory from the I/O range */ ! 571: return ofmem_claim_io_( virt, size, align, ! 572: ofmem_arch_get_iomem_base(), ofmem_arch_get_iomem_top(), 0 ); ! 573: } ! 574: ! 575: /* if align != 0, phys is ignored. Returns -1 on error */ ! 576: phys_addr_t ofmem_retain( phys_addr_t phys, ucell size, ucell align ) ! 577: { ! 578: retain_t *retained = ofmem_arch_get_retained(); ! 579: phys_addr_t retain_phys; ! 580: ! 581: OFMEM_TRACE("ofmem_retain phys=" FMT_plx " size=" FMT_ucellx ! 582: " align=" FMT_ucellx "\n", ! 583: phys, size, align); ! 584: ! 585: retain_phys = ofmem_claim_phys_( phys, size, align, 0, get_ram_size(), 0 ); ! 586: ! 587: /* Add to the retain_phys_range list */ ! 588: retained->retain_phys_range[retained->numentries].next = NULL; ! 589: retained->retain_phys_range[retained->numentries].start = retain_phys; ! 590: retained->retain_phys_range[retained->numentries].size = size; ! 591: retained->numentries++; ! 592: ! 593: return retain_phys; ! 594: } ! 595: ! 596: /* allocate both physical and virtual space and add a translation */ ! 597: ucell ofmem_claim( ucell addr, ucell size, ucell align ) ! 598: { ! 599: ofmem_t *ofmem = ofmem_arch_get_private(); ! 600: ucell virt; ! 601: phys_addr_t phys; ! 602: ucell offs = addr & 0xfff; ! 603: ! 604: OFMEM_TRACE("ofmem_claim " FMT_ucellx " " FMT_ucellx " " FMT_ucellx "\n", addr, size, align ); ! 605: virt = phys = 0; ! 606: if( !align ) { ! 607: if( is_free(addr, size, ofmem->virt_range) && ! 608: is_free(addr, size, ofmem->phys_range) ) { ! 609: ofmem_claim_phys_( addr, size, 0, 0, 0, 0 ); ! 610: ofmem_claim_virt_( addr, size, 0, 0, 0, 0 ); ! 611: virt = phys = addr; ! 612: } else { ! 613: OFMEM_TRACE("**** ofmem_claim failure ***!\n"); ! 614: return -1; ! 615: } ! 616: } else { ! 617: if( align < 0x1000 ) ! 618: align = 0x1000; ! 619: phys = ofmem_claim_phys_( addr, size, align, 0, ofmem_arch_get_phys_top(), 1 /* reverse */ ); ! 620: virt = ofmem_claim_virt_( addr, size, align, 0, get_ram_size(), 1 /* reverse */ ); ! 621: if( phys == -1 || virt == -1 ) { ! 622: OFMEM_TRACE("ofmem_claim failed\n"); ! 623: return -1; ! 624: } ! 625: /* printk("...phys = %08lX, virt = %08lX, size = %08lX\n", phys, virt, size ); */ ! 626: } ! 627: ! 628: /* align */ ! 629: if( phys & 0xfff ) { ! 630: size += (phys & 0xfff); ! 631: virt -= (phys & 0xfff); ! 632: phys &= ~0xfff; ! 633: } ! 634: if( size & 0xfff ) ! 635: size = (size + 0xfff) & ~0xfff; ! 636: ! 637: /* printk("...free memory found... phys: %08lX, virt: %08lX, size %lX\n", phys, virt, size ); */ ! 638: ofmem_map( phys, virt, size, -1 ); ! 639: return virt + offs; ! 640: } ! 641: ! 642: ! 643: /************************************************************************/ ! 644: /* keep track of ea -> phys translations */ ! 645: /************************************************************************/ ! 646: ! 647: static void split_trans( ucell virt ) ! 648: { ! 649: ofmem_t *ofmem = ofmem_arch_get_private(); ! 650: translation_t *t, *t2; ! 651: ! 652: for( t=ofmem->trans; t; t=t->next ) { ! 653: if( virt > t->virt && virt < t->virt + t->size-1 ) { ! 654: t2 = (translation_t*)malloc( sizeof(translation_t) ); ! 655: t2->virt = virt; ! 656: t2->size = t->size - (virt - t->virt); ! 657: t->size = virt - t->virt; ! 658: t2->phys = t->phys + t->size; ! 659: t2->mode = t->mode; ! 660: t2->next = t->next; ! 661: t->next = t2; ! 662: } ! 663: } ! 664: } ! 665: ! 666: int ofmem_map_page_range( phys_addr_t phys, ucell virt, ucell size, ucell mode ) ! 667: { ! 668: ofmem_t *ofmem = ofmem_arch_get_private(); ! 669: translation_t *t, **tt; ! 670: ! 671: OFMEM_TRACE("ofmem_map_page_range " FMT_ucellx ! 672: " -> " FMT_plx " " FMT_ucellx " mode " FMT_ucellx "\n", ! 673: virt, phys, size, mode ); ! 674: ! 675: split_trans( virt ); ! 676: split_trans( virt + size ); ! 677: ! 678: /* detect remappings */ ! 679: for( t=ofmem->trans; t; ) { ! 680: if( virt == t->virt || (virt < t->virt && virt + size > t->virt )) { ! 681: if( t->phys + virt - t->virt != phys ) { ! 682: OFMEM_TRACE("mapping altered virt=" FMT_ucellx ")\n", t->virt ); ! 683: } else if( t->mode != mode ){ ! 684: OFMEM_TRACE("mapping mode altered virt=" FMT_ucellx ! 685: " old mode=" FMT_ucellx " new mode=" FMT_ucellx "\n", ! 686: t->virt, t->mode, mode); ! 687: } ! 688: ! 689: for( tt=&ofmem->trans; *tt != t ; tt=&(**tt).next ) { ! 690: } ! 691: ! 692: *tt = t->next; ! 693: ! 694: /* really unmap these pages */ ! 695: ofmem_arch_unmap_pages(t->virt, t->size); ! 696: ! 697: free((char*)t); ! 698: ! 699: t=ofmem->trans; ! 700: continue; ! 701: } ! 702: t=t->next; ! 703: } ! 704: ! 705: /* add mapping */ ! 706: for( tt=&ofmem->trans; *tt && (**tt).virt < virt ; tt=&(**tt).next ) { ! 707: } ! 708: ! 709: t = (translation_t*)malloc( sizeof(translation_t) ); ! 710: t->virt = virt; ! 711: t->phys = phys; ! 712: t->size = size; ! 713: t->mode = mode; ! 714: t->next = *tt; ! 715: *tt = t; ! 716: ! 717: ofmem_update_translations(); ! 718: ! 719: return 0; ! 720: } ! 721: ! 722: static int unmap_page_range( ucell virt, ucell size ) ! 723: { ! 724: ofmem_t *ofmem = ofmem_arch_get_private(); ! 725: translation_t **plink; ! 726: ! 727: /* make sure there is exactly one matching translation entry */ ! 728: ! 729: split_trans( virt ); ! 730: split_trans( virt + size ); ! 731: ! 732: /* find and unlink entries in range */ ! 733: plink = &ofmem->trans; ! 734: ! 735: while (*plink && (*plink)->virt < virt+size) { ! 736: translation_t **plinkentry = plink; ! 737: translation_t *t = *plink; ! 738: ! 739: /* move ahead */ ! 740: plink = &t->next; ! 741: ! 742: if (t->virt >= virt && t->virt + t->size <= virt+size) { ! 743: ! 744: /* unlink entry */ ! 745: *plinkentry = t->next; ! 746: ! 747: OFMEM_TRACE("unmap_page_range found " ! 748: FMT_ucellx " -> " FMT_plx " " FMT_ucellx ! 749: " mode " FMT_ucellx "\n", ! 750: t->virt, t->phys, t->size, t->mode ); ! 751: ! 752: // really map these pages ! 753: ofmem_arch_unmap_pages(t->virt, t->size); ! 754: ! 755: free((char*)t); ! 756: } ! 757: } ! 758: ! 759: ofmem_update_translations(); ! 760: ! 761: return 0; ! 762: } ! 763: ! 764: int ofmem_map( phys_addr_t phys, ucell virt, ucell size, ucell mode ) ! 765: { ! 766: /* printk("+ofmem_map: %08lX --> %08lX (size %08lX, mode 0x%02X)\n", ! 767: virt, phys, size, mode ); */ ! 768: ! 769: if( (phys & 0xfff) || (virt & 0xfff) || (size & 0xfff) ) { ! 770: ! 771: OFMEM_TRACE("ofmem_map: Bad parameters (" ! 772: FMT_plx " " FMT_ucellX " " FMT_ucellX ")\n", ! 773: phys, virt, size ); ! 774: ! 775: phys &= ~0xfff; ! 776: virt &= ~0xfff; ! 777: size = (size + 0xfff) & ~0xfff; ! 778: } ! 779: ! 780: #if defined(OFMEM_FILL_RANGE) ! 781: { ! 782: ofmem_t *ofmem = ofmem_arch_get_private(); ! 783: /* claim any unclaimed virtual memory in the range */ ! 784: fill_range( virt, size, &ofmem->virt_range ); ! 785: /* hmm... we better claim the physical range too */ ! 786: fill_range( phys, size, &ofmem->phys_range ); ! 787: } ! 788: #endif ! 789: ! 790: if (mode==-1) { ! 791: mode = ofmem_arch_default_translation_mode(phys); ! 792: } ! 793: ! 794: /* install translations */ ! 795: ofmem_map_page_range(phys, virt, size, mode); ! 796: ! 797: /* allow arch to install mappings early, e.g. for locked mappings */ ! 798: ofmem_arch_early_map_pages(phys, virt, size, mode); ! 799: ! 800: return 0; ! 801: } ! 802: ! 803: int ofmem_unmap( ucell virt, ucell size ) ! 804: { ! 805: OFMEM_TRACE("ofmem_unmap " FMT_ucellx " " FMT_ucellx "\n", ! 806: virt, size ); ! 807: ! 808: if( (virt & 0xfff) || (size & 0xfff) ) { ! 809: /* printk("ofmem_unmap: Bad parameters (%08lX %08lX)\n", ! 810: virt, size ); */ ! 811: virt &= ~0xfff; ! 812: size = (size + 0xfff) & ~0xfff; ! 813: } ! 814: ! 815: /* remove translations and unmap pages */ ! 816: unmap_page_range(virt, size); ! 817: ! 818: return 0; ! 819: } ! 820: ! 821: ucell ofmem_map_io( phys_addr_t phys, ucell size ) ! 822: { ! 823: /* Claim virtual memory from the I/O range and map the page-aligned ! 824: physical address phys to it, returning the newly allocated ! 825: virtual address */ ! 826: ucell virt, mode; ! 827: phys_addr_t off; ! 828: int npages; ! 829: ! 830: off = phys & (PAGE_SIZE - 1); ! 831: npages = (off + size - 1) / PAGE_SIZE + 1; ! 832: phys &= ~(PAGE_SIZE - 1); ! 833: ! 834: virt = ofmem_claim_io(-1, npages * PAGE_SIZE, PAGE_SIZE); ! 835: ! 836: mode = ofmem_arch_io_translation_mode(off); ! 837: ! 838: ofmem_map_page_range(phys, virt, npages * PAGE_SIZE, mode); ! 839: ofmem_arch_early_map_pages(phys, virt, npages * PAGE_SIZE, mode); ! 840: ! 841: return (virt + off); ! 842: } ! 843: ! 844: /* virtual -> physical. */ ! 845: phys_addr_t ofmem_translate( ucell virt, ucell *mode ) ! 846: { ! 847: ofmem_t *ofmem = ofmem_arch_get_private(); ! 848: translation_t *t; ! 849: ! 850: for( t=ofmem->trans; t && t->virt <= virt ; t=t->next ) { ! 851: ucell offs; ! 852: if( t->virt + t->size - 1 < virt ) ! 853: continue; ! 854: offs = virt - t->virt; ! 855: *mode = t->mode; ! 856: return t->phys + offs; ! 857: } ! 858: ! 859: /*printk("ofmem_translate: no translation defined (%08lx)\n", virt);*/ ! 860: /*print_trans();*/ ! 861: return -1; ! 862: } ! 863: ! 864: static void remove_range( ucell ea, ucell size, range_t **r ) ! 865: { ! 866: OFMEM_TRACE("%s: not implemented\n", __func__); ! 867: } ! 868: ! 869: /* release memory allocated by ofmem_claim_phys */ ! 870: void ofmem_release_phys( phys_addr_t phys, ucell size ) ! 871: { ! 872: OFMEM_TRACE("ofmem_release_phys addr=" FMT_plx " size=" FMT_ucellx "\n", ! 873: phys, size); ! 874: ! 875: ofmem_t *ofmem = ofmem_arch_get_private(); ! 876: remove_range(phys, size, &ofmem->phys_range); ! 877: } ! 878: ! 879: /* release memory allocated by ofmem_claim_virt */ ! 880: void ofmem_release_virt( ucell virt, ucell size ) ! 881: { ! 882: OFMEM_TRACE("ofmem_release_virt addr=" FMT_ucellx " size=" FMT_ucellx "\n", ! 883: virt, size); ! 884: ! 885: ofmem_t *ofmem = ofmem_arch_get_private(); ! 886: remove_range(virt, size, &ofmem->virt_range); ! 887: } ! 888: ! 889: /* release memory allocated by ofmem_claim - 6.3.2.4 */ ! 890: void ofmem_release( ucell virt, ucell size ) ! 891: { ! 892: OFMEM_TRACE("%s addr=" FMT_ucellx " size=" FMT_ucellx "\n", ! 893: __func__, virt, size); ! 894: ! 895: ucell mode; ! 896: phys_addr_t phys = ofmem_translate(virt, &mode); ! 897: if (phys == (phys_addr_t)-1) { ! 898: OFMEM_TRACE("%s: no mapping\n", __func__); ! 899: return; ! 900: } ! 901: ofmem_unmap(virt, size); ! 902: ofmem_release_virt(virt, size); ! 903: ofmem_release_phys(phys, size); ! 904: } ! 905: ! 906: /************************************************************************/ ! 907: /* init / cleanup */ ! 908: /************************************************************************/ ! 909: ! 910: void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu ) ! 911: { ! 912: s_phandle_memory = ph_memory; ! 913: s_phandle_mmu = ph_mmu; ! 914: ! 915: /* Initialise some default property sizes */ ! 916: trans_prop_size = phys_range_prop_size = virt_range_prop_size = OFMEM_DEFAULT_PROP_SIZE; ! 917: trans_prop = malloc(trans_prop_size); ! 918: phys_range_prop = malloc(phys_range_prop_size); ! 919: virt_range_prop = malloc(virt_range_prop_size); ! 920: ! 921: ofmem_update_translations(); ! 922: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.