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