1/* $Id: memory.c,v 1.1.1.1 2007/08/03 18:52:18 Exp $ 2 * memory.c: Prom routine for acquiring various bits of information 3 * about RAM on the machine, both virtual and physical. 4 * 5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6 * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) 7 */ 8 9#include <linux/kernel.h> 10#include <linux/init.h> 11 12#include <asm/openprom.h> 13#include <asm/sun4prom.h> 14#include <asm/oplib.h> 15 16/* This routine, for consistency, returns the ram parameters in the 17 * V0 prom memory descriptor format. I choose this format because I 18 * think it was the easiest to work with. I feel the religious 19 * arguments now... ;) Also, I return the linked lists sorted to 20 * prevent paging_init() upset stomach as I have not yet written 21 * the pepto-bismol kernel module yet. 22 */ 23 24struct linux_prom_registers prom_reg_memlist[64]; 25struct linux_prom_registers prom_reg_tmp[64]; 26 27struct linux_mlist_v0 prom_phys_total[64]; 28struct linux_mlist_v0 prom_prom_taken[64]; 29struct linux_mlist_v0 prom_phys_avail[64]; 30 31struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total; 32struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken; 33struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail; 34 35struct linux_mem_v0 prom_memlist; 36 37 38/* Internal Prom library routine to sort a linux_mlist_v0 memory 39 * list. Used below in initialization. 40 */ 41static void __init 42prom_sortmemlist(struct linux_mlist_v0 *thislist) 43{ 44 int swapi = 0; 45 int i, mitr, tmpsize; 46 char *tmpaddr; 47 char *lowest; 48 49 for(i=0; thislist[i].theres_more; i++) { 50 lowest = thislist[i].start_adr; 51 for(mitr = i+1; thislist[mitr-1].theres_more; mitr++) 52 if(thislist[mitr].start_adr < lowest) { 53 lowest = thislist[mitr].start_adr; 54 swapi = mitr; 55 } 56 if(lowest == thislist[i].start_adr) continue; 57 tmpaddr = thislist[swapi].start_adr; 58 tmpsize = thislist[swapi].num_bytes; 59 for(mitr = swapi; mitr > i; mitr--) { 60 thislist[mitr].start_adr = thislist[mitr-1].start_adr; 61 thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; 62 } 63 thislist[i].start_adr = tmpaddr; 64 thislist[i].num_bytes = tmpsize; 65 } 66 67 return; 68} 69 70/* Initialize the memory lists based upon the prom version. */ 71void __init prom_meminit(void) 72{ 73 int node = 0; 74 unsigned int iter, num_regs; 75 struct linux_mlist_v0 *mptr; /* ptr for traversal */ 76 77 switch(prom_vers) { 78 case PROM_V0: 79 /* Nice, kind of easier to do in this case. */ 80 /* First, the total physical descriptors. */ 81 for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0; 82 mptr; mptr=mptr->theres_more, iter++) { 83 prom_phys_total[iter].start_adr = mptr->start_adr; 84 prom_phys_total[iter].num_bytes = mptr->num_bytes; 85 prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; 86 } 87 prom_phys_total[iter-1].theres_more = NULL; 88 /* Second, the total prom taken descriptors. */ 89 for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0; 90 mptr; mptr=mptr->theres_more, iter++) { 91 prom_prom_taken[iter].start_adr = mptr->start_adr; 92 prom_prom_taken[iter].num_bytes = mptr->num_bytes; 93 prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1]; 94 } 95 prom_prom_taken[iter-1].theres_more = NULL; 96 /* Last, the available physical descriptors. */ 97 for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0; 98 mptr; mptr=mptr->theres_more, iter++) { 99 prom_phys_avail[iter].start_adr = mptr->start_adr; 100 prom_phys_avail[iter].num_bytes = mptr->num_bytes; 101 prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; 102 } 103 prom_phys_avail[iter-1].theres_more = NULL; 104 /* Sort all the lists. */ 105 prom_sortmemlist(prom_phys_total); 106 prom_sortmemlist(prom_prom_taken); 107 prom_sortmemlist(prom_phys_avail); 108 break; 109 case PROM_V2: 110 case PROM_V3: 111 /* Grrr, have to traverse the prom device tree ;( */ 112 node = prom_getchild(prom_root_node); 113 node = prom_searchsiblings(node, "memory"); 114 num_regs = prom_getproperty(node, "available", 115 (char *) prom_reg_memlist, 116 sizeof(prom_reg_memlist)); 117 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 118 for(iter=0; iter<num_regs; iter++) { 119 prom_phys_avail[iter].start_adr = 120 (char *) prom_reg_memlist[iter].phys_addr; 121 prom_phys_avail[iter].num_bytes = 122 (unsigned long) prom_reg_memlist[iter].reg_size; 123 prom_phys_avail[iter].theres_more = 124 &prom_phys_avail[iter+1]; 125 } 126 prom_phys_avail[iter-1].theres_more = NULL; 127 128 num_regs = prom_getproperty(node, "reg", 129 (char *) prom_reg_memlist, 130 sizeof(prom_reg_memlist)); 131 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 132 for(iter=0; iter<num_regs; iter++) { 133 prom_phys_total[iter].start_adr = 134 (char *) prom_reg_memlist[iter].phys_addr; 135 prom_phys_total[iter].num_bytes = 136 (unsigned long) prom_reg_memlist[iter].reg_size; 137 prom_phys_total[iter].theres_more = 138 &prom_phys_total[iter+1]; 139 } 140 prom_phys_total[iter-1].theres_more = NULL; 141 142 node = prom_getchild(prom_root_node); 143 node = prom_searchsiblings(node, "virtual-memory"); 144 num_regs = prom_getproperty(node, "available", 145 (char *) prom_reg_memlist, 146 sizeof(prom_reg_memlist)); 147 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 148 149 /* Convert available virtual areas to taken virtual 150 * areas. First sort, then convert. 151 */ 152 for(iter=0; iter<num_regs; iter++) { 153 prom_prom_taken[iter].start_adr = 154 (char *) prom_reg_memlist[iter].phys_addr; 155 prom_prom_taken[iter].num_bytes = 156 (unsigned long) prom_reg_memlist[iter].reg_size; 157 prom_prom_taken[iter].theres_more = 158 &prom_prom_taken[iter+1]; 159 } 160 prom_prom_taken[iter-1].theres_more = NULL; 161 162 prom_sortmemlist(prom_prom_taken); 163 164 /* Finally, convert. */ 165 for(iter=0; iter<num_regs; iter++) { 166 prom_prom_taken[iter].start_adr = 167 prom_prom_taken[iter].start_adr + 168 prom_prom_taken[iter].num_bytes; 169 prom_prom_taken[iter].num_bytes = 170 prom_prom_taken[iter+1].start_adr - 171 prom_prom_taken[iter].start_adr; 172 } 173 prom_prom_taken[iter-1].num_bytes = 174 0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr; 175 176 /* Sort the other two lists. */ 177 prom_sortmemlist(prom_phys_total); 178 prom_sortmemlist(prom_phys_avail); 179 break; 180 181 case PROM_SUN4: 182#ifdef CONFIG_SUN4 183 /* how simple :) */ 184 prom_phys_total[0].start_adr = NULL; 185 prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize); 186 prom_phys_total[0].theres_more = NULL; 187 prom_prom_taken[0].start_adr = NULL; 188 prom_prom_taken[0].num_bytes = 0x0; 189 prom_prom_taken[0].theres_more = NULL; 190 prom_phys_avail[0].start_adr = NULL; 191 prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail); 192 prom_phys_avail[0].theres_more = NULL; 193#endif 194 break; 195 196 default: 197 break; 198 }; 199 200 /* Link all the lists into the top-level descriptor. */ 201 prom_memlist.v0_totphys=&prom_ptot_ptr; 202 prom_memlist.v0_prommap=&prom_ptak_ptr; 203 prom_memlist.v0_available=&prom_pavl_ptr; 204 205 return; 206} 207 208/* This returns a pointer to our libraries internal v0 format 209 * memory descriptor. 210 */ 211struct linux_mem_v0 * 212prom_meminfo(void) 213{ 214 return &prom_memlist; 215} 216