xref: /openbmc/linux/arch/s390/mm/hugetlbpage.c (revision cbd7d9c2b70f5e2fc78e0c90b3034b94dca6c82b)
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