linux/arch/arm/mm/copypage-v6.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mm/copypage-v6.c
   3 *
   4 *  Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/init.h>
  11#include <linux/spinlock.h>
  12#include <linux/mm.h>
  13#include <linux/highmem.h>
  14
  15#include <asm/pgtable.h>
  16#include <asm/shmparam.h>
  17#include <asm/tlbflush.h>
  18#include <asm/cacheflush.h>
  19#include <asm/cachetype.h>
  20
  21#include "mm.h"
  22
  23#if SHMLBA > 16384
  24#error FIX ME
  25#endif
  26
  27static DEFINE_RAW_SPINLOCK(v6_lock);
  28
  29/*
  30 * Copy the user page.  No aliasing to deal with so we can just
  31 * attack the kernel's existing mapping of these pages.
  32 */
  33static void v6_copy_user_highpage_nonaliasing(struct page *to,
  34        struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
  35{
  36        void *kto, *kfrom;
  37
  38        kfrom = kmap_atomic(from);
  39        kto = kmap_atomic(to);
  40        copy_page(kto, kfrom);
  41        kunmap_atomic(kto);
  42        kunmap_atomic(kfrom);
  43}
  44
  45/*
  46 * Clear the user page.  No aliasing to deal with so we can just
  47 * attack the kernel's existing mapping of this page.
  48 */
  49static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr)
  50{
  51        void *kaddr = kmap_atomic(page);
  52        clear_page(kaddr);
  53        kunmap_atomic(kaddr);
  54}
  55
  56/*
  57 * Discard data in the kernel mapping for the new page.
  58 * FIXME: needs this MCRR to be supported.
  59 */
  60static void discard_old_kernel_data(void *kto)
  61{
  62        __asm__("mcrr   p15, 0, %1, %0, c6      @ 0xec401f06"
  63           :
  64           : "r" (kto),
  65             "r" ((unsigned long)kto + PAGE_SIZE - 1)
  66           : "cc");
  67}
  68
  69/*
  70 * Copy the page, taking account of the cache colour.
  71 */
  72static void v6_copy_user_highpage_aliasing(struct page *to,
  73        struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
  74{
  75        unsigned int offset = CACHE_COLOUR(vaddr);
  76        unsigned long kfrom, kto;
  77
  78        if (!test_and_set_bit(PG_dcache_clean, &from->flags))
  79                __flush_dcache_page(page_mapping(from), from);
  80
  81        /* FIXME: not highmem safe */
  82        discard_old_kernel_data(page_address(to));
  83
  84        /*
  85         * Now copy the page using the same cache colour as the
  86         * pages ultimate destination.
  87         */
  88        raw_spin_lock(&v6_lock);
  89
  90        kfrom = COPYPAGE_V6_FROM + (offset << PAGE_SHIFT);
  91        kto   = COPYPAGE_V6_TO + (offset << PAGE_SHIFT);
  92
  93        set_top_pte(kfrom, mk_pte(from, PAGE_KERNEL));
  94        set_top_pte(kto, mk_pte(to, PAGE_KERNEL));
  95
  96        copy_page((void *)kto, (void *)kfrom);
  97
  98        raw_spin_unlock(&v6_lock);
  99}
 100
 101/*
 102 * Clear the user page.  We need to deal with the aliasing issues,
 103 * so remap the kernel page into the same cache colour as the user
 104 * page.
 105 */
 106static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
 107{
 108        unsigned long to = COPYPAGE_V6_TO + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
 109
 110        /* FIXME: not highmem safe */
 111        discard_old_kernel_data(page_address(page));
 112
 113        /*
 114         * Now clear the page using the same cache colour as
 115         * the pages ultimate destination.
 116         */
 117        raw_spin_lock(&v6_lock);
 118
 119        set_top_pte(to, mk_pte(page, PAGE_KERNEL));
 120        clear_page((void *)to);
 121
 122        raw_spin_unlock(&v6_lock);
 123}
 124
 125struct cpu_user_fns v6_user_fns __initdata = {
 126        .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing,
 127        .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing,
 128};
 129
 130static int __init v6_userpage_init(void)
 131{
 132        if (cache_is_vipt_aliasing()) {
 133                cpu_user.cpu_clear_user_highpage = v6_clear_user_highpage_aliasing;
 134                cpu_user.cpu_copy_user_highpage = v6_copy_user_highpage_aliasing;
 135        }
 136
 137        return 0;
 138}
 139
 140core_initcall(v6_userpage_init);
 141