diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:11:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:11:25 +0300 |
commit | 7b7adc4a016a1decb806eb71ecab98721fa7f146 (patch) | |
tree | 0a6f9a6e5659faa94604fbc575382a18f143c657 /arch/unicore32/mm/pgd.c | |
parent | 31598e8713ef501c8f6aad2e2ec8a9457e8877c1 (diff) | |
parent | 289d6b0e287e0acd85f3e6b7ea6c2cb5c234909a (diff) | |
download | linux-7b7adc4a016a1decb806eb71ecab98721fa7f146.tar.xz |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32: (40 commits)
unicore32: rewrite arch-specific tlb.h to use asm-generic version
unicore32: modify io_p2v and io_v2p macros, and adjust PKUNITY_mmio_BASEs
unicore32: replace unicore32-specific iomap functions with generic lib implementation
unicore32 machine related: add frame buffer driver for pkunity-v3 soc
unicore32 machine related files: add i2c bus drivers for pkunity-v3 soc
unicore32 io: redefine __REG(x) and re-use readl/writel funcs
unicore32 i8042 upgrade and bugfix: adjust resource request region type
unicore32 upgrade to v2.6.38-rc5: add one more paramter for pte_alloc_map call
unicore32 i8042: adjust io funcs of i8042-unicore32io.h
unicore32: rename PKUNITY_IOSPACE_BASE to PKUNITY_MMIO_BASE
unicore32: modify function names and parameters for irq_chips
unicore32: remove unused lines in arch/unicore32/include/asm/irq.h
unicore32 time.c: change calculate method for clock_event_device
unicore32: ADD MAINTAINER for unicore32 architecture
unicore32 machine related files: ps2 driver
unicore32 machine related files: pci bus handling
unicore32 machine related files: hardware registers
unicore32 machine related files: core files
unicore32 additional architecture files: boot process
unicore32 additional architecture files: low-level lib: misc
...
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/unicore32/mm/pgd.c')
-rw-r--r-- | arch/unicore32/mm/pgd.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/unicore32/mm/pgd.c b/arch/unicore32/mm/pgd.c new file mode 100644 index 000000000000..08b8d4295e70 --- /dev/null +++ b/arch/unicore32/mm/pgd.c @@ -0,0 +1,102 @@ +/* + * linux/arch/unicore32/mm/pgd.c + * + * Code specific to PKUnity SoC and UniCore ISA + * + * Copyright (C) 2001-2010 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/mm.h> +#include <linux/gfp.h> +#include <linux/highmem.h> + +#include <asm/pgalloc.h> +#include <asm/page.h> +#include <asm/tlbflush.h> + +#include "mm.h" + +#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) + +/* + * need to get a 4k page for level 1 + */ +pgd_t *get_pgd_slow(struct mm_struct *mm) +{ + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + + new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0); + if (!new_pgd) + goto no_pgd; + + memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); + + /* + * Copy over the kernel and IO PGD entries + */ + init_pgd = pgd_offset_k(0); + memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, + (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); + + clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); + + if (!vectors_high()) { + /* + * On UniCore, first page must always be allocated since it + * contains the machine vectors. + */ + new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0); + if (!new_pmd) + goto no_pmd; + + new_pte = pte_alloc_map(mm, NULL, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pmd = pmd_offset((pud_t *)init_pgd, 0); + init_pte = pte_offset_map(init_pmd, 0); + set_pte(new_pte, *init_pte); + pte_unmap(init_pte); + pte_unmap(new_pte); + } + + return new_pgd; + +no_pte: + pmd_free(mm, new_pmd); +no_pmd: + free_pages((unsigned long)new_pgd, 0); +no_pgd: + return NULL; +} + +void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd) +{ + pmd_t *pmd; + pgtable_t pte; + + if (!pgd) + return; + + /* pgd is always present and good */ + pmd = pmd_off(pgd, 0); + if (pmd_none(*pmd)) + goto free; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + goto free; + } + + pte = pmd_pgtable(*pmd); + pmd_clear(pmd); + pte_free(mm, pte); + pmd_free(mm, pmd); +free: + free_pages((unsigned long) pgd, 0); +} |