2011-01-15 18:17:56 +08:00
/*
* linux / arch / unicore32 / mm / pgd . c
*
* Code specific to PKUnity SoC and UniCore ISA
*
* Copyright ( C ) 2001 - 2010 GUAN Xue - tao
*
* 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/mm.h>
# include <linux/gfp.h>
# include <linux/highmem.h>
# include <asm/pgalloc.h>
# include <asm/page.h>
# include <asm/tlbflush.h>
# include "mm.h"
# define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
/*
* need to get a 4 k page for level 1
*/
pgd_t * get_pgd_slow ( struct mm_struct * mm )
{
pgd_t * new_pgd , * init_pgd ;
pmd_t * new_pmd , * init_pmd ;
pte_t * new_pte , * init_pte ;
new_pgd = ( pgd_t * ) __get_free_pages ( GFP_KERNEL , 0 ) ;
if ( ! new_pgd )
goto no_pgd ;
memset ( new_pgd , 0 , FIRST_KERNEL_PGD_NR * sizeof ( pgd_t ) ) ;
/*
* Copy over the kernel and IO PGD entries
*/
init_pgd = pgd_offset_k ( 0 ) ;
memcpy ( new_pgd + FIRST_KERNEL_PGD_NR , init_pgd + FIRST_KERNEL_PGD_NR ,
( PTRS_PER_PGD - FIRST_KERNEL_PGD_NR ) * sizeof ( pgd_t ) ) ;
clean_dcache_area ( new_pgd , PTRS_PER_PGD * sizeof ( pgd_t ) ) ;
if ( ! vectors_high ( ) ) {
/*
* On UniCore , first page must always be allocated since it
* contains the machine vectors .
*/
new_pmd = pmd_alloc ( mm , ( pud_t * ) new_pgd , 0 ) ;
if ( ! new_pmd )
goto no_pmd ;
2016-03-17 14:19:11 -07:00
new_pte = pte_alloc_map ( mm , new_pmd , 0 ) ;
2011-01-15 18:17:56 +08:00
if ( ! new_pte )
goto no_pte ;
init_pmd = pmd_offset ( ( pud_t * ) init_pgd , 0 ) ;
init_pte = pte_offset_map ( init_pmd , 0 ) ;
set_pte ( new_pte , * init_pte ) ;
pte_unmap ( init_pte ) ;
pte_unmap ( new_pte ) ;
}
return new_pgd ;
no_pte :
pmd_free ( mm , new_pmd ) ;
2015-02-11 15:26:53 -08:00
mm_dec_nr_pmds ( mm ) ;
2011-01-15 18:17:56 +08:00
no_pmd :
free_pages ( ( unsigned long ) new_pgd , 0 ) ;
no_pgd :
return NULL ;
}
void free_pgd_slow ( struct mm_struct * mm , pgd_t * pgd )
{
pmd_t * pmd ;
pgtable_t pte ;
if ( ! pgd )
return ;
/* pgd is always present and good */
pmd = pmd_off ( pgd , 0 ) ;
if ( pmd_none ( * pmd ) )
goto free ;
if ( pmd_bad ( * pmd ) ) {
pmd_ERROR ( * pmd ) ;
pmd_clear ( pmd ) ;
goto free ;
}
pte = pmd_pgtable ( * pmd ) ;
pmd_clear ( pmd ) ;
pte_free ( mm , pte ) ;
2017-11-15 17:35:37 -08:00
mm_dec_nr_ptes ( mm ) ;
2011-01-15 18:17:56 +08:00
pmd_free ( mm , pmd ) ;
2015-02-11 15:26:53 -08:00
mm_dec_nr_pmds ( mm ) ;
2011-01-15 18:17:56 +08:00
free :
free_pages ( ( unsigned long ) pgd , 0 ) ;
}