linux-old/arch/s390x/mm/init.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/mm/init.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Hartmut Penner (hpenner@de.ibm.com)
   7 *
   8 *  Derived from "arch/i386/mm/init.c"
   9 *    Copyright (C) 1995  Linus Torvalds
  10 */
  11
  12#include <linux/config.h>
  13#include <linux/signal.h>
  14#include <linux/sched.h>
  15#include <linux/kernel.h>
  16#include <linux/errno.h>
  17#include <linux/string.h>
  18#include <linux/types.h>
  19#include <linux/ptrace.h>
  20#include <linux/mman.h>
  21#include <linux/mm.h>
  22#include <linux/swap.h>
  23#include <linux/smp.h>
  24#include <linux/init.h>
  25#ifdef CONFIG_BLK_DEV_INITRD
  26#include <linux/blk.h>
  27#endif
  28#include <linux/pagemap.h>
  29#include <linux/bootmem.h>
  30
  31#include <asm/processor.h>
  32#include <asm/system.h>
  33#include <asm/uaccess.h>
  34#include <asm/pgtable.h>
  35#include <asm/pgalloc.h>
  36#include <asm/dma.h>
  37#include <asm/lowcore.h>
  38#include <asm/tlb.h>
  39
  40mmu_gather_t mmu_gathers[NR_CPUS];
  41
  42static unsigned long totalram_pages;
  43extern unsigned long memory_size;
  44
  45pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
  46char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
  47
  48static inline int
  49__pgd_populate(unsigned long *pgd_slot, unsigned long offset, pmd_t *pmd)
  50{
  51        if (offset == 0 && 
  52            ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
  53             (*pgd_slot & _PGD_ENTRY_LEN(2)) == 0)) {
  54                /* Set lower pmd, upper pmd is empty. */
  55                *pgd_slot = __pa(pmd) | _PGD_ENTRY_MASK |
  56                                _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(1);
  57                return 1;
  58        }
  59        if (offset == 4 &&
  60            ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
  61             (*pgd_slot & _PGD_ENTRY_OFF(2)) != 0)) {
  62                /* Lower pmd empty, set upper pmd. */
  63                *pgd_slot = (__pa(pmd) - 0x2000) | _PGD_ENTRY_MASK |
  64                                _PGD_ENTRY_OFF(2) | _PGD_ENTRY_LEN(3);
  65                return 1;
  66        }
  67        return 0;
  68}
  69
  70pmd_t *pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
  71{
  72        unsigned long addr = (unsigned long) pgd;
  73        unsigned long *pgd_slot =  (unsigned long *) (addr & -8);
  74        unsigned long offset = addr & 4;
  75        pmd_t *new, *pmd2;
  76        int i;
  77
  78        /* Check if we can get away with a half-sized pmd. */
  79        if (__pgd_populate(pgd_slot, offset, pmd))
  80                return pmd;
  81
  82        /* We have to enlarge the pmd to 16K if we arrive here. */
  83        spin_unlock(&mm->page_table_lock);
  84        new = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
  85        spin_lock(&mm->page_table_lock);
  86
  87        /*
  88         * Because we dropped the lock, we should re-check the
  89         * entry, as somebody else could have populated it..
  90         */
  91        if (!pgd_none(*pgd)) {
  92                if (new)
  93                        free_pages((unsigned long) new, 2);
  94                pmd_free(pmd);
  95                return (pmd_t *) pgd_val(*pgd);
  96        }
  97
  98        if (!new) {
  99                pmd_free(pmd);
 100                return NULL;
 101        }
 102
 103        /*
 104         * Re-check if we can get away with a half-sized pmd. We
 105         * dropped the lock so somebody else could have freed the
 106         * other half of the pmd.
 107         */
 108        if (__pgd_populate(pgd_slot, offset, pmd)) {
 109                free_pages((unsigned long) new, 2);
 110                return pmd;
 111        }
 112
 113        /* Set the PG_arch_1 bit on the first and the third pmd page
 114           so that pmd_free_fast can recognize pmds that have been
 115           allocated with an order 2 allocation.  */
 116        set_bit(PG_arch_1, &virt_to_page(new)->flags);
 117        set_bit(PG_arch_1, &virt_to_page(new+PTRS_PER_PMD)->flags);
 118        /* Now copy the two pmds to the new memory area. */
 119        if (offset == 0) {
 120                pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK) + PTRS_PER_PMD;
 121                memcpy(new, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
 122                memcpy(new + PTRS_PER_PMD, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
 123        } else {
 124                pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK);
 125                memcpy(new, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
 126                memcpy(new + PTRS_PER_PMD, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
 127        }
 128        *pgd_slot = __pa(new) | _PGD_ENTRY_MASK |
 129                        _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(3);
 130        for (i = 0; i < PTRS_PER_PMD; i++) {
 131                pmd_clear(pmd + i);
 132                pmd_clear(pmd2 + i);
 133        }
 134        pmd_free(pmd);
 135        pmd_free(pmd2);
 136        return new;
 137}
 138
 139void pmd_free_order2(pmd_t *pmd)
 140{
 141        pmd_t *pmd2 = (pmd_t *) ((unsigned long) pmd ^ 8192);
 142
 143        clear_bit(PG_arch_1, &virt_to_page(pmd)->flags);
 144        if (test_bit(PG_arch_1, &virt_to_page(pmd2)->flags) == 0) {
 145                /* The other pmd of the order 2 allocation has already
 146                   been freed. Now we can release the order 2 allocation.  */
 147                free_pages((unsigned long) pmd & ~8192, 2);
 148        }
 149}
 150
 151int do_check_pgt_cache(int low, int high)
 152{
 153        int freed = 0;
 154        if(pgtable_cache_size > high) {
 155                do {
 156                        if(pgd_quicklist) {
 157                                free_pgd_slow(get_pgd_fast());
 158                                freed += 2;
 159                        }
 160                        if(pmd_quicklist) {
 161                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
 162                                freed += 2;
 163                        }
 164                        if(pte_quicklist) {
 165                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
 166                                freed += 1;
 167                        }
 168                } while(pgtable_cache_size > low);
 169        }
 170        return freed;
 171}
 172
 173void diag10(unsigned long addr)
 174{
 175        if (addr >= 0x80000000)
 176                return;
 177        asm volatile ("sam31\n\t"
 178                      "diag %0,%0,0x10\n\t"
 179                      "sam64" : : "a" (addr) );
 180}
 181
 182void show_mem(void)
 183{
 184        int i, total = 0,reserved = 0;
 185        int shared = 0, cached = 0;
 186
 187        printk("Mem-info:\n");
 188        show_free_areas();
 189        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 190        i = max_mapnr;
 191        while (i-- > 0) {
 192                total++;
 193                if (PageReserved(mem_map+i))
 194                        reserved++;
 195                else if (PageSwapCache(mem_map+i))
 196                        cached++;
 197                else if (page_count(mem_map+i))
 198                        shared += atomic_read(&mem_map[i].count) - 1;
 199        }
 200        printk("%d pages of RAM\n",total);
 201        printk("%d reserved pages\n",reserved);
 202        printk("%d pages shared\n",shared);
 203        printk("%d pages swap cached\n",cached);
 204        printk("%ld pages in page table cache\n",pgtable_cache_size);
 205        show_buffers();
 206}
 207
 208/* References to section boundaries */
 209
 210extern unsigned long _text;
 211extern unsigned long _etext;
 212extern unsigned long _edata;
 213extern unsigned long __bss_start;
 214extern unsigned long _end;
 215
 216extern unsigned long __init_begin;
 217extern unsigned long __init_end;
 218
 219/*
 220 * paging_init() sets up the page tables
 221 */
 222
 223unsigned long last_valid_pfn;
 224
 225void __init paging_init(void)
 226{
 227        unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
 228        static const int ssm_mask = 0x04000000L;
 229        unsigned long dma_pfn, address, end_mem;
 230        pgd_t * pg_dir;
 231        int     i,j,k;
 232
 233        dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
 234
 235        if (dma_pfn > max_low_pfn)
 236                zones_size[ZONE_DMA] = max_low_pfn;
 237        else {
 238                zones_size[ZONE_DMA] = dma_pfn;
 239                zones_size[ZONE_NORMAL] = max_low_pfn - dma_pfn;
 240        }
 241
 242        /* Initialize mem_map[].  */
 243        free_area_init(zones_size);
 244
 245        /*
 246         * map whole physical memory to virtual memory (identity mapping) 
 247         */
 248        pg_dir = swapper_pg_dir;
 249        address = 0;
 250        end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
 251        for (i = 0 ; i < PTRS_PER_PGD/2 ; i++, pg_dir += 2) {
 252                pmd_t *pm_dir;
 253
 254                if (address >= end_mem) {
 255                        pgd_clear(pg_dir);
 256                        continue;
 257                }
 258        
 259                pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
 260                *((unsigned long *) pg_dir) = __pa(pm_dir) | _PGD_ENTRY_MASK |
 261                        _PGD_ENTRY_LEN(3) | _PGD_ENTRY_OFF(0);
 262
 263                for (j = 0 ; j < PTRS_PER_PMD*2 ; j++, pm_dir++) {
 264                        pte_t *pt_dir;
 265
 266                        if (address >= end_mem) {
 267                                pmd_clear(pm_dir);
 268                                continue; 
 269                        }          
 270                        
 271                        pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 272                        pmd_populate(&init_mm, pm_dir, pt_dir);
 273        
 274                        for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
 275                                pte_t pte = mk_pte_phys(address, PAGE_KERNEL);
 276                                if (address >= end_mem) {
 277                                        pte_clear(&pte); 
 278                                        continue;
 279                                }
 280                                set_pte(pt_dir, pte);
 281                                address += PAGE_SIZE;
 282                        }
 283                }
 284        }
 285        
 286        /* enable virtual mapping in kernel mode */
 287        __asm__ __volatile__("lctlg 1,1,%0\n\t"
 288                             "lctlg 7,7,%0\n\t"
 289                             "lctlg 13,13,%0\n\t"
 290                             "ssm   %1"
 291                             : :"m" (__pa(swapper_pg_dir) | _KERN_REGION_TABLE),
 292                                "m" (ssm_mask));
 293        local_flush_tlb();
 294
 295        return;
 296}
 297
 298void __init mem_init(void)
 299{
 300        unsigned long codesize, reservedpages, datasize, initsize;
 301
 302        max_mapnr = num_physpages = max_low_pfn;
 303        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 304
 305        /* clear the zero-page */
 306        memset(empty_zero_page, 0, PAGE_SIZE);
 307
 308        /* this will put all low memory onto the freelists */
 309        totalram_pages += free_all_bootmem();
 310
 311        reservedpages = 0;
 312
 313        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 314        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 315        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 316        printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
 317                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 318                max_mapnr << (PAGE_SHIFT-10),
 319                codesize >> 10,
 320                reservedpages << (PAGE_SHIFT-10),
 321                datasize >>10,
 322                initsize >> 10);
 323}
 324
 325void free_initmem(void)
 326{
 327        unsigned long addr;
 328
 329        addr = (unsigned long)(&__init_begin);
 330        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 331                ClearPageReserved(virt_to_page(addr));
 332                set_page_count(virt_to_page(addr), 1);
 333                free_page(addr);
 334                totalram_pages++;
 335        }
 336        printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
 337                (&__init_end - &__init_begin) >> 10);
 338}
 339
 340#ifdef CONFIG_BLK_DEV_INITRD
 341void free_initrd_mem(unsigned long start, unsigned long end)
 342{
 343        if (start < end)
 344                printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 345        for (; start < end; start += PAGE_SIZE) {
 346                ClearPageReserved(virt_to_page(start));
 347                set_page_count(virt_to_page(start), 1);
 348                free_page(start);
 349                totalram_pages++;
 350        }
 351}
 352#endif
 353
 354void si_meminfo(struct sysinfo *val)
 355{
 356        val->totalram = totalram_pages;
 357        val->sharedram = 0;
 358        val->freeram = nr_free_pages();
 359        val->bufferram = atomic_read(&buffermem_pages);
 360        val->totalhigh = 0;
 361        val->freehigh = 0;
 362        val->mem_unit = PAGE_SIZE;
 363}
 364
 365/*
 366 * Overrides for Emacs so that we follow Linus's tabbing style.
 367 * Emacs will notice this stuff at the end of the file and automatically
 368 * adjust the settings for this buffer only.  This must remain at the end
 369 * of the file.
 370 * ---------------------------------------------------------------------------
 371 * Local variables:
 372 * c-indent-level: 4 
 373 * c-brace-imaginary-offset: 0
 374 * c-brace-offset: -4
 375 * c-argdecl-indent: 4
 376 * c-label-offset: -4
 377 * c-continued-statement-offset: 4
 378 * c-continued-brace-offset: 0
 379 * indent-tabs-mode: nil
 380 * tab-width: 8
 381 * End:
 382 */
 383
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.