MIPS: Transparent Huge Pages support

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Ralf Baechle 2012-10-18 13:54:15 +02:00
parent f65aad4177
commit 970d032fec
8 changed files with 243 additions and 6 deletions

View file

@ -8,6 +8,7 @@
#ifndef _ASM_PGTABLE_H
#define _ASM_PGTABLE_H
#include <linux/mmzone.h>
#ifdef CONFIG_32BIT
#include <asm/pgtable-32.h>
#endif
@ -94,7 +95,12 @@ extern void paging_init(void);
* and a page entry and page directory to the page they refer to.
*/
#define pmd_phys(pmd) virt_to_phys((void *)pmd_val(pmd))
#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
#define __pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
#ifndef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_page(pmd) __pmd_page(pmd)
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#define pmd_page_vaddr(pmd) pmd_val(pmd)
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
@ -374,6 +380,14 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
__update_cache(vma, address, pte);
}
static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp)
{
pte_t pte = *(pte_t *)pmdp;
__update_tlb(vma, address, pte);
}
#define kern_addr_valid(addr) (1)
#ifdef CONFIG_64BIT_PHYS_ADDR
@ -393,6 +407,157 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
extern int has_transparent_hugepage(void);
static inline int pmd_trans_huge(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_HUGE);
}
static inline pmd_t pmd_mkhuge(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_HUGE;
return pmd;
}
static inline int pmd_trans_splitting(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_SPLITTING);
}
static inline pmd_t pmd_mksplitting(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_SPLITTING;
return pmd;
}
extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd);
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
/* Extern to avoid header file madness */
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
unsigned long address,
pmd_t *pmdp);
#define __HAVE_ARCH_PMD_WRITE
static inline int pmd_write(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_WRITE);
}
static inline pmd_t pmd_wrprotect(pmd_t pmd)
{
pmd_val(pmd) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
return pmd;
}
static inline pmd_t pmd_mkwrite(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_WRITE;
if (pmd_val(pmd) & _PAGE_MODIFIED)
pmd_val(pmd) |= _PAGE_SILENT_WRITE;
return pmd;
}
static inline int pmd_dirty(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_MODIFIED);
}
static inline pmd_t pmd_mkclean(pmd_t pmd)
{
pmd_val(pmd) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
return pmd;
}
static inline pmd_t pmd_mkdirty(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_MODIFIED;
if (pmd_val(pmd) & _PAGE_WRITE)
pmd_val(pmd) |= _PAGE_SILENT_WRITE;
return pmd;
}
static inline int pmd_young(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_ACCESSED);
}
static inline pmd_t pmd_mkold(pmd_t pmd)
{
pmd_val(pmd) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ);
return pmd;
}
static inline pmd_t pmd_mkyoung(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_ACCESSED;
if (cpu_has_rixi) {
if (!(pmd_val(pmd) & _PAGE_NO_READ))
pmd_val(pmd) |= _PAGE_SILENT_READ;
} else {
if (pmd_val(pmd) & _PAGE_READ)
pmd_val(pmd) |= _PAGE_SILENT_READ;
}
return pmd;
}
/* Extern to avoid header file madness */
extern pmd_t mk_pmd(struct page *page, pgprot_t prot);
static inline unsigned long pmd_pfn(pmd_t pmd)
{
return pmd_val(pmd) >> _PFN_SHIFT;
}
static inline struct page *pmd_page(pmd_t pmd)
{
if (pmd_trans_huge(pmd))
return pfn_to_page(pmd_pfn(pmd));
return pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT);
}
static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
{
pmd_val(pmd) = (pmd_val(pmd) & _PAGE_CHG_MASK) | pgprot_val(newprot);
return pmd;
}
static inline pmd_t pmd_mknotpresent(pmd_t pmd)
{
pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY);
return pmd;
}
/*
* The generic version pmdp_get_and_clear uses a version of pmd_clear() with a
* different prototype.
*/
#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
pmd_t old = *pmdp;
pmd_clear(pmdp);
return old;
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#include <asm-generic/pgtable.h>
/*