1 #include <linux/types.h>
2 #include <linux/string.h>
3 #include <linux/sched.h>
4 #include <linux/hardirq.h>
5 #include <linux/module.h>
12 * MMX 3DNow! library helper functions
15 * We can use MMX just for prefetch in IRQ's. This may be a win.
16 * (reported so on K6-III)
17 * We should use a better code neutral filler for the short jump
18 * leal ebx. [ebx] is apparently best for K6-2, but Cyrix ??
19 * We also want to clobber the filler register so we don't get any
20 * register forwarding stalls on the filler.
22 * Add *user handling. Checksums are not a win with MMX on any CPU
23 * tested so far for any MMX solution figured.
25 * 22/09/2000 - Arjan van de Ven
26 * Improved for non-egineering-sample Athlons
30 void *_mmx_memcpy(void *to, const void *from, size_t len)
35 if (unlikely(in_interrupt()))
36 return __memcpy(to, from, len);
39 i = len >> 6; /* len/64 */
43 __asm__ __volatile__ (
44 "1: prefetch (%0)\n" /* This set is 28 bytes */
50 ".section .fixup, \"ax\"\n"
51 "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
60 __asm__ __volatile__ (
61 "1: prefetch 320(%0)\n"
62 "2: movq (%0), %%mm0\n"
63 " movq 8(%0), %%mm1\n"
64 " movq 16(%0), %%mm2\n"
65 " movq 24(%0), %%mm3\n"
67 " movq %%mm1, 8(%1)\n"
68 " movq %%mm2, 16(%1)\n"
69 " movq %%mm3, 24(%1)\n"
70 " movq 32(%0), %%mm0\n"
71 " movq 40(%0), %%mm1\n"
72 " movq 48(%0), %%mm2\n"
73 " movq 56(%0), %%mm3\n"
74 " movq %%mm0, 32(%1)\n"
75 " movq %%mm1, 40(%1)\n"
76 " movq %%mm2, 48(%1)\n"
77 " movq %%mm3, 56(%1)\n"
78 ".section .fixup, \"ax\"\n"
79 "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
83 : : "r" (from), "r" (to) : "memory");
90 __asm__ __volatile__ (
92 " movq 8(%0), %%mm1\n"
93 " movq 16(%0), %%mm2\n"
94 " movq 24(%0), %%mm3\n"
96 " movq %%mm1, 8(%1)\n"
97 " movq %%mm2, 16(%1)\n"
98 " movq %%mm3, 24(%1)\n"
99 " movq 32(%0), %%mm0\n"
100 " movq 40(%0), %%mm1\n"
101 " movq 48(%0), %%mm2\n"
102 " movq 56(%0), %%mm3\n"
103 " movq %%mm0, 32(%1)\n"
104 " movq %%mm1, 40(%1)\n"
105 " movq %%mm2, 48(%1)\n"
106 " movq %%mm3, 56(%1)\n"
107 : : "r" (from), "r" (to) : "memory");
112 * Now do the tail of the block
114 __memcpy(to, from, len&63);
122 * The K7 has streaming cache bypass load/store. The Cyrix III, K6 and
123 * other MMX using processors do not.
126 static void fast_clear_page(void *page)
132 __asm__ __volatile__ (
133 " pxor %%mm0, %%mm0\n" : :
136 for(i=0;i<4096/64;i++)
138 __asm__ __volatile__ (
139 " movntq %%mm0, (%0)\n"
140 " movntq %%mm0, 8(%0)\n"
141 " movntq %%mm0, 16(%0)\n"
142 " movntq %%mm0, 24(%0)\n"
143 " movntq %%mm0, 32(%0)\n"
144 " movntq %%mm0, 40(%0)\n"
145 " movntq %%mm0, 48(%0)\n"
146 " movntq %%mm0, 56(%0)\n"
147 : : "r" (page) : "memory");
150 /* since movntq is weakly-ordered, a "sfence" is needed to become
153 __asm__ __volatile__ (
159 static void fast_copy_page(void *to, void *from)
165 /* maybe the prefetch stuff can go before the expensive fnsave...
166 * but that is for later. -AV
168 __asm__ __volatile__ (
171 " prefetch 128(%0)\n"
172 " prefetch 192(%0)\n"
173 " prefetch 256(%0)\n"
175 ".section .fixup, \"ax\"\n"
176 "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
182 for(i=0; i<(4096-320)/64; i++)
184 __asm__ __volatile__ (
185 "1: prefetch 320(%0)\n"
186 "2: movq (%0), %%mm0\n"
187 " movntq %%mm0, (%1)\n"
188 " movq 8(%0), %%mm1\n"
189 " movntq %%mm1, 8(%1)\n"
190 " movq 16(%0), %%mm2\n"
191 " movntq %%mm2, 16(%1)\n"
192 " movq 24(%0), %%mm3\n"
193 " movntq %%mm3, 24(%1)\n"
194 " movq 32(%0), %%mm4\n"
195 " movntq %%mm4, 32(%1)\n"
196 " movq 40(%0), %%mm5\n"
197 " movntq %%mm5, 40(%1)\n"
198 " movq 48(%0), %%mm6\n"
199 " movntq %%mm6, 48(%1)\n"
200 " movq 56(%0), %%mm7\n"
201 " movntq %%mm7, 56(%1)\n"
202 ".section .fixup, \"ax\"\n"
203 "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
207 : : "r" (from), "r" (to) : "memory");
211 for(i=(4096-320)/64; i<4096/64; i++)
213 __asm__ __volatile__ (
214 "2: movq (%0), %%mm0\n"
215 " movntq %%mm0, (%1)\n"
216 " movq 8(%0), %%mm1\n"
217 " movntq %%mm1, 8(%1)\n"
218 " movq 16(%0), %%mm2\n"
219 " movntq %%mm2, 16(%1)\n"
220 " movq 24(%0), %%mm3\n"
221 " movntq %%mm3, 24(%1)\n"
222 " movq 32(%0), %%mm4\n"
223 " movntq %%mm4, 32(%1)\n"
224 " movq 40(%0), %%mm5\n"
225 " movntq %%mm5, 40(%1)\n"
226 " movq 48(%0), %%mm6\n"
227 " movntq %%mm6, 48(%1)\n"
228 " movq 56(%0), %%mm7\n"
229 " movntq %%mm7, 56(%1)\n"
230 : : "r" (from), "r" (to) : "memory");
234 /* since movntq is weakly-ordered, a "sfence" is needed to become
237 __asm__ __volatile__ (
246 * Generic MMX implementation without K7 specific streaming
249 static void fast_clear_page(void *page)
255 __asm__ __volatile__ (
256 " pxor %%mm0, %%mm0\n" : :
259 for(i=0;i<4096/128;i++)
261 __asm__ __volatile__ (
262 " movq %%mm0, (%0)\n"
263 " movq %%mm0, 8(%0)\n"
264 " movq %%mm0, 16(%0)\n"
265 " movq %%mm0, 24(%0)\n"
266 " movq %%mm0, 32(%0)\n"
267 " movq %%mm0, 40(%0)\n"
268 " movq %%mm0, 48(%0)\n"
269 " movq %%mm0, 56(%0)\n"
270 " movq %%mm0, 64(%0)\n"
271 " movq %%mm0, 72(%0)\n"
272 " movq %%mm0, 80(%0)\n"
273 " movq %%mm0, 88(%0)\n"
274 " movq %%mm0, 96(%0)\n"
275 " movq %%mm0, 104(%0)\n"
276 " movq %%mm0, 112(%0)\n"
277 " movq %%mm0, 120(%0)\n"
278 : : "r" (page) : "memory");
285 static void fast_copy_page(void *to, void *from)
292 __asm__ __volatile__ (
295 " prefetch 128(%0)\n"
296 " prefetch 192(%0)\n"
297 " prefetch 256(%0)\n"
299 ".section .fixup, \"ax\"\n"
300 "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
306 for(i=0; i<4096/64; i++)
308 __asm__ __volatile__ (
309 "1: prefetch 320(%0)\n"
310 "2: movq (%0), %%mm0\n"
311 " movq 8(%0), %%mm1\n"
312 " movq 16(%0), %%mm2\n"
313 " movq 24(%0), %%mm3\n"
314 " movq %%mm0, (%1)\n"
315 " movq %%mm1, 8(%1)\n"
316 " movq %%mm2, 16(%1)\n"
317 " movq %%mm3, 24(%1)\n"
318 " movq 32(%0), %%mm0\n"
319 " movq 40(%0), %%mm1\n"
320 " movq 48(%0), %%mm2\n"
321 " movq 56(%0), %%mm3\n"
322 " movq %%mm0, 32(%1)\n"
323 " movq %%mm1, 40(%1)\n"
324 " movq %%mm2, 48(%1)\n"
325 " movq %%mm3, 56(%1)\n"
326 ".section .fixup, \"ax\"\n"
327 "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
331 : : "r" (from), "r" (to) : "memory");
342 * Favour MMX for page clear and copy.
345 static void slow_zero_page(void * page)
348 __asm__ __volatile__( \
351 : "=&c" (d0), "=&D" (d1)
352 :"a" (0),"1" (page),"0" (1024)
356 void mmx_clear_page(void * page)
358 if(unlikely(in_interrupt()))
359 slow_zero_page(page);
361 fast_clear_page(page);
364 static void slow_copy_page(void *to, void *from)
367 __asm__ __volatile__( \
370 : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
371 : "0" (1024),"1" ((long) to),"2" ((long) from) \
376 void mmx_copy_page(void *to, void *from)
378 if(unlikely(in_interrupt()))
379 slow_copy_page(to, from);
381 fast_copy_page(to, from);
384 EXPORT_SYMBOL(_mmx_memcpy);
385 EXPORT_SYMBOL(mmx_clear_page);
386 EXPORT_SYMBOL(mmx_copy_page);