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