1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/promif.h>
29 #include <sys/memlist.h>
30 #include <sys/bootconf.h>
31 #include <sys/salib.h>
32
33 /*
34 * This file defines the interface from the prom and platform-dependent
35 * form of the memory lists, to boot's more generic form of the memory
36 * list. For sun4u, the memory list properties are {hi, lo, size_hi, size_lo},
37 * which is similar to boot's format, except boot's format is a linked
38 * list, and the prom's is an array of these structures. Note that the
39 * native property on sparc machines is identical to the property encoded
40 * format, so no property decoding is required.
41 *
42 * Note that the format of the memory lists is really 4 encoded integers,
43 * but the encoding is the same as that given in the following structure
44 * on SPARC systems ...
45 */
46
47 struct sun4u_prom_memlist {
48 u_longlong_t addr;
49 u_longlong_t size;
50 };
51
52 struct sun4u_prom_memlist scratch_memlist[200];
53
54 struct memlist *fill_memlists(char *name, char *prop, struct memlist *);
55 extern struct memlist *pfreelistp, *vfreelistp, *pinstalledp;
56
57 static struct memlist *reg_to_list(struct sun4u_prom_memlist *a, size_t size,
58 struct memlist *old);
59 static void sort_reglist(struct sun4u_prom_memlist *ar, size_t size);
60 extern void kmem_init(void);
61
62 void
init_memlists(void)63 init_memlists(void)
64 {
65 /* this list is a map of pmem actually installed */
66 pinstalledp = fill_memlists("memory", "reg", pinstalledp);
67
68 vfreelistp = fill_memlists("virtual-memory", "available", vfreelistp);
69 pfreelistp = fill_memlists("memory", "available", pfreelistp);
70
71 kmem_init();
72 }
73
74 struct memlist *
fill_memlists(char * name,char * prop,struct memlist * old)75 fill_memlists(char *name, char *prop, struct memlist *old)
76 {
77 static pnode_t pmem = 0;
78 static pnode_t pmmu = 0;
79 pnode_t node;
80 size_t links;
81 struct memlist *al;
82 struct sun4u_prom_memlist *pm = scratch_memlist;
83
84 if (pmem == (pnode_t)0) {
85
86 /*
87 * Figure out the interesting phandles, one time
88 * only.
89 */
90
91 ihandle_t ih;
92
93 if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1)
94 prom_panic("Can't get mmu ihandle");
95 pmmu = prom_getphandle(ih);
96
97 if ((ih = prom_memory_ihandle()) == (ihandle_t)-1)
98 prom_panic("Can't get memory ihandle");
99 pmem = prom_getphandle(ih);
100 }
101
102 if (strcmp(name, "memory") == 0)
103 node = pmem;
104 else
105 node = pmmu;
106
107 /*
108 * Read memory node and calculate the number of entries
109 */
110 if ((links = prom_getproplen(node, prop)) == -1)
111 prom_panic("Cannot get list.\n");
112 if (links > sizeof (scratch_memlist)) {
113 prom_printf("%s list <%s> exceeds boot capabilities\n",
114 name, prop);
115 prom_panic("fill_memlists - memlist size");
116 }
117 links = links / sizeof (struct sun4u_prom_memlist);
118
119
120 (void) prom_getprop(node, prop, (caddr_t)pm);
121 sort_reglist(pm, links);
122 al = reg_to_list(pm, links, old);
123 return (al);
124 }
125
126 /*
127 * Simple selection sort routine.
128 * Sorts platform dependent memory lists into ascending order
129 */
130
131 static void
sort_reglist(struct sun4u_prom_memlist * ar,size_t n)132 sort_reglist(struct sun4u_prom_memlist *ar, size_t n)
133 {
134 int i, j, min;
135 struct sun4u_prom_memlist temp;
136
137 for (i = 0; i < n; i++) {
138 min = i;
139
140 for (j = i+1; j < n; j++) {
141 if (ar[j].addr < ar[min].addr)
142 min = j;
143 }
144
145 if (i != min) {
146 /* Swap ar[i] and ar[min] */
147 temp = ar[min];
148 ar[min] = ar[i];
149 ar[i] = temp;
150 }
151 }
152 }
153
154 /*
155 * This routine will convert our platform dependent memory list into
156 * struct memlists's. And it will also coalesce adjacent nodes if
157 * possible.
158 */
159 static struct memlist *
reg_to_list(struct sun4u_prom_memlist * ar,size_t n,struct memlist * old)160 reg_to_list(struct sun4u_prom_memlist *ar, size_t n, struct memlist *old)
161 {
162 struct memlist *ptr, *head, *last;
163 int i;
164 u_longlong_t size = 0;
165 u_longlong_t addr = 0;
166 u_longlong_t start1, start2;
167 int flag = 0;
168
169 if (n == 0)
170 return ((struct memlist *)0);
171
172 /*
173 * if there was a memory list allocated before, free it first.
174 */
175 if (old)
176 (void) add_to_freelist(old);
177
178 head = NULL;
179 last = NULL;
180
181 for (i = 0; i < n; i++) {
182 start1 = ar[i].addr;
183 start2 = ar[i+1].addr;
184 if (i < n-1 && (start1 + ar[i].size == start2)) {
185 size += ar[i].size;
186 if (!flag) {
187 addr = start1;
188 flag++;
189 }
190 continue;
191 } else if (flag) {
192 /*
193 * catch the last one on the way out of
194 * this iteration
195 */
196 size += ar[i].size;
197 }
198
199 ptr = (struct memlist *)get_memlist_struct();
200 if (!head)
201 head = ptr;
202 if (last)
203 last->ml_next = ptr;
204 ptr->ml_address = flag ? addr : start1;
205 ptr->ml_size = size ? size : ar[i].size;
206 ptr->ml_prev = last;
207 last = ptr;
208
209 size = 0;
210 flag = 0;
211 addr = 0;
212 }
213
214 last->ml_next = NULL;
215 return (head);
216 }
217