sh: Generalise the pte handling code for the fixmap path
[safe/jmp/linux-2.6] / arch / sh / mm / init.c
index d5fb014..30a9b53 100644 (file)
@@ -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)
 {