153492b1dSGerald Schaefer /* 253492b1dSGerald Schaefer * IBM System z Huge TLB Page Support for Kernel. 353492b1dSGerald Schaefer * 453492b1dSGerald Schaefer * Copyright 2007 IBM Corp. 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 1153492b1dSGerald Schaefer 1253492b1dSGerald Schaefer void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, 1353492b1dSGerald Schaefer pte_t *pteptr, pte_t pteval) 1453492b1dSGerald Schaefer { 1553492b1dSGerald Schaefer pmd_t *pmdp = (pmd_t *) pteptr; 1653492b1dSGerald Schaefer pte_t shadow_pteval = pteval; 1753492b1dSGerald Schaefer unsigned long mask; 1853492b1dSGerald Schaefer 1953492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) { 2053492b1dSGerald Schaefer pteptr = (pte_t *) pte_page(pteval)[1].index; 2153492b1dSGerald Schaefer mask = pte_val(pteval) & 2253492b1dSGerald Schaefer (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); 2353492b1dSGerald Schaefer pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; 2453492b1dSGerald Schaefer if (mm->context.noexec) { 2553492b1dSGerald Schaefer pteptr += PTRS_PER_PTE; 2653492b1dSGerald Schaefer pte_val(shadow_pteval) = 2753492b1dSGerald Schaefer (_SEGMENT_ENTRY + __pa(pteptr)) | mask; 2853492b1dSGerald Schaefer } 2953492b1dSGerald Schaefer } 3053492b1dSGerald Schaefer 3153492b1dSGerald Schaefer pmd_val(*pmdp) = pte_val(pteval); 3253492b1dSGerald Schaefer if (mm->context.noexec) { 3353492b1dSGerald Schaefer pmdp = get_shadow_table(pmdp); 3453492b1dSGerald Schaefer pmd_val(*pmdp) = pte_val(shadow_pteval); 3553492b1dSGerald Schaefer } 3653492b1dSGerald Schaefer } 3753492b1dSGerald Schaefer 3853492b1dSGerald Schaefer int arch_prepare_hugepage(struct page *page) 3953492b1dSGerald Schaefer { 4053492b1dSGerald Schaefer unsigned long addr = page_to_phys(page); 4153492b1dSGerald Schaefer pte_t pte; 4253492b1dSGerald Schaefer pte_t *ptep; 4353492b1dSGerald Schaefer int i; 4453492b1dSGerald Schaefer 4553492b1dSGerald Schaefer if (MACHINE_HAS_HPAGE) 4653492b1dSGerald Schaefer return 0; 4753492b1dSGerald Schaefer 4853492b1dSGerald Schaefer ptep = (pte_t *) pte_alloc_one(&init_mm, address); 4953492b1dSGerald Schaefer if (!ptep) 5053492b1dSGerald Schaefer return -ENOMEM; 5153492b1dSGerald Schaefer 5253492b1dSGerald Schaefer pte = mk_pte(page, PAGE_RW); 5353492b1dSGerald Schaefer for (i = 0; i < PTRS_PER_PTE; i++) { 5453492b1dSGerald Schaefer set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte); 5553492b1dSGerald Schaefer pte_val(pte) += PAGE_SIZE; 5653492b1dSGerald Schaefer } 5753492b1dSGerald Schaefer page[1].index = (unsigned long) ptep; 5853492b1dSGerald Schaefer return 0; 5953492b1dSGerald Schaefer } 6053492b1dSGerald Schaefer 6153492b1dSGerald Schaefer void arch_release_hugepage(struct page *page) 6253492b1dSGerald Schaefer { 6353492b1dSGerald Schaefer pte_t *ptep; 6453492b1dSGerald Schaefer 6553492b1dSGerald Schaefer if (MACHINE_HAS_HPAGE) 6653492b1dSGerald Schaefer return; 6753492b1dSGerald Schaefer 6853492b1dSGerald Schaefer ptep = (pte_t *) page[1].index; 6953492b1dSGerald Schaefer if (!ptep) 7053492b1dSGerald Schaefer return; 71*80217147SMartin Schwidefsky page_table_free(&init_mm, (unsigned long *) ptep); 7253492b1dSGerald Schaefer page[1].index = 0; 7353492b1dSGerald Schaefer } 7453492b1dSGerald Schaefer 75a5516438SAndi Kleen pte_t *huge_pte_alloc(struct mm_struct *mm, 76a5516438SAndi Kleen unsigned long addr, unsigned long sz) 7753492b1dSGerald Schaefer { 7853492b1dSGerald Schaefer pgd_t *pgdp; 7953492b1dSGerald Schaefer pud_t *pudp; 8053492b1dSGerald Schaefer pmd_t *pmdp = NULL; 8153492b1dSGerald Schaefer 8253492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 8353492b1dSGerald Schaefer pudp = pud_alloc(mm, pgdp, addr); 8453492b1dSGerald Schaefer if (pudp) 8553492b1dSGerald Schaefer pmdp = pmd_alloc(mm, pudp, addr); 8653492b1dSGerald Schaefer return (pte_t *) pmdp; 8753492b1dSGerald Schaefer } 8853492b1dSGerald Schaefer 8953492b1dSGerald Schaefer pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) 9053492b1dSGerald Schaefer { 9153492b1dSGerald Schaefer pgd_t *pgdp; 9253492b1dSGerald Schaefer pud_t *pudp; 9353492b1dSGerald Schaefer pmd_t *pmdp = NULL; 9453492b1dSGerald Schaefer 9553492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 9653492b1dSGerald Schaefer if (pgd_present(*pgdp)) { 9753492b1dSGerald Schaefer pudp = pud_offset(pgdp, addr); 9853492b1dSGerald Schaefer if (pud_present(*pudp)) 9953492b1dSGerald Schaefer pmdp = pmd_offset(pudp, addr); 10053492b1dSGerald Schaefer } 10153492b1dSGerald Schaefer return (pte_t *) pmdp; 10253492b1dSGerald Schaefer } 10353492b1dSGerald Schaefer 10453492b1dSGerald Schaefer int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) 10553492b1dSGerald Schaefer { 10653492b1dSGerald Schaefer return 0; 10753492b1dSGerald Schaefer } 10853492b1dSGerald Schaefer 10953492b1dSGerald Schaefer struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, 11053492b1dSGerald Schaefer int write) 11153492b1dSGerald Schaefer { 11253492b1dSGerald Schaefer return ERR_PTR(-EINVAL); 11353492b1dSGerald Schaefer } 11453492b1dSGerald Schaefer 11553492b1dSGerald Schaefer int pmd_huge(pmd_t pmd) 11653492b1dSGerald Schaefer { 11753492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) 11853492b1dSGerald Schaefer return 0; 11953492b1dSGerald Schaefer 12053492b1dSGerald Schaefer return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE); 12153492b1dSGerald Schaefer } 12253492b1dSGerald Schaefer 123ceb86879SAndi Kleen int pud_huge(pud_t pud) 124ceb86879SAndi Kleen { 125ceb86879SAndi Kleen return 0; 126ceb86879SAndi Kleen } 127ceb86879SAndi Kleen 12853492b1dSGerald Schaefer struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, 12953492b1dSGerald Schaefer pmd_t *pmdp, int write) 13053492b1dSGerald Schaefer { 13153492b1dSGerald Schaefer struct page *page; 13253492b1dSGerald Schaefer 13353492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) 13453492b1dSGerald Schaefer return NULL; 13553492b1dSGerald Schaefer 13653492b1dSGerald Schaefer page = pmd_page(*pmdp); 13753492b1dSGerald Schaefer if (page) 13853492b1dSGerald Schaefer page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); 13953492b1dSGerald Schaefer return page; 14053492b1dSGerald Schaefer } 141