linux/arch/mips/mm/highmem.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/highmem.h>
   3#include <linux/sched.h>
   4#include <linux/smp.h>
   5#include <asm/fixmap.h>
   6#include <asm/tlbflush.h>
   7
   8static pte_t *kmap_pte;
   9
  10unsigned long highstart_pfn, highend_pfn;
  11
  12void *kmap(struct page *page)
  13{
  14        void *addr;
  15
  16        might_sleep();
  17        if (!PageHighMem(page))
  18                return page_address(page);
  19        addr = kmap_high(page);
  20        flush_tlb_one((unsigned long)addr);
  21
  22        return addr;
  23}
  24EXPORT_SYMBOL(kmap);
  25
  26void kunmap(struct page *page)
  27{
  28        BUG_ON(in_interrupt());
  29        if (!PageHighMem(page))
  30                return;
  31        kunmap_high(page);
  32}
  33EXPORT_SYMBOL(kunmap);
  34
  35/*
  36 * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
  37 * no global lock is needed and because the kmap code must perform a global TLB
  38 * invalidation when the kmap pool wraps.
  39 *
  40 * However when holding an atomic kmap is is not legal to sleep, so atomic
  41 * kmaps are appropriate for short, tight code paths only.
  42 */
  43
  44void *__kmap_atomic(struct page *page)
  45{
  46        unsigned long vaddr;
  47        int idx, type;
  48
  49        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
  50        pagefault_disable();
  51        if (!PageHighMem(page))
  52                return page_address(page);
  53
  54        type = kmap_atomic_idx_push();
  55        idx = type + KM_TYPE_NR*smp_processor_id();
  56        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
  57#ifdef CONFIG_DEBUG_HIGHMEM
  58        BUG_ON(!pte_none(*(kmap_pte - idx)));
  59#endif
  60        set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
  61        local_flush_tlb_one((unsigned long)vaddr);
  62
  63        return (void*) vaddr;
  64}
  65EXPORT_SYMBOL(__kmap_atomic);
  66
  67void __kunmap_atomic(void *kvaddr)
  68{
  69        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
  70        int type;
  71
  72        if (vaddr < FIXADDR_START) { // FIXME
  73                pagefault_enable();
  74                return;
  75        }
  76
  77        type = kmap_atomic_idx();
  78#ifdef CONFIG_DEBUG_HIGHMEM
  79        {
  80                int idx = type + KM_TYPE_NR * smp_processor_id();
  81
  82                BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
  83
  84                /*
  85                 * force other mappings to Oops if they'll try to access
  86                 * this pte without first remap it
  87                 */
  88                pte_clear(&init_mm, vaddr, kmap_pte-idx);
  89                local_flush_tlb_one(vaddr);
  90        }
  91#endif
  92        kmap_atomic_idx_pop();
  93        pagefault_enable();
  94}
  95EXPORT_SYMBOL(__kunmap_atomic);
  96
  97/*
  98 * This is the same as kmap_atomic() but can map memory that doesn't
  99 * have a struct page associated with it.
 100 */
 101void *kmap_atomic_pfn(unsigned long pfn)
 102{
 103        unsigned long vaddr;
 104        int idx, type;
 105
 106        pagefault_disable();
 107
 108        type = kmap_atomic_idx_push();
 109        idx = type + KM_TYPE_NR*smp_processor_id();
 110        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 111        set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
 112        flush_tlb_one(vaddr);
 113
 114        return (void*) vaddr;
 115}
 116
 117struct page *kmap_atomic_to_page(void *ptr)
 118{
 119        unsigned long idx, vaddr = (unsigned long)ptr;
 120        pte_t *pte;
 121
 122        if (vaddr < FIXADDR_START)
 123                return virt_to_page(ptr);
 124
 125        idx = virt_to_fix(vaddr);
 126        pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
 127        return pte_page(*pte);
 128}
 129
 130void __init kmap_init(void)
 131{
 132        unsigned long kmap_vstart;
 133
 134        /* cache the first kmap pte */
 135        kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
 136        kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
 137}
 138