* Copyright 1999 SuSE GmbH
* changed by Philipp Rumpf
* Copyright 1999 Philipp Rumpf (prumpf@tux.org)
- * Copyright 2004 Randolph Chung (tausq@debian.org)
*
*/
#include <asm/pgalloc.h>
#include <asm/tlb.h>
#include <asm/pdc_chassis.h>
-#include <asm/mmzone.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
extern char __init_begin, __init_end;
#ifdef CONFIG_DISCONTIGMEM
-struct node_map_data node_data[MAX_NUMNODES];
-bootmem_data_t bmem_data[MAX_NUMNODES];
-unsigned char pfnnid_map[PFNNID_MAP_MAX];
+struct node_map_data node_data[MAX_PHYSMEM_RANGES];
+bootmem_data_t bmem_data[MAX_PHYSMEM_RANGES];
+unsigned char *chunkmap;
+unsigned int maxchunkmap;
#endif
static struct resource data_resource = {
disable_sr_hashing(); /* Turn off space register hashing */
+#ifdef CONFIG_DISCONTIGMEM
+ /*
+ * The below is still true as of 2.4.2. If this is ever fixed,
+ * we can remove this warning!
+ */
+
+ printk(KERN_WARNING "\n\n");
+ printk(KERN_WARNING "CONFIG_DISCONTIGMEM is enabled, which is probably a mistake. This\n");
+ printk(KERN_WARNING "option can lead to heavy swapping, even when there are gigabytes\n");
+ printk(KERN_WARNING "of free memory.\n\n");
+#endif
+
+#ifdef __LP64__
+
+#ifndef CONFIG_DISCONTIGMEM
/*
* Sort the ranges. Since the number of ranges is typically
* small, and performance is not an issue here, just do
}
}
-#ifndef CONFIG_DISCONTIGMEM
/*
* Throw out ranges that are too far apart (controlled by
- * MAX_GAP).
+ * MAX_GAP). If CONFIG_DISCONTIGMEM wasn't implemented so
+ * poorly, we would recommend enabling that option, but,
+ * until it is fixed, this is the best way to go.
*/
for (i = 1; i < npmem_ranges; i++) {
(pmem_ranges[i-1].start_pfn +
pmem_ranges[i-1].pages) > MAX_GAP) {
npmem_ranges = i;
- printk("Large gap in memory detected (%ld pages). "
- "Consider turning on CONFIG_DISCONTIGMEM\n",
- pmem_ranges[i].start_pfn -
- (pmem_ranges[i-1].start_pfn +
- pmem_ranges[i-1].pages));
break;
}
}
}
}
+#endif /* __LP64__ */
+
sysram_resource_count = npmem_ranges;
for (i = 0; i < sysram_resource_count; i++) {
struct resource *res = &sysram_resources[i];
mem_limit_func(); /* check for "mem=" argument */
mem_max = 0;
- num_physpages = 0;
for (i = 0; i < npmem_ranges; i++) {
unsigned long rsize;
npmem_ranges = i + 1;
mem_max = mem_limit;
}
- num_physpages += pmem_ranges[i].pages;
break;
}
- num_physpages += pmem_ranges[i].pages;
mem_max += rsize;
}
printk(KERN_INFO "Total Memory: %ld Mb\n",mem_max >> 20);
#ifndef CONFIG_DISCONTIGMEM
+
/* Merge the ranges, keeping track of the holes */
{
bootmap_start_pfn = PAGE_ALIGN(__pa((unsigned long) &_end)) >> PAGE_SHIFT;
#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];
- }
- memset(pfnnid_map, 0xff, sizeof(pfnnid_map));
-
- numnodes = npmem_ranges;
-
for (i = 0; i < npmem_ranges; i++)
- node_set_online(i);
+ node_data[i].pg_data.bdata = &bmem_data[i];
#endif
-
/*
* Initialize and free the full range of memory in each range.
* Note that the only writing these routines do are to the bootmap,
void __init mem_init(void)
{
- high_memory = __va((max_pfn << PAGE_SHIFT));
+ int i;
-#ifndef CONFIG_DISCONTIGMEM
- max_mapnr = page_to_pfn(virt_to_page(high_memory - 1)) + 1;
- mem_map = zone_table[ZONE_DMA]->zone_mem_map;
- totalram_pages += free_all_bootmem();
-#else
- {
- int i;
+ high_memory = __va((max_pfn << PAGE_SHIFT));
+ max_mapnr = (virt_to_page(high_memory - 1) - mem_map) + 1;
- for (i = 0; i < npmem_ranges; i++)
- totalram_pages += free_all_bootmem_node(NODE_DATA(i));
- }
-#endif
+ num_physpages = 0;
+ mem_map = zone_table[0]->zone_mem_map;
+ for (i = 0; i < npmem_ranges; i++)
+ num_physpages += free_all_bootmem_node(NODE_DATA(i));
+ totalram_pages = num_physpages;
printk(KERN_INFO "Memory: %luk available\n", num_physpages << (PAGE_SHIFT-10));
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) {
total++;
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
- else if (!page_count(&mem_map[i]))
+ else if (!atomic_read(&mem_map[i].count))
free++;
else
- shared += page_count(&mem_map[i]) - 1;
- }
-#else
- for (i = 0; i < npmem_ranges; i++) {
- int j;
-
- for (j = node_start_pfn(i); j < node_end_pfn(i); j++) {
- struct page *p;
-
- p = node_mem_map(i) + j - node_start_pfn(i);
-
- total++;
- if (PageReserved(p))
- reserved++;
- else if (PageSwapCache(p))
- cached++;
- else if (!page_count(p))
- free++;
- else
- shared += page_count(p) - 1;
- }
+ shared += atomic_read(&mem_map[i].count) - 1;
}
-#endif
printk(KERN_INFO "%d pages of RAM\n", total);
printk(KERN_INFO "%d reserved pages\n", reserved);
printk(KERN_INFO "%d pages shared\n", shared);
printk(KERN_INFO "%d pages swap cached\n", cached);
-
-
-#ifdef CONFIG_DISCONTIGMEM
- {
- struct zonelist *zl;
- int i, j, k;
-
- for (i = 0; i < npmem_ranges; i++) {
- for (j = 0; j < MAX_NR_ZONES; j++) {
- zl = NODE_DATA(i)->node_zonelists + j;
-
- 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);
- printk("\n");
- }
- }
- }
-#endif
}
#if PTRS_PER_PMD == 1
pmd = (pmd_t *)__pa(pg_dir);
#else
- pmd = (pmd_t *)pgd_address(*pg_dir);
+ pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
/*
* pmd is physical at this point
pmd = (pmd_t *) __pa(pmd);
}
- pgd_populate(NULL, pg_dir, __va(pmd));
+ pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
#endif
pg_dir++;
* pg_table is physical at this point
*/
- pg_table = (pte_t *)pmd_address(*pmd);
+ pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
if (!pg_table) {
pg_table = (pte_t *)
alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
pg_table = (pte_t *) __pa(pg_table);
}
- pmd_populate_kernel(NULL, pmd, __va(pg_table));
+ pmd_val(*pmd) = _PAGE_TABLE |
+ (unsigned long) pg_table;
/* now change pg_table to kernel virtual addresses */
for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
pte_t pte;
+#if !defined(CONFIG_STI_CONSOLE)
+#warning STI console should explicitly allocate executable pages but does not
/*
* Map the fault vector writable so we can
* write the HPMC checksum.
&& address != gw_addr)
pte = __mk_pte(address, PAGE_KERNEL_RO);
else
+#endif
pte = __mk_pte(address, pgprot);
if (address >= end_paddr)
flush_tlb_all_local();
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, 0, 0, };
- /* We have an IOMMU, so all memory can go into a single
- ZONE_DMA zone. */
zones_size[ZONE_DMA] = pmem_ranges[i].pages;
-
free_area_init_node(i,NODE_DATA(i),NULL,zones_size,
- pmem_ranges[i].start_pfn, 0);
+ (pmem_ranges[i].start_pfn << PAGE_SHIFT),0);
+ }
#ifdef CONFIG_DISCONTIGMEM
+ /*
+ * Initialize support for virt_to_page() macro.
+ *
+ * Note that MAX_ADDRESS is the largest virtual address that
+ * we can map. However, since we map all physical memory into
+ * the kernel address space, it also has an effect on the maximum
+ * physical address we can map (MAX_ADDRESS - PAGE_OFFSET).
+ */
+
+ maxchunkmap = MAX_ADDRESS >> CHUNKSHIFT;
+ chunkmap = (unsigned char *)alloc_bootmem(maxchunkmap);
+
+ for (i = 0; i < maxchunkmap; i++)
+ chunkmap[i] = BADCHUNK;
+
+ for (i = 0; i < npmem_ranges; i++) {
+
+ ADJ_NODE_MEM_MAP(i) = NODE_MEM_MAP(i) - pmem_ranges[i].start_pfn;
{
- int j;
- for (j = (node_start_pfn(i) >> PFNNID_SHIFT);
- j <= (node_end_pfn(i) >> PFNNID_SHIFT);
- j++) {
- pfnnid_map[j] = i;
- }
+ unsigned long chunk_paddr;
+ unsigned long end_paddr;
+ int chunknum;
+
+ chunk_paddr = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+ end_paddr = chunk_paddr + (pmem_ranges[i].pages << PAGE_SHIFT);
+ chunk_paddr &= CHUNKMASK;
+
+ chunknum = (int)CHUNKNUM(chunk_paddr);
+ while (chunk_paddr < end_paddr) {
+ if (chunknum >= maxchunkmap)
+ goto badchunkmap1;
+ if (chunkmap[chunknum] != BADCHUNK)
+ goto badchunkmap2;
+ chunkmap[chunknum] = (unsigned char)i;
+ chunk_paddr += CHUNKSZ;
+ chunknum++;
+ }
}
-#endif
}
+
+ return;
+
+badchunkmap1:
+ panic("paging_init: Physical address exceeds maximum address space!\n");
+badchunkmap2:
+ panic("paging_init: Collision in chunk map array. CHUNKSZ needs to be smaller\n");
+#endif
}
#ifdef CONFIG_PA20