1 1.4 riastrad /* $NetBSD: drm_cache.c,v 1.4 2021/12/19 01:24:25 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /************************************************************************** 4 1.1 riastrad * 5 1.1 riastrad * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA 6 1.1 riastrad * All Rights Reserved. 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the 10 1.1 riastrad * "Software"), to deal in the Software without restriction, including 11 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 12 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 13 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 14 1.1 riastrad * the following conditions: 15 1.1 riastrad * 16 1.1 riastrad * The above copyright notice and this permission notice (including the 17 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 18 1.1 riastrad * of the Software. 19 1.1 riastrad * 20 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 1.1 riastrad * 28 1.1 riastrad **************************************************************************/ 29 1.1 riastrad /* 30 1.1 riastrad * Authors: Thomas Hellstrm <thomas-at-tungstengraphics-dot-com> 31 1.1 riastrad */ 32 1.1 riastrad 33 1.2 riastrad #include <sys/cdefs.h> 34 1.4 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_cache.c,v 1.4 2021/12/19 01:24:25 riastradh Exp $"); 35 1.2 riastrad 36 1.1 riastrad #include <linux/export.h> 37 1.3 riastrad #include <linux/highmem.h> 38 1.3 riastrad 39 1.3 riastrad #include <drm/drm_cache.h> 40 1.1 riastrad 41 1.1 riastrad #if defined(CONFIG_X86) 42 1.2 riastrad #include <asm/smp.h> 43 1.2 riastrad 44 1.2 riastrad /* 45 1.2 riastrad * clflushopt is an unordered instruction which needs fencing with mfence or 46 1.2 riastrad * sfence to avoid ordering issues. For drm_clflush_page this fencing happens 47 1.2 riastrad * in the caller. 48 1.2 riastrad */ 49 1.1 riastrad static void 50 1.1 riastrad drm_clflush_page(struct page *page) 51 1.1 riastrad { 52 1.1 riastrad uint8_t *page_virtual; 53 1.1 riastrad unsigned int i; 54 1.1 riastrad const int size = boot_cpu_data.x86_clflush_size; 55 1.1 riastrad 56 1.1 riastrad if (unlikely(page == NULL)) 57 1.1 riastrad return; 58 1.1 riastrad 59 1.1 riastrad page_virtual = kmap_atomic(page); 60 1.1 riastrad for (i = 0; i < PAGE_SIZE; i += size) 61 1.2 riastrad clflushopt(page_virtual + i); 62 1.1 riastrad kunmap_atomic(page_virtual); 63 1.1 riastrad } 64 1.1 riastrad 65 1.1 riastrad static void drm_cache_flush_clflush(struct page *pages[], 66 1.1 riastrad unsigned long num_pages) 67 1.1 riastrad { 68 1.1 riastrad unsigned long i; 69 1.1 riastrad 70 1.3 riastrad mb(); /*Full memory barrier used before so that CLFLUSH is ordered*/ 71 1.1 riastrad for (i = 0; i < num_pages; i++) 72 1.1 riastrad drm_clflush_page(*pages++); 73 1.3 riastrad mb(); /*Also used after CLFLUSH so that all cache is flushed*/ 74 1.1 riastrad } 75 1.1 riastrad #endif 76 1.1 riastrad 77 1.3 riastrad /** 78 1.3 riastrad * drm_clflush_pages - Flush dcache lines of a set of pages. 79 1.3 riastrad * @pages: List of pages to be flushed. 80 1.3 riastrad * @num_pages: Number of pages in the array. 81 1.3 riastrad * 82 1.3 riastrad * Flush every data cache line entry that points to an address belonging 83 1.3 riastrad * to a page in the array. 84 1.3 riastrad */ 85 1.1 riastrad void 86 1.1 riastrad drm_clflush_pages(struct page *pages[], unsigned long num_pages) 87 1.1 riastrad { 88 1.1 riastrad 89 1.1 riastrad #if defined(CONFIG_X86) 90 1.3 riastrad if (static_cpu_has(X86_FEATURE_CLFLUSH)) { 91 1.1 riastrad drm_cache_flush_clflush(pages, num_pages); 92 1.1 riastrad return; 93 1.1 riastrad } 94 1.1 riastrad 95 1.2 riastrad if (wbinvd_on_all_cpus()) 96 1.3 riastrad pr_err("Timed out waiting for cache flush\n"); 97 1.1 riastrad 98 1.1 riastrad #elif defined(__powerpc__) 99 1.1 riastrad unsigned long i; 100 1.3 riastrad 101 1.1 riastrad for (i = 0; i < num_pages; i++) { 102 1.1 riastrad struct page *page = pages[i]; 103 1.1 riastrad void *page_virtual; 104 1.1 riastrad 105 1.1 riastrad if (unlikely(page == NULL)) 106 1.1 riastrad continue; 107 1.1 riastrad 108 1.1 riastrad page_virtual = kmap_atomic(page); 109 1.1 riastrad flush_dcache_range((unsigned long)page_virtual, 110 1.1 riastrad (unsigned long)page_virtual + PAGE_SIZE); 111 1.1 riastrad kunmap_atomic(page_virtual); 112 1.1 riastrad } 113 1.1 riastrad #else 114 1.3 riastrad pr_err("Architecture has no drm_cache.c support\n"); 115 1.1 riastrad WARN_ON_ONCE(1); 116 1.1 riastrad #endif 117 1.1 riastrad } 118 1.1 riastrad EXPORT_SYMBOL(drm_clflush_pages); 119 1.1 riastrad 120 1.3 riastrad /** 121 1.3 riastrad * drm_clflush_sg - Flush dcache lines pointing to a scather-gather. 122 1.3 riastrad * @st: struct sg_table. 123 1.3 riastrad * 124 1.3 riastrad * Flush every data cache line entry that points to an address in the 125 1.3 riastrad * sg. 126 1.3 riastrad */ 127 1.1 riastrad void 128 1.1 riastrad drm_clflush_sg(struct sg_table *st) 129 1.1 riastrad { 130 1.1 riastrad #if defined(CONFIG_X86) 131 1.3 riastrad if (static_cpu_has(X86_FEATURE_CLFLUSH)) { 132 1.2 riastrad struct sg_page_iter sg_iter; 133 1.1 riastrad 134 1.3 riastrad mb(); /*CLFLUSH is ordered only by using memory barriers*/ 135 1.2 riastrad for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) 136 1.2 riastrad drm_clflush_page(sg_page_iter_page(&sg_iter)); 137 1.3 riastrad mb(); /*Make sure that all cache line entry is flushed*/ 138 1.1 riastrad 139 1.1 riastrad return; 140 1.1 riastrad } 141 1.1 riastrad 142 1.2 riastrad if (wbinvd_on_all_cpus()) 143 1.3 riastrad pr_err("Timed out waiting for cache flush\n"); 144 1.1 riastrad #else 145 1.3 riastrad pr_err("Architecture has no drm_cache.c support\n"); 146 1.1 riastrad WARN_ON_ONCE(1); 147 1.1 riastrad #endif 148 1.1 riastrad } 149 1.1 riastrad EXPORT_SYMBOL(drm_clflush_sg); 150 1.1 riastrad 151 1.3 riastrad /** 152 1.3 riastrad * drm_clflush_virt_range - Flush dcache lines of a region 153 1.3 riastrad * @addr: Initial kernel memory address. 154 1.3 riastrad * @length: Region size. 155 1.3 riastrad * 156 1.3 riastrad * Flush every data cache line entry that points to an address in the 157 1.3 riastrad * region requested. 158 1.3 riastrad */ 159 1.1 riastrad void 160 1.2 riastrad drm_clflush_virt_range(void *addr, unsigned long length) 161 1.1 riastrad { 162 1.1 riastrad #if defined(CONFIG_X86) 163 1.3 riastrad if (static_cpu_has(X86_FEATURE_CLFLUSH)) { 164 1.4 riastrad #ifdef __NetBSD__ 165 1.4 riastrad const int size = cpu_info_primary.ci_cflush_lsize; 166 1.4 riastrad #else 167 1.2 riastrad const int size = boot_cpu_data.x86_clflush_size; 168 1.4 riastrad #endif 169 1.2 riastrad void *end = addr + length; 170 1.3 riastrad 171 1.2 riastrad addr = (void *)(((unsigned long)addr) & -size); 172 1.3 riastrad mb(); /*CLFLUSH is only ordered with a full memory barrier*/ 173 1.2 riastrad for (; addr < end; addr += size) 174 1.2 riastrad clflushopt(addr); 175 1.2 riastrad clflushopt(end - 1); /* force serialisation */ 176 1.3 riastrad mb(); /*Ensure that evry data cache line entry is flushed*/ 177 1.1 riastrad return; 178 1.1 riastrad } 179 1.1 riastrad 180 1.2 riastrad if (wbinvd_on_all_cpus()) 181 1.3 riastrad pr_err("Timed out waiting for cache flush\n"); 182 1.1 riastrad #else 183 1.3 riastrad pr_err("Architecture has no drm_cache.c support\n"); 184 1.1 riastrad WARN_ON_ONCE(1); 185 1.1 riastrad #endif 186 1.1 riastrad } 187 1.1 riastrad EXPORT_SYMBOL(drm_clflush_virt_range); 188