-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The kmap virtual area borrows a 2MB range at the top of the 16MB area below PAGE_OFFSET currently reserved for kernel modules and/or the XIP kernel. This 2MB corresponds to the range covered by 2 consecutive second-level page tables, or a single pmd entry as seen by the Linux page table abstraction. Because XIP kernels are unlikely to be seen on systems needing highmem support, there shouldn't be any shortage of VM space for modules (14 MB for modules is still way more than twice the typical usage). Because the virtual mapping of highmem pages can go away at any moment after kunmap() is called on them, we need to bypass the delayed cache flushing provided by flush_dcache_page() in that case. The atomic kmap versions are based on fixmaps, and __cpuc_flush_dcache_page() is used directly in that case. Signed-off-by: Nicolas Pitre <nico@marvell.com>
- Loading branch information
Nicolas Pitre
committed
Mar 16, 2009
1 parent
5f0fbf9
commit d73cd42
Showing
6 changed files
with
169 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#ifndef _ASM_HIGHMEM_H | ||
#define _ASM_HIGHMEM_H | ||
|
||
#include <asm/kmap_types.h> | ||
|
||
#define PKMAP_BASE (PAGE_OFFSET - PMD_SIZE) | ||
#define LAST_PKMAP PTRS_PER_PTE | ||
#define LAST_PKMAP_MASK (LAST_PKMAP - 1) | ||
#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) | ||
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) | ||
|
||
#define kmap_prot PAGE_KERNEL | ||
|
||
#define flush_cache_kmaps() flush_cache_all() | ||
|
||
extern pte_t *pkmap_page_table; | ||
|
||
extern void *kmap_high(struct page *page); | ||
extern void kunmap_high(struct page *page); | ||
|
||
extern void *kmap(struct page *page); | ||
extern void kunmap(struct page *page); | ||
extern void *kmap_atomic(struct page *page, enum km_type type); | ||
extern void kunmap_atomic(void *kvaddr, enum km_type type); | ||
extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); | ||
extern struct page *kmap_atomic_to_page(const void *ptr); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* arch/arm/mm/highmem.c -- ARM highmem support | ||
* | ||
* Author: Nicolas Pitre | ||
* Created: september 8, 2008 | ||
* Copyright: Marvell Semiconductors Inc. | ||
* | ||
* 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/module.h> | ||
#include <linux/highmem.h> | ||
#include <linux/interrupt.h> | ||
#include <asm/fixmap.h> | ||
#include <asm/cacheflush.h> | ||
#include <asm/tlbflush.h> | ||
#include "mm.h" | ||
|
||
void *kmap(struct page *page) | ||
{ | ||
might_sleep(); | ||
if (!PageHighMem(page)) | ||
return page_address(page); | ||
return kmap_high(page); | ||
} | ||
EXPORT_SYMBOL(kmap); | ||
|
||
void kunmap(struct page *page) | ||
{ | ||
BUG_ON(in_interrupt()); | ||
if (!PageHighMem(page)) | ||
return; | ||
kunmap_high(page); | ||
} | ||
EXPORT_SYMBOL(kunmap); | ||
|
||
void *kmap_atomic(struct page *page, enum km_type type) | ||
{ | ||
unsigned int idx; | ||
unsigned long vaddr; | ||
|
||
pagefault_disable(); | ||
if (!PageHighMem(page)) | ||
return page_address(page); | ||
|
||
idx = type + KM_TYPE_NR * smp_processor_id(); | ||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
#ifdef CONFIG_DEBUG_HIGHMEM | ||
/* | ||
* With debugging enabled, kunmap_atomic forces that entry to 0. | ||
* Make sure it was indeed properly unmapped. | ||
*/ | ||
BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); | ||
#endif | ||
set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0); | ||
/* | ||
* When debugging is off, kunmap_atomic leaves the previous mapping | ||
* in place, so this TLB flush ensures the TLB is updated with the | ||
* new mapping. | ||
*/ | ||
local_flush_tlb_kernel_page(vaddr); | ||
|
||
return (void *)vaddr; | ||
} | ||
EXPORT_SYMBOL(kmap_atomic); | ||
|
||
void kunmap_atomic(void *kvaddr, enum km_type type) | ||
{ | ||
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; | ||
unsigned int idx = type + KM_TYPE_NR * smp_processor_id(); | ||
|
||
if (kvaddr >= (void *)FIXADDR_START) { | ||
__cpuc_flush_dcache_page((void *)vaddr); | ||
#ifdef CONFIG_DEBUG_HIGHMEM | ||
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); | ||
set_pte_ext(TOP_PTE(vaddr), __pte(0), 0); | ||
local_flush_tlb_kernel_page(vaddr); | ||
#else | ||
(void) idx; /* to kill a warning */ | ||
#endif | ||
} | ||
pagefault_enable(); | ||
} | ||
EXPORT_SYMBOL(kunmap_atomic); | ||
|
||
void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) | ||
{ | ||
unsigned int idx; | ||
unsigned long vaddr; | ||
|
||
pagefault_disable(); | ||
|
||
idx = type + KM_TYPE_NR * smp_processor_id(); | ||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
#ifdef CONFIG_DEBUG_HIGHMEM | ||
BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); | ||
#endif | ||
set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0); | ||
local_flush_tlb_kernel_page(vaddr); | ||
|
||
return (void *)vaddr; | ||
} | ||
|
||
struct page *kmap_atomic_to_page(const void *ptr) | ||
{ | ||
unsigned long vaddr = (unsigned long)ptr; | ||
pte_t *pte; | ||
|
||
if (vaddr < FIXADDR_START) | ||
return virt_to_page(ptr); | ||
|
||
pte = TOP_PTE(vaddr); | ||
return pte_page(*pte); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters