MIPS: Introduce accessors for MSA vector registers
authorPaul Burton <paul.burton@imgtec.com>
Mon, 22 Jun 2015 11:20:59 +0000 (12:20 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 3 Sep 2015 10:07:40 +0000 (12:07 +0200)
Introduce accessor functions allowing the kernel to access arbitrary
vector registers using an arbitrary data format. The accessors are
implemented in assembly, using macros to avoid massive duplication, in
order to make use of the existing support for MSA with & without
toolchain support. The accessors will be used in a later patch.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Cc: linux-kernel@vger.kernel.org
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: Manuel Lauss <manuel.lauss@gmail.com>
Patchwork: https://patchwork.linux-mips.org/patch/10572/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/msa.h
arch/mips/kernel/r4k_fpu.S

index 76317a70200d18048404438bd85b69fb8bf8ec3e..867f924b05c79522a2d397d0002bc8a1397319e2 100644 (file)
        .set    pop
        .endm
 
+       .macro  ld_b    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       ld.b    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
+       .macro  ld_h    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       ld.h    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
+       .macro  ld_w    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       ld.w    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
        .macro  ld_d    wd, off, base
        .set    push
        .set    mips32r2
        .set    pop
        .endm
 
+       .macro  st_b    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       st.b    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
+       .macro  st_h    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       st.h    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
+       .macro  st_w    wd, off, base
+       .set    push
+       .set    mips32r2
+       .set    msa
+       st.w    $w\wd, \off(\base)
+       .set    pop
+       .endm
+
        .macro  st_d    wd, off, base
        .set    push
        .set    mips32r2
 #ifdef CONFIG_CPU_MICROMIPS
 #define CFC_MSA_INSN           0x587e0056
 #define CTC_MSA_INSN           0x583e0816
+#define LDB_MSA_INSN           0x58000807
+#define LDH_MSA_INSN           0x58000817
+#define LDW_MSA_INSN           0x58000827
 #define LDD_MSA_INSN           0x58000837
+#define STB_MSA_INSN           0x5800080f
+#define STH_MSA_INSN           0x5800081f
+#define STW_MSA_INSN           0x5800082f
 #define STD_MSA_INSN           0x5800083f
 #define COPY_UW_MSA_INSN       0x58f00056
 #define COPY_UD_MSA_INSN       0x58f80056
 #else
 #define CFC_MSA_INSN           0x787e0059
 #define CTC_MSA_INSN           0x783e0819
+#define LDB_MSA_INSN           0x78000820
+#define LDH_MSA_INSN           0x78000821
+#define LDW_MSA_INSN           0x78000822
 #define LDD_MSA_INSN           0x78000823
+#define STB_MSA_INSN           0x78000824
+#define STH_MSA_INSN           0x78000825
+#define STW_MSA_INSN           0x78000826
 #define STD_MSA_INSN           0x78000827
 #define COPY_UW_MSA_INSN       0x78f00059
 #define COPY_UD_MSA_INSN       0x78f80059
        .set    pop
        .endm
 
+       .macro  ld_b    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   LDB_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
+       .macro  ld_h    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   LDH_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
+       .macro  ld_w    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   LDW_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
        .macro  ld_d    wd, off, base
        .set    push
        .set    noat
        .set    pop
        .endm
 
+       .macro  st_b    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   STB_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
+       .macro  st_h    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   STH_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
+       .macro  st_w    wd, off, base
+       .set    push
+       .set    noat
+       SET_HARDFLOAT
+       addu    $1, \base, \off
+       .word   STW_MSA_INSN | (\wd << 6)
+       .set    pop
+       .endm
+
        .macro  st_d    wd, off, base
        .set    push
        .set    noat
index af5638b12c756794b72df9adaeee27a828e1ddc7..bbb85fe21642f0e7f01b45bd4ba70076ed7a8b4c 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <asm/inst.h>
+
 extern void _save_msa(struct task_struct *);
 extern void _restore_msa(struct task_struct *);
 extern void _init_msa_upper(void);
 
+extern void read_msa_wr_b(unsigned idx, union fpureg *to);
+extern void read_msa_wr_h(unsigned idx, union fpureg *to);
+extern void read_msa_wr_w(unsigned idx, union fpureg *to);
+extern void read_msa_wr_d(unsigned idx, union fpureg *to);
+
+/**
+ * read_msa_wr() - Read a single MSA vector register
+ * @idx:       The index of the vector register to read
+ * @to:                The FPU register union to store the registers value in
+ * @fmt:       The format of the data in the vector register
+ *
+ * Read the value of MSA vector register idx into the FPU register
+ * union to, using the format fmt.
+ */
+static inline void read_msa_wr(unsigned idx, union fpureg *to,
+                              enum msa_2b_fmt fmt)
+{
+       switch (fmt) {
+       case msa_fmt_b:
+               read_msa_wr_b(idx, to);
+               break;
+
+       case msa_fmt_h:
+               read_msa_wr_h(idx, to);
+               break;
+
+       case msa_fmt_w:
+               read_msa_wr_w(idx, to);
+               break;
+
+       case msa_fmt_d:
+               read_msa_wr_d(idx, to);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+extern void write_msa_wr_b(unsigned idx, union fpureg *from);
+extern void write_msa_wr_h(unsigned idx, union fpureg *from);
+extern void write_msa_wr_w(unsigned idx, union fpureg *from);
+extern void write_msa_wr_d(unsigned idx, union fpureg *from);
+
+/**
+ * write_msa_wr() - Write a single MSA vector register
+ * @idx:       The index of the vector register to write
+ * @from:      The FPU register union to take the registers value from
+ * @fmt:       The format of the data in the vector register
+ *
+ * Write the value from the FPU register union from into MSA vector
+ * register idx, using the format fmt.
+ */
+static inline void write_msa_wr(unsigned idx, union fpureg *from,
+                               enum msa_2b_fmt fmt)
+{
+       switch (fmt) {
+       case msa_fmt_b:
+               write_msa_wr_b(idx, from);
+               break;
+
+       case msa_fmt_h:
+               write_msa_wr_h(idx, from);
+               break;
+
+       case msa_fmt_w:
+               write_msa_wr_w(idx, from);
+               break;
+
+       case msa_fmt_d:
+               write_msa_wr_d(idx, from);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
 static inline void enable_msa(void)
 {
        if (cpu_has_msa) {
index 1d88af26ba82a0c3ee58ff8ff3b2b1661dad9455..ca887da1a48a29d16c8c055912472f77b48014eb 100644 (file)
@@ -13,6 +13,7 @@
  * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
  */
 #include <asm/asm.h>
+#include <asm/asmmacro.h>
 #include <asm/errno.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
@@ -274,6 +275,72 @@ LEAF(_restore_fp_context32)
        END(_restore_fp_context32)
 #endif
 
+#ifdef CONFIG_CPU_HAS_MSA
+
+       .macro  op_one_wr       op, idx, base
+       .align  4
+\idx:  \op     \idx, 0, \base
+       jr      ra
+        nop
+       .endm
+
+       .macro  op_msa_wr       name, op
+LEAF(\name)
+       .set            push
+       .set            noreorder
+       sll             t0, a0, 4
+       PTR_LA          t1, 0f
+       PTR_ADDU        t0, t0, t1
+       jr              t0
+         nop
+       op_one_wr       \op, 0, a1
+       op_one_wr       \op, 1, a1
+       op_one_wr       \op, 2, a1
+       op_one_wr       \op, 3, a1
+       op_one_wr       \op, 4, a1
+       op_one_wr       \op, 5, a1
+       op_one_wr       \op, 6, a1
+       op_one_wr       \op, 7, a1
+       op_one_wr       \op, 8, a1
+       op_one_wr       \op, 9, a1
+       op_one_wr       \op, 10, a1
+       op_one_wr       \op, 11, a1
+       op_one_wr       \op, 12, a1
+       op_one_wr       \op, 13, a1
+       op_one_wr       \op, 14, a1
+       op_one_wr       \op, 15, a1
+       op_one_wr       \op, 16, a1
+       op_one_wr       \op, 17, a1
+       op_one_wr       \op, 18, a1
+       op_one_wr       \op, 19, a1
+       op_one_wr       \op, 20, a1
+       op_one_wr       \op, 21, a1
+       op_one_wr       \op, 22, a1
+       op_one_wr       \op, 23, a1
+       op_one_wr       \op, 24, a1
+       op_one_wr       \op, 25, a1
+       op_one_wr       \op, 26, a1
+       op_one_wr       \op, 27, a1
+       op_one_wr       \op, 28, a1
+       op_one_wr       \op, 29, a1
+       op_one_wr       \op, 30, a1
+       op_one_wr       \op, 31, a1
+       .set            pop
+       END(\name)
+       .endm
+
+       op_msa_wr       read_msa_wr_b, st_b
+       op_msa_wr       read_msa_wr_h, st_h
+       op_msa_wr       read_msa_wr_w, st_w
+       op_msa_wr       read_msa_wr_d, st_d
+
+       op_msa_wr       write_msa_wr_b, ld_b
+       op_msa_wr       write_msa_wr_h, ld_h
+       op_msa_wr       write_msa_wr_w, ld_w
+       op_msa_wr       write_msa_wr_d, ld_d
+
+#endif /* CONFIG_CPU_HAS_MSA */
+
        .set    reorder
 
        .type   fault@function