0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include <linux/cc_platform.h>
0031 #include <linux/export.h>
0032 #include <linux/highmem.h>
0033 #include <linux/ioport.h>
0034 #include <linux/iosys-map.h>
0035 #include <xen/xen.h>
0036
0037 #include <drm/drm_cache.h>
0038
0039
0040 #define MEMCPY_BOUNCE_SIZE 128
0041
0042 #if defined(CONFIG_X86)
0043 #include <asm/smp.h>
0044
0045
0046
0047
0048
0049
0050 static void
0051 drm_clflush_page(struct page *page)
0052 {
0053 uint8_t *page_virtual;
0054 unsigned int i;
0055 const int size = boot_cpu_data.x86_clflush_size;
0056
0057 if (unlikely(page == NULL))
0058 return;
0059
0060 page_virtual = kmap_atomic(page);
0061 for (i = 0; i < PAGE_SIZE; i += size)
0062 clflushopt(page_virtual + i);
0063 kunmap_atomic(page_virtual);
0064 }
0065
0066 static void drm_cache_flush_clflush(struct page *pages[],
0067 unsigned long num_pages)
0068 {
0069 unsigned long i;
0070
0071 mb();
0072 for (i = 0; i < num_pages; i++)
0073 drm_clflush_page(*pages++);
0074 mb();
0075 }
0076 #endif
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 void
0087 drm_clflush_pages(struct page *pages[], unsigned long num_pages)
0088 {
0089
0090 #if defined(CONFIG_X86)
0091 if (static_cpu_has(X86_FEATURE_CLFLUSH)) {
0092 drm_cache_flush_clflush(pages, num_pages);
0093 return;
0094 }
0095
0096 if (wbinvd_on_all_cpus())
0097 pr_err("Timed out waiting for cache flush\n");
0098
0099 #elif defined(__powerpc__)
0100 unsigned long i;
0101
0102 for (i = 0; i < num_pages; i++) {
0103 struct page *page = pages[i];
0104 void *page_virtual;
0105
0106 if (unlikely(page == NULL))
0107 continue;
0108
0109 page_virtual = kmap_atomic(page);
0110 flush_dcache_range((unsigned long)page_virtual,
0111 (unsigned long)page_virtual + PAGE_SIZE);
0112 kunmap_atomic(page_virtual);
0113 }
0114 #else
0115 WARN_ONCE(1, "Architecture has no drm_cache.c support\n");
0116 #endif
0117 }
0118 EXPORT_SYMBOL(drm_clflush_pages);
0119
0120
0121
0122
0123
0124
0125
0126
0127 void
0128 drm_clflush_sg(struct sg_table *st)
0129 {
0130 #if defined(CONFIG_X86)
0131 if (static_cpu_has(X86_FEATURE_CLFLUSH)) {
0132 struct sg_page_iter sg_iter;
0133
0134 mb();
0135 for_each_sgtable_page(st, &sg_iter, 0)
0136 drm_clflush_page(sg_page_iter_page(&sg_iter));
0137 mb();
0138
0139 return;
0140 }
0141
0142 if (wbinvd_on_all_cpus())
0143 pr_err("Timed out waiting for cache flush\n");
0144 #else
0145 WARN_ONCE(1, "Architecture has no drm_cache.c support\n");
0146 #endif
0147 }
0148 EXPORT_SYMBOL(drm_clflush_sg);
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 void
0159 drm_clflush_virt_range(void *addr, unsigned long length)
0160 {
0161 #if defined(CONFIG_X86)
0162 if (static_cpu_has(X86_FEATURE_CLFLUSH)) {
0163 const int size = boot_cpu_data.x86_clflush_size;
0164 void *end = addr + length;
0165
0166 addr = (void *)(((unsigned long)addr) & -size);
0167 mb();
0168 for (; addr < end; addr += size)
0169 clflushopt(addr);
0170 clflushopt(end - 1);
0171 mb();
0172 return;
0173 }
0174
0175 if (wbinvd_on_all_cpus())
0176 pr_err("Timed out waiting for cache flush\n");
0177 #else
0178 WARN_ONCE(1, "Architecture has no drm_cache.c support\n");
0179 #endif
0180 }
0181 EXPORT_SYMBOL(drm_clflush_virt_range);
0182
0183 bool drm_need_swiotlb(int dma_bits)
0184 {
0185 struct resource *tmp;
0186 resource_size_t max_iomem = 0;
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 if (xen_pv_domain())
0198 return true;
0199
0200
0201
0202
0203
0204 if (cc_platform_has(CC_ATTR_MEM_ENCRYPT))
0205 return true;
0206
0207 for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling)
0208 max_iomem = max(max_iomem, tmp->end);
0209
0210 return max_iomem > ((u64)1 << dma_bits);
0211 }
0212 EXPORT_SYMBOL(drm_need_swiotlb);
0213
0214 static void memcpy_fallback(struct iosys_map *dst,
0215 const struct iosys_map *src,
0216 unsigned long len)
0217 {
0218 if (!dst->is_iomem && !src->is_iomem) {
0219 memcpy(dst->vaddr, src->vaddr, len);
0220 } else if (!src->is_iomem) {
0221 iosys_map_memcpy_to(dst, 0, src->vaddr, len);
0222 } else if (!dst->is_iomem) {
0223 memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
0224 } else {
0225
0226
0227
0228
0229
0230 char bounce[MEMCPY_BOUNCE_SIZE];
0231 void __iomem *_src = src->vaddr_iomem;
0232 void __iomem *_dst = dst->vaddr_iomem;
0233
0234 while (len >= MEMCPY_BOUNCE_SIZE) {
0235 memcpy_fromio(bounce, _src, MEMCPY_BOUNCE_SIZE);
0236 memcpy_toio(_dst, bounce, MEMCPY_BOUNCE_SIZE);
0237 _src += MEMCPY_BOUNCE_SIZE;
0238 _dst += MEMCPY_BOUNCE_SIZE;
0239 len -= MEMCPY_BOUNCE_SIZE;
0240 }
0241 if (len) {
0242 memcpy_fromio(bounce, _src, MEMCPY_BOUNCE_SIZE);
0243 memcpy_toio(_dst, bounce, MEMCPY_BOUNCE_SIZE);
0244 }
0245 }
0246 }
0247
0248 #ifdef CONFIG_X86
0249
0250 static DEFINE_STATIC_KEY_FALSE(has_movntdqa);
0251
0252 static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len)
0253 {
0254 kernel_fpu_begin();
0255
0256 while (len >= 4) {
0257 asm("movntdqa (%0), %%xmm0\n"
0258 "movntdqa 16(%0), %%xmm1\n"
0259 "movntdqa 32(%0), %%xmm2\n"
0260 "movntdqa 48(%0), %%xmm3\n"
0261 "movaps %%xmm0, (%1)\n"
0262 "movaps %%xmm1, 16(%1)\n"
0263 "movaps %%xmm2, 32(%1)\n"
0264 "movaps %%xmm3, 48(%1)\n"
0265 :: "r" (src), "r" (dst) : "memory");
0266 src += 64;
0267 dst += 64;
0268 len -= 4;
0269 }
0270 while (len--) {
0271 asm("movntdqa (%0), %%xmm0\n"
0272 "movaps %%xmm0, (%1)\n"
0273 :: "r" (src), "r" (dst) : "memory");
0274 src += 16;
0275 dst += 16;
0276 }
0277
0278 kernel_fpu_end();
0279 }
0280
0281
0282
0283
0284
0285
0286
0287 static void __drm_memcpy_from_wc(void *dst, const void *src, unsigned long len)
0288 {
0289 if (unlikely(((unsigned long)dst | (unsigned long)src | len) & 15))
0290 memcpy(dst, src, len);
0291 else if (likely(len))
0292 __memcpy_ntdqa(dst, src, len >> 4);
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 void drm_memcpy_from_wc(struct iosys_map *dst,
0306 const struct iosys_map *src,
0307 unsigned long len)
0308 {
0309 if (WARN_ON(in_interrupt())) {
0310 memcpy_fallback(dst, src, len);
0311 return;
0312 }
0313
0314 if (static_branch_likely(&has_movntdqa)) {
0315 __drm_memcpy_from_wc(dst->is_iomem ?
0316 (void __force *)dst->vaddr_iomem :
0317 dst->vaddr,
0318 src->is_iomem ?
0319 (void const __force *)src->vaddr_iomem :
0320 src->vaddr,
0321 len);
0322 return;
0323 }
0324
0325 memcpy_fallback(dst, src, len);
0326 }
0327 EXPORT_SYMBOL(drm_memcpy_from_wc);
0328
0329
0330
0331
0332 void drm_memcpy_init_early(void)
0333 {
0334
0335
0336
0337
0338 if (static_cpu_has(X86_FEATURE_XMM4_1) &&
0339 !boot_cpu_has(X86_FEATURE_HYPERVISOR))
0340 static_branch_enable(&has_movntdqa);
0341 }
0342 #else
0343 void drm_memcpy_from_wc(struct iosys_map *dst,
0344 const struct iosys_map *src,
0345 unsigned long len)
0346 {
0347 WARN_ON(in_interrupt());
0348
0349 memcpy_fallback(dst, src, len);
0350 }
0351 EXPORT_SYMBOL(drm_memcpy_from_wc);
0352
0353 void drm_memcpy_init_early(void)
0354 {
0355 }
0356 #endif