Commit 13edad7a authored by David S. Miller's avatar David S. Miller

[SPARC64]: Rewrite convoluted physical memory probing.

Delete all of the code working with sp_banks[] and replace
with clean acquisition and sorting of physical memory
parameters from the firmware.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ed3ffaf7
...@@ -1333,7 +1333,7 @@ static int cheetah_check_main_memory(unsigned long paddr) ...@@ -1333,7 +1333,7 @@ static int cheetah_check_main_memory(unsigned long paddr)
{ {
unsigned long vaddr = PAGE_OFFSET + paddr; unsigned long vaddr = PAGE_OFFSET + paddr;
if (vaddr > high_memory) if (vaddr > (unsigned long) high_memory)
return 0; return 0;
return kern_addr_valid(vaddr); return kern_addr_valid(vaddr);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/sort.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -41,14 +42,72 @@ ...@@ -41,14 +42,72 @@
extern void device_scan(void); extern void device_scan(void);
struct sparc_phys_banks { #define MAX_BANKS 32
unsigned long base_addr;
unsigned long num_bytes; static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;
}; static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;
static int pavail_ents __initdata;
static int pavail_rescan_ents __initdata;
static int cmp_p64(const void *a, const void *b)
{
const struct linux_prom64_registers *x = a, *y = b;
if (x->phys_addr > y->phys_addr)
return 1;
if (x->phys_addr < y->phys_addr)
return -1;
return 0;
}
static void __init read_obp_memory(const char *property,
struct linux_prom64_registers *regs,
int *num_ents)
{
int node = prom_finddevice("/memory");
int prop_size = prom_getproplen(node, property);
int ents, ret, i;
ents = prop_size / sizeof(struct linux_prom64_registers);
if (ents > MAX_BANKS) {
prom_printf("The machine has more %s property entries than "
"this kernel can support (%d).\n",
property, MAX_BANKS);
prom_halt();
}
ret = prom_getproperty(node, property, (char *) regs, prop_size);
if (ret == -1) {
prom_printf("Couldn't get %s property from /memory.\n");
prom_halt();
}
*num_ents = ents;
#define SPARC_PHYS_BANKS 32 /* Sanitize what we got from the firmware, by page aligning
* everything.
*/
for (i = 0; i < ents; i++) {
unsigned long base, size;
base = regs[i].phys_addr;
size = regs[i].reg_size;
static struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; size &= PAGE_MASK;
if (base & ~PAGE_MASK) {
unsigned long new_base = PAGE_ALIGN(base);
size -= new_base - base;
if ((long) size < 0L)
size = 0UL;
base = new_base;
}
regs[i].phys_addr = base;
regs[i].reg_size = size;
}
sort(regs, ents, sizeof(struct linux_prom64_registers),
cmp_p64, NULL);
}
unsigned long *sparc64_valid_addr_bitmap __read_mostly; unsigned long *sparc64_valid_addr_bitmap __read_mostly;
...@@ -1213,14 +1272,14 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) ...@@ -1213,14 +1272,14 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
int i; int i;
#ifdef CONFIG_DEBUG_BOOTMEM #ifdef CONFIG_DEBUG_BOOTMEM
prom_printf("bootmem_init: Scan sp_banks, "); prom_printf("bootmem_init: Scan pavail, ");
#endif #endif
bytes_avail = 0UL; bytes_avail = 0UL;
for (i = 0; sp_banks[i].num_bytes != 0; i++) { for (i = 0; i < pavail_ents; i++) {
end_of_phys_memory = sp_banks[i].base_addr + end_of_phys_memory = pavail[i].phys_addr +
sp_banks[i].num_bytes; pavail[i].reg_size;
bytes_avail += sp_banks[i].num_bytes; bytes_avail += pavail[i].reg_size;
if (cmdline_memory_size) { if (cmdline_memory_size) {
if (bytes_avail > cmdline_memory_size) { if (bytes_avail > cmdline_memory_size) {
unsigned long slack = bytes_avail - cmdline_memory_size; unsigned long slack = bytes_avail - cmdline_memory_size;
...@@ -1228,12 +1287,15 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) ...@@ -1228,12 +1287,15 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
bytes_avail -= slack; bytes_avail -= slack;
end_of_phys_memory -= slack; end_of_phys_memory -= slack;
sp_banks[i].num_bytes -= slack; pavail[i].reg_size -= slack;
if (sp_banks[i].num_bytes == 0) { if ((long)pavail[i].reg_size <= 0L) {
sp_banks[i].base_addr = 0xdeadbeef; pavail[i].phys_addr = 0xdeadbeefUL;
pavail[i].reg_size = 0UL;
pavail_ents = i;
} else { } else {
sp_banks[i+1].num_bytes = 0; pavail[i+1].reg_size = 0Ul;
sp_banks[i+1].base_addr = 0xdeadbeef; pavail[i+1].phys_addr = 0xdeadbeefUL;
pavail_ents = i + 1;
} }
break; break;
} }
...@@ -1287,12 +1349,12 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) ...@@ -1287,12 +1349,12 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
/* Now register the available physical memory with the /* Now register the available physical memory with the
* allocator. * allocator.
*/ */
for (i = 0; sp_banks[i].num_bytes != 0; i++) { for (i = 0; i < pavail_ents; i++) {
#ifdef CONFIG_DEBUG_BOOTMEM #ifdef CONFIG_DEBUG_BOOTMEM
prom_printf("free_bootmem(sp_banks:%d): base[%lx] size[%lx]\n", prom_printf("free_bootmem(pavail:%d): base[%lx] size[%lx]\n",
i, sp_banks[i].base_addr, sp_banks[i].num_bytes); i, pavail[i].phys_addr, pavail[i].reg_size);
#endif #endif
free_bootmem(sp_banks[i].base_addr, sp_banks[i].num_bytes); free_bootmem(pavail[i].phys_addr, pavail[i].reg_size);
} }
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
...@@ -1341,7 +1403,7 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, ...@@ -1341,7 +1403,7 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend,
unsigned long alloc_bytes = 0UL; unsigned long alloc_bytes = 0UL;
if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) { if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) {
prom_printf("kernel_map: Unaligned sp_banks[%lx:%lx]\n", prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n",
vstart, vend); vstart, vend);
prom_halt(); prom_halt();
} }
...@@ -1388,23 +1450,24 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, ...@@ -1388,23 +1450,24 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend,
return alloc_bytes; return alloc_bytes;
} }
extern struct linux_mlist_p1275 *prom_ptot_ptr; static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
static int pall_ents __initdata;
extern unsigned int kvmap_linear_patch[1]; extern unsigned int kvmap_linear_patch[1];
static void __init kernel_physical_mapping_init(void) static void __init kernel_physical_mapping_init(void)
{ {
struct linux_mlist_p1275 *p = prom_ptot_ptr; unsigned long i, mem_alloced = 0UL;
unsigned long mem_alloced = 0UL;
while (p) { read_obp_memory("reg", &pall[0], &pall_ents);
for (i = 0; i < pall_ents; i++) {
unsigned long phys_start, phys_end; unsigned long phys_start, phys_end;
phys_start = p->start_adr; phys_start = pall[i].phys_addr;
phys_end = phys_start + p->num_bytes; phys_end = phys_start + pall[i].reg_size;
mem_alloced += kernel_map_range(phys_start, phys_end, mem_alloced += kernel_map_range(phys_start, phys_end,
PAGE_KERNEL); PAGE_KERNEL);
p = p->theres_more;
} }
printk("Allocated %ld bytes for kernel page tables.\n", printk("Allocated %ld bytes for kernel page tables.\n",
...@@ -1434,60 +1497,14 @@ void kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -1434,60 +1497,14 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
unsigned long __init find_ecache_flush_span(unsigned long size) unsigned long __init find_ecache_flush_span(unsigned long size)
{ {
unsigned long i;
for (i = 0; ; i++) {
if (sp_banks[i].num_bytes == 0)
break;
if (sp_banks[i].num_bytes >= size)
return sp_banks[i].base_addr;
}
return ~0UL;
}
static void __init prom_probe_memory(void)
{
struct linux_mlist_p1275 *mlist;
unsigned long bytes, base_paddr, tally;
int i; int i;
i = 0; for (i = 0; i < pavail_ents; i++) {
mlist = *prom_meminfo()->p1275_available; if (pavail[i].reg_size >= size)
bytes = tally = mlist->num_bytes; return pavail[i].phys_addr;
base_paddr = mlist->start_adr;
sp_banks[0].base_addr = base_paddr;
sp_banks[0].num_bytes = bytes;
while (mlist->theres_more != (void *) 0) {
i++;
mlist = mlist->theres_more;
bytes = mlist->num_bytes;
tally += bytes;
if (i >= SPARC_PHYS_BANKS-1) {
printk ("The machine has more banks than "
"this kernel can support\n"
"Increase the SPARC_PHYS_BANKS "
"setting (currently %d)\n",
SPARC_PHYS_BANKS);
i = SPARC_PHYS_BANKS-1;
break;
}
sp_banks[i].base_addr = mlist->start_adr;
sp_banks[i].num_bytes = mlist->num_bytes;
} }
i++; return ~0UL;
sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
sp_banks[i].num_bytes = 0;
/* Now mask all bank sizes on a page boundary, it is all we can
* use anyways.
*/
for (i = 0; sp_banks[i].num_bytes != 0; i++)
sp_banks[i].num_bytes &= PAGE_MASK;
} }
/* paging_init() sets up the page tables */ /* paging_init() sets up the page tables */
...@@ -1502,17 +1519,13 @@ void __init paging_init(void) ...@@ -1502,17 +1519,13 @@ void __init paging_init(void)
unsigned long end_pfn, pages_avail, shift; unsigned long end_pfn, pages_avail, shift;
unsigned long real_end, i; unsigned long real_end, i;
prom_probe_memory(); /* Find available physical memory... */
read_obp_memory("available", &pavail[0], &pavail_ents);
phys_base = 0xffffffffffffffffUL; phys_base = 0xffffffffffffffffUL;
for (i = 0; sp_banks[i].num_bytes != 0; i++) { for (i = 0; i < pavail_ents; i++)
unsigned long top; phys_base = min(phys_base, pavail[i].phys_addr);
if (sp_banks[i].base_addr < phys_base)
phys_base = sp_banks[i].base_addr;
top = sp_banks[i].base_addr +
sp_banks[i].num_bytes;
}
pfn_base = phys_base >> PAGE_SHIFT; pfn_base = phys_base >> PAGE_SHIFT;
kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
...@@ -1588,128 +1601,35 @@ void __init paging_init(void) ...@@ -1588,128 +1601,35 @@ void __init paging_init(void)
device_scan(); device_scan();
} }
/* Ok, it seems that the prom can allocate some more memory chunks
* as a side effect of some prom calls we perform during the
* boot sequence. My most likely theory is that it is from the
* prom_set_traptable() call, and OBP is allocating a scratchpad
* for saving client program register state etc.
*/
static void __init sort_memlist(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 != 0; i++) {
lowest = thislist[i].start_adr;
for (mitr = i+1; thislist[mitr-1].theres_more != 0; 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;
}
}
void __init rescan_sp_banks(void)
{
struct linux_prom64_registers memlist[64];
struct linux_mlist_p1275 avail[64], *mlist;
unsigned long bytes, base_paddr;
int num_regs, node = prom_finddevice("/memory");
int i;
num_regs = prom_getproperty(node, "available",
(char *) memlist, sizeof(memlist));
num_regs = (num_regs / sizeof(struct linux_prom64_registers));
for (i = 0; i < num_regs; i++) {
avail[i].start_adr = memlist[i].phys_addr;
avail[i].num_bytes = memlist[i].reg_size;
avail[i].theres_more = &avail[i + 1];
}
avail[i - 1].theres_more = NULL;
sort_memlist(avail);
mlist = &avail[0];
i = 0;
bytes = mlist->num_bytes;
base_paddr = mlist->start_adr;
sp_banks[0].base_addr = base_paddr;
sp_banks[0].num_bytes = bytes;
while (mlist->theres_more != NULL){
i++;
mlist = mlist->theres_more;
bytes = mlist->num_bytes;
if (i >= SPARC_PHYS_BANKS-1) {
printk ("The machine has more banks than "
"this kernel can support\n"
"Increase the SPARC_PHYS_BANKS "
"setting (currently %d)\n",
SPARC_PHYS_BANKS);
i = SPARC_PHYS_BANKS-1;
break;
}
sp_banks[i].base_addr = mlist->start_adr;
sp_banks[i].num_bytes = mlist->num_bytes;
}
i++;
sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
sp_banks[i].num_bytes = 0;
for (i = 0; sp_banks[i].num_bytes != 0; i++)
sp_banks[i].num_bytes &= PAGE_MASK;
}
static void __init taint_real_pages(void) static void __init taint_real_pages(void)
{ {
struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS];
int i; int i;
for (i = 0; i < SPARC_PHYS_BANKS; i++) { read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents);
saved_sp_banks[i].base_addr =
sp_banks[i].base_addr;
saved_sp_banks[i].num_bytes =
sp_banks[i].num_bytes;
}
rescan_sp_banks();
/* Find changes discovered in the sp_bank rescan and /* Find changes discovered in the physmem available rescan and
* reserve the lost portions in the bootmem maps. * reserve the lost portions in the bootmem maps.
*/ */
for (i = 0; saved_sp_banks[i].num_bytes; i++) { for (i = 0; i < pavail_ents; i++) {
unsigned long old_start, old_end; unsigned long old_start, old_end;
old_start = saved_sp_banks[i].base_addr; old_start = pavail[i].phys_addr;
old_end = old_start + old_end = old_start +
saved_sp_banks[i].num_bytes; pavail[i].reg_size;
while (old_start < old_end) { while (old_start < old_end) {
int n; int n;
for (n = 0; sp_banks[n].num_bytes; n++) { for (n = 0; pavail_rescan_ents; n++) {
unsigned long new_start, new_end; unsigned long new_start, new_end;
new_start = sp_banks[n].base_addr; new_start = pavail_rescan[n].phys_addr;
new_end = new_start + sp_banks[n].num_bytes; new_end = new_start +
pavail_rescan[n].reg_size;
if (new_start <= old_start && if (new_start <= old_start &&
new_end >= (old_start + PAGE_SIZE)) { new_end >= (old_start + PAGE_SIZE)) {
set_bit (old_start >> 22, set_bit(old_start >> 22,
sparc64_valid_addr_bitmap); sparc64_valid_addr_bitmap);
goto do_next_page; goto do_next_page;
} }
} }
......
...@@ -186,8 +186,8 @@ struct linux_prom_registers { ...@@ -186,8 +186,8 @@ struct linux_prom_registers {
}; };
struct linux_prom64_registers { struct linux_prom64_registers {
long phys_addr; unsigned long phys_addr;
long reg_size; unsigned long reg_size;
}; };
struct linux_prom_irqs { struct linux_prom_irqs {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment