sh: Generalise the pte handling code for the fixmap path
authorMatt Fleming <matt@console-pimps.org>
Tue, 17 Nov 2009 22:03:41 +0000 (22:03 +0000)
committerMatt Fleming <matt@console-pimps.org>
Sat, 16 Jan 2010 14:29:23 +0000 (14:29 +0000)
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>
arch/sh/include/asm/fixmap.h
arch/sh/mm/init.c

index 5ac1e40..1566d33 100644 (file)
@@ -65,6 +65,7 @@ enum fixed_addresses {
 
 extern void __set_fixmap(enum fixed_addresses idx,
                         unsigned long phys, pgprot_t flags);
 
 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)
 
 #define set_fixmap(idx, phys) \
                __set_fixmap(idx, phys, PAGE_KERNEL)
index d5fb014..30a9b53 100644 (file)
@@ -39,7 +39,7 @@ unsigned long cached_to_uncached = P2SEG - P1SEG;
 #endif
 
 #ifdef CONFIG_MMU
 #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;
 {
        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);
        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);
        }
 
        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);
        }
 
        pmd = pmd_alloc(NULL, pud, addr);
        if (unlikely(!pmd)) {
                pmd_ERROR(*pmd);
-               return;
+               return NULL;
        }
 
        pte = pte_offset_kernel(pmd, addr);
        }
 
        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;
        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);
 
        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);
 }
 
        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)
 {
 void __init page_table_range_init(unsigned long start, unsigned long end,
                                         pgd_t *pgd_base)
 {