linux/arch/unicore32/mm/pgd.c
<<
>>
Prefs
   1/*
   2 * linux/arch/unicore32/mm/pgd.c
   3 *
   4 * Code specific to PKUnity SoC and UniCore ISA
   5 *
   6 * Copyright (C) 2001-2010 GUAN Xue-tao
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12#include <linux/mm.h>
  13#include <linux/gfp.h>
  14#include <linux/highmem.h>
  15
  16#include <asm/pgalloc.h>
  17#include <asm/page.h>
  18#include <asm/tlbflush.h>
  19
  20#include "mm.h"
  21
  22#define FIRST_KERNEL_PGD_NR     (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
  23
  24/*
  25 * need to get a 4k page for level 1
  26 */
  27pgd_t *get_pgd_slow(struct mm_struct *mm)
  28{
  29        pgd_t *new_pgd, *init_pgd;
  30        pmd_t *new_pmd, *init_pmd;
  31        pte_t *new_pte, *init_pte;
  32
  33        new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0);
  34        if (!new_pgd)
  35                goto no_pgd;
  36
  37        memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
  38
  39        /*
  40         * Copy over the kernel and IO PGD entries
  41         */
  42        init_pgd = pgd_offset_k(0);
  43        memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
  44                       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
  45
  46        clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
  47
  48        if (!vectors_high()) {
  49                /*
  50                 * On UniCore, first page must always be allocated since it
  51                 * contains the machine vectors.
  52                 */
  53                new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0);
  54                if (!new_pmd)
  55                        goto no_pmd;
  56
  57                new_pte = pte_alloc_map(mm, NULL, new_pmd, 0);
  58                if (!new_pte)
  59                        goto no_pte;
  60
  61                init_pmd = pmd_offset((pud_t *)init_pgd, 0);
  62                init_pte = pte_offset_map(init_pmd, 0);
  63                set_pte(new_pte, *init_pte);
  64                pte_unmap(init_pte);
  65                pte_unmap(new_pte);
  66        }
  67
  68        return new_pgd;
  69
  70no_pte:
  71        pmd_free(mm, new_pmd);
  72no_pmd:
  73        free_pages((unsigned long)new_pgd, 0);
  74no_pgd:
  75        return NULL;
  76}
  77
  78void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
  79{
  80        pmd_t *pmd;
  81        pgtable_t pte;
  82
  83        if (!pgd)
  84                return;
  85
  86        /* pgd is always present and good */
  87        pmd = pmd_off(pgd, 0);
  88        if (pmd_none(*pmd))
  89                goto free;
  90        if (pmd_bad(*pmd)) {
  91                pmd_ERROR(*pmd);
  92                pmd_clear(pmd);
  93                goto free;
  94        }
  95
  96        pte = pmd_pgtable(*pmd);
  97        pmd_clear(pmd);
  98        pte_free(mm, pte);
  99        pmd_free(mm, pmd);
 100free:
 101        free_pages((unsigned long) pgd, 0);
 102}
 103