memory.c 4.6 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 50 51 52 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem 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 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 */

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

#include <asm/openprom.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_prom64_registers prom_reg_memlist[64];
struct linux_prom64_registers prom_reg_tmp[64];

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

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

struct linux_mem_p1275 prom_memlist;


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

	for(i=0; thislist[i].theres_more; i++) {
		lowest = thislist[i].start_adr;
		for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
			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;
	}
}

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

	node = prom_finddevice("/memory");
	num_regs = prom_getproperty(node, "available",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
	for(iter=0; iter<num_regs; iter++) {
		prom_phys_avail[iter].start_adr =
			prom_reg_memlist[iter].phys_addr;
		prom_phys_avail[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_phys_avail[iter].theres_more =
			&prom_phys_avail[iter+1];
	}
	prom_phys_avail[iter-1].theres_more = NULL;

	num_regs = prom_getproperty(node, "reg",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
	for(iter=0; iter<num_regs; iter++) {
		prom_phys_total[iter].start_adr =
			prom_reg_memlist[iter].phys_addr;
		prom_phys_total[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_phys_total[iter].theres_more =
			&prom_phys_total[iter+1];
	}
	prom_phys_total[iter-1].theres_more = NULL;

	node = prom_finddevice("/virtual-memory");
	num_regs = prom_getproperty(node, "available",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_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 =
			prom_reg_memlist[iter].phys_addr;
		prom_prom_taken[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_prom_taken[iter].theres_more =
			&prom_prom_taken[iter+1];
	}
	prom_prom_taken[iter-1].theres_more = NULL;

	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 =
		-1UL - prom_prom_taken[iter-1].start_adr;

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

	/* Link all the lists into the top-level descriptor. */
	prom_memlist.p1275_totphys=&prom_ptot_ptr;
	prom_memlist.p1275_prommap=&prom_ptak_ptr;
	prom_memlist.p1275_available=&prom_pavl_ptr;
}

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