153492b1dSGerald Schaefer /* 253492b1dSGerald Schaefer * IBM System z Huge TLB Page Support for Kernel. 353492b1dSGerald Schaefer * 4a53c8fabSHeiko Carstens * Copyright IBM Corp. 2007 553492b1dSGerald Schaefer * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> 653492b1dSGerald Schaefer */ 753492b1dSGerald Schaefer 853492b1dSGerald Schaefer #include <linux/mm.h> 953492b1dSGerald Schaefer #include <linux/hugetlb.h> 1053492b1dSGerald Schaefer 11e5098611SMartin Schwidefsky static inline pmd_t __pte_to_pmd(pte_t pte) 1253492b1dSGerald Schaefer { 13e5098611SMartin Schwidefsky pmd_t pmd; 1453492b1dSGerald Schaefer 15e5098611SMartin Schwidefsky /* 16e5098611SMartin Schwidefsky * Convert encoding pte bits pmd bits 17a1c843b8SMartin Schwidefsky * lIR.uswrdy.p dy..R...I...wr 18a1c843b8SMartin Schwidefsky * empty 010.000000.0 -> 00..0...1...00 19a1c843b8SMartin Schwidefsky * prot-none, clean, old 111.000000.1 -> 00..1...1...00 20a1c843b8SMartin Schwidefsky * prot-none, clean, young 111.000001.1 -> 01..1...1...00 21a1c843b8SMartin Schwidefsky * prot-none, dirty, old 111.000010.1 -> 10..1...1...00 22a1c843b8SMartin Schwidefsky * prot-none, dirty, young 111.000011.1 -> 11..1...1...00 23a1c843b8SMartin Schwidefsky * read-only, clean, old 111.000100.1 -> 00..1...1...01 24a1c843b8SMartin Schwidefsky * read-only, clean, young 101.000101.1 -> 01..1...0...01 25a1c843b8SMartin Schwidefsky * read-only, dirty, old 111.000110.1 -> 10..1...1...01 26a1c843b8SMartin Schwidefsky * read-only, dirty, young 101.000111.1 -> 11..1...0...01 27a1c843b8SMartin Schwidefsky * read-write, clean, old 111.001100.1 -> 00..1...1...11 28a1c843b8SMartin Schwidefsky * read-write, clean, young 101.001101.1 -> 01..1...0...11 29a1c843b8SMartin Schwidefsky * read-write, dirty, old 110.001110.1 -> 10..0...1...11 30a1c843b8SMartin Schwidefsky * read-write, dirty, young 100.001111.1 -> 11..0...0...11 31a1c843b8SMartin Schwidefsky * HW-bits: R read-only, I invalid 32a1c843b8SMartin Schwidefsky * SW-bits: p present, y young, d dirty, r read, w write, s special, 33a1c843b8SMartin Schwidefsky * u unused, l large 34e5098611SMartin Schwidefsky */ 35e5098611SMartin Schwidefsky if (pte_present(pte)) { 36e5098611SMartin Schwidefsky pmd_val(pmd) = pte_val(pte) & PAGE_MASK; 37152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_READ) >> 4; 38152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_WRITE) >> 4; 39152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_INVALID) >> 5; 40152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_PROTECT); 41152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; 42152125b7SMartin Schwidefsky pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; 43e5098611SMartin Schwidefsky } else 44e5098611SMartin Schwidefsky pmd_val(pmd) = _SEGMENT_ENTRY_INVALID; 45e5098611SMartin Schwidefsky return pmd; 4653492b1dSGerald Schaefer } 4753492b1dSGerald Schaefer 48e5098611SMartin Schwidefsky static inline pte_t __pmd_to_pte(pmd_t pmd) 49e5098611SMartin Schwidefsky { 50e5098611SMartin Schwidefsky pte_t pte; 51e5098611SMartin Schwidefsky 52e5098611SMartin Schwidefsky /* 53e5098611SMartin Schwidefsky * Convert encoding pmd bits pte bits 54a1c843b8SMartin Schwidefsky * dy..R...I...wr lIR.uswrdy.p 55a1c843b8SMartin Schwidefsky * empty 00..0...1...00 -> 010.000000.0 56a1c843b8SMartin Schwidefsky * prot-none, clean, old 00..1...1...00 -> 111.000000.1 57a1c843b8SMartin Schwidefsky * prot-none, clean, young 01..1...1...00 -> 111.000001.1 58a1c843b8SMartin Schwidefsky * prot-none, dirty, old 10..1...1...00 -> 111.000010.1 59a1c843b8SMartin Schwidefsky * prot-none, dirty, young 11..1...1...00 -> 111.000011.1 60a1c843b8SMartin Schwidefsky * read-only, clean, old 00..1...1...01 -> 111.000100.1 61a1c843b8SMartin Schwidefsky * read-only, clean, young 01..1...0...01 -> 101.000101.1 62a1c843b8SMartin Schwidefsky * read-only, dirty, old 10..1...1...01 -> 111.000110.1 63a1c843b8SMartin Schwidefsky * read-only, dirty, young 11..1...0...01 -> 101.000111.1 64a1c843b8SMartin Schwidefsky * read-write, clean, old 00..1...1...11 -> 111.001100.1 65a1c843b8SMartin Schwidefsky * read-write, clean, young 01..1...0...11 -> 101.001101.1 66a1c843b8SMartin Schwidefsky * read-write, dirty, old 10..0...1...11 -> 110.001110.1 67a1c843b8SMartin Schwidefsky * read-write, dirty, young 11..0...0...11 -> 100.001111.1 68a1c843b8SMartin Schwidefsky * HW-bits: R read-only, I invalid 69a1c843b8SMartin Schwidefsky * SW-bits: p present, y young, d dirty, r read, w write, s special, 70a1c843b8SMartin Schwidefsky * u unused, l large 71e5098611SMartin Schwidefsky */ 72e5098611SMartin Schwidefsky if (pmd_present(pmd)) { 73152125b7SMartin Schwidefsky pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE; 74152125b7SMartin Schwidefsky pte_val(pte) |= _PAGE_LARGE | _PAGE_PRESENT; 75152125b7SMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_READ) << 4; 76152125b7SMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4; 77152125b7SMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5; 78152125b7SMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT); 79b7d14f3aSMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10; 80b7d14f3aSMartin Schwidefsky pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10; 81e5098611SMartin Schwidefsky } else 82e5098611SMartin Schwidefsky pte_val(pte) = _PAGE_INVALID; 83e5098611SMartin Schwidefsky return pte; 84e5098611SMartin Schwidefsky } 85e5098611SMartin Schwidefsky 86e5098611SMartin Schwidefsky void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, 87e5098611SMartin Schwidefsky pte_t *ptep, pte_t pte) 88e5098611SMartin Schwidefsky { 89ce415712SDominik Dingel pmd_t pmd = __pte_to_pmd(pte); 90e5098611SMartin Schwidefsky 916a5c1482SHeiko Carstens pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; 92e5098611SMartin Schwidefsky *(pmd_t *) ptep = pmd; 93e5098611SMartin Schwidefsky } 94e5098611SMartin Schwidefsky 95e5098611SMartin Schwidefsky pte_t huge_ptep_get(pte_t *ptep) 96e5098611SMartin Schwidefsky { 97ce415712SDominik Dingel pmd_t pmd = *(pmd_t *) ptep; 98e5098611SMartin Schwidefsky 99e5098611SMartin Schwidefsky return __pmd_to_pte(pmd); 100e5098611SMartin Schwidefsky } 101e5098611SMartin Schwidefsky 102e5098611SMartin Schwidefsky pte_t huge_ptep_get_and_clear(struct mm_struct *mm, 103e5098611SMartin Schwidefsky unsigned long addr, pte_t *ptep) 104e5098611SMartin Schwidefsky { 105e5098611SMartin Schwidefsky pmd_t *pmdp = (pmd_t *) ptep; 106e5098611SMartin Schwidefsky pte_t pte = huge_ptep_get(ptep); 107e5098611SMartin Schwidefsky 1081b948d6cSMartin Schwidefsky pmdp_flush_direct(mm, addr, pmdp); 109e5098611SMartin Schwidefsky pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; 110e5098611SMartin Schwidefsky return pte; 11153492b1dSGerald Schaefer } 11253492b1dSGerald Schaefer 113a5516438SAndi Kleen pte_t *huge_pte_alloc(struct mm_struct *mm, 114a5516438SAndi Kleen unsigned long addr, unsigned long sz) 11553492b1dSGerald Schaefer { 11653492b1dSGerald Schaefer pgd_t *pgdp; 11753492b1dSGerald Schaefer pud_t *pudp; 11853492b1dSGerald Schaefer pmd_t *pmdp = NULL; 11953492b1dSGerald Schaefer 12053492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 12153492b1dSGerald Schaefer pudp = pud_alloc(mm, pgdp, addr); 12253492b1dSGerald Schaefer if (pudp) 12353492b1dSGerald Schaefer pmdp = pmd_alloc(mm, pudp, addr); 12453492b1dSGerald Schaefer return (pte_t *) pmdp; 12553492b1dSGerald Schaefer } 12653492b1dSGerald Schaefer 12753492b1dSGerald Schaefer pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) 12853492b1dSGerald Schaefer { 12953492b1dSGerald Schaefer pgd_t *pgdp; 13053492b1dSGerald Schaefer pud_t *pudp; 13153492b1dSGerald Schaefer pmd_t *pmdp = NULL; 13253492b1dSGerald Schaefer 13353492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 13453492b1dSGerald Schaefer if (pgd_present(*pgdp)) { 13553492b1dSGerald Schaefer pudp = pud_offset(pgdp, addr); 13653492b1dSGerald Schaefer if (pud_present(*pudp)) 13753492b1dSGerald Schaefer pmdp = pmd_offset(pudp, addr); 13853492b1dSGerald Schaefer } 13953492b1dSGerald Schaefer return (pte_t *) pmdp; 14053492b1dSGerald Schaefer } 14153492b1dSGerald Schaefer 14253492b1dSGerald Schaefer int pmd_huge(pmd_t pmd) 14353492b1dSGerald Schaefer { 144*cbd7d9c2SDominik Dingel return pmd_large(pmd); 14553492b1dSGerald Schaefer } 14653492b1dSGerald Schaefer 147ceb86879SAndi Kleen int pud_huge(pud_t pud) 148ceb86879SAndi Kleen { 149ceb86879SAndi Kleen return 0; 150ceb86879SAndi Kleen } 151