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

xtensa: support aliasing cache in kmap

Define ARCH_PKMAP_COLORING and provide corresponding macro definitions
on cores with aliasing data cache.

Instead of single last_pkmap_nr maintain an array last_pkmap_nr_arr of
pkmap counters for each page color. Make sure that kmap maps physical
page at virtual address with color matching its physical address.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>

+56 -2
+38 -2
arch/xtensa/include/asm/highmem.h
··· 12 12 #ifndef _XTENSA_HIGHMEM_H 13 13 #define _XTENSA_HIGHMEM_H 14 14 15 + #include <linux/wait.h> 15 16 #include <asm/cacheflush.h> 16 17 #include <asm/fixmap.h> 17 18 #include <asm/kmap_types.h> 18 19 #include <asm/pgtable.h> 19 20 20 - #define PKMAP_BASE (FIXADDR_START - PMD_SIZE) 21 - #define LAST_PKMAP PTRS_PER_PTE 21 + #define PKMAP_BASE ((FIXADDR_START - \ 22 + (LAST_PKMAP + 1) * PAGE_SIZE) & PMD_MASK) 23 + #define LAST_PKMAP (PTRS_PER_PTE * DCACHE_N_COLORS) 22 24 #define LAST_PKMAP_MASK (LAST_PKMAP - 1) 23 25 #define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) 24 26 #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) 25 27 26 28 #define kmap_prot PAGE_KERNEL 29 + 30 + #if DCACHE_WAY_SIZE > PAGE_SIZE 31 + #define get_pkmap_color get_pkmap_color 32 + static inline int get_pkmap_color(struct page *page) 33 + { 34 + return DCACHE_ALIAS(page_to_phys(page)); 35 + } 36 + 37 + extern unsigned int last_pkmap_nr_arr[]; 38 + 39 + static inline unsigned int get_next_pkmap_nr(unsigned int color) 40 + { 41 + last_pkmap_nr_arr[color] = 42 + (last_pkmap_nr_arr[color] + DCACHE_N_COLORS) & LAST_PKMAP_MASK; 43 + return last_pkmap_nr_arr[color] + color; 44 + } 45 + 46 + static inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color) 47 + { 48 + return pkmap_nr < DCACHE_N_COLORS; 49 + } 50 + 51 + static inline int get_pkmap_entries_count(unsigned int color) 52 + { 53 + return LAST_PKMAP / DCACHE_N_COLORS; 54 + } 55 + 56 + extern wait_queue_head_t pkmap_map_wait_arr[]; 57 + 58 + static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color) 59 + { 60 + return pkmap_map_wait_arr + color; 61 + } 62 + #endif 27 63 28 64 extern pte_t *pkmap_page_table; 29 65
+18
arch/xtensa/mm/highmem.c
··· 14 14 15 15 static pte_t *kmap_pte; 16 16 17 + #if DCACHE_WAY_SIZE > PAGE_SIZE 18 + unsigned int last_pkmap_nr_arr[DCACHE_N_COLORS]; 19 + wait_queue_head_t pkmap_map_wait_arr[DCACHE_N_COLORS]; 20 + 21 + static void __init kmap_waitqueues_init(void) 22 + { 23 + unsigned int i; 24 + 25 + for (i = 0; i < ARRAY_SIZE(pkmap_map_wait_arr); ++i) 26 + init_waitqueue_head(pkmap_map_wait_arr + i); 27 + } 28 + #else 29 + static inline void kmap_waitqueues_init(void) 30 + { 31 + } 32 + #endif 33 + 17 34 static inline enum fixed_addresses kmap_idx(int type, unsigned long color) 18 35 { 19 36 return (type + KM_TYPE_NR * smp_processor_id()) * DCACHE_N_COLORS + ··· 89 72 /* cache the first kmap pte */ 90 73 kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); 91 74 kmap_pte = kmap_get_fixmap_pte(kmap_vstart); 75 + kmap_waitqueues_init(); 92 76 }