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 16525aaf9bSIra Weiny void kmap_flush_tlb(unsigned long addr) 17013de2d6SGuo Ren { 18525aaf9bSIra Weiny flush_tlb_one(addr); 19013de2d6SGuo Ren } 20525aaf9bSIra Weiny EXPORT_SYMBOL(kmap_flush_tlb); 21525aaf9bSIra Weiny 22013de2d6SGuo Ren EXPORT_SYMBOL(kmap); 23013de2d6SGuo Ren 24013de2d6SGuo Ren void kunmap(struct page *page) 25013de2d6SGuo Ren { 2601c4b788SIra Weiny might_sleep(); 27013de2d6SGuo Ren if (!PageHighMem(page)) 28013de2d6SGuo Ren return; 29013de2d6SGuo Ren kunmap_high(page); 30013de2d6SGuo Ren } 31013de2d6SGuo Ren EXPORT_SYMBOL(kunmap); 32013de2d6SGuo Ren 33013de2d6SGuo Ren void *kmap_atomic(struct page *page) 34013de2d6SGuo Ren { 35013de2d6SGuo Ren unsigned long vaddr; 36013de2d6SGuo Ren int idx, type; 37013de2d6SGuo Ren 38013de2d6SGuo Ren preempt_disable(); 39013de2d6SGuo Ren pagefault_disable(); 40013de2d6SGuo Ren if (!PageHighMem(page)) 41013de2d6SGuo Ren return page_address(page); 42013de2d6SGuo Ren 43013de2d6SGuo Ren type = kmap_atomic_idx_push(); 44013de2d6SGuo Ren idx = type + KM_TYPE_NR*smp_processor_id(); 45013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 46013de2d6SGuo Ren #ifdef CONFIG_DEBUG_HIGHMEM 47013de2d6SGuo Ren BUG_ON(!pte_none(*(kmap_pte - idx))); 48013de2d6SGuo Ren #endif 49013de2d6SGuo Ren set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); 50013de2d6SGuo Ren flush_tlb_one((unsigned long)vaddr); 51013de2d6SGuo Ren 52013de2d6SGuo Ren return (void *)vaddr; 53013de2d6SGuo Ren } 54013de2d6SGuo Ren EXPORT_SYMBOL(kmap_atomic); 55013de2d6SGuo Ren 56013de2d6SGuo Ren void __kunmap_atomic(void *kvaddr) 57013de2d6SGuo Ren { 58013de2d6SGuo Ren unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; 59013de2d6SGuo Ren int idx; 60013de2d6SGuo Ren 61013de2d6SGuo Ren if (vaddr < FIXADDR_START) 62013de2d6SGuo Ren goto out; 63013de2d6SGuo Ren 64013de2d6SGuo Ren #ifdef CONFIG_DEBUG_HIGHMEM 65013de2d6SGuo Ren idx = KM_TYPE_NR*smp_processor_id() + kmap_atomic_idx(); 66013de2d6SGuo Ren 67013de2d6SGuo Ren BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); 68013de2d6SGuo Ren 69013de2d6SGuo Ren pte_clear(&init_mm, vaddr, kmap_pte - idx); 70013de2d6SGuo Ren flush_tlb_one(vaddr); 71013de2d6SGuo Ren #else 72013de2d6SGuo Ren (void) idx; /* to kill a warning */ 73013de2d6SGuo Ren #endif 74013de2d6SGuo Ren kmap_atomic_idx_pop(); 75013de2d6SGuo Ren out: 76013de2d6SGuo Ren pagefault_enable(); 77013de2d6SGuo Ren preempt_enable(); 78013de2d6SGuo Ren } 79013de2d6SGuo Ren EXPORT_SYMBOL(__kunmap_atomic); 80013de2d6SGuo Ren 81013de2d6SGuo Ren /* 82013de2d6SGuo Ren * This is the same as kmap_atomic() but can map memory that doesn't 83013de2d6SGuo Ren * have a struct page associated with it. 84013de2d6SGuo Ren */ 85013de2d6SGuo Ren void *kmap_atomic_pfn(unsigned long pfn) 86013de2d6SGuo Ren { 87013de2d6SGuo Ren unsigned long vaddr; 88013de2d6SGuo Ren int idx, type; 89013de2d6SGuo Ren 90013de2d6SGuo Ren pagefault_disable(); 91013de2d6SGuo Ren 92013de2d6SGuo Ren type = kmap_atomic_idx_push(); 93013de2d6SGuo Ren idx = type + KM_TYPE_NR*smp_processor_id(); 94013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 95013de2d6SGuo Ren set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL)); 96013de2d6SGuo Ren flush_tlb_one(vaddr); 97013de2d6SGuo Ren 98013de2d6SGuo Ren return (void *) vaddr; 99013de2d6SGuo Ren } 100013de2d6SGuo Ren 101013de2d6SGuo Ren struct page *kmap_atomic_to_page(void *ptr) 102013de2d6SGuo Ren { 103013de2d6SGuo Ren unsigned long idx, vaddr = (unsigned long)ptr; 104013de2d6SGuo Ren pte_t *pte; 105013de2d6SGuo Ren 106013de2d6SGuo Ren if (vaddr < FIXADDR_START) 107013de2d6SGuo Ren return virt_to_page(ptr); 108013de2d6SGuo Ren 109013de2d6SGuo Ren idx = virt_to_fix(vaddr); 110013de2d6SGuo Ren pte = kmap_pte - (idx - FIX_KMAP_BEGIN); 111013de2d6SGuo Ren return pte_page(*pte); 112013de2d6SGuo Ren } 113013de2d6SGuo Ren 114f136008fSGuo Ren static void __init kmap_pages_init(void) 115013de2d6SGuo Ren { 116013de2d6SGuo Ren unsigned long vaddr; 117013de2d6SGuo Ren pgd_t *pgd; 118013de2d6SGuo Ren pmd_t *pmd; 119013de2d6SGuo Ren pud_t *pud; 120013de2d6SGuo Ren pte_t *pte; 121013de2d6SGuo Ren 122013de2d6SGuo Ren vaddr = PKMAP_BASE; 123f136008fSGuo Ren fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir); 124013de2d6SGuo Ren 125013de2d6SGuo Ren pgd = swapper_pg_dir + __pgd_offset(vaddr); 126013de2d6SGuo Ren pud = (pud_t *)pgd; 127013de2d6SGuo Ren pmd = pmd_offset(pud, vaddr); 128013de2d6SGuo Ren pte = pte_offset_kernel(pmd, vaddr); 129013de2d6SGuo Ren pkmap_page_table = pte; 130013de2d6SGuo Ren } 131013de2d6SGuo Ren 132013de2d6SGuo Ren void __init kmap_init(void) 133013de2d6SGuo Ren { 134013de2d6SGuo Ren unsigned long vaddr; 135013de2d6SGuo Ren 136f136008fSGuo Ren kmap_pages_init(); 137013de2d6SGuo Ren 138013de2d6SGuo Ren vaddr = __fix_to_virt(FIX_KMAP_BEGIN); 139013de2d6SGuo Ren 140013de2d6SGuo Ren kmap_pte = pte_offset_kernel((pmd_t *)pgd_offset_k(vaddr), vaddr); 141013de2d6SGuo Ren } 142