summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-11-17 22:03:41 +0000
committerMatt Fleming <matt@console-pimps.org>2010-01-16 14:29:23 +0000
commit07cad4dc1bfdaefd20c6329e9d8179ad1c600e92 (patch)
tree1ca1e2758dc14245315fc9a9d7334d739d3f0816 /arch
parent24ef7fc4dcc57afa0c33166c25bfe7676ffd4296 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/include/asm/fixmap.h1
-rw-r--r--arch/sh/mm/init.c44
2 files changed, 41 insertions, 4 deletions
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 5ac1e40a511..1566d3361ca 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -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)
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index d5fb014279a..30a9b530d45 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -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)
{