diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
new file mode 100644
index 000000000000..16304b0c6a6f
--- /dev/null
+++ b/arch/riscv/include/asm/vector.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#ifndef __ASM_RISCV_VECTOR_H
+#define __ASM_RISCV_VECTOR_H
+
+#include <linux/types.h>
+
+void rvv_enable(void);
+void rvv_disable(void);
+
+#endif /* ! __ASM_RISCV_VECTOR_H */
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 8d4448c2d4f4..0487ab19b234 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -30,6 +30,14 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX)
__read_mostly;

 __ro_after_init DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys,
RISCV_ISA_EXT_KEY_MAX);
 EXPORT_SYMBOL(riscv_isa_ext_keys);
+#ifdef CONFIG_FPU
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
+#endif
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
+unsigned long riscv_vsize __read_mostly;
+#endif

 /**
  * riscv_isa_extension_base() - Get base extension word
@@ -249,6 +257,16 @@ void __init riscv_fill_hwcap(void)
                if (j >= 0)
                        static_branch_enable(&riscv_isa_ext_keys[j]);
        }
+
+#ifdef CONFIG_VECTOR
+       if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+               static_branch_enable(&cpu_hwcap_vector);
+               /* There are 32 vector registers with vlenb length. */
+               rvv_enable();
+               riscv_vsize = csr_read(CSR_VLENB) * 32;
+               rvv_disable();
+       }
+#endif
 }

 #ifdef CONFIG_RISCV_ALTERNATIVE
@@ -328,3 +346,4 @@ void __init_or_module
riscv_cpufeature_patch_func(struct alt_entry *begin,
        }
 }
 #endif
+}
diff --git a/arch/riscv/kernel/riscv_ksyms.c b/arch/riscv/kernel/riscv_ksyms.c
index 5ab1c7e1a6ed..3489d2a20ca3 100644
--- a/arch/riscv/kernel/riscv_ksyms.c
+++ b/arch/riscv/kernel/riscv_ksyms.c
@@ -15,3 +15,9 @@ EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memmove);
+
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+EXPORT_SYMBOL(rvv_enable);
+EXPORT_SYMBOL(rvv_disable);
+#endif
diff --git a/arch/riscv/kernel/vector.S b/arch/riscv/kernel/vector.S
new file mode 100644
index 000000000000..9f7dc70c4443
--- /dev/null
+++ b/arch/riscv/kernel/vector.S
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ * Copyright (C) 2019 Alibaba Group Holding Limited
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm.h>
+#include <asm/csr.h>
+#include <asm/asm-offsets.h>
+
+#define vstatep  a0
+#define datap    a1
+#define x_vstart t0
+#define x_vtype  t1
+#define x_vl     t2
+#define x_vcsr   t3
+#define incr     t4
+#define status   t5
+
+ENTRY(__vstate_save)
+       li      status, SR_VS
+       csrs    CSR_STATUS, status
+
+       csrr    x_vstart, CSR_VSTART
+       csrr    x_vtype, CSR_VTYPE
+       csrr    x_vl, CSR_VL
+       csrr    x_vcsr, CSR_VCSR
+       vsetvli incr, x0, e8, m8, ta, ma
+       vse8.v   v0, (datap)
+       add     datap, datap, incr
+       vse8.v   v8, (datap)
+       add     datap, datap, incr
+       vse8.v   v16, (datap)
+       add     datap, datap, incr
+       vse8.v   v24, (datap)
+
+       REG_S   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+       REG_S   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+       REG_S   x_vl, RISCV_V_STATE_VL(vstatep)
+       REG_S   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+
+       csrc    CSR_STATUS, status
+       ret
+ENDPROC(__vstate_save)
+
+ENTRY(__vstate_restore)
+       li      status, SR_VS
+       csrs    CSR_STATUS, status
+
+       vsetvli incr, x0, e8, m8, ta, ma
+       vle8.v   v0, (datap)
+       add     datap, datap, incr
+       vle8.v   v8, (datap)
+       add     datap, datap, incr
+       vle8.v   v16, (datap)
+       add     datap, datap, incr
+       vle8.v   v24, (datap)
+
+       REG_L   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+       REG_L   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+       REG_L   x_vl, RISCV_V_STATE_VL(vstatep)
+       REG_L   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+       vsetvl  x0, x_vl, x_vtype
+       csrw    CSR_VSTART, x_vstart
+       csrw    CSR_VCSR, x_vcsr
+
+       csrc    CSR_STATUS, status
+       ret
+ENDPROC(__vstate_restore)
+
+ENTRY(rvv_enable)
+       li      status, SR_VS
+       csrs    CSR_STATUS, status
+       ret
+ENDPROC(rvv_enable)
+
+ENTRY(rvv_disable)
+       li      status, SR_VS
+       csrc    CSR_STATUS, status
+       ret
+ENDPROC(rvv_disable)
