linux/arch/s390/include/asm/hugetlb.h
<<
>>
Prefs
   1/*
   2 *  IBM System z Huge TLB Page Support for Kernel.
   3 *
   4 *    Copyright IBM Corp. 2008
   5 *    Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
   6 */
   7
   8#ifndef _ASM_S390_HUGETLB_H
   9#define _ASM_S390_HUGETLB_H
  10
  11#include <asm/page.h>
  12#include <asm/pgtable.h>
  13
  14
  15#define is_hugepage_only_range(mm, addr, len)   0
  16#define hugetlb_free_pgd_range                  free_pgd_range
  17
  18void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
  19                     pte_t *ptep, pte_t pte);
  20
  21/*
  22 * If the arch doesn't supply something else, assume that hugepage
  23 * size aligned regions are ok without further preparation.
  24 */
  25static inline int prepare_hugepage_range(struct file *file,
  26                        unsigned long addr, unsigned long len)
  27{
  28        if (len & ~HPAGE_MASK)
  29                return -EINVAL;
  30        if (addr & ~HPAGE_MASK)
  31                return -EINVAL;
  32        return 0;
  33}
  34
  35#define hugetlb_prefault_arch_hook(mm)          do { } while (0)
  36#define arch_clear_hugepage_flags(page)         do { } while (0)
  37
  38int arch_prepare_hugepage(struct page *page);
  39void arch_release_hugepage(struct page *page);
  40
  41static inline pte_t huge_pte_wrprotect(pte_t pte)
  42{
  43        pte_val(pte) |= _PAGE_RO;
  44        return pte;
  45}
  46
  47static inline int huge_pte_none(pte_t pte)
  48{
  49        return (pte_val(pte) & _SEGMENT_ENTRY_INV) &&
  50                !(pte_val(pte) & _SEGMENT_ENTRY_RO);
  51}
  52
  53static inline pte_t huge_ptep_get(pte_t *ptep)
  54{
  55        pte_t pte = *ptep;
  56        unsigned long mask;
  57
  58        if (!MACHINE_HAS_HPAGE) {
  59                ptep = (pte_t *) (pte_val(pte) & _SEGMENT_ENTRY_ORIGIN);
  60                if (ptep) {
  61                        mask = pte_val(pte) &
  62                                (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
  63                        pte = pte_mkhuge(*ptep);
  64                        pte_val(pte) |= mask;
  65                }
  66        }
  67        return pte;
  68}
  69
  70static inline void __pmd_csp(pmd_t *pmdp)
  71{
  72        register unsigned long reg2 asm("2") = pmd_val(*pmdp);
  73        register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
  74                                               _SEGMENT_ENTRY_INV;
  75        register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
  76
  77        asm volatile(
  78                "       csp %1,%3"
  79                : "=m" (*pmdp)
  80                : "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
  81}
  82
  83static inline void huge_ptep_invalidate(struct mm_struct *mm,
  84                                        unsigned long address, pte_t *ptep)
  85{
  86        pmd_t *pmdp = (pmd_t *) ptep;
  87
  88        if (MACHINE_HAS_IDTE)
  89                __pmd_idte(address, pmdp);
  90        else
  91                __pmd_csp(pmdp);
  92        pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY;
  93}
  94
  95static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
  96                                            unsigned long addr, pte_t *ptep)
  97{
  98        pte_t pte = huge_ptep_get(ptep);
  99
 100        huge_ptep_invalidate(mm, addr, ptep);
 101        return pte;
 102}
 103
 104#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
 105({                                                                          \
 106        int __changed = !pte_same(huge_ptep_get(__ptep), __entry);          \
 107        if (__changed) {                                                    \
 108                huge_ptep_invalidate((__vma)->vm_mm, __addr, __ptep);       \
 109                set_huge_pte_at((__vma)->vm_mm, __addr, __ptep, __entry);   \
 110        }                                                                   \
 111        __changed;                                                          \
 112})
 113
 114#define huge_ptep_set_wrprotect(__mm, __addr, __ptep)                   \
 115({                                                                      \
 116        pte_t __pte = huge_ptep_get(__ptep);                            \
 117        if (huge_pte_write(__pte)) {                                    \
 118                huge_ptep_invalidate(__mm, __addr, __ptep);             \
 119                set_huge_pte_at(__mm, __addr, __ptep,                   \
 120                                huge_pte_wrprotect(__pte));             \
 121        }                                                               \
 122})
 123
 124static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
 125                                         unsigned long address, pte_t *ptep)
 126{
 127        huge_ptep_invalidate(vma->vm_mm, address, ptep);
 128}
 129
 130static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
 131{
 132        pte_t pte;
 133        pmd_t pmd;
 134
 135        pmd = mk_pmd_phys(page_to_phys(page), pgprot);
 136        pte_val(pte) = pmd_val(pmd);
 137        return pte;
 138}
 139
 140static inline int huge_pte_write(pte_t pte)
 141{
 142        pmd_t pmd;
 143
 144        pmd_val(pmd) = pte_val(pte);
 145        return pmd_write(pmd);
 146}
 147
 148static inline int huge_pte_dirty(pte_t pte)
 149{
 150        /* No dirty bit in the segment table entry. */
 151        return 0;
 152}
 153
 154static inline pte_t huge_pte_mkwrite(pte_t pte)
 155{
 156        pmd_t pmd;
 157
 158        pmd_val(pmd) = pte_val(pte);
 159        pte_val(pte) = pmd_val(pmd_mkwrite(pmd));
 160        return pte;
 161}
 162
 163static inline pte_t huge_pte_mkdirty(pte_t pte)
 164{
 165        /* No dirty bit in the segment table entry. */
 166        return pte;
 167}
 168
 169static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
 170{
 171        pmd_t pmd;
 172
 173        pmd_val(pmd) = pte_val(pte);
 174        pte_val(pte) = pmd_val(pmd_modify(pmd, newprot));
 175        return pte;
 176}
 177
 178static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
 179                                  pte_t *ptep)
 180{
 181        pmd_clear((pmd_t *) ptep);
 182}
 183
 184#endif /* _ASM_S390_HUGETLB_H */
 185