Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2016 Intel Corporation
3 : : *
4 : : * Permission is hereby granted, free of charge, to any person obtaining a
5 : : * copy of this software and associated documentation files (the "Software"),
6 : : * to deal in the Software without restriction, including without limitation
7 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : : * and/or sell copies of the Software, and to permit persons to whom the
9 : : * Software is furnished to do so, subject to the following conditions:
10 : : *
11 : : * The above copyright notice and this permission notice (including the next
12 : : * paragraph) shall be included in all copies or substantial portions of the
13 : : * Software.
14 : : *
15 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 : : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 : : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 : : * IN THE SOFTWARE.
22 : : *
23 : : */
24 : :
25 : : #include <linux/kernel.h>
26 : : #include <asm/fpu/api.h>
27 : :
28 : : #include "i915_memcpy.h"
29 : :
30 : : #if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
31 : : #define CI_BUG_ON(expr) BUG_ON(expr)
32 : : #else
33 : : #define CI_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
34 : : #endif
35 : :
36 : : static DEFINE_STATIC_KEY_FALSE(has_movntdqa);
37 : :
38 : : #ifdef CONFIG_AS_MOVNTDQA
39 : 0 : static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len)
40 : : {
41 : 0 : kernel_fpu_begin();
42 : :
43 [ # # ]: 0 : while (len >= 4) {
44 : 0 : asm("movntdqa (%0), %%xmm0\n"
45 : : "movntdqa 16(%0), %%xmm1\n"
46 : : "movntdqa 32(%0), %%xmm2\n"
47 : : "movntdqa 48(%0), %%xmm3\n"
48 : : "movaps %%xmm0, (%1)\n"
49 : : "movaps %%xmm1, 16(%1)\n"
50 : : "movaps %%xmm2, 32(%1)\n"
51 : : "movaps %%xmm3, 48(%1)\n"
52 : : :: "r" (src), "r" (dst) : "memory");
53 : 0 : src += 64;
54 : 0 : dst += 64;
55 : 0 : len -= 4;
56 : : }
57 [ # # ]: 0 : while (len--) {
58 : 0 : asm("movntdqa (%0), %%xmm0\n"
59 : : "movaps %%xmm0, (%1)\n"
60 : : :: "r" (src), "r" (dst) : "memory");
61 : 0 : src += 16;
62 : 0 : dst += 16;
63 : : }
64 : :
65 : 0 : kernel_fpu_end();
66 : 0 : }
67 : :
68 : 0 : static void __memcpy_ntdqu(void *dst, const void *src, unsigned long len)
69 : : {
70 : 0 : kernel_fpu_begin();
71 : :
72 [ # # ]: 0 : while (len >= 4) {
73 : 0 : asm("movntdqa (%0), %%xmm0\n"
74 : : "movntdqa 16(%0), %%xmm1\n"
75 : : "movntdqa 32(%0), %%xmm2\n"
76 : : "movntdqa 48(%0), %%xmm3\n"
77 : : "movups %%xmm0, (%1)\n"
78 : : "movups %%xmm1, 16(%1)\n"
79 : : "movups %%xmm2, 32(%1)\n"
80 : : "movups %%xmm3, 48(%1)\n"
81 : : :: "r" (src), "r" (dst) : "memory");
82 : 0 : src += 64;
83 : 0 : dst += 64;
84 : 0 : len -= 4;
85 : : }
86 [ # # ]: 0 : while (len--) {
87 : 0 : asm("movntdqa (%0), %%xmm0\n"
88 : : "movups %%xmm0, (%1)\n"
89 : : :: "r" (src), "r" (dst) : "memory");
90 : 0 : src += 16;
91 : 0 : dst += 16;
92 : : }
93 : :
94 : 0 : kernel_fpu_end();
95 : 0 : }
96 : : #else
97 : : static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len) {}
98 : : static void __memcpy_ntdqu(void *dst, const void *src, unsigned long len) {}
99 : : #endif
100 : :
101 : : /**
102 : : * i915_memcpy_from_wc: perform an accelerated *aligned* read from WC
103 : : * @dst: destination pointer
104 : : * @src: source pointer
105 : : * @len: how many bytes to copy
106 : : *
107 : : * i915_memcpy_from_wc copies @len bytes from @src to @dst using
108 : : * non-temporal instructions where available. Note that all arguments
109 : : * (@src, @dst) must be aligned to 16 bytes and @len must be a multiple
110 : : * of 16.
111 : : *
112 : : * To test whether accelerated reads from WC are supported, use
113 : : * i915_memcpy_from_wc(NULL, NULL, 0);
114 : : *
115 : : * Returns true if the copy was successful, false if the preconditions
116 : : * are not met.
117 : : */
118 : 0 : bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len)
119 : : {
120 [ # # ]: 0 : if (unlikely(((unsigned long)dst | (unsigned long)src | len) & 15))
121 : : return false;
122 : :
123 [ # # # # ]: 0 : if (static_branch_likely(&has_movntdqa)) {
124 [ # # ]: 0 : if (likely(len))
125 : 0 : __memcpy_ntdqa(dst, src, len >> 4);
126 : 0 : return true;
127 : : }
128 : :
129 : : return false;
130 : : }
131 : :
132 : : /**
133 : : * i915_unaligned_memcpy_from_wc: perform a mostly accelerated read from WC
134 : : * @dst: destination pointer
135 : : * @src: source pointer
136 : : * @len: how many bytes to copy
137 : : *
138 : : * Like i915_memcpy_from_wc(), the unaligned variant copies @len bytes from
139 : : * @src to @dst using * non-temporal instructions where available, but
140 : : * accepts that its arguments may not be aligned, but are valid for the
141 : : * potential 16-byte read past the end.
142 : : */
143 : 0 : void i915_unaligned_memcpy_from_wc(void *dst, void *src, unsigned long len)
144 : : {
145 : 0 : unsigned long addr;
146 : :
147 : 0 : CI_BUG_ON(!i915_has_memcpy_from_wc());
148 : :
149 : 0 : addr = (unsigned long)src;
150 [ # # ]: 0 : if (!IS_ALIGNED(addr, 16)) {
151 : 0 : unsigned long x = min(ALIGN(addr, 16) - addr, len);
152 : :
153 : 0 : memcpy(dst, src, x);
154 : :
155 : 0 : len -= x;
156 : 0 : dst += x;
157 : 0 : src += x;
158 : : }
159 : :
160 [ # # ]: 0 : if (likely(len))
161 : 0 : __memcpy_ntdqu(dst, src, DIV_ROUND_UP(len, 16));
162 : 0 : }
163 : :
164 : 0 : void i915_memcpy_init_early(struct drm_i915_private *dev_priv)
165 : : {
166 : : /*
167 : : * Some hypervisors (e.g. KVM) don't support VEX-prefix instructions
168 : : * emulation. So don't enable movntdqa in hypervisor guest.
169 : : */
170 [ # # # # : 0 : if (static_cpu_has(X86_FEATURE_XMM4_1) &&
# ]
171 : : !boot_cpu_has(X86_FEATURE_HYPERVISOR))
172 : 0 : static_branch_enable(&has_movntdqa);
173 : 0 : }
|