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 120f136008fSGuo Ren static void __init kmap_pages_init(void) 121013de2d6SGuo Ren { 122013de2d6SGuo Ren unsigned long vaddr; 123013de2d6SGuo Ren pgd_t *pgd; 124013de2d6SGuo Ren pmd_t *pmd; 125013de2d6SGuo Ren pud_t *pud; 126013de2d6SGuo Ren pte_t *pte; 127013de2d6SGuo Ren 128013de2d6SGuo Ren vaddr = PKMAP_BASE; 129f136008fSGuo Ren fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir); 130013de2d6SGuo Ren 131013de2d6SGuo Ren pgd = swapper_pg_dir + __pgd_offset(vaddr); 132013de2d6SGuo Ren pud = (pud_t *)pgd; 133013de2d6SGuo Ren pmd = pmd_offset(pud, vaddr); 134013de2d6SGuo Ren pte = pte_offset_kernel(pmd, vaddr); 135013de2d6SGuo Ren pkmap_page_table = pte; 136013de2d6SGuo Ren } 137013de2d6SGuo Ren 138013de2d6SGuo Ren void __init kmap_init(void) 139013de2d6SGuo Ren { 140013de2d6SGuo Ren unsigned long vaddr; 141013de2d6SGuo Ren 142f136008fSGuo Ren kmap_pages_init(); 143013de2d6SGuo Ren 144013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN); 145013de2d6SGuo Ren 146013de2d6SGuo Ren kmap_pte = pte_offset_kernel((pmd_t *)pgd_offset_k(vaddr), vaddr); 147013de2d6SGuo Ren } 148