#ifndef _PPC64_PGTABLE_H
#define _PPC64_PGTABLE_H
+#include <asm-generic/4level-fixup.h>
+
/*
* This file contains the functions and defines necessary to modify and use
* the ppc64 hashed page table.
#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
PGD_INDEX_SIZE + PAGE_SHIFT)
+/*
+ * Size of EA range mapped by our pagetables.
+ */
+#define PGTABLE_EA_BITS 41
+#define PGTABLE_EA_MASK ((1UL<<PGTABLE_EA_BITS)-1)
+
/*
* Define the address range of the vmalloc VM area.
*/
-#define VMALLOC_START (0xD000000000000000)
-#define VMALLOC_END (VMALLOC_START + VALID_EA_BITS)
+#define VMALLOC_START (0xD000000000000000ul)
+#define VMALLOC_END (VMALLOC_START + PGTABLE_EA_MASK)
/*
* Define the address range of the imalloc VM area.
*/
#define IMALLOC_START (ioremap_bot)
#define IMALLOC_VMADDR(x) ((unsigned long)(x))
-#define PHBS_IO_BASE (0xE000000000000000) /* Reserve 2 gigs for PHBs */
-#define IMALLOC_BASE (0xE000000080000000)
-#define IMALLOC_END (IMALLOC_BASE + VALID_EA_BITS)
-
-/*
- * Define the address range mapped virt <-> physical
- */
-#define KRANGE_START KERNELBASE
-#define KRANGE_END (KRANGE_START + VALID_EA_BITS)
+#define PHBS_IO_BASE (0xE000000000000000ul) /* Reserve 2 gigs for PHBs */
+#define IMALLOC_BASE (0xE000000080000000ul)
+#define IMALLOC_END (IMALLOC_BASE + PGTABLE_EA_MASK)
/*
* Define the user address range
*/
#define USER_START (0UL)
-#define USER_END (USER_START + VALID_EA_BITS)
+#define USER_END (USER_START + PGTABLE_EA_MASK)
/*
#define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */
#define _PAGE_SECONDARY 0x8000 /* software: HPTE is in secondary group */
#define _PAGE_GROUP_IX 0x7000 /* software: HPTE index within group */
+#define _PAGE_HUGE 0x10000 /* 16MB page */
/* Bits 0x7000 identify the index within an HPT Group */
#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | _PAGE_SECONDARY | _PAGE_GROUP_IX)
/* PAGE_MASK gives the right answer below, but only by accident */
#endif /* __ASSEMBLY__ */
/* shift to put page number into pte */
-#define PTE_SHIFT (16)
+#define PTE_SHIFT (17)
/* We allow 2^41 bytes of real memory, so we need 29 bits in the PMD
* to give the PTE page number. The bottom two bits are for flags. */
#define PMD_TO_PTEPAGE_SHIFT (2)
#ifdef CONFIG_HUGETLB_PAGE
-#define _PMD_HUGEPAGE 0x00000001U
-#define HUGEPTE_BATCH_SIZE (1<<(HPAGE_SHIFT-PMD_SHIFT))
#ifndef __ASSEMBLY__
int hash_huge_page(struct mm_struct *mm, unsigned long access,
unsigned long ea, unsigned long vsid, int local);
+
+void hugetlb_mm_free_pgd(struct mm_struct *mm);
#endif /* __ASSEMBLY__ */
#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
#else
#define hash_huge_page(mm,a,ea,vsid,local) -1
-#define _PMD_HUGEPAGE 0
+#define hugetlb_mm_free_pgd(mm) do {} while (0)
#endif
#define pmd_set(pmdp, ptep) \
(pmd_val(*(pmdp)) = (__ba_to_bpn(ptep) << PMD_TO_PTEPAGE_SHIFT))
#define pmd_none(pmd) (!pmd_val(pmd))
-#define pmd_hugepage(pmd) (!!(pmd_val(pmd) & _PMD_HUGEPAGE))
-#define pmd_bad(pmd) (((pmd_val(pmd)) == 0) || pmd_hugepage(pmd))
-#define pmd_present(pmd) ((!pmd_hugepage(pmd)) \
- && (pmd_val(pmd) & ~_PMD_HUGEPAGE) != 0)
+#define pmd_bad(pmd) (pmd_val(pmd) == 0)
+#define pmd_present(pmd) (pmd_val(pmd) != 0)
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
#define pmd_page_kernel(pmd) \
(__bpn_to_ba(pmd_val(pmd) >> PMD_TO_PTEPAGE_SHIFT))
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+static inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_HUGE;}
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
pte_val(pte) |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) {
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) {
+ pte_val(pte) |= _PAGE_HUGE; return pte; }
/* Atomic PTE updates */
static inline unsigned long pte_update(pte_t *p, unsigned long clr)
return old;
}
-/* PTE updating functions */
+/* PTE updating functions, this function puts the PTE in the
+ * batch, doesn't actually triggers the hash flush immediately,
+ * you need to call flush_tlb_pending() to do that.
+ */
extern void hpte_update(pte_t *ptep, unsigned long pte, int wrprot);
static inline int ptep_test_and_clear_young(pte_t *ptep)
old = pte_update(ptep, _PAGE_ACCESSED);
if (old & _PAGE_HASHPTE) {
hpte_update(ptep, old, 0);
- flush_tlb_pending(); /* XXX generic code doesn't flush */
+ flush_tlb_pending();
}
return (old & _PAGE_ACCESSED) != 0;
}
*/
static inline void set_pte(pte_t *ptep, pte_t pte)
{
- if (pte_present(*ptep))
+ if (pte_present(*ptep)) {
pte_clear(ptep);
+ flush_tlb_pending();
+ }
*ptep = __pte(pte_val(pte)) & ~_PAGE_HPTEFLAGS;
}
+/* Set the dirty and/or accessed bits atomically in a linux PTE, this
+ * function doesn't need to flush the hash entry
+ */
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+ unsigned long bits = pte_val(entry) &
+ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
+ unsigned long old, tmp;
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%4\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ or %0,%3,%0\n\
+ stdcx. %0,0,%4\n\
+ bne- 1b"
+ :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
+ :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
+ :"cc");
+}
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+ do { \
+ __ptep_set_access_flags(__ptep, __entry, __dirty); \
+ flush_tlb_page_nohash(__vma, __address); \
+ } while(0)
+
/*
* Macro to mark a page protection value as "uncacheable".
*/
extern void paging_init(void);
+struct mmu_gather;
+void hugetlb_free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *prev,
+ unsigned long start, unsigned long end);
+
/*
* This gets called at the end of handling a page fault, when
* the kernel has put a new PTE into the page table for the process.
*/
#define kern_addr_valid(addr) (1)
-#define io_remap_page_range remap_page_range
+#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
+ remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
void pgtable_cache_init(void);
-extern void hpte_init_pSeries(void);
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
extern void hpte_init_iSeries(void);
/* imalloc region types */
#define IM_REGION_SUBSET 0x2
#define IM_REGION_EXISTS 0x4
#define IM_REGION_OVERLAP 0x8
+#define IM_REGION_SUPERSET 0x10
extern struct vm_struct * im_get_free_area(unsigned long size);
extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
int region_type);
unsigned long im_free(void *addr);
-typedef pte_t *pte_addr_t;
-
-long pSeries_lpar_hpte_insert(unsigned long hpte_group,
- unsigned long va, unsigned long prpn,
- int secondary, unsigned long hpteflags,
- int bolted, int large);
+extern long pSeries_lpar_hpte_insert(unsigned long hpte_group,
+ unsigned long va, unsigned long prpn,
+ int secondary, unsigned long hpteflags,
+ int bolted, int large);
-long pSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
- unsigned long prpn, int secondary,
- unsigned long hpteflags, int bolted, int large);
+extern long native_hpte_insert(unsigned long hpte_group, unsigned long va,
+ unsigned long prpn, int secondary,
+ unsigned long hpteflags, int bolted, int large);
/*
* find_linux_pte returns the address of a linux pte for a given