memory.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Carsten Langgaard, carstenl@mips.com
  3.  * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
  4.  *
  5.  * ########################################################################
  6.  *
  7.  *  This program is free software; you can distribute it and/or modify it
  8.  *  under the terms of the GNU General Public License (Version 2) as
  9.  *  published by the Free Software Foundation.
  10.  *
  11.  *  This program is distributed in the hope it will be useful, but WITHOUT
  12.  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  *  for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License along
  17.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  18.  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  19.  *
  20.  * ########################################################################
  21.  *
  22.  * PROM library functions for acquiring/using memory descriptors given to 
  23.  * us from the YAMON.
  24.  * 
  25.  */
  26. #include <linux/config.h>
  27. #include <linux/init.h>
  28. #include <linux/mm.h>
  29. #include <linux/bootmem.h>
  30. #include <asm/bootinfo.h>
  31. #include <asm/page.h>
  32. #include <asm/mips-boards/prom.h>
  33. /*#define DEBUG*/
  34. enum yamon_memtypes {
  35. yamon_dontuse,
  36. yamon_prom,
  37. yamon_free,
  38. };
  39. struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
  40. #define MEMTYPE_DONTUSE 0
  41. #define MEMTYPE_PROM    1
  42. #define MEMTYPE_FREE    2
  43. #ifdef DEBUG
  44. static char *mtypes[3] = {
  45. "Dont use memory",
  46. "YAMON PROM memory",
  47. "Free memmory",
  48. };
  49. #endif
  50. /* References to section boundaries */
  51. extern char _end;
  52. #define PFN_ALIGN(x)    (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
  53. struct prom_pmemblock * __init prom_getmdesc(void)
  54. {
  55. char *memsize_str;
  56. unsigned int memsize;
  57. memsize_str = prom_getenv("memsize");
  58. if (!memsize_str) {
  59. prom_printf("memsize not set in boot prom, set to default (32Mb)n");
  60. memsize = 0x02000000;
  61. } else {
  62. #ifdef DEBUG
  63. prom_printf("prom_memsize = %sn", memsize_str);
  64. #endif
  65. memsize = simple_strtol(memsize_str, NULL, 0);
  66. }
  67. memset(mdesc, 0, sizeof(mdesc));
  68. mdesc[0].type = yamon_dontuse;
  69. mdesc[0].base = 0x00000000;
  70. mdesc[0].size = 0x00001000;
  71. mdesc[1].type = yamon_prom;
  72. mdesc[1].base = 0x00001000;
  73. mdesc[1].size = 0x000ef000;
  74. #if (CONFIG_MIPS_MALTA)
  75. /* 
  76.  * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
  77.  * south bridge and PCI access always forwarded to the ISA Bus and 
  78.  * BIOSCS# is always generated.
  79.  * This mean that this area can't be used as DMA memory for PCI 
  80.  * devices.
  81.  */
  82. mdesc[2].type = yamon_dontuse;
  83. mdesc[2].base = 0x000f0000;
  84. mdesc[2].size = 0x00010000;
  85. #else
  86. mdesc[2].type = yamon_prom;
  87. mdesc[2].base = 0x000f0000;
  88. mdesc[2].size = 0x00010000;
  89. #endif
  90. mdesc[3].type = yamon_dontuse;
  91. mdesc[3].base = 0x00100000;
  92. mdesc[3].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[3].base;
  93. mdesc[4].type = yamon_free;
  94. mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
  95. mdesc[4].size = memsize - mdesc[4].base;
  96. return &mdesc[0];
  97. }
  98. int __init page_is_ram(unsigned long pagenr)
  99. {
  100. if ((pagenr << PAGE_SHIFT) < mdesc[4].base + mdesc[4].size)
  101. return 1;
  102. return 0;
  103. }
  104. static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS];
  105. static int __init prom_memtype_classify (unsigned int type)
  106. {
  107. switch (type) {
  108. case yamon_free:
  109. return MEMTYPE_FREE;
  110. case yamon_prom:
  111. return MEMTYPE_PROM;
  112. default:
  113. return MEMTYPE_DONTUSE;
  114. }
  115. }
  116. static inline unsigned long find_max_low_pfn(void)
  117. {
  118. struct prom_pmemblock *p, *highest;
  119. unsigned long pfn;
  120. p = pblocks;
  121. highest = 0;
  122. while (p->size != 0) {
  123. if (!highest || p->base > highest->base)
  124. highest = p;
  125. p++;
  126.         }
  127. pfn = (highest->base + highest->size) >> PAGE_SHIFT;
  128. #ifdef DEBUG
  129. prom_printf("find_max_low_pfn: 0x%lx pfns.n", pfn);
  130. #endif
  131. return pfn;
  132. }
  133. static inline struct prom_pmemblock *find_largest_memblock(void)
  134. {
  135. struct prom_pmemblock *p, *largest;
  136. p = pblocks;
  137. largest = 0;
  138. while (p->size != 0) {
  139. if (!largest || p->size > largest->size)
  140. largest = p;
  141. p++;
  142. }
  143. return largest;
  144. }
  145. void __init prom_meminit(void)
  146. {
  147. struct prom_pmemblock *largest, *p;
  148. unsigned long bootmap_size;
  149. int totram;
  150. int i = 0;
  151. #ifdef DEBUG
  152. prom_printf("YAMON MEMORY DESCRIPTOR dump:n");
  153. p = prom_getmdesc();
  154. while (p->size) {
  155. prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>n",
  156.     i, p, p->base, p->size, mtypes[p->type]);
  157. p++;
  158. i++;
  159. }
  160. #endif
  161. totram = 0;
  162. i = 0;
  163. p = prom_getmdesc();
  164. while (p->size) {
  165. pblocks[i].type = prom_memtype_classify (p->type);
  166. pblocks[i].base = p->base;
  167. pblocks[i].size = p->size;
  168. switch (pblocks[i].type) {
  169. case MEMTYPE_FREE:
  170. totram += pblocks[i].size;
  171. #ifdef DEBUG
  172. prom_printf("free_chunk[%d]: base=%08lx size=%dn",
  173.     i, pblocks[i].base, pblocks[i].size);
  174. #endif
  175. i++;
  176. break;
  177. case MEMTYPE_PROM:
  178. #ifdef DEBUG
  179.         prom_printf("prom_chunk[%d]: base=%08lx size=%dn",
  180.     i, pblocks[i].base, pblocks[i].size);
  181. #endif
  182. i++;
  183. break;
  184. default:
  185. break;
  186. }
  187. p++;
  188. }
  189. pblocks[i].base = 0xdeadbeef;
  190. pblocks[i].size = 0; /* indicates last elem. of array */
  191. max_low_pfn = find_max_low_pfn();
  192. largest = find_largest_memblock();
  193. bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn);
  194. for (i = 0; pblocks[i].size; i++)
  195. if (pblocks[i].type == MEMTYPE_FREE)
  196. free_bootmem(pblocks[i].base, pblocks[i].size);
  197. /* This test is simpleminded.  It will fail if the bootmem bitmap
  198.    falls into multiple adjacent PROM memory areas.  */
  199. if (bootmap_size > largest->size) {
  200. prom_printf("CRITIAL: overwriting PROM data.n");
  201. BUG();
  202. }
  203. /* Reserve the memory bootmap itself */
  204. reserve_bootmem(largest->base, bootmap_size);
  205. printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)n",
  206.        totram, (totram/1024), (totram/1024/1024));
  207. }
  208. void prom_free_prom_memory (void)
  209. {
  210. struct prom_pmemblock *p;
  211. unsigned long freed = 0;
  212. unsigned long addr;
  213. for (p = pblocks; p->size != 0; p++) {
  214. if (p->type != MEMTYPE_PROM)
  215. continue;
  216. addr = p->base;
  217. while (addr < p->base + p->size) {
  218.         ClearPageReserved(virt_to_page(__va(addr)));
  219. set_page_count(virt_to_page(__va(addr)), 1);
  220. free_page(__va(addr));
  221. addr += PAGE_SIZE;
  222. freed += PAGE_SIZE;
  223. }
  224. }
  225. printk("Freeing prom memory: %ldkb freedn", freed >> 10);
  226. }