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.
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
9 #include <linux/kernel.h>
10 #include <linux/init.h>
12 #include <asm/openprom.h>
13 #include <asm/sun4prom.h>
14 #include <asm/oplib.h>
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.
24 struct linux_prom_registers prom_reg_memlist
[64];
25 struct linux_prom_registers prom_reg_tmp
[64];
27 struct linux_mlist_v0 prom_phys_total
[64];
28 struct linux_mlist_v0 prom_prom_taken
[64];
29 struct linux_mlist_v0 prom_phys_avail
[64];
31 struct linux_mlist_v0
*prom_ptot_ptr
= prom_phys_total
;
32 struct linux_mlist_v0
*prom_ptak_ptr
= prom_prom_taken
;
33 struct linux_mlist_v0
*prom_pavl_ptr
= prom_phys_avail
;
35 struct linux_mem_v0 prom_memlist
;
38 /* Internal Prom library routine to sort a linux_mlist_v0 memory
39 * list. Used below in initialization.
42 prom_sortmemlist(struct linux_mlist_v0
*thislist
)
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
;
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
;
63 thislist
[i
].start_adr
= tmpaddr
;
64 thislist
[i
].num_bytes
= tmpsize
;
70 /* Initialize the memory lists based upon the prom version. */
71 void __init
prom_meminit(void)
74 unsigned int iter
, num_regs
;
75 struct linux_mlist_v0
*mptr
; /* ptr for traversal */
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];
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];
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];
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
);
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];
126 prom_phys_avail
[iter
-1].theres_more
= NULL
;
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];
140 prom_phys_total
[iter
-1].theres_more
= NULL
;
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
));
149 /* Convert available virtual areas to taken virtual
150 * areas. First sort, then convert.
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];
160 prom_prom_taken
[iter
-1].theres_more
= NULL
;
162 prom_sortmemlist(prom_prom_taken
);
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
;
173 prom_prom_taken
[iter
-1].num_bytes
=
174 0xffffffff - (unsigned long) prom_prom_taken
[iter
-1].start_adr
;
176 /* Sort the other two lists. */
177 prom_sortmemlist(prom_phys_total
);
178 prom_sortmemlist(prom_phys_avail
);
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
;
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
;
208 /* This returns a pointer to our libraries internal v0 format
211 struct linux_mem_v0
*
214 return &prom_memlist
;