linux-old/arch/m68k/mm/motorola.c
<<
>>
Prefs
   1/*
   2 * linux/arch/m68k/motorola.c
   3 *
   4 * Routines specific to the Motorola MMU, originally from:
   5 * linux/arch/m68k/init.c 
   6 * which are Copyright (C) 1995 Hamish Macdonald
   7 * 
   8 * Moved 8/20/1999 Sam Creasey
   9 */
  10
  11#include <linux/config.h>
  12#include <linux/signal.h>
  13#include <linux/sched.h>
  14#include <linux/mm.h>
  15#include <linux/swap.h>
  16#include <linux/kernel.h>
  17#include <linux/string.h>
  18#include <linux/types.h>
  19#include <linux/init.h>
  20#include <linux/bootmem.h>
  21#ifdef CONFIG_BLK_DEV_RAM
  22#include <linux/blk.h>
  23#endif
  24
  25#include <asm/setup.h>
  26#include <asm/uaccess.h>
  27#include <asm/page.h>
  28#include <asm/pgalloc.h>
  29#include <asm/system.h>
  30#include <asm/machdep.h>
  31#include <asm/io.h>
  32#include <asm/dma.h>
  33#ifdef CONFIG_ATARI
  34#include <asm/atari_stram.h>
  35#endif
  36
  37#undef DEBUG
  38
  39#ifndef mm_cachebits
  40/*
  41 * Bits to add to page descriptors for "normal" caching mode.
  42 * For 68020/030 this is 0.
  43 * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
  44 */
  45unsigned long mm_cachebits = 0;
  46#endif
  47
  48static pte_t * __init kernel_page_table(void)
  49{
  50        pte_t *ptablep;
  51
  52        ptablep = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
  53
  54        clear_page(ptablep);
  55        __flush_page_to_ram((unsigned long) ptablep);
  56        flush_tlb_kernel_page((unsigned long) ptablep);
  57        nocache_page ((unsigned long)ptablep);
  58
  59        return ptablep;
  60}
  61
  62static pmd_t *last_pgtable __initdata = NULL;
  63pmd_t *zero_pgtable __initdata = NULL;
  64
  65static pmd_t * __init kernel_ptr_table(void)
  66{
  67        if (!last_pgtable) {
  68                unsigned long pmd, last;
  69                int i;
  70
  71                /* Find the last ptr table that was used in head.S and
  72                 * reuse the remaining space in that page for further
  73                 * ptr tables.
  74                 */
  75                last = (unsigned long)kernel_pg_dir;
  76                for (i = 0; i < PTRS_PER_PGD; i++) {
  77                        if (!pgd_present(kernel_pg_dir[i]))
  78                                continue;
  79                        pmd = __pgd_page(kernel_pg_dir[i]);
  80                        if (pmd > last)
  81                                last = pmd;
  82                }
  83
  84                last_pgtable = (pmd_t *)last;
  85#ifdef DEBUG
  86                printk("kernel_ptr_init: %p\n", last_pgtable);
  87#endif
  88        }
  89
  90        if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) {
  91                last_pgtable = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
  92
  93                clear_page(last_pgtable);
  94                __flush_page_to_ram((unsigned long)last_pgtable);
  95                flush_tlb_kernel_page((unsigned long)last_pgtable);
  96                nocache_page((unsigned long)last_pgtable);
  97        } else
  98                last_pgtable += PTRS_PER_PMD;
  99
 100        return last_pgtable;
 101}
 102
 103static unsigned long __init 
 104map_chunk (unsigned long addr, long size)
 105{
 106#define PTRTREESIZE (256*1024)
 107#define ROOTTREESIZE (32*1024*1024)
 108        static unsigned long virtaddr = PAGE_OFFSET;
 109        unsigned long physaddr;
 110        pgd_t *pgd_dir;
 111        pmd_t *pmd_dir;
 112        pte_t *pte_dir;
 113
 114        physaddr = (addr | m68k_supervisor_cachemode |
 115                    _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
 116        if (CPU_IS_040_OR_060)
 117                physaddr |= _PAGE_GLOBAL040;
 118
 119        while (size > 0) {
 120#ifdef DEBUG
 121                if (!(virtaddr & (PTRTREESIZE-1)))
 122                        printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
 123                                virtaddr);
 124#endif
 125                pgd_dir = pgd_offset_k(virtaddr);
 126                if (virtaddr && CPU_IS_020_OR_030) {
 127                        if (!(virtaddr & (ROOTTREESIZE-1)) &&
 128                            size >= ROOTTREESIZE) {
 129#ifdef DEBUG
 130                                printk ("[very early term]");
 131#endif
 132                                pgd_val(*pgd_dir) = physaddr;
 133                                size -= ROOTTREESIZE;
 134                                virtaddr += ROOTTREESIZE;
 135                                physaddr += ROOTTREESIZE;
 136                                continue;
 137                        }
 138                }
 139                if (!pgd_present(*pgd_dir)) {
 140                        pmd_dir = kernel_ptr_table();
 141#ifdef DEBUG
 142                        printk ("[new pointer %p]", pmd_dir);
 143#endif
 144                        pgd_set(pgd_dir, pmd_dir);
 145                } else
 146                        pmd_dir = pmd_offset(pgd_dir, virtaddr);
 147
 148                if (CPU_IS_020_OR_030) {
 149                        if (virtaddr) {
 150#ifdef DEBUG
 151                                printk ("[early term]");
 152#endif
 153                                pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
 154                                physaddr += PTRTREESIZE;
 155                        } else {
 156                                int i;
 157#ifdef DEBUG
 158                                printk ("[zero map]");
 159#endif
 160                                zero_pgtable = kernel_ptr_table();
 161                                pte_dir = (pte_t *)zero_pgtable;
 162                                pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
 163                                        _PAGE_TABLE | _PAGE_ACCESSED;
 164                                pte_val(*pte_dir++) = 0;
 165                                physaddr += PAGE_SIZE;
 166                                for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
 167                                        pte_val(*pte_dir++) = physaddr;
 168                        }
 169                        size -= PTRTREESIZE;
 170                        virtaddr += PTRTREESIZE;
 171                } else {
 172                        if (!pmd_present(*pmd_dir)) {
 173#ifdef DEBUG
 174                                printk ("[new table]");
 175#endif
 176                                pte_dir = kernel_page_table();
 177                                pmd_set(pmd_dir, pte_dir);
 178                        }
 179                        pte_dir = pte_offset(pmd_dir, virtaddr);
 180
 181                        if (virtaddr) {
 182                                if (!pte_present(*pte_dir))
 183                                        pte_val(*pte_dir) = physaddr;
 184                        } else
 185                                pte_val(*pte_dir) = 0;
 186                        size -= PAGE_SIZE;
 187                        virtaddr += PAGE_SIZE;
 188                        physaddr += PAGE_SIZE;
 189                }
 190
 191        }
 192#ifdef DEBUG
 193        printk("\n");
 194#endif
 195
 196        return virtaddr;
 197}
 198
 199extern unsigned long empty_bad_page_table;
 200extern unsigned long empty_bad_page;
 201
 202/*
 203 * paging_init() continues the virtual memory environment setup which
 204 * was begun by the code in arch/head.S.
 205 */
 206void __init paging_init(void)
 207{
 208        int chunk;
 209        unsigned long mem_avail = 0;
 210        unsigned long zones_size[3] = { 0, };
 211
 212#ifdef DEBUG
 213        {
 214                extern unsigned long availmem;
 215                printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
 216                        kernel_pg_dir, availmem, start_mem, end_mem);
 217        }
 218#endif
 219
 220        /* Fix the cache mode in the page descriptors for the 680[46]0.  */
 221        if (CPU_IS_040_OR_060) {
 222                int i;
 223#ifndef mm_cachebits
 224                mm_cachebits = _PAGE_CACHE040;
 225#endif
 226                for (i = 0; i < 16; i++)
 227                        pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
 228        }
 229
 230        /*
 231         * Map the physical memory available into the kernel virtual
 232         * address space.  It may allocate some memory for page
 233         * tables and thus modify availmem.
 234         */
 235
 236        for (chunk = 0; chunk < m68k_num_memory; chunk++) {
 237                mem_avail = map_chunk (m68k_memory[chunk].addr,
 238                                       m68k_memory[chunk].size);
 239
 240        }
 241
 242        flush_tlb_all();
 243#ifdef DEBUG
 244        printk ("memory available is %ldKB\n", mem_avail >> 10);
 245        printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
 246                start_mem, end_mem);
 247#endif
 248
 249        /*
 250         * initialize the bad page table and bad page to point
 251         * to a couple of allocated pages
 252         */
 253        empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
 254        empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
 255        empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
 256        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 257
 258        /*
 259         * Set up SFC/DFC registers (user data space)
 260         */
 261        set_fs (USER_DS);
 262
 263#ifdef DEBUG
 264        printk ("before free_area_init\n");
 265#endif
 266        zones_size[0] = (mach_max_dma_address < (unsigned long)high_memory ?
 267                         (mach_max_dma_address+1) : (unsigned long)high_memory);
 268        zones_size[1] = (unsigned long)high_memory - zones_size[0];
 269
 270        zones_size[0] = (zones_size[0] - PAGE_OFFSET) >> PAGE_SHIFT;
 271        zones_size[1] >>= PAGE_SHIFT;
 272
 273        free_area_init(zones_size);
 274}
 275
 276extern char __init_begin, __init_end;
 277extern unsigned long totalram_pages;
 278
 279void free_initmem(void)
 280{
 281        unsigned long addr;
 282
 283        addr = (unsigned long)&__init_begin;
 284        for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
 285                virt_to_page(addr)->flags &= ~(1 << PG_reserved);
 286                set_page_count(virt_to_page(addr), 1);
 287                free_page(addr);
 288                totalram_pages++;
 289        }
 290}
 291
 292
 293
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.