|
|
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.