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