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 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 unsigned long mask; 1753492b1dSGerald Schaefer 1853492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) { 1953492b1dSGerald Schaefer pteptr = (pte_t *) pte_page(pteval)[1].index; 2053492b1dSGerald Schaefer mask = pte_val(pteval) & 2153492b1dSGerald Schaefer (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); 2253492b1dSGerald Schaefer pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; 2353492b1dSGerald Schaefer } 2453492b1dSGerald Schaefer 2553492b1dSGerald Schaefer pmd_val(*pmdp) = pte_val(pteval); 2653492b1dSGerald Schaefer } 2753492b1dSGerald Schaefer 2853492b1dSGerald Schaefer int arch_prepare_hugepage(struct page *page) 2953492b1dSGerald Schaefer { 3053492b1dSGerald Schaefer unsigned long addr = page_to_phys(page); 3153492b1dSGerald Schaefer pte_t pte; 3253492b1dSGerald Schaefer pte_t *ptep; 3353492b1dSGerald Schaefer int i; 3453492b1dSGerald Schaefer 3553492b1dSGerald Schaefer if (MACHINE_HAS_HPAGE) 3653492b1dSGerald Schaefer return 0; 3753492b1dSGerald Schaefer 38e5992f2eSMartin Schwidefsky ptep = (pte_t *) pte_alloc_one(&init_mm, addr); 3953492b1dSGerald Schaefer if (!ptep) 4053492b1dSGerald Schaefer return -ENOMEM; 4153492b1dSGerald Schaefer 42*106c992aSGerald Schaefer pte_val(pte) = addr; 4353492b1dSGerald Schaefer for (i = 0; i < PTRS_PER_PTE; i++) { 4453492b1dSGerald Schaefer set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte); 4553492b1dSGerald Schaefer pte_val(pte) += PAGE_SIZE; 4653492b1dSGerald Schaefer } 4753492b1dSGerald Schaefer page[1].index = (unsigned long) ptep; 4853492b1dSGerald Schaefer return 0; 4953492b1dSGerald Schaefer } 5053492b1dSGerald Schaefer 5153492b1dSGerald Schaefer void arch_release_hugepage(struct page *page) 5253492b1dSGerald Schaefer { 5353492b1dSGerald Schaefer pte_t *ptep; 5453492b1dSGerald Schaefer 5553492b1dSGerald Schaefer if (MACHINE_HAS_HPAGE) 5653492b1dSGerald Schaefer return; 5753492b1dSGerald Schaefer 5853492b1dSGerald Schaefer ptep = (pte_t *) page[1].index; 5953492b1dSGerald Schaefer if (!ptep) 6053492b1dSGerald Schaefer return; 61a686425bSGerald Schaefer clear_table((unsigned long *) ptep, _PAGE_TYPE_EMPTY, 62a686425bSGerald Schaefer PTRS_PER_PTE * sizeof(pte_t)); 6380217147SMartin Schwidefsky page_table_free(&init_mm, (unsigned long *) ptep); 6453492b1dSGerald Schaefer page[1].index = 0; 6553492b1dSGerald Schaefer } 6653492b1dSGerald Schaefer 67a5516438SAndi Kleen pte_t *huge_pte_alloc(struct mm_struct *mm, 68a5516438SAndi Kleen unsigned long addr, unsigned long sz) 6953492b1dSGerald Schaefer { 7053492b1dSGerald Schaefer pgd_t *pgdp; 7153492b1dSGerald Schaefer pud_t *pudp; 7253492b1dSGerald Schaefer pmd_t *pmdp = NULL; 7353492b1dSGerald Schaefer 7453492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 7553492b1dSGerald Schaefer pudp = pud_alloc(mm, pgdp, addr); 7653492b1dSGerald Schaefer if (pudp) 7753492b1dSGerald Schaefer pmdp = pmd_alloc(mm, pudp, addr); 7853492b1dSGerald Schaefer return (pte_t *) pmdp; 7953492b1dSGerald Schaefer } 8053492b1dSGerald Schaefer 8153492b1dSGerald Schaefer pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) 8253492b1dSGerald Schaefer { 8353492b1dSGerald Schaefer pgd_t *pgdp; 8453492b1dSGerald Schaefer pud_t *pudp; 8553492b1dSGerald Schaefer pmd_t *pmdp = NULL; 8653492b1dSGerald Schaefer 8753492b1dSGerald Schaefer pgdp = pgd_offset(mm, addr); 8853492b1dSGerald Schaefer if (pgd_present(*pgdp)) { 8953492b1dSGerald Schaefer pudp = pud_offset(pgdp, addr); 9053492b1dSGerald Schaefer if (pud_present(*pudp)) 9153492b1dSGerald Schaefer pmdp = pmd_offset(pudp, addr); 9253492b1dSGerald Schaefer } 9353492b1dSGerald Schaefer return (pte_t *) pmdp; 9453492b1dSGerald Schaefer } 9553492b1dSGerald Schaefer 9653492b1dSGerald Schaefer int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) 9753492b1dSGerald Schaefer { 9853492b1dSGerald Schaefer return 0; 9953492b1dSGerald Schaefer } 10053492b1dSGerald Schaefer 10153492b1dSGerald Schaefer struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, 10253492b1dSGerald Schaefer int write) 10353492b1dSGerald Schaefer { 10453492b1dSGerald Schaefer return ERR_PTR(-EINVAL); 10553492b1dSGerald Schaefer } 10653492b1dSGerald Schaefer 10753492b1dSGerald Schaefer int pmd_huge(pmd_t pmd) 10853492b1dSGerald Schaefer { 10953492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) 11053492b1dSGerald Schaefer return 0; 11153492b1dSGerald Schaefer 11253492b1dSGerald Schaefer return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE); 11353492b1dSGerald Schaefer } 11453492b1dSGerald Schaefer 115ceb86879SAndi Kleen int pud_huge(pud_t pud) 116ceb86879SAndi Kleen { 117ceb86879SAndi Kleen return 0; 118ceb86879SAndi Kleen } 119ceb86879SAndi Kleen 12053492b1dSGerald Schaefer struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, 12153492b1dSGerald Schaefer pmd_t *pmdp, int write) 12253492b1dSGerald Schaefer { 12353492b1dSGerald Schaefer struct page *page; 12453492b1dSGerald Schaefer 12553492b1dSGerald Schaefer if (!MACHINE_HAS_HPAGE) 12653492b1dSGerald Schaefer return NULL; 12753492b1dSGerald Schaefer 12853492b1dSGerald Schaefer page = pmd_page(*pmdp); 12953492b1dSGerald Schaefer if (page) 13053492b1dSGerald Schaefer page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); 13153492b1dSGerald Schaefer return page; 13253492b1dSGerald Schaefer } 133