memory.c 6.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $
 * memory.c: Prom routine for acquiring various bits of information
 *           about RAM on the machine, both virtual and physical.
 *
 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <asm/openprom.h>
#include <asm/sun4prom.h>
#include <asm/oplib.h>

/* This routine, for consistency, returns the ram parameters in the
 * V0 prom memory descriptor format.  I choose this format because I
 * think it was the easiest to work with.  I feel the religious
 * arguments now... ;)  Also, I return the linked lists sorted to
 * prevent paging_init() upset stomach as I have not yet written
 * the pepto-bismol kernel module yet.
 */

struct linux_prom_registers prom_reg_memlist[64];
struct linux_prom_registers prom_reg_tmp[64];

struct linux_mlist_v0 prom_phys_total[64];
struct linux_mlist_v0 prom_prom_taken[64];
struct linux_mlist_v0 prom_phys_avail[64];

struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total;
struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken;
struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail;

struct linux_mem_v0 prom_memlist;


/* Internal Prom library routine to sort a linux_mlist_v0 memory
 * list.  Used below in initialization.
 */
static void __init
prom_sortmemlist(struct linux_mlist_v0 *thislist)
{
	int swapi = 0;
	int i, mitr, tmpsize;
	char *tmpaddr;
	char *lowest;

A
Al Viro 已提交
50
	for(i=0; thislist[i].theres_more; i++) {
L
Linus Torvalds 已提交
51
		lowest = thislist[i].start_adr;
A
Al Viro 已提交
52
		for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
L
Linus Torvalds 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
			if(thislist[mitr].start_adr < lowest) {
				lowest = thislist[mitr].start_adr;
				swapi = mitr;
			}
		if(lowest == thislist[i].start_adr) continue;
		tmpaddr = thislist[swapi].start_adr;
		tmpsize = thislist[swapi].num_bytes;
		for(mitr = swapi; mitr > i; mitr--) {
			thislist[mitr].start_adr = thislist[mitr-1].start_adr;
			thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
		}
		thislist[i].start_adr = tmpaddr;
		thislist[i].num_bytes = tmpsize;
	}

	return;
}

/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
	int node = 0;
	unsigned int iter, num_regs;
	struct linux_mlist_v0 *mptr;  /* ptr for traversal */

	switch(prom_vers) {
	case PROM_V0:
		/* Nice, kind of easier to do in this case. */
		/* First, the total physical descriptors. */
		for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0;
		    mptr; mptr=mptr->theres_more, iter++) {
			prom_phys_total[iter].start_adr = mptr->start_adr;
			prom_phys_total[iter].num_bytes = mptr->num_bytes;
			prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
		}
A
Al Viro 已提交
88
		prom_phys_total[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
89 90 91 92 93 94 95
		/* Second, the total prom taken descriptors. */
		for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
		    mptr; mptr=mptr->theres_more, iter++) {
			prom_prom_taken[iter].start_adr = mptr->start_adr;
			prom_prom_taken[iter].num_bytes = mptr->num_bytes;
			prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
		}
A
Al Viro 已提交
96
		prom_prom_taken[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
97 98 99 100 101 102 103
		/* Last, the available physical descriptors. */
		for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
		    mptr; mptr=mptr->theres_more, iter++) {
			prom_phys_avail[iter].start_adr = mptr->start_adr;
			prom_phys_avail[iter].num_bytes = mptr->num_bytes;
			prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
		}
A
Al Viro 已提交
104
		prom_phys_avail[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
		/* Sort all the lists. */
		prom_sortmemlist(prom_phys_total);
		prom_sortmemlist(prom_prom_taken);
		prom_sortmemlist(prom_phys_avail);
		break;
	case PROM_V2:
	case PROM_V3:
		/* Grrr, have to traverse the prom device tree ;( */
		node = prom_getchild(prom_root_node);
		node = prom_searchsiblings(node, "memory");
		num_regs = prom_getproperty(node, "available",
					    (char *) prom_reg_memlist,
					    sizeof(prom_reg_memlist));
		num_regs = (num_regs/sizeof(struct linux_prom_registers));
		for(iter=0; iter<num_regs; iter++) {
			prom_phys_avail[iter].start_adr =
				(char *) prom_reg_memlist[iter].phys_addr;
			prom_phys_avail[iter].num_bytes =
				(unsigned long) prom_reg_memlist[iter].reg_size;
			prom_phys_avail[iter].theres_more =
				&prom_phys_avail[iter+1];
		}
A
Al Viro 已提交
127
		prom_phys_avail[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140

		num_regs = prom_getproperty(node, "reg",
					    (char *) prom_reg_memlist,
					    sizeof(prom_reg_memlist));
		num_regs = (num_regs/sizeof(struct linux_prom_registers));
		for(iter=0; iter<num_regs; iter++) {
			prom_phys_total[iter].start_adr =
				(char *) prom_reg_memlist[iter].phys_addr;
			prom_phys_total[iter].num_bytes =
				(unsigned long) prom_reg_memlist[iter].reg_size;
			prom_phys_total[iter].theres_more =
				&prom_phys_total[iter+1];
		}
A
Al Viro 已提交
141
		prom_phys_total[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

		node = prom_getchild(prom_root_node);
		node = prom_searchsiblings(node, "virtual-memory");
		num_regs = prom_getproperty(node, "available",
					    (char *) prom_reg_memlist,
					    sizeof(prom_reg_memlist));
		num_regs = (num_regs/sizeof(struct linux_prom_registers));

		/* Convert available virtual areas to taken virtual
		 * areas.  First sort, then convert.
		 */
		for(iter=0; iter<num_regs; iter++) {
			prom_prom_taken[iter].start_adr =
				(char *) prom_reg_memlist[iter].phys_addr;
			prom_prom_taken[iter].num_bytes =
				(unsigned long) prom_reg_memlist[iter].reg_size;
			prom_prom_taken[iter].theres_more =
				&prom_prom_taken[iter+1];
		}
A
Al Viro 已提交
161
		prom_prom_taken[iter-1].theres_more = NULL;
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

		prom_sortmemlist(prom_prom_taken);

		/* Finally, convert. */
		for(iter=0; iter<num_regs; iter++) {
			prom_prom_taken[iter].start_adr =
				prom_prom_taken[iter].start_adr +
					prom_prom_taken[iter].num_bytes;
			prom_prom_taken[iter].num_bytes =
				prom_prom_taken[iter+1].start_adr -
					prom_prom_taken[iter].start_adr;
		}
		prom_prom_taken[iter-1].num_bytes =
			0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr;

		/* Sort the other two lists. */
		prom_sortmemlist(prom_phys_total);
		prom_sortmemlist(prom_phys_avail);
		break;

	case PROM_SUN4:
#ifdef CONFIG_SUN4	
		/* how simple :) */
A
Al Viro 已提交
185
		prom_phys_total[0].start_adr = NULL;
L
Linus Torvalds 已提交
186
		prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize);
A
Al Viro 已提交
187 188
		prom_phys_total[0].theres_more = NULL;
		prom_prom_taken[0].start_adr = NULL; 
L
Linus Torvalds 已提交
189
		prom_prom_taken[0].num_bytes = 0x0;
A
Al Viro 已提交
190 191
		prom_prom_taken[0].theres_more = NULL;
		prom_phys_avail[0].start_adr = NULL;
L
Linus Torvalds 已提交
192
		prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail);
A
Al Viro 已提交
193
		prom_phys_avail[0].theres_more = NULL;
L
Linus Torvalds 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
#endif
		break;

	default:
		break;
	};

	/* Link all the lists into the top-level descriptor. */
	prom_memlist.v0_totphys=&prom_ptot_ptr;
	prom_memlist.v0_prommap=&prom_ptak_ptr;
	prom_memlist.v0_available=&prom_pavl_ptr;

	return;
}

/* This returns a pointer to our libraries internal v0 format
 * memory descriptor.
 */
struct linux_mem_v0 *
prom_meminfo(void)
{
	return &prom_memlist;
}