* changed by Philipp Rumpf
* Copyright 1999 Philipp Rumpf (prumpf@tux.org)
* Copyright 2004 Randolph Chung (tausq@debian.org)
- * Copyright 2006 Helge Deller (deller@gmx.de)
+ * Copyright 2006-2007 Helge Deller (deller@gmx.de)
*
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h> /* for hppa_dma_ops and pcxl_dma_ops */
#include <linux/pagemap.h> /* for release_pages and page_cache_release */
#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
#include <asm/tlb.h>
#include <asm/pdc_chassis.h>
#include <asm/mmzone.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-extern char _text; /* start of kernel code, defined by linker */
extern int data_start;
-extern char _end; /* end of BSS, defined by linker */
-extern char __init_begin, __init_end;
#ifdef CONFIG_DISCONTIGMEM
struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
-bootmem_data_t bmem_data[MAX_NUMNODES] __read_mostly;
unsigned char pfnnid_map[PFNNID_MAP_MAX] __read_mostly;
#endif
physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __read_mostly;
int npmem_ranges __read_mostly;
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
#define MAX_MEM (~0UL)
-#else /* !__LP64__ */
+#else /* !CONFIG_64BIT */
#define MAX_MEM (3584U*1024U*1024U)
-#endif /* !__LP64__ */
+#endif /* !CONFIG_64BIT */
static unsigned long mem_limit __read_mostly = MAX_MEM;
{
char *cp, *end;
unsigned long limit;
- extern char saved_command_line[];
/* We need this before __setup() functions are called */
limit = MAX_MEM;
- for (cp = saved_command_line; *cp; ) {
+ for (cp = boot_command_line; *cp; ) {
if (memcmp(cp, "mem=", 4) == 0) {
cp += 4;
limit = memparse(cp, &end);
#ifdef CONFIG_DISCONTIGMEM
for (i = 0; i < MAX_PHYSMEM_RANGES; i++) {
memset(NODE_DATA(i), 0, sizeof(pg_data_t));
- NODE_DATA(i)->bdata = &bmem_data[i];
+ NODE_DATA(i)->bdata = &bootmem_node_data[i];
}
memset(pfnnid_map, 0xff, sizeof(pfnnid_map));
*/
max_low_pfn = max_pfn;
- if ((bootmap_pfn - bootmap_start_pfn) != bootmap_pages) {
- printk(KERN_WARNING "WARNING! bootmap sizing is messed up!\n");
- BUG();
- }
+ /* bootmap sizing messed up? */
+ BUG_ON((bootmap_pfn - bootmap_start_pfn) != bootmap_pages);
/* reserve PAGE0 pdc memory, kernel text/data/bss & bootmap */
#define PDC_CONSOLE_IO_IODC_SIZE 32768
reserve_bootmem_node(NODE_DATA(0), 0UL,
- (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
- reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
- (unsigned long)(&_end - &_text));
+ (unsigned long)(PAGE0->mem_free +
+ PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT);
+ reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
+ (unsigned long)(_end - _text), BOOTMEM_DEFAULT);
reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
- ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+ ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),
+ BOOTMEM_DEFAULT);
#ifndef CONFIG_DISCONTIGMEM
for (i = 0; i < npmem_holes; i++) {
reserve_bootmem_node(NODE_DATA(0),
(pmem_holes[i].start_pfn << PAGE_SHIFT),
- (pmem_holes[i].pages << PAGE_SHIFT));
+ (pmem_holes[i].pages << PAGE_SHIFT),
+ BOOTMEM_DEFAULT);
}
#endif
initrd_below_start_ok = 1;
printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
- reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
+ reserve_bootmem_node(NODE_DATA(0), __pa(initrd_start),
+ initrd_reserve, BOOTMEM_DEFAULT);
}
}
#endif
data_resource.start = virt_to_phys(&data_start);
- data_resource.end = virt_to_phys(&_end)-1;
- code_resource.start = virt_to_phys(&_text);
+ data_resource.end = virt_to_phys(_end) - 1;
+ code_resource.start = virt_to_phys(_text);
code_resource.end = virt_to_phys(&data_start)-1;
/* We don't know which region the kernel will be in, so try
void free_initmem(void)
{
- unsigned long addr, init_begin, init_end;
-
- printk(KERN_INFO "Freeing unused kernel memory: ");
+ unsigned long addr;
+ unsigned long init_begin = (unsigned long)__init_begin;
+ unsigned long init_end = (unsigned long)__init_end;
#ifdef CONFIG_DEBUG_KERNEL
/* Attempt to catch anyone trying to execute code here
* by filling the page with BRK insns.
- *
- * If we disable interrupts for all CPUs, then IPI stops working.
- * Kinda breaks the global cache flushing.
*/
- local_irq_disable();
-
- memset(&__init_begin, 0x00,
- (unsigned long)&__init_end - (unsigned long)&__init_begin);
-
- flush_data_cache();
- asm volatile("sync" : : );
- flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
- asm volatile("sync" : : );
-
- local_irq_enable();
+ memset((void *)init_begin, 0x00, init_end - init_begin);
+ flush_icache_range(init_begin, init_end);
#endif
/* align __init_begin and __init_end to page size,
ignoring linker script where we might have tried to save RAM */
- init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
- init_end = PAGE_ALIGN((unsigned long)(&__init_end));
+ init_begin = PAGE_ALIGN(init_begin);
+ init_end = PAGE_ALIGN(init_end);
for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
/* set up a new led state on systems shipped LED State panel */
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
- printk("%luk freed\n", (init_end - init_begin) >> 10);
+ printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n",
+ (init_end - init_begin) >> 10);
}
#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
& ~(VM_MAP_OFFSET-1)))
-void *vmalloc_start __read_mostly;
-EXPORT_SYMBOL(vmalloc_start);
+void *parisc_vmalloc_start __read_mostly;
+EXPORT_SYMBOL(parisc_vmalloc_start);
#ifdef CONFIG_PA11
unsigned long pcxl_dma_start __read_mostly;
void __init mem_init(void)
{
+ int codesize, reservedpages, datasize, initsize;
+
+ /* Do sanity checks on page table constants */
+ BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t));
+ BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t));
+ BUILD_BUG_ON(PGD_ENTRY_SIZE != sizeof(pgd_t));
+ BUILD_BUG_ON(PAGE_SHIFT + BITS_PER_PTE + BITS_PER_PMD + BITS_PER_PGD
+ > BITS_PER_LONG);
+
high_memory = __va((max_pfn << PAGE_SHIFT));
#ifndef CONFIG_DISCONTIGMEM
}
#endif
- printk(KERN_INFO "Memory: %luk available\n", num_physpages << (PAGE_SHIFT-10));
+ codesize = (unsigned long)_etext - (unsigned long)_text;
+ datasize = (unsigned long)_edata - (unsigned long)_etext;
+ initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
+
+ reservedpages = 0;
+{
+ unsigned long pfn;
+#ifdef CONFIG_DISCONTIGMEM
+ int i;
+
+ for (i = 0; i < npmem_ranges; i++) {
+ for (pfn = node_start_pfn(i); pfn < node_end_pfn(i); pfn++) {
+ if (PageReserved(pfn_to_page(pfn)))
+ reservedpages++;
+ }
+ }
+#else /* !CONFIG_DISCONTIGMEM */
+ for (pfn = 0; pfn < max_pfn; pfn++) {
+ /*
+ * Only count reserved RAM pages
+ */
+ if (PageReserved(pfn_to_page(pfn)))
+ reservedpages++;
+ }
+#endif
+}
#ifdef CONFIG_PA11
if (hppa_dma_ops == &pcxl_dma_ops) {
pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START);
- vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE);
+ parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start
+ + PCXL_DMA_MAP_SIZE);
} else {
pcxl_dma_start = 0;
- vmalloc_start = SET_MAP_OFFSET(MAP_START);
+ parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
}
#else
- vmalloc_start = SET_MAP_OFFSET(MAP_START);
+ parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
#endif
+ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+ nr_free_pages() << (PAGE_SHIFT-10),
+ num_physpages << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ initsize >> 10
+ );
+
+#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
+ printk("virtual kernel memory layout:\n"
+ " vmalloc : 0x%p - 0x%p (%4ld MB)\n"
+ " memory : 0x%p - 0x%p (%4ld MB)\n"
+ " .init : 0x%p - 0x%p (%4ld kB)\n"
+ " .data : 0x%p - 0x%p (%4ld kB)\n"
+ " .text : 0x%p - 0x%p (%4ld kB)\n",
+
+ (void*)VMALLOC_START, (void*)VMALLOC_END,
+ (VMALLOC_END - VMALLOC_START) >> 20,
+
+ __va(0), high_memory,
+ ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20,
+
+ __init_begin, __init_end,
+ ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10,
+
+ _etext, _edata,
+ ((unsigned long)_edata - (unsigned long)_etext) >> 10,
+
+ _text, _etext,
+ ((unsigned long)_etext - (unsigned long)_text) >> 10);
+#endif
}
unsigned long *empty_zero_page __read_mostly;
+EXPORT_SYMBOL(empty_zero_page);
void show_mem(void)
{
printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk(KERN_INFO "Free swap: %6ldkB\n",
- nr_swap_pages<<(PAGE_SHIFT-10));
#ifndef CONFIG_DISCONTIGMEM
i = max_mapnr;
while (i-- > 0) {
#ifdef CONFIG_DISCONTIGMEM
{
struct zonelist *zl;
- int i, j, k;
+ int i, j;
for (i = 0; i < npmem_ranges; i++) {
+ zl = node_zonelist(i, 0);
for (j = 0; j < MAX_NR_ZONES; j++) {
- zl = NODE_DATA(i)->node_zonelists + j;
+ struct zoneref *z;
+ struct zone *zone;
printk("Zone list for zone %d on node %d: ", j, i);
- for (k = 0; zl->zones[k] != NULL; k++)
- printk("[%d/%s] ", zl->zones[k]->zone_pgdat->node_id, zl->zones[k]->name);
+ for_each_zone_zonelist(zone, z, zl, j)
+ printk("[%d/%s] ", zone_to_nid(zone),
+ zone->name);
printk("\n");
}
}
extern const unsigned long fault_vector_20;
extern void * const linux_gateway_page;
- ro_start = __pa((unsigned long)&_text);
+ ro_start = __pa((unsigned long)_text);
ro_end = __pa((unsigned long)&data_start);
fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
flush_tlb_all_local(NULL);
for (i = 0; i < npmem_ranges; i++) {
- unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0 };
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
- /* We have an IOMMU, so all memory can go into a single
- ZONE_DMA zone. */
- zones_size[ZONE_DMA] = pmem_ranges[i].pages;
+ zones_size[ZONE_NORMAL] = pmem_ranges[i].pages;
#ifdef CONFIG_DISCONTIGMEM
/* Need to initialize the pfnnid_map before we can initialize
}
#endif
- free_area_init_node(i, NODE_DATA(i), zones_size,
+ free_area_init_node(i, zones_size,
pmem_ranges[i].start_pfn, NULL);
}
}
#ifdef CONFIG_PA20
/*
- * Currently, all PA20 chips have 18 bit protection id's, which is the
+ * Currently, all PA20 chips have 18 bit protection IDs, which is the
* limiting factor (space ids are 32 bits).
*/
#else
/*
- * Currently we have a one-to-one relationship between space id's and
- * protection id's. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only
- * support 15 bit protection id's, so that is the limiting factor.
- * PCXT' has 18 bit protection id's, but only 16 bit spaceids, so it's
+ * Currently we have a one-to-one relationship between space IDs and
+ * protection IDs. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only
+ * support 15 bit protection IDs, so that is the limiting factor.
+ * PCXT' has 18 bit protection IDs, but only 16 bit spaceids, so it's
* probably not worth the effort for a special case here.
*/
do_recycle++;
}
spin_unlock(&sid_lock);
- on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
+ on_each_cpu(flush_tlb_all_local, NULL, 1);
if (do_recycle) {
spin_lock(&sid_lock);
recycle_sids(recycle_ndirty,recycle_dirty_array);