linux/arch/x86/lib/mmx_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *      MMX 3DNow! library helper functions
   4 *
   5 *      To do:
   6 *      We can use MMX just for prefetch in IRQ's. This may be a win.
   7 *              (reported so on K6-III)
   8 *      We should use a better code neutral filler for the short jump
   9 *              leal ebx. [ebx] is apparently best for K6-2, but Cyrix ??
  10 *      We also want to clobber the filler register so we don't get any
  11 *              register forwarding stalls on the filler.
  12 *
  13 *      Add *user handling. Checksums are not a win with MMX on any CPU
  14 *      tested so far for any MMX solution figured.
  15 *
  16 *      22/09/2000 - Arjan van de Ven
  17 *              Improved for non-engineering-sample Athlons
  18 *
  19 */
  20#include <linux/hardirq.h>
  21#include <linux/string.h>
  22#include <linux/export.h>
  23#include <linux/sched.h>
  24#include <linux/types.h>
  25
  26#include <asm/fpu/api.h>
  27#include <asm/asm.h>
  28
  29/*
  30 * Use KFPU_387.  MMX instructions are not affected by MXCSR,
  31 * but both AMD and Intel documentation states that even integer MMX
  32 * operations will result in #MF if an exception is pending in FCW.
  33 *
  34 * EMMS is not needed afterwards because, after calling kernel_fpu_end(),
  35 * any subsequent user of the 387 stack will reinitialize it using
  36 * KFPU_387.
  37 */
  38
  39void *_mmx_memcpy(void *to, const void *from, size_t len)
  40{
  41        void *p;
  42        int i;
  43
  44        if (unlikely(in_interrupt()))
  45                return __memcpy(to, from, len);
  46
  47        p = to;
  48        i = len >> 6; /* len/64 */
  49
  50        kernel_fpu_begin_mask(KFPU_387);
  51
  52        __asm__ __volatile__ (
  53                "1: prefetch (%0)\n"            /* This set is 28 bytes */
  54                "   prefetch 64(%0)\n"
  55                "   prefetch 128(%0)\n"
  56                "   prefetch 192(%0)\n"
  57                "   prefetch 256(%0)\n"
  58                "2:  \n"
  59                ".section .fixup, \"ax\"\n"
  60                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
  61                "   jmp 2b\n"
  62                ".previous\n"
  63                        _ASM_EXTABLE(1b, 3b)
  64                        : : "r" (from));
  65
  66        for ( ; i > 5; i--) {
  67                __asm__ __volatile__ (
  68                "1:  prefetch 320(%0)\n"
  69                "2:  movq (%0), %%mm0\n"
  70                "  movq 8(%0), %%mm1\n"
  71                "  movq 16(%0), %%mm2\n"
  72                "  movq 24(%0), %%mm3\n"
  73                "  movq %%mm0, (%1)\n"
  74                "  movq %%mm1, 8(%1)\n"
  75                "  movq %%mm2, 16(%1)\n"
  76                "  movq %%mm3, 24(%1)\n"
  77                "  movq 32(%0), %%mm0\n"
  78                "  movq 40(%0), %%mm1\n"
  79                "  movq 48(%0), %%mm2\n"
  80                "  movq 56(%0), %%mm3\n"
  81                "  movq %%mm0, 32(%1)\n"
  82                "  movq %%mm1, 40(%1)\n"
  83                "  movq %%mm2, 48(%1)\n"
  84                "  movq %%mm3, 56(%1)\n"
  85                ".section .fixup, \"ax\"\n"
  86                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
  87                "   jmp 2b\n"
  88                ".previous\n"
  89                        _ASM_EXTABLE(1b, 3b)
  90                        : : "r" (from), "r" (to) : "memory");
  91
  92                from += 64;
  93                to += 64;
  94        }
  95
  96        for ( ; i > 0; i--) {
  97                __asm__ __volatile__ (
  98                "  movq (%0), %%mm0\n"
  99                "  movq 8(%0), %%mm1\n"
 100                "  movq 16(%0), %%mm2\n"
 101                "  movq 24(%0), %%mm3\n"
 102                "  movq %%mm0, (%1)\n"
 103                "  movq %%mm1, 8(%1)\n"
 104                "  movq %%mm2, 16(%1)\n"
 105                "  movq %%mm3, 24(%1)\n"
 106                "  movq 32(%0), %%mm0\n"
 107                "  movq 40(%0), %%mm1\n"
 108                "  movq 48(%0), %%mm2\n"
 109                "  movq 56(%0), %%mm3\n"
 110                "  movq %%mm0, 32(%1)\n"
 111                "  movq %%mm1, 40(%1)\n"
 112                "  movq %%mm2, 48(%1)\n"
 113                "  movq %%mm3, 56(%1)\n"
 114                        : : "r" (from), "r" (to) : "memory");
 115
 116                from += 64;
 117                to += 64;
 118        }
 119        /*
 120         * Now do the tail of the block:
 121         */
 122        __memcpy(to, from, len & 63);
 123        kernel_fpu_end();
 124
 125        return p;
 126}
 127EXPORT_SYMBOL(_mmx_memcpy);
 128
 129#ifdef CONFIG_MK7
 130
 131/*
 132 *      The K7 has streaming cache bypass load/store. The Cyrix III, K6 and
 133 *      other MMX using processors do not.
 134 */
 135
 136static void fast_clear_page(void *page)
 137{
 138        int i;
 139
 140        kernel_fpu_begin_mask(KFPU_387);
 141
 142        __asm__ __volatile__ (
 143                "  pxor %%mm0, %%mm0\n" : :
 144        );
 145
 146        for (i = 0; i < 4096/64; i++) {
 147                __asm__ __volatile__ (
 148                "  movntq %%mm0, (%0)\n"
 149                "  movntq %%mm0, 8(%0)\n"
 150                "  movntq %%mm0, 16(%0)\n"
 151                "  movntq %%mm0, 24(%0)\n"
 152                "  movntq %%mm0, 32(%0)\n"
 153                "  movntq %%mm0, 40(%0)\n"
 154                "  movntq %%mm0, 48(%0)\n"
 155                "  movntq %%mm0, 56(%0)\n"
 156                : : "r" (page) : "memory");
 157                page += 64;
 158        }
 159
 160        /*
 161         * Since movntq is weakly-ordered, a "sfence" is needed to become
 162         * ordered again:
 163         */
 164        __asm__ __volatile__("sfence\n"::);
 165
 166        kernel_fpu_end();
 167}
 168
 169static void fast_copy_page(void *to, void *from)
 170{
 171        int i;
 172
 173        kernel_fpu_begin_mask(KFPU_387);
 174
 175        /*
 176         * maybe the prefetch stuff can go before the expensive fnsave...
 177         * but that is for later. -AV
 178         */
 179        __asm__ __volatile__(
 180                "1: prefetch (%0)\n"
 181                "   prefetch 64(%0)\n"
 182                "   prefetch 128(%0)\n"
 183                "   prefetch 192(%0)\n"
 184                "   prefetch 256(%0)\n"
 185                "2:  \n"
 186                ".section .fixup, \"ax\"\n"
 187                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
 188                "   jmp 2b\n"
 189                ".previous\n"
 190                        _ASM_EXTABLE(1b, 3b) : : "r" (from));
 191
 192        for (i = 0; i < (4096-320)/64; i++) {
 193                __asm__ __volatile__ (
 194                "1: prefetch 320(%0)\n"
 195                "2: movq (%0), %%mm0\n"
 196                "   movntq %%mm0, (%1)\n"
 197                "   movq 8(%0), %%mm1\n"
 198                "   movntq %%mm1, 8(%1)\n"
 199                "   movq 16(%0), %%mm2\n"
 200                "   movntq %%mm2, 16(%1)\n"
 201                "   movq 24(%0), %%mm3\n"
 202                "   movntq %%mm3, 24(%1)\n"
 203                "   movq 32(%0), %%mm4\n"
 204                "   movntq %%mm4, 32(%1)\n"
 205                "   movq 40(%0), %%mm5\n"
 206                "   movntq %%mm5, 40(%1)\n"
 207                "   movq 48(%0), %%mm6\n"
 208                "   movntq %%mm6, 48(%1)\n"
 209                "   movq 56(%0), %%mm7\n"
 210                "   movntq %%mm7, 56(%1)\n"
 211                ".section .fixup, \"ax\"\n"
 212                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
 213                "   jmp 2b\n"
 214                ".previous\n"
 215                _ASM_EXTABLE(1b, 3b) : : "r" (from), "r" (to) : "memory");
 216
 217                from += 64;
 218                to += 64;
 219        }
 220
 221        for (i = (4096-320)/64; i < 4096/64; i++) {
 222                __asm__ __volatile__ (
 223                "2: movq (%0), %%mm0\n"
 224                "   movntq %%mm0, (%1)\n"
 225                "   movq 8(%0), %%mm1\n"
 226                "   movntq %%mm1, 8(%1)\n"
 227                "   movq 16(%0), %%mm2\n"
 228                "   movntq %%mm2, 16(%1)\n"
 229                "   movq 24(%0), %%mm3\n"
 230                "   movntq %%mm3, 24(%1)\n"
 231                "   movq 32(%0), %%mm4\n"
 232                "   movntq %%mm4, 32(%1)\n"
 233                "   movq 40(%0), %%mm5\n"
 234                "   movntq %%mm5, 40(%1)\n"
 235                "   movq 48(%0), %%mm6\n"
 236                "   movntq %%mm6, 48(%1)\n"
 237                "   movq 56(%0), %%mm7\n"
 238                "   movntq %%mm7, 56(%1)\n"
 239                        : : "r" (from), "r" (to) : "memory");
 240                from += 64;
 241                to += 64;
 242        }
 243        /*
 244         * Since movntq is weakly-ordered, a "sfence" is needed to become
 245         * ordered again:
 246         */
 247        __asm__ __volatile__("sfence \n"::);
 248        kernel_fpu_end();
 249}
 250
 251#else /* CONFIG_MK7 */
 252
 253/*
 254 *      Generic MMX implementation without K7 specific streaming
 255 */
 256static void fast_clear_page(void *page)
 257{
 258        int i;
 259
 260        kernel_fpu_begin_mask(KFPU_387);
 261
 262        __asm__ __volatile__ (
 263                "  pxor %%mm0, %%mm0\n" : :
 264        );
 265
 266        for (i = 0; i < 4096/128; i++) {
 267                __asm__ __volatile__ (
 268                "  movq %%mm0, (%0)\n"
 269                "  movq %%mm0, 8(%0)\n"
 270                "  movq %%mm0, 16(%0)\n"
 271                "  movq %%mm0, 24(%0)\n"
 272                "  movq %%mm0, 32(%0)\n"
 273                "  movq %%mm0, 40(%0)\n"
 274                "  movq %%mm0, 48(%0)\n"
 275                "  movq %%mm0, 56(%0)\n"
 276                "  movq %%mm0, 64(%0)\n"
 277                "  movq %%mm0, 72(%0)\n"
 278                "  movq %%mm0, 80(%0)\n"
 279                "  movq %%mm0, 88(%0)\n"
 280                "  movq %%mm0, 96(%0)\n"
 281                "  movq %%mm0, 104(%0)\n"
 282                "  movq %%mm0, 112(%0)\n"
 283                "  movq %%mm0, 120(%0)\n"
 284                        : : "r" (page) : "memory");
 285                page += 128;
 286        }
 287
 288        kernel_fpu_end();
 289}
 290
 291static void fast_copy_page(void *to, void *from)
 292{
 293        int i;
 294
 295        kernel_fpu_begin_mask(KFPU_387);
 296
 297        __asm__ __volatile__ (
 298                "1: prefetch (%0)\n"
 299                "   prefetch 64(%0)\n"
 300                "   prefetch 128(%0)\n"
 301                "   prefetch 192(%0)\n"
 302                "   prefetch 256(%0)\n"
 303                "2:  \n"
 304                ".section .fixup, \"ax\"\n"
 305                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
 306                "   jmp 2b\n"
 307                ".previous\n"
 308                        _ASM_EXTABLE(1b, 3b) : : "r" (from));
 309
 310        for (i = 0; i < 4096/64; i++) {
 311                __asm__ __volatile__ (
 312                "1: prefetch 320(%0)\n"
 313                "2: movq (%0), %%mm0\n"
 314                "   movq 8(%0), %%mm1\n"
 315                "   movq 16(%0), %%mm2\n"
 316                "   movq 24(%0), %%mm3\n"
 317                "   movq %%mm0, (%1)\n"
 318                "   movq %%mm1, 8(%1)\n"
 319                "   movq %%mm2, 16(%1)\n"
 320                "   movq %%mm3, 24(%1)\n"
 321                "   movq 32(%0), %%mm0\n"
 322                "   movq 40(%0), %%mm1\n"
 323                "   movq 48(%0), %%mm2\n"
 324                "   movq 56(%0), %%mm3\n"
 325                "   movq %%mm0, 32(%1)\n"
 326                "   movq %%mm1, 40(%1)\n"
 327                "   movq %%mm2, 48(%1)\n"
 328                "   movq %%mm3, 56(%1)\n"
 329                ".section .fixup, \"ax\"\n"
 330                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
 331                "   jmp 2b\n"
 332                ".previous\n"
 333                        _ASM_EXTABLE(1b, 3b)
 334                        : : "r" (from), "r" (to) : "memory");
 335
 336                from += 64;
 337                to += 64;
 338        }
 339        kernel_fpu_end();
 340}
 341
 342#endif /* !CONFIG_MK7 */
 343
 344/*
 345 * Favour MMX for page clear and copy:
 346 */
 347static void slow_zero_page(void *page)
 348{
 349        int d0, d1;
 350
 351        __asm__ __volatile__(
 352                "cld\n\t"
 353                "rep ; stosl"
 354
 355                        : "=&c" (d0), "=&D" (d1)
 356                        :"a" (0), "1" (page), "0" (1024)
 357                        :"memory");
 358}
 359
 360void mmx_clear_page(void *page)
 361{
 362        if (unlikely(in_interrupt()))
 363                slow_zero_page(page);
 364        else
 365                fast_clear_page(page);
 366}
 367EXPORT_SYMBOL(mmx_clear_page);
 368
 369static void slow_copy_page(void *to, void *from)
 370{
 371        int d0, d1, d2;
 372
 373        __asm__ __volatile__(
 374                "cld\n\t"
 375                "rep ; movsl"
 376                : "=&c" (d0), "=&D" (d1), "=&S" (d2)
 377                : "0" (1024), "1" ((long) to), "2" ((long) from)
 378                : "memory");
 379}
 380
 381void mmx_copy_page(void *to, void *from)
 382{
 383        if (unlikely(in_interrupt()))
 384                slow_copy_page(to, from);
 385        else
 386                fast_copy_page(to, from);
 387}
 388EXPORT_SYMBOL(mmx_copy_page);
 389