Vineet Gupta | 45890f6 | 2015-03-09 18:53:49 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 Synopsys, Inc. (www.synopsys.com) |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as |
| 6 | * published by the Free Software Foundation. |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | #include <linux/bootmem.h> |
| 11 | #include <linux/export.h> |
| 12 | #include <linux/highmem.h> |
| 13 | #include <asm/processor.h> |
| 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/pgalloc.h> |
| 16 | #include <asm/tlbflush.h> |
| 17 | |
| 18 | /* |
| 19 | * HIGHMEM API: |
| 20 | * |
Adam Buchbinder | 7423cc0 | 2016-02-23 15:24:55 -0800 | [diff] [blame^] | 21 | * kmap() API provides sleep semantics hence referred to as "permanent maps" |
Vineet Gupta | 45890f6 | 2015-03-09 18:53:49 +0530 | [diff] [blame] | 22 | * It allows mapping LAST_PKMAP pages, using @last_pkmap_nr as the cursor |
| 23 | * for book-keeping |
| 24 | * |
| 25 | * kmap_atomic() can't sleep (calls pagefault_disable()), thus it provides |
| 26 | * shortlived ala "temporary mappings" which historically were implemented as |
| 27 | * fixmaps (compile time addr etc). Their book-keeping is done per cpu. |
| 28 | * |
| 29 | * Both these facts combined (preemption disabled and per-cpu allocation) |
| 30 | * means the total number of concurrent fixmaps will be limited to max |
| 31 | * such allocations in a single control path. Thus KM_TYPE_NR (another |
| 32 | * historic relic) is a small'ish number which caps max percpu fixmaps |
| 33 | * |
| 34 | * ARC HIGHMEM Details |
| 35 | * |
| 36 | * - the kernel vaddr space from 0x7z to 0x8z (currently used by vmalloc/module) |
| 37 | * is now shared between vmalloc and kmap (non overlapping though) |
| 38 | * |
| 39 | * - Both fixmap/pkmap use a dedicated page table each, hooked up to swapper PGD |
| 40 | * This means each only has 1 PGDIR_SIZE worth of kvaddr mappings, which means |
| 41 | * 2M of kvaddr space for typical config (8K page and 11:8:13 traversal split) |
| 42 | * |
| 43 | * - fixmap anyhow needs a limited number of mappings. So 2M kvaddr == 256 PTE |
| 44 | * slots across NR_CPUS would be more than sufficient (generic code defines |
| 45 | * KM_TYPE_NR as 20). |
| 46 | * |
| 47 | * - pkmap being preemptible, in theory could do with more than 256 concurrent |
| 48 | * mappings. However, generic pkmap code: map_new_virtual(), doesn't traverse |
| 49 | * the PGD and only works with a single page table @pkmap_page_table, hence |
| 50 | * sets the limit |
| 51 | */ |
| 52 | |
| 53 | extern pte_t * pkmap_page_table; |
| 54 | static pte_t * fixmap_page_table; |
| 55 | |
| 56 | void *kmap(struct page *page) |
| 57 | { |
| 58 | BUG_ON(in_interrupt()); |
| 59 | if (!PageHighMem(page)) |
| 60 | return page_address(page); |
| 61 | |
| 62 | return kmap_high(page); |
| 63 | } |
| 64 | |
| 65 | void *kmap_atomic(struct page *page) |
| 66 | { |
| 67 | int idx, cpu_idx; |
| 68 | unsigned long vaddr; |
| 69 | |
| 70 | preempt_disable(); |
| 71 | pagefault_disable(); |
| 72 | if (!PageHighMem(page)) |
| 73 | return page_address(page); |
| 74 | |
| 75 | cpu_idx = kmap_atomic_idx_push(); |
| 76 | idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); |
| 77 | vaddr = FIXMAP_ADDR(idx); |
| 78 | |
| 79 | set_pte_at(&init_mm, vaddr, fixmap_page_table + idx, |
| 80 | mk_pte(page, kmap_prot)); |
| 81 | |
| 82 | return (void *)vaddr; |
| 83 | } |
| 84 | EXPORT_SYMBOL(kmap_atomic); |
| 85 | |
| 86 | void __kunmap_atomic(void *kv) |
| 87 | { |
| 88 | unsigned long kvaddr = (unsigned long)kv; |
| 89 | |
| 90 | if (kvaddr >= FIXMAP_BASE && kvaddr < (FIXMAP_BASE + FIXMAP_SIZE)) { |
| 91 | |
| 92 | /* |
| 93 | * Because preemption is disabled, this vaddr can be associated |
| 94 | * with the current allocated index. |
| 95 | * But in case of multiple live kmap_atomic(), it still relies on |
| 96 | * callers to unmap in right order. |
| 97 | */ |
| 98 | int cpu_idx = kmap_atomic_idx(); |
| 99 | int idx = cpu_idx + KM_TYPE_NR * smp_processor_id(); |
| 100 | |
| 101 | WARN_ON(kvaddr != FIXMAP_ADDR(idx)); |
| 102 | |
| 103 | pte_clear(&init_mm, kvaddr, fixmap_page_table + idx); |
| 104 | local_flush_tlb_kernel_range(kvaddr, kvaddr + PAGE_SIZE); |
| 105 | |
| 106 | kmap_atomic_idx_pop(); |
| 107 | } |
| 108 | |
| 109 | pagefault_enable(); |
| 110 | preempt_enable(); |
| 111 | } |
| 112 | EXPORT_SYMBOL(__kunmap_atomic); |
| 113 | |
Vineet Gupta | 899cfd2 | 2015-12-19 13:43:34 +0530 | [diff] [blame] | 114 | static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr) |
Vineet Gupta | 45890f6 | 2015-03-09 18:53:49 +0530 | [diff] [blame] | 115 | { |
| 116 | pgd_t *pgd_k; |
| 117 | pud_t *pud_k; |
| 118 | pmd_t *pmd_k; |
| 119 | pte_t *pte_k; |
| 120 | |
| 121 | pgd_k = pgd_offset_k(kvaddr); |
| 122 | pud_k = pud_offset(pgd_k, kvaddr); |
| 123 | pmd_k = pmd_offset(pud_k, kvaddr); |
| 124 | |
| 125 | pte_k = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); |
| 126 | pmd_populate_kernel(&init_mm, pmd_k, pte_k); |
| 127 | return pte_k; |
| 128 | } |
| 129 | |
Vineet Gupta | 899cfd2 | 2015-12-19 13:43:34 +0530 | [diff] [blame] | 130 | void __init kmap_init(void) |
Vineet Gupta | 45890f6 | 2015-03-09 18:53:49 +0530 | [diff] [blame] | 131 | { |
| 132 | /* Due to recursive include hell, we can't do this in processor.h */ |
| 133 | BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE)); |
| 134 | |
| 135 | BUILD_BUG_ON(KM_TYPE_NR > PTRS_PER_PTE); |
| 136 | pkmap_page_table = alloc_kmap_pgtable(PKMAP_BASE); |
| 137 | |
| 138 | BUILD_BUG_ON(LAST_PKMAP > PTRS_PER_PTE); |
| 139 | fixmap_page_table = alloc_kmap_pgtable(FIXMAP_BASE); |
| 140 | } |