1013de2d6SGuo Ren // SPDX-License-Identifier: GPL-2.0 2013de2d6SGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3013de2d6SGuo Ren 4013de2d6SGuo Ren #include <linux/module.h> 5013de2d6SGuo Ren #include <linux/highmem.h> 6013de2d6SGuo Ren #include <linux/smp.h> 7aca52c39SMike Rapoport #include <linux/memblock.h> 8013de2d6SGuo Ren #include <asm/fixmap.h> 9013de2d6SGuo Ren #include <asm/tlbflush.h> 10013de2d6SGuo Ren #include <asm/cacheflush.h> 11013de2d6SGuo Ren 12013de2d6SGuo Ren static pte_t *kmap_pte; 13013de2d6SGuo Ren 14013de2d6SGuo Ren unsigned long highstart_pfn, highend_pfn; 15013de2d6SGuo Ren 16013de2d6SGuo Ren void *kmap(struct page *page) 17013de2d6SGuo Ren { 18013de2d6SGuo Ren void *addr; 19013de2d6SGuo Ren 20013de2d6SGuo Ren might_sleep(); 21013de2d6SGuo Ren if (!PageHighMem(page)) 22013de2d6SGuo Ren return page_address(page); 23013de2d6SGuo Ren addr = kmap_high(page); 24013de2d6SGuo Ren flush_tlb_one((unsigned long)addr); 25013de2d6SGuo Ren 26013de2d6SGuo Ren return addr; 27013de2d6SGuo Ren } 28013de2d6SGuo Ren EXPORT_SYMBOL(kmap); 29013de2d6SGuo Ren 30013de2d6SGuo Ren void kunmap(struct page *page) 31013de2d6SGuo Ren { 32013de2d6SGuo Ren BUG_ON(in_interrupt()); 33013de2d6SGuo Ren if (!PageHighMem(page)) 34013de2d6SGuo Ren return; 35013de2d6SGuo Ren kunmap_high(page); 36013de2d6SGuo Ren } 37013de2d6SGuo Ren EXPORT_SYMBOL(kunmap); 38013de2d6SGuo Ren 39013de2d6SGuo Ren void *kmap_atomic(struct page *page) 40013de2d6SGuo Ren { 41013de2d6SGuo Ren unsigned long vaddr; 42013de2d6SGuo Ren int idx, type; 43013de2d6SGuo Ren 44013de2d6SGuo Ren preempt_disable(); 45013de2d6SGuo Ren pagefault_disable(); 46013de2d6SGuo Ren if (!PageHighMem(page)) 47013de2d6SGuo Ren return page_address(page); 48013de2d6SGuo Ren 49013de2d6SGuo Ren type = kmap_atomic_idx_push(); 50013de2d6SGuo Ren idx = type + KM_TYPE_NR*smp_processor_id(); 51013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 52013de2d6SGuo Ren #ifdef CONFIG_DEBUG_HIGHMEM 53013de2d6SGuo Ren BUG_ON(!pte_none(*(kmap_pte - idx))); 54013de2d6SGuo Ren #endif 55013de2d6SGuo Ren set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); 56013de2d6SGuo Ren flush_tlb_one((unsigned long)vaddr); 57013de2d6SGuo Ren 58013de2d6SGuo Ren return (void *)vaddr; 59013de2d6SGuo Ren } 60013de2d6SGuo Ren EXPORT_SYMBOL(kmap_atomic); 61013de2d6SGuo Ren 62013de2d6SGuo Ren void __kunmap_atomic(void *kvaddr) 63013de2d6SGuo Ren { 64013de2d6SGuo Ren unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; 65013de2d6SGuo Ren int idx; 66013de2d6SGuo Ren 67013de2d6SGuo Ren if (vaddr < FIXADDR_START) 68013de2d6SGuo Ren goto out; 69013de2d6SGuo Ren 70013de2d6SGuo Ren #ifdef CONFIG_DEBUG_HIGHMEM 71013de2d6SGuo Ren idx = KM_TYPE_NR*smp_processor_id() + kmap_atomic_idx(); 72013de2d6SGuo Ren 73013de2d6SGuo Ren BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); 74013de2d6SGuo Ren 75013de2d6SGuo Ren pte_clear(&init_mm, vaddr, kmap_pte - idx); 76013de2d6SGuo Ren flush_tlb_one(vaddr); 77013de2d6SGuo Ren #else 78013de2d6SGuo Ren (void) idx; /* to kill a warning */ 79013de2d6SGuo Ren #endif 80013de2d6SGuo Ren kmap_atomic_idx_pop(); 81013de2d6SGuo Ren out: 82013de2d6SGuo Ren pagefault_enable(); 83013de2d6SGuo Ren preempt_enable(); 84013de2d6SGuo Ren } 85013de2d6SGuo Ren EXPORT_SYMBOL(__kunmap_atomic); 86013de2d6SGuo Ren 87013de2d6SGuo Ren /* 88013de2d6SGuo Ren * This is the same as kmap_atomic() but can map memory that doesn't 89013de2d6SGuo Ren * have a struct page associated with it. 90013de2d6SGuo Ren */ 91013de2d6SGuo Ren void *kmap_atomic_pfn(unsigned long pfn) 92013de2d6SGuo Ren { 93013de2d6SGuo Ren unsigned long vaddr; 94013de2d6SGuo Ren int idx, type; 95013de2d6SGuo Ren 96013de2d6SGuo Ren pagefault_disable(); 97013de2d6SGuo Ren 98013de2d6SGuo Ren type = kmap_atomic_idx_push(); 99013de2d6SGuo Ren idx = type + KM_TYPE_NR*smp_processor_id(); 100013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 101013de2d6SGuo Ren set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL)); 102013de2d6SGuo Ren flush_tlb_one(vaddr); 103013de2d6SGuo Ren 104013de2d6SGuo Ren return (void *) vaddr; 105013de2d6SGuo Ren } 106013de2d6SGuo Ren 107013de2d6SGuo Ren struct page *kmap_atomic_to_page(void *ptr) 108013de2d6SGuo Ren { 109013de2d6SGuo Ren unsigned long idx, vaddr = (unsigned long)ptr; 110013de2d6SGuo Ren pte_t *pte; 111013de2d6SGuo Ren 112013de2d6SGuo Ren if (vaddr < FIXADDR_START) 113013de2d6SGuo Ren return virt_to_page(ptr); 114013de2d6SGuo Ren 115013de2d6SGuo Ren idx = virt_to_fix(vaddr); 116013de2d6SGuo Ren pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 117013de2d6SGuo Ren return pte_page(*pte); 118013de2d6SGuo Ren } 119013de2d6SGuo Ren 120013de2d6SGuo Ren static void __init fixrange_init(unsigned long start, unsigned long end, 121013de2d6SGuo Ren pgd_t *pgd_base) 122013de2d6SGuo Ren { 123013de2d6SGuo Ren #ifdef CONFIG_HIGHMEM 124013de2d6SGuo Ren pgd_t *pgd; 125013de2d6SGuo Ren pud_t *pud; 126013de2d6SGuo Ren pmd_t *pmd; 127013de2d6SGuo Ren pte_t *pte; 128013de2d6SGuo Ren int i, j, k; 129013de2d6SGuo Ren unsigned long vaddr; 130013de2d6SGuo Ren 131013de2d6SGuo Ren vaddr = start; 132013de2d6SGuo Ren i = __pgd_offset(vaddr); 133013de2d6SGuo Ren j = __pud_offset(vaddr); 134013de2d6SGuo Ren k = __pmd_offset(vaddr); 135013de2d6SGuo Ren pgd = pgd_base + i; 136013de2d6SGuo Ren 137013de2d6SGuo Ren for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { 138013de2d6SGuo Ren pud = (pud_t *)pgd; 139013de2d6SGuo Ren for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { 140013de2d6SGuo Ren pmd = (pmd_t *)pud; 141013de2d6SGuo Ren for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { 142013de2d6SGuo Ren if (pmd_none(*pmd)) { 143aca52c39SMike Rapoport pte = (pte_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 144013de2d6SGuo Ren set_pmd(pmd, __pmd(__pa(pte))); 145013de2d6SGuo Ren BUG_ON(pte != pte_offset_kernel(pmd, 0)); 146013de2d6SGuo Ren } 147013de2d6SGuo Ren vaddr += PMD_SIZE; 148013de2d6SGuo Ren } 149013de2d6SGuo Ren k = 0; 150013de2d6SGuo Ren } 151013de2d6SGuo Ren j = 0; 152013de2d6SGuo Ren } 153013de2d6SGuo Ren #endif 154013de2d6SGuo Ren } 155013de2d6SGuo Ren 156013de2d6SGuo Ren void __init fixaddr_kmap_pages_init(void) 157013de2d6SGuo Ren { 158013de2d6SGuo Ren unsigned long vaddr; 159013de2d6SGuo Ren pgd_t *pgd_base; 160013de2d6SGuo Ren #ifdef CONFIG_HIGHMEM 161013de2d6SGuo Ren pgd_t *pgd; 162013de2d6SGuo Ren pmd_t *pmd; 163013de2d6SGuo Ren pud_t *pud; 164013de2d6SGuo Ren pte_t *pte; 165013de2d6SGuo Ren #endif 166013de2d6SGuo Ren pgd_base = swapper_pg_dir; 167013de2d6SGuo Ren 168013de2d6SGuo Ren /* 169013de2d6SGuo Ren * Fixed mappings: 170013de2d6SGuo Ren */ 171013de2d6SGuo Ren vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; 172013de2d6SGuo Ren fixrange_init(vaddr, 0, pgd_base); 173013de2d6SGuo Ren 174013de2d6SGuo Ren #ifdef CONFIG_HIGHMEM 175013de2d6SGuo Ren /* 176013de2d6SGuo Ren * Permanent kmaps: 177013de2d6SGuo Ren */ 178013de2d6SGuo Ren vaddr = PKMAP_BASE; 179013de2d6SGuo Ren fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); 180013de2d6SGuo Ren 181013de2d6SGuo Ren pgd = swapper_pg_dir + __pgd_offset(vaddr); 182013de2d6SGuo Ren pud = (pud_t *)pgd; 183013de2d6SGuo Ren pmd = pmd_offset(pud, vaddr); 184013de2d6SGuo Ren pte = pte_offset_kernel(pmd, vaddr); 185013de2d6SGuo Ren pkmap_page_table = pte; 186013de2d6SGuo Ren #endif 187013de2d6SGuo Ren } 188013de2d6SGuo Ren 189013de2d6SGuo Ren void __init kmap_init(void) 190013de2d6SGuo Ren { 191013de2d6SGuo Ren unsigned long vaddr; 192013de2d6SGuo Ren 193013de2d6SGuo Ren fixaddr_kmap_pages_init(); 194013de2d6SGuo Ren 195013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN); 196013de2d6SGuo Ren 197013de2d6SGuo Ren kmap_pte = pte_offset_kernel((pmd_t *)pgd_offset_k(vaddr), vaddr); 198013de2d6SGuo Ren } 199