sh: Generalise the pte handling code for the fixmap path
Generalise the code for setting and clearing pte's and allow TLB entries to be pinned and unpinned if the _PAGE_WIRED flag is present. Signed-off-by: Matt Fleming <matt@console-pimps.org>
This commit is contained in:
parent
24ef7fc4dc
commit
07cad4dc1b
2 changed files with 41 additions and 4 deletions
|
@ -65,6 +65,7 @@ enum fixed_addresses {
|
|||
|
||||
extern void __set_fixmap(enum fixed_addresses idx,
|
||||
unsigned long phys, pgprot_t flags);
|
||||
extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags);
|
||||
|
||||
#define set_fixmap(idx, phys) \
|
||||
__set_fixmap(idx, phys, PAGE_KERNEL)
|
||||
|
|
|
@ -39,7 +39,7 @@ unsigned long cached_to_uncached = P2SEG - P1SEG;
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
|
||||
static pte_t *__get_pte_phys(unsigned long addr)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
|
@ -49,22 +49,30 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
|
|||
pgd = pgd_offset_k(addr);
|
||||
if (pgd_none(*pgd)) {
|
||||
pgd_ERROR(*pgd);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pud = pud_alloc(NULL, pgd, addr);
|
||||
if (unlikely(!pud)) {
|
||||
pud_ERROR(*pud);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pmd = pmd_alloc(NULL, pud, addr);
|
||||
if (unlikely(!pmd)) {
|
||||
pmd_ERROR(*pmd);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pte = pte_offset_kernel(pmd, addr);
|
||||
return pte;
|
||||
}
|
||||
|
||||
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
|
||||
{
|
||||
pte_t *pte;
|
||||
|
||||
pte = __get_pte_phys(addr);
|
||||
if (!pte_none(*pte)) {
|
||||
pte_ERROR(*pte);
|
||||
return;
|
||||
|
@ -72,6 +80,22 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
|
|||
|
||||
set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
|
||||
local_flush_tlb_one(get_asid(), addr);
|
||||
|
||||
if (pgprot_val(prot) & _PAGE_WIRED)
|
||||
tlb_wire_entry(NULL, addr, *pte);
|
||||
}
|
||||
|
||||
static void clear_pte_phys(unsigned long addr, pgprot_t prot)
|
||||
{
|
||||
pte_t *pte;
|
||||
|
||||
pte = __get_pte_phys(addr);
|
||||
|
||||
if (pgprot_val(prot) & _PAGE_WIRED)
|
||||
tlb_unwire_entry();
|
||||
|
||||
set_pte(pte, pfn_pte(0, __pgprot(0)));
|
||||
local_flush_tlb_one(get_asid(), addr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -101,6 +125,18 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
|
|||
set_pte_phys(address, phys, prot);
|
||||
}
|
||||
|
||||
void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
|
||||
{
|
||||
unsigned long address = __fix_to_virt(idx);
|
||||
|
||||
if (idx >= __end_of_fixed_addresses) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
clear_pte_phys(address, prot);
|
||||
}
|
||||
|
||||
void __init page_table_range_init(unsigned long start, unsigned long end,
|
||||
pgd_t *pgd_base)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue