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