2005-04-16 15:20:36 -07:00
/*
2008-08-02 10:55:55 +01:00
* arch / arm / include / asm / pgalloc . h
2005-04-16 15:20:36 -07:00
*
* Copyright ( C ) 2000 - 2001 Russell King
*
* 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 .
*/
# ifndef _ASMARM_PGALLOC_H
# define _ASMARM_PGALLOC_H
2011-02-22 23:29:37 +01:00
# include <linux/pagemap.h>
2006-03-16 14:44:36 +00:00
# include <asm/domain.h>
# include <asm/pgtable-hwdef.h>
2005-04-16 15:20:36 -07:00
# include <asm/processor.h>
# include <asm/cacheflush.h>
# include <asm/tlbflush.h>
2006-06-20 20:46:52 +01:00
# define check_pgt_cache() do { } while (0)
# ifdef CONFIG_MMU
2006-03-16 14:44:36 +00:00
# define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
# define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
2011-11-22 17:30:29 +00:00
# ifdef CONFIG_ARM_LPAE
static inline pmd_t * pmd_alloc_one ( struct mm_struct * mm , unsigned long addr )
{
return ( pmd_t * ) get_zeroed_page ( GFP_KERNEL | __GFP_REPEAT ) ;
}
static inline void pmd_free ( struct mm_struct * mm , pmd_t * pmd )
{
BUG_ON ( ( unsigned long ) pmd & ( PAGE_SIZE - 1 ) ) ;
free_page ( ( unsigned long ) pmd ) ;
}
static inline void pud_populate ( struct mm_struct * mm , pud_t * pud , pmd_t * pmd )
{
set_pud ( pud , __pud ( __pa ( pmd ) | PMD_TYPE_TABLE ) ) ;
}
# else /* !CONFIG_ARM_LPAE */
2005-04-16 15:20:36 -07:00
/*
* Since we have only two - level page tables , these are trivial
*/
# define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); })
2008-02-04 22:29:14 -08:00
# define pmd_free(mm, pmd) do { } while (0)
2011-11-22 17:30:28 +00:00
# define pud_populate(mm,pmd,pte) BUG()
2005-04-16 15:20:36 -07:00
2011-11-22 17:30:29 +00:00
# endif /* CONFIG_ARM_LPAE */
2010-11-21 11:00:56 +00:00
extern pgd_t * pgd_alloc ( struct mm_struct * mm ) ;
extern void pgd_free ( struct mm_struct * mm , pgd_t * pgd ) ;
2005-04-16 15:20:36 -07:00
2009-08-17 20:02:06 +01:00
# define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
2010-11-16 00:16:01 +00:00
static inline void clean_pte_table ( pte_t * pte )
{
clean_dcache_area ( pte + PTE_HWTABLE_PTRS , PTE_HWTABLE_SIZE ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Allocate one PTE table .
*
* This actually allocates two hardware PTE tables , but we wrap this up
* into one table thus :
*
* + - - - - - - - - - - - - +
* | Linux pt 0 |
* + - - - - - - - - - - - - +
* | Linux pt 1 |
* + - - - - - - - - - - - - +
2010-11-16 00:16:01 +00:00
* | h / w pt 0 |
* + - - - - - - - - - - - - +
* | h / w pt 1 |
* + - - - - - - - - - - - - +
2005-04-16 15:20:36 -07:00
*/
static inline pte_t *
pte_alloc_one_kernel ( struct mm_struct * mm , unsigned long addr )
{
pte_t * pte ;
2009-08-17 20:02:06 +01:00
pte = ( pte_t * ) __get_free_page ( PGALLOC_GFP ) ;
2010-11-16 00:16:01 +00:00
if ( pte )
clean_pte_table ( pte ) ;
2005-04-16 15:20:36 -07:00
return pte ;
}
2008-02-08 04:22:04 -08:00
static inline pgtable_t
2005-04-16 15:20:36 -07:00
pte_alloc_one ( struct mm_struct * mm , unsigned long addr )
{
struct page * pte ;
2009-08-17 20:02:06 +01:00
# ifdef CONFIG_HIGHPTE
pte = alloc_pages ( PGALLOC_GFP | __GFP_HIGHMEM , 0 ) ;
# else
pte = alloc_pages ( PGALLOC_GFP , 0 ) ;
# endif
2005-04-16 15:20:36 -07:00
if ( pte ) {
2010-11-16 00:16:01 +00:00
if ( ! PageHighMem ( pte ) )
clean_pte_table ( page_address ( pte ) ) ;
2008-02-08 04:22:04 -08:00
pgtable_page_ctor ( pte ) ;
2005-04-16 15:20:36 -07:00
}
return pte ;
}
/*
* Free one PTE table .
*/
2008-02-04 22:29:14 -08:00
static inline void pte_free_kernel ( struct mm_struct * mm , pte_t * pte )
2005-04-16 15:20:36 -07:00
{
2010-11-16 00:16:01 +00:00
if ( pte )
2005-04-16 15:20:36 -07:00
free_page ( ( unsigned long ) pte ) ;
}
2008-02-08 04:22:04 -08:00
static inline void pte_free ( struct mm_struct * mm , pgtable_t pte )
2005-04-16 15:20:36 -07:00
{
2008-02-08 04:22:04 -08:00
pgtable_page_dtor ( pte ) ;
2005-04-16 15:20:36 -07:00
__free_page ( pte ) ;
}
2010-11-16 00:16:01 +00:00
static inline void __pmd_populate ( pmd_t * pmdp , phys_addr_t pte ,
2011-09-05 17:51:56 +01:00
pmdval_t prot )
2005-06-22 20:58:29 +01:00
{
2011-09-05 17:51:56 +01:00
pmdval_t pmdval = ( pte + PTE_HWTABLE_OFF ) | prot ;
2005-06-22 20:58:29 +01:00
pmdp [ 0 ] = __pmd ( pmdval ) ;
2011-11-22 17:30:29 +00:00
# ifndef CONFIG_ARM_LPAE
2005-06-22 20:58:29 +01:00
pmdp [ 1 ] = __pmd ( pmdval + 256 * sizeof ( pte_t ) ) ;
2011-11-22 17:30:29 +00:00
# endif
2005-06-22 20:58:29 +01:00
flush_pmd_entry ( pmdp ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Populate the pmdp entry with a pointer to the pte . This pmd is part
* of the mm address space .
*
* Ensure that we always set both PMD entries .
*/
static inline void
pmd_populate_kernel ( struct mm_struct * mm , pmd_t * pmdp , pte_t * ptep )
{
/*
2010-11-16 00:16:01 +00:00
* The pmd must be loaded with the physical address of the PTE table
2005-04-16 15:20:36 -07:00
*/
2010-11-16 00:16:01 +00:00
__pmd_populate ( pmdp , __pa ( ptep ) , _PAGE_KERNEL_TABLE ) ;
2005-04-16 15:20:36 -07:00
}
static inline void
2008-02-08 04:22:04 -08:00
pmd_populate ( struct mm_struct * mm , pmd_t * pmdp , pgtable_t ptep )
2005-04-16 15:20:36 -07:00
{
2010-11-16 00:16:01 +00:00
__pmd_populate ( pmdp , page_to_phys ( ptep ) , _PAGE_USER_TABLE ) ;
2005-04-16 15:20:36 -07:00
}
2008-02-08 04:22:04 -08:00
# define pmd_pgtable(pmd) pmd_page(pmd)
2005-04-16 15:20:36 -07:00
2006-06-20 20:46:52 +01:00
# endif /* CONFIG_MMU */
2005-04-16 15:20:36 -07:00
# endif