linux-bk/arch/ia64/mm/contig.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1998-2003 Hewlett-Packard Co
   7 *      David Mosberger-Tang <davidm@hpl.hp.com>
   8 *      Stephane Eranian <eranian@hpl.hp.com>
   9 * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
  10 * Copyright (C) 1999 VA Linux Systems
  11 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  12 * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved.
  13 *
  14 * Routines used by ia64 machines with contiguous (or virtually contiguous)
  15 * memory.
  16 */
  17#include <linux/config.h>
  18#include <linux/bootmem.h>
  19#include <linux/efi.h>
  20#include <linux/mm.h>
  21#include <linux/swap.h>
  22
  23#include <asm/meminit.h>
  24#include <asm/pgalloc.h>
  25#include <asm/pgtable.h>
  26#include <asm/sections.h>
  27#include <asm/mca.h>
  28
  29#ifdef CONFIG_VIRTUAL_MEM_MAP
  30static unsigned long num_dma_physpages;
  31#endif
  32
  33/**
  34 * show_mem - display a memory statistics summary
  35 *
  36 * Just walks the pages in the system and describes where they're allocated.
  37 */
  38void
  39show_mem (void)
  40{
  41        int i, total = 0, reserved = 0;
  42        int shared = 0, cached = 0;
  43
  44        printk("Mem-info:\n");
  45        show_free_areas();
  46
  47        printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
  48        i = max_mapnr;
  49        while (i-- > 0) {
  50                if (!pfn_valid(i))
  51                        continue;
  52                total++;
  53                if (PageReserved(mem_map+i))
  54                        reserved++;
  55                else if (PageSwapCache(mem_map+i))
  56                        cached++;
  57                else if (page_count(mem_map + i))
  58                        shared += page_count(mem_map + i) - 1;
  59        }
  60        printk("%d pages of RAM\n", total);
  61        printk("%d reserved pages\n", reserved);
  62        printk("%d pages shared\n", shared);
  63        printk("%d pages swap cached\n", cached);
  64        printk("%ld pages in page table cache\n", pgtable_cache_size);
  65}
  66
  67/* physical address where the bootmem map is located */
  68unsigned long bootmap_start;
  69
  70/**
  71 * find_max_pfn - adjust the maximum page number callback
  72 * @start: start of range
  73 * @end: end of range
  74 * @arg: address of pointer to global max_pfn variable
  75 *
  76 * Passed as a callback function to efi_memmap_walk() to determine the highest
  77 * available page frame number in the system.
  78 */
  79int
  80find_max_pfn (unsigned long start, unsigned long end, void *arg)
  81{
  82        unsigned long *max_pfnp = arg, pfn;
  83
  84        pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT;
  85        if (pfn > *max_pfnp)
  86                *max_pfnp = pfn;
  87        return 0;
  88}
  89
  90/**
  91 * find_bootmap_location - callback to find a memory area for the bootmap
  92 * @start: start of region
  93 * @end: end of region
  94 * @arg: unused callback data
  95 *
  96 * Find a place to put the bootmap and return its starting address in
  97 * bootmap_start.  This address must be page-aligned.
  98 */
  99int
 100find_bootmap_location (unsigned long start, unsigned long end, void *arg)
 101{
 102        unsigned long needed = *(unsigned long *)arg;
 103        unsigned long range_start, range_end, free_start;
 104        int i;
 105
 106#if IGNORE_PFN0
 107        if (start == PAGE_OFFSET) {
 108                start += PAGE_SIZE;
 109                if (start >= end)
 110                        return 0;
 111        }
 112#endif
 113
 114        free_start = PAGE_OFFSET;
 115
 116        for (i = 0; i < num_rsvd_regions; i++) {
 117                range_start = max(start, free_start);
 118                range_end   = min(end, rsvd_region[i].start & PAGE_MASK);
 119
 120                free_start = PAGE_ALIGN(rsvd_region[i].end);
 121
 122                if (range_end <= range_start)
 123                        continue; /* skip over empty range */
 124
 125                if (range_end - range_start >= needed) {
 126                        bootmap_start = __pa(range_start);
 127                        return -1;      /* done */
 128                }
 129
 130                /* nothing more available in this segment */
 131                if (range_end == end)
 132                        return 0;
 133        }
 134        return 0;
 135}
 136
 137/**
 138 * find_memory - setup memory map
 139 *
 140 * Walk the EFI memory map and find usable memory for the system, taking
 141 * into account reserved areas.
 142 */
 143void
 144find_memory (void)
 145{
 146        unsigned long bootmap_size;
 147
 148        reserve_memory();
 149
 150        /* first find highest page frame number */
 151        max_pfn = 0;
 152        efi_memmap_walk(find_max_pfn, &max_pfn);
 153
 154        /* how many bytes to cover all the pages */
 155        bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;
 156
 157        /* look for a location to hold the bootmap */
 158        bootmap_start = ~0UL;
 159        efi_memmap_walk(find_bootmap_location, &bootmap_size);
 160        if (bootmap_start == ~0UL)
 161                panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
 162
 163        bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
 164
 165        /* Free all available memory, then mark bootmem-map as being in use. */
 166        efi_memmap_walk(filter_rsvd_memory, free_bootmem);
 167        reserve_bootmem(bootmap_start, bootmap_size);
 168
 169        find_initrd();
 170}
 171
 172#ifdef CONFIG_SMP
 173/**
 174 * per_cpu_init - setup per-cpu variables
 175 *
 176 * Allocate and setup per-cpu data areas.
 177 */
 178void *
 179per_cpu_init (void)
 180{
 181        void *cpu_data;
 182        int cpu;
 183
 184        /*
 185         * get_free_pages() cannot be used before cpu_init() done.  BSP
 186         * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls
 187         * get_zeroed_page().
 188         */
 189        if (smp_processor_id() == 0) {
 190                cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS,
 191                                           PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
 192                for (cpu = 0; cpu < NR_CPUS; cpu++) {
 193                        memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
 194                        __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
 195                        cpu_data += PERCPU_PAGE_SIZE;
 196                        per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
 197                }
 198        }
 199        return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
 200}
 201#endif /* CONFIG_SMP */
 202
 203static int
 204count_pages (u64 start, u64 end, void *arg)
 205{
 206        unsigned long *count = arg;
 207
 208        *count += (end - start) >> PAGE_SHIFT;
 209        return 0;
 210}
 211
 212#ifdef CONFIG_VIRTUAL_MEM_MAP
 213static int
 214count_dma_pages (u64 start, u64 end, void *arg)
 215{
 216        unsigned long *count = arg;
 217
 218        if (start < MAX_DMA_ADDRESS)
 219                *count += (min(end, MAX_DMA_ADDRESS) - start) >> PAGE_SHIFT;
 220        return 0;
 221}
 222#endif
 223
 224/*
 225 * Set up the page tables.
 226 */
 227
 228void
 229paging_init (void)
 230{
 231        unsigned long max_dma;
 232        unsigned long zones_size[MAX_NR_ZONES];
 233#ifdef CONFIG_VIRTUAL_MEM_MAP
 234        unsigned long zholes_size[MAX_NR_ZONES];
 235        unsigned long max_gap;
 236#endif
 237
 238        /* initialize mem_map[] */
 239
 240        memset(zones_size, 0, sizeof(zones_size));
 241
 242        num_physpages = 0;
 243        efi_memmap_walk(count_pages, &num_physpages);
 244
 245        max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 246
 247#ifdef CONFIG_VIRTUAL_MEM_MAP
 248        memset(zholes_size, 0, sizeof(zholes_size));
 249
 250        num_dma_physpages = 0;
 251        efi_memmap_walk(count_dma_pages, &num_dma_physpages);
 252
 253        if (max_low_pfn < max_dma) {
 254                zones_size[ZONE_DMA] = max_low_pfn;
 255                zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
 256        } else {
 257                zones_size[ZONE_DMA] = max_dma;
 258                zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
 259                if (num_physpages > num_dma_physpages) {
 260                        zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
 261                        zholes_size[ZONE_NORMAL] =
 262                                ((max_low_pfn - max_dma) -
 263                                 (num_physpages - num_dma_physpages));
 264                }
 265        }
 266
 267        max_gap = 0;
 268        efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
 269        if (max_gap < LARGE_GAP) {
 270                vmem_map = (struct page *) 0;
 271                free_area_init_node(0, &contig_page_data, zones_size, 0,
 272                                    zholes_size);
 273        } else {
 274                unsigned long map_size;
 275
 276                /* allocate virtual_mem_map */
 277
 278                map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
 279                vmalloc_end -= map_size;
 280                vmem_map = (struct page *) vmalloc_end;
 281                efi_memmap_walk(create_mem_map_page_table, NULL);
 282
 283                mem_map = contig_page_data.node_mem_map = vmem_map;
 284                free_area_init_node(0, &contig_page_data, zones_size,
 285                                    0, zholes_size);
 286
 287                printk("Virtual mem_map starts at 0x%p\n", mem_map);
 288        }
 289#else /* !CONFIG_VIRTUAL_MEM_MAP */
 290        if (max_low_pfn < max_dma)
 291                zones_size[ZONE_DMA] = max_low_pfn;
 292        else {
 293                zones_size[ZONE_DMA] = max_dma;
 294                zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
 295        }
 296        free_area_init(zones_size);
 297#endif /* !CONFIG_VIRTUAL_MEM_MAP */
 298        zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 299}
 300
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.