17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*56f33205SJonathan Adams  * Common Development and Distribution License (the "License").
6*56f33205SJonathan Adams  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*56f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/promif.h>
297c478bd9Sstevel@tonic-gate #include <sys/memlist.h>
307c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
317c478bd9Sstevel@tonic-gate #include <sys/salib.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * This file defines the interface from the prom and platform-dependent
357c478bd9Sstevel@tonic-gate  * form of the memory lists, to boot's more generic form of the memory
367c478bd9Sstevel@tonic-gate  * list.  For sun4u, the memory list properties are {hi, lo, size_hi, size_lo},
377c478bd9Sstevel@tonic-gate  * which is similar to boot's format, except boot's format is a linked
387c478bd9Sstevel@tonic-gate  * list, and the prom's is an array of these structures. Note that the
397c478bd9Sstevel@tonic-gate  * native property on sparc machines is identical to the property encoded
407c478bd9Sstevel@tonic-gate  * format, so no property decoding is required.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * Note that the format of the memory lists is really 4 encoded integers,
437c478bd9Sstevel@tonic-gate  * but the encoding is the same as that given in the following structure
447c478bd9Sstevel@tonic-gate  * on SPARC systems ...
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate struct sun4u_prom_memlist {
487c478bd9Sstevel@tonic-gate 	u_longlong_t	addr;
497c478bd9Sstevel@tonic-gate 	u_longlong_t	size;
507c478bd9Sstevel@tonic-gate };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate struct sun4u_prom_memlist scratch_memlist[200];
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate struct memlist *fill_memlists(char *name, char *prop, struct memlist *);
557c478bd9Sstevel@tonic-gate extern struct memlist *pfreelistp, *vfreelistp, *pinstalledp;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static struct memlist *reg_to_list(struct sun4u_prom_memlist *a, size_t size,
587c478bd9Sstevel@tonic-gate     struct memlist *old);
597c478bd9Sstevel@tonic-gate static void sort_reglist(struct sun4u_prom_memlist *ar, size_t size);
607c478bd9Sstevel@tonic-gate extern void kmem_init(void);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate void
init_memlists(void)637c478bd9Sstevel@tonic-gate init_memlists(void)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	/* this list is a map of pmem actually installed */
667c478bd9Sstevel@tonic-gate 	pinstalledp = fill_memlists("memory", "reg", pinstalledp);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	vfreelistp = fill_memlists("virtual-memory", "available", vfreelistp);
697c478bd9Sstevel@tonic-gate 	pfreelistp = fill_memlists("memory", "available", pfreelistp);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	kmem_init();
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate struct memlist *
fill_memlists(char * name,char * prop,struct memlist * old)757c478bd9Sstevel@tonic-gate fill_memlists(char *name, char *prop, struct memlist *old)
767c478bd9Sstevel@tonic-gate {
77fa9e4066Sahrens 	static pnode_t pmem = 0;
78fa9e4066Sahrens 	static pnode_t pmmu = 0;
79fa9e4066Sahrens 	pnode_t node;
807c478bd9Sstevel@tonic-gate 	size_t links;
817c478bd9Sstevel@tonic-gate 	struct memlist *al;
827c478bd9Sstevel@tonic-gate 	struct sun4u_prom_memlist *pm = scratch_memlist;
837c478bd9Sstevel@tonic-gate 
84fa9e4066Sahrens 	if (pmem == (pnode_t)0)  {
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 		/*
877c478bd9Sstevel@tonic-gate 		 * Figure out the interesting phandles, one time
887c478bd9Sstevel@tonic-gate 		 * only.
897c478bd9Sstevel@tonic-gate 		 */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 		ihandle_t ih;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 		if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1)
947c478bd9Sstevel@tonic-gate 			prom_panic("Can't get mmu ihandle");
957c478bd9Sstevel@tonic-gate 		pmmu = prom_getphandle(ih);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		if ((ih = prom_memory_ihandle()) == (ihandle_t)-1)
987c478bd9Sstevel@tonic-gate 			prom_panic("Can't get memory ihandle");
997c478bd9Sstevel@tonic-gate 		pmem = prom_getphandle(ih);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (strcmp(name, "memory") == 0)
1037c478bd9Sstevel@tonic-gate 		node = pmem;
1047c478bd9Sstevel@tonic-gate 	else
1057c478bd9Sstevel@tonic-gate 		node = pmmu;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * Read memory node and calculate the number of entries
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	if ((links = prom_getproplen(node, prop)) == -1)
1117c478bd9Sstevel@tonic-gate 		prom_panic("Cannot get list.\n");
1127c478bd9Sstevel@tonic-gate 	if (links > sizeof (scratch_memlist)) {
1137c478bd9Sstevel@tonic-gate 		prom_printf("%s list <%s> exceeds boot capabilities\n",
114*56f33205SJonathan Adams 		    name, prop);
1157c478bd9Sstevel@tonic-gate 		prom_panic("fill_memlists - memlist size");
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 	links = links / sizeof (struct sun4u_prom_memlist);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	(void) prom_getprop(node, prop, (caddr_t)pm);
1217c478bd9Sstevel@tonic-gate 	sort_reglist(pm, links);
1227c478bd9Sstevel@tonic-gate 	al = reg_to_list(pm, links, old);
1237c478bd9Sstevel@tonic-gate 	return (al);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  *  Simple selection sort routine.
1287c478bd9Sstevel@tonic-gate  *  Sorts platform dependent memory lists into ascending order
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static void
sort_reglist(struct sun4u_prom_memlist * ar,size_t n)1327c478bd9Sstevel@tonic-gate sort_reglist(struct sun4u_prom_memlist *ar, size_t n)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	int i, j, min;
1357c478bd9Sstevel@tonic-gate 	struct sun4u_prom_memlist temp;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
1387c478bd9Sstevel@tonic-gate 		min = i;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 		for (j = i+1; j < n; j++)  {
1417c478bd9Sstevel@tonic-gate 			if (ar[j].addr < ar[min].addr)
1427c478bd9Sstevel@tonic-gate 				min = j;
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		if (i != min)  {
1467c478bd9Sstevel@tonic-gate 			/* Swap ar[i] and ar[min] */
1477c478bd9Sstevel@tonic-gate 			temp = ar[min];
1487c478bd9Sstevel@tonic-gate 			ar[min] = ar[i];
1497c478bd9Sstevel@tonic-gate 			ar[i] = temp;
1507c478bd9Sstevel@tonic-gate 		}
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  *  This routine will convert our platform dependent memory list into
1567c478bd9Sstevel@tonic-gate  *  struct memlists's.  And it will also coalesce adjacent  nodes if
1577c478bd9Sstevel@tonic-gate  *  possible.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static struct memlist *
reg_to_list(struct sun4u_prom_memlist * ar,size_t n,struct memlist * old)1607c478bd9Sstevel@tonic-gate reg_to_list(struct sun4u_prom_memlist *ar, size_t n, struct memlist *old)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	struct memlist *ptr, *head, *last;
1637c478bd9Sstevel@tonic-gate 	int i;
1647c478bd9Sstevel@tonic-gate 	u_longlong_t size = 0;
1657c478bd9Sstevel@tonic-gate 	u_longlong_t addr = 0;
1667c478bd9Sstevel@tonic-gate 	u_longlong_t start1, start2;
1677c478bd9Sstevel@tonic-gate 	int flag = 0;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (n == 0)
1707c478bd9Sstevel@tonic-gate 		return ((struct memlist *)0);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * if there was a memory list allocated before, free it first.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 	if (old)
1767c478bd9Sstevel@tonic-gate 		(void) add_to_freelist(old);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	head = NULL;
1797c478bd9Sstevel@tonic-gate 	last = NULL;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
1827c478bd9Sstevel@tonic-gate 		start1 = ar[i].addr;
1837c478bd9Sstevel@tonic-gate 		start2 = ar[i+1].addr;
1847c478bd9Sstevel@tonic-gate 		if (i < n-1 && (start1 + ar[i].size == start2)) {
1857c478bd9Sstevel@tonic-gate 			size += ar[i].size;
1867c478bd9Sstevel@tonic-gate 			if (!flag) {
1877c478bd9Sstevel@tonic-gate 				addr = start1;
1887c478bd9Sstevel@tonic-gate 				flag++;
1897c478bd9Sstevel@tonic-gate 			}
1907c478bd9Sstevel@tonic-gate 			continue;
1917c478bd9Sstevel@tonic-gate 		} else if (flag) {
1927c478bd9Sstevel@tonic-gate 			/*
1937c478bd9Sstevel@tonic-gate 			 * catch the last one on the way out of
1947c478bd9Sstevel@tonic-gate 			 * this iteration
1957c478bd9Sstevel@tonic-gate 			 */
1967c478bd9Sstevel@tonic-gate 			size += ar[i].size;
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		ptr = (struct memlist *)get_memlist_struct();
2007c478bd9Sstevel@tonic-gate 		if (!head)
2017c478bd9Sstevel@tonic-gate 			head = ptr;
2027c478bd9Sstevel@tonic-gate 		if (last)
203*56f33205SJonathan Adams 			last->ml_next = ptr;
204*56f33205SJonathan Adams 		ptr->ml_address = flag ? addr : start1;
205*56f33205SJonathan Adams 		ptr->ml_size = size ? size : ar[i].size;
206*56f33205SJonathan Adams 		ptr->ml_prev = last;
2077c478bd9Sstevel@tonic-gate 		last = ptr;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		size = 0;
2107c478bd9Sstevel@tonic-gate 		flag = 0;
2117c478bd9Sstevel@tonic-gate 		addr = 0;
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
214*56f33205SJonathan Adams 	last->ml_next = NULL;
2157c478bd9Sstevel@tonic-gate 	return (head);
2167c478bd9Sstevel@tonic-gate }
217