xref: /openbmc/linux/arch/s390/mm/hugetlbpage.c (revision 53492b1de46a7576170e865062ffcfc93bb5650b)
1*53492b1dSGerald Schaefer /*
2*53492b1dSGerald Schaefer  *  IBM System z Huge TLB Page Support for Kernel.
3*53492b1dSGerald Schaefer  *
4*53492b1dSGerald Schaefer  *    Copyright 2007 IBM Corp.
5*53492b1dSGerald Schaefer  *    Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
6*53492b1dSGerald Schaefer  */
7*53492b1dSGerald Schaefer 
8*53492b1dSGerald Schaefer #include <linux/mm.h>
9*53492b1dSGerald Schaefer #include <linux/hugetlb.h>
10*53492b1dSGerald Schaefer 
11*53492b1dSGerald Schaefer 
12*53492b1dSGerald Schaefer void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
13*53492b1dSGerald Schaefer 				   pte_t *pteptr, pte_t pteval)
14*53492b1dSGerald Schaefer {
15*53492b1dSGerald Schaefer 	pmd_t *pmdp = (pmd_t *) pteptr;
16*53492b1dSGerald Schaefer 	pte_t shadow_pteval = pteval;
17*53492b1dSGerald Schaefer 	unsigned long mask;
18*53492b1dSGerald Schaefer 
19*53492b1dSGerald Schaefer 	if (!MACHINE_HAS_HPAGE) {
20*53492b1dSGerald Schaefer 		pteptr = (pte_t *) pte_page(pteval)[1].index;
21*53492b1dSGerald Schaefer 		mask = pte_val(pteval) &
22*53492b1dSGerald Schaefer 				(_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
23*53492b1dSGerald Schaefer 		pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
24*53492b1dSGerald Schaefer 		if (mm->context.noexec) {
25*53492b1dSGerald Schaefer 			pteptr += PTRS_PER_PTE;
26*53492b1dSGerald Schaefer 			pte_val(shadow_pteval) =
27*53492b1dSGerald Schaefer 					(_SEGMENT_ENTRY + __pa(pteptr)) | mask;
28*53492b1dSGerald Schaefer 		}
29*53492b1dSGerald Schaefer 	}
30*53492b1dSGerald Schaefer 
31*53492b1dSGerald Schaefer 	pmd_val(*pmdp) = pte_val(pteval);
32*53492b1dSGerald Schaefer 	if (mm->context.noexec) {
33*53492b1dSGerald Schaefer 		pmdp = get_shadow_table(pmdp);
34*53492b1dSGerald Schaefer 		pmd_val(*pmdp) = pte_val(shadow_pteval);
35*53492b1dSGerald Schaefer 	}
36*53492b1dSGerald Schaefer }
37*53492b1dSGerald Schaefer 
38*53492b1dSGerald Schaefer int arch_prepare_hugepage(struct page *page)
39*53492b1dSGerald Schaefer {
40*53492b1dSGerald Schaefer 	unsigned long addr = page_to_phys(page);
41*53492b1dSGerald Schaefer 	pte_t pte;
42*53492b1dSGerald Schaefer 	pte_t *ptep;
43*53492b1dSGerald Schaefer 	int i;
44*53492b1dSGerald Schaefer 
45*53492b1dSGerald Schaefer 	if (MACHINE_HAS_HPAGE)
46*53492b1dSGerald Schaefer 		return 0;
47*53492b1dSGerald Schaefer 
48*53492b1dSGerald Schaefer 	ptep = (pte_t *) pte_alloc_one(&init_mm, address);
49*53492b1dSGerald Schaefer 	if (!ptep)
50*53492b1dSGerald Schaefer 		return -ENOMEM;
51*53492b1dSGerald Schaefer 
52*53492b1dSGerald Schaefer 	pte = mk_pte(page, PAGE_RW);
53*53492b1dSGerald Schaefer 	for (i = 0; i < PTRS_PER_PTE; i++) {
54*53492b1dSGerald Schaefer 		set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte);
55*53492b1dSGerald Schaefer 		pte_val(pte) += PAGE_SIZE;
56*53492b1dSGerald Schaefer 	}
57*53492b1dSGerald Schaefer 	page[1].index = (unsigned long) ptep;
58*53492b1dSGerald Schaefer 	return 0;
59*53492b1dSGerald Schaefer }
60*53492b1dSGerald Schaefer 
61*53492b1dSGerald Schaefer void arch_release_hugepage(struct page *page)
62*53492b1dSGerald Schaefer {
63*53492b1dSGerald Schaefer 	pte_t *ptep;
64*53492b1dSGerald Schaefer 
65*53492b1dSGerald Schaefer 	if (MACHINE_HAS_HPAGE)
66*53492b1dSGerald Schaefer 		return;
67*53492b1dSGerald Schaefer 
68*53492b1dSGerald Schaefer 	ptep = (pte_t *) page[1].index;
69*53492b1dSGerald Schaefer 	if (!ptep)
70*53492b1dSGerald Schaefer 		return;
71*53492b1dSGerald Schaefer 	pte_free(&init_mm, ptep);
72*53492b1dSGerald Schaefer 	page[1].index = 0;
73*53492b1dSGerald Schaefer }
74*53492b1dSGerald Schaefer 
75*53492b1dSGerald Schaefer pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
76*53492b1dSGerald Schaefer {
77*53492b1dSGerald Schaefer 	pgd_t *pgdp;
78*53492b1dSGerald Schaefer 	pud_t *pudp;
79*53492b1dSGerald Schaefer 	pmd_t *pmdp = NULL;
80*53492b1dSGerald Schaefer 
81*53492b1dSGerald Schaefer 	pgdp = pgd_offset(mm, addr);
82*53492b1dSGerald Schaefer 	pudp = pud_alloc(mm, pgdp, addr);
83*53492b1dSGerald Schaefer 	if (pudp)
84*53492b1dSGerald Schaefer 		pmdp = pmd_alloc(mm, pudp, addr);
85*53492b1dSGerald Schaefer 	return (pte_t *) pmdp;
86*53492b1dSGerald Schaefer }
87*53492b1dSGerald Schaefer 
88*53492b1dSGerald Schaefer pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
89*53492b1dSGerald Schaefer {
90*53492b1dSGerald Schaefer 	pgd_t *pgdp;
91*53492b1dSGerald Schaefer 	pud_t *pudp;
92*53492b1dSGerald Schaefer 	pmd_t *pmdp = NULL;
93*53492b1dSGerald Schaefer 
94*53492b1dSGerald Schaefer 	pgdp = pgd_offset(mm, addr);
95*53492b1dSGerald Schaefer 	if (pgd_present(*pgdp)) {
96*53492b1dSGerald Schaefer 		pudp = pud_offset(pgdp, addr);
97*53492b1dSGerald Schaefer 		if (pud_present(*pudp))
98*53492b1dSGerald Schaefer 			pmdp = pmd_offset(pudp, addr);
99*53492b1dSGerald Schaefer 	}
100*53492b1dSGerald Schaefer 	return (pte_t *) pmdp;
101*53492b1dSGerald Schaefer }
102*53492b1dSGerald Schaefer 
103*53492b1dSGerald Schaefer int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
104*53492b1dSGerald Schaefer {
105*53492b1dSGerald Schaefer 	return 0;
106*53492b1dSGerald Schaefer }
107*53492b1dSGerald Schaefer 
108*53492b1dSGerald Schaefer struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
109*53492b1dSGerald Schaefer 			      int write)
110*53492b1dSGerald Schaefer {
111*53492b1dSGerald Schaefer 	return ERR_PTR(-EINVAL);
112*53492b1dSGerald Schaefer }
113*53492b1dSGerald Schaefer 
114*53492b1dSGerald Schaefer int pmd_huge(pmd_t pmd)
115*53492b1dSGerald Schaefer {
116*53492b1dSGerald Schaefer 	if (!MACHINE_HAS_HPAGE)
117*53492b1dSGerald Schaefer 		return 0;
118*53492b1dSGerald Schaefer 
119*53492b1dSGerald Schaefer 	return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
120*53492b1dSGerald Schaefer }
121*53492b1dSGerald Schaefer 
122*53492b1dSGerald Schaefer struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
123*53492b1dSGerald Schaefer 			     pmd_t *pmdp, int write)
124*53492b1dSGerald Schaefer {
125*53492b1dSGerald Schaefer 	struct page *page;
126*53492b1dSGerald Schaefer 
127*53492b1dSGerald Schaefer 	if (!MACHINE_HAS_HPAGE)
128*53492b1dSGerald Schaefer 		return NULL;
129*53492b1dSGerald Schaefer 
130*53492b1dSGerald Schaefer 	page = pmd_page(*pmdp);
131*53492b1dSGerald Schaefer 	if (page)
132*53492b1dSGerald Schaefer 		page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT);
133*53492b1dSGerald Schaefer 	return page;
134*53492b1dSGerald Schaefer }
135