Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: Fix up and optimize the kmap_coherent() interface.

This fixes up the kmap_coherent/kunmap_coherent() interface for recent
changes both in the page fault path and the shared cache flushers, as
well as adding in some optimizations.

One of the key things to note here is that the TLB flush itself is
deferred until the unmap, and the call in to update_mmu_cache() itself
goes away, relying on the regular page fault path to handle the lazy
dcache writeback if necessary.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>

+61 -47
+1 -1
arch/sh/include/asm/cacheflush.h
··· 85 85 86 86 void kmap_coherent_init(void); 87 87 void *kmap_coherent(struct page *page, unsigned long addr); 88 - void kunmap_coherent(void); 88 + void kunmap_coherent(void *kvaddr); 89 89 90 90 #define PG_dcache_dirty PG_arch_1 91 91
+7 -1
arch/sh/include/asm/pgtable_32.h
··· 408 408 409 409 /* to find an entry in a page-table-directory. */ 410 410 #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) 411 - #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) 411 + #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) 412 + #define __pgd_offset(address) pgd_index(address) 412 413 413 414 /* to find an entry in a kernel page-table-directory */ 414 415 #define pgd_offset_k(address) pgd_offset(&init_mm, address) 415 416 417 + #define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) 418 + #define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) 419 + 416 420 /* Find an entry in the third-level page table.. */ 417 421 #define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 422 + #define __pte_offset(address) pte_index(address) 423 + 418 424 #define pte_offset_kernel(dir, address) \ 419 425 ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) 420 426 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
+5
arch/sh/include/asm/pgtable_64.h
··· 60 60 /* To find an entry in a kernel PGD. */ 61 61 #define pgd_offset_k(address) pgd_offset(&init_mm, address) 62 62 63 + #define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) 64 + #define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) 65 + 63 66 /* 64 67 * PMD level access routines. Same notes as above. 65 68 */ ··· 82 79 /* PMD to PTE dereferencing */ 83 80 #define pte_index(address) \ 84 81 ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 82 + 83 + #define __pte_offset(address) pte_index(address) 85 84 86 85 #define pte_offset_kernel(dir, addr) \ 87 86 ((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
+4 -4
arch/sh/mm/cache.c
··· 51 51 !test_bit(PG_dcache_dirty, &page->flags)) { 52 52 void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 53 53 memcpy(vto, src, len); 54 - kunmap_coherent(); 54 + kunmap_coherent(vto); 55 55 } else { 56 56 memcpy(dst, src, len); 57 57 if (boot_cpu_data.dcache.n_aliases) ··· 70 70 !test_bit(PG_dcache_dirty, &page->flags)) { 71 71 void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 72 72 memcpy(dst, vfrom, len); 73 - kunmap_coherent(); 73 + kunmap_coherent(vfrom); 74 74 } else { 75 75 memcpy(dst, src, len); 76 76 if (boot_cpu_data.dcache.n_aliases) ··· 89 89 !test_bit(PG_dcache_dirty, &from->flags)) { 90 90 vfrom = kmap_coherent(from, vaddr); 91 91 copy_page(vto, vfrom); 92 - kunmap_coherent(); 92 + kunmap_coherent(vfrom); 93 93 } else { 94 94 vfrom = kmap_atomic(from, KM_USER0); 95 95 copy_page(vto, vfrom); ··· 150 150 151 151 kaddr = kmap_coherent(page, vmaddr); 152 152 __flush_wback_region((void *)kaddr, PAGE_SIZE); 153 - kunmap_coherent(); 153 + kunmap_coherent(kaddr); 154 154 } else 155 155 __flush_wback_region((void *)addr, PAGE_SIZE); 156 156 }
+2 -2
arch/sh/mm/fault_32.c
··· 82 82 pmd_t *pmd_k; 83 83 pte_t *pte_k; 84 84 85 - /* Make sure we are in vmalloc area: */ 86 - if (!(address >= VMALLOC_START && address < VMALLOC_END)) 85 + /* Make sure we are in vmalloc/module/P3 area: */ 86 + if (!(address >= VMALLOC_START && address < P3_ADDR_MAX)) 87 87 return -1; 88 88 89 89 /*
+24 -19
arch/sh/mm/init.c
··· 106 106 pgd_t *pgd; 107 107 pud_t *pud; 108 108 pmd_t *pmd; 109 - int pgd_idx; 109 + pte_t *pte; 110 + int i, j, k; 110 111 unsigned long vaddr; 111 112 112 - vaddr = start & PMD_MASK; 113 - end = (end + PMD_SIZE - 1) & PMD_MASK; 114 - pgd_idx = pgd_index(vaddr); 115 - pgd = pgd_base + pgd_idx; 113 + vaddr = start; 114 + i = __pgd_offset(vaddr); 115 + j = __pud_offset(vaddr); 116 + k = __pmd_offset(vaddr); 117 + pgd = pgd_base + i; 116 118 117 - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { 118 - BUG_ON(pgd_none(*pgd)); 119 - pud = pud_offset(pgd, 0); 120 - BUG_ON(pud_none(*pud)); 121 - pmd = pmd_offset(pud, 0); 122 - 123 - if (!pmd_present(*pmd)) { 124 - pte_t *pte_table; 125 - pte_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); 126 - pmd_populate_kernel(&init_mm, pmd, pte_table); 119 + for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { 120 + pud = (pud_t *)pgd; 121 + for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { 122 + pmd = (pmd_t *)pud; 123 + for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { 124 + if (pmd_none(*pmd)) { 125 + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); 126 + pmd_populate_kernel(&init_mm, pmd, pte); 127 + BUG_ON(pte != pte_offset_kernel(pmd, 0)); 128 + } 129 + vaddr += PMD_SIZE; 130 + } 131 + k = 0; 127 132 } 128 - 129 - vaddr += PMD_SIZE; 133 + j = 0; 130 134 } 131 135 } 132 136 #endif /* CONFIG_MMU */ ··· 141 137 void __init paging_init(void) 142 138 { 143 139 unsigned long max_zone_pfns[MAX_NR_ZONES]; 144 - unsigned long vaddr; 140 + unsigned long vaddr, end; 145 141 int nid; 146 142 147 143 /* We don't need to map the kernel through the TLB, as ··· 159 155 * pte's will be filled in by __set_fixmap(). 160 156 */ 161 157 vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; 162 - page_table_range_init(vaddr, 0, swapper_pg_dir); 158 + end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; 159 + page_table_range_init(vaddr, end, swapper_pg_dir); 163 160 164 161 kmap_coherent_init(); 165 162
+17 -19
arch/sh/mm/kmap.c
··· 24 24 { 25 25 unsigned long vaddr; 26 26 27 - if (!boot_cpu_data.dcache.n_aliases) 28 - return; 29 - 30 27 /* cache the first coherent kmap pte */ 31 28 vaddr = __fix_to_virt(FIX_CMAP_BEGIN); 32 29 kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); ··· 32 35 void *kmap_coherent(struct page *page, unsigned long addr) 33 36 { 34 37 enum fixed_addresses idx; 35 - unsigned long vaddr, flags; 36 - pte_t pte; 38 + unsigned long vaddr; 37 39 38 40 BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); 39 41 40 - inc_preempt_count(); 42 + pagefault_disable(); 41 43 42 - idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; 43 - vaddr = __fix_to_virt(FIX_CMAP_END - idx); 44 - pte = mk_pte(page, PAGE_KERNEL); 44 + idx = FIX_CMAP_END - 45 + ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT); 46 + vaddr = __fix_to_virt(idx); 45 47 46 - local_irq_save(flags); 47 - flush_tlb_one(get_asid(), vaddr); 48 - local_irq_restore(flags); 49 - 50 - update_mmu_cache(NULL, vaddr, pte); 51 - 52 - set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); 48 + BUG_ON(!pte_none(*(kmap_coherent_pte - idx))); 49 + set_pte(kmap_coherent_pte - idx, mk_pte(page, PAGE_KERNEL)); 53 50 54 51 return (void *)vaddr; 55 52 } 56 53 57 - void kunmap_coherent(void) 54 + void kunmap_coherent(void *kvaddr) 58 55 { 59 - dec_preempt_count(); 60 - preempt_check_resched(); 56 + if (kvaddr >= (void *)FIXADDR_START) { 57 + unsigned long vaddr = (unsigned long)kvaddr & PAGE_MASK; 58 + enum fixed_addresses idx = __virt_to_fix(vaddr); 59 + 60 + pte_clear(&init_mm, vaddr, kmap_coherent_pte - idx); 61 + local_flush_tlb_one(get_asid(), vaddr); 62 + } 63 + 64 + pagefault_enable(); 61 65 }
+1 -1
arch/sh/mm/nommu.c
··· 81 81 return NULL; 82 82 } 83 83 84 - void kunmap_coherent(void) 84 + void kunmap_coherent(void *kvaddr) 85 85 { 86 86 BUG(); 87 87 }