diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
index 8096d30c5e39..943d37d66c10 100644
--- a/arch/arm64/include/asm/module.h
+++ b/arch/arm64/include/asm/module.h
@@ -20,6 +20,11 @@ struct mod_arch_specific {
 
 	/* for CONFIG_DYNAMIC_FTRACE */
 	struct plt_entry	*ftrace_trampolines;
+
+#if defined(CONFIG_DYNAMIC_FTRACE) && !defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS)
+	struct plt_entry	*mcount_plt_init;
+	struct plt_entry	*mcount_plt;
+#endif
 };
 #endif
 
@@ -58,5 +63,7 @@ static inline bool is_forbidden_offset_for_adrp(void *place)
 }
 
 struct plt_entry get_plt_entry(u64 dst, void *pc);
+struct plt_entry *find_plt_entry(struct module *mod, const Elf_Shdr *sechdrs,
+				 u64 dest, bool init_sec);
 
 #endif /* __ASM_MODULE_H */
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index ea5dc7c90f46..a61f41fa8e73 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -77,6 +77,17 @@ static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
 	return NULL;
 }
 
+static struct plt_entry *get_mcount_plt(struct module *mod, unsigned long addr,
+					unsigned long loc)
+{
+#if defined(CONFIG_ARM64_MODULE_PLTS) && !defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS)
+	if (addr == MCOUNT_ADDR)
+		return !within_module_init(loc, mod) ? mod->arch.mcount_plt :
+						       mod->arch.mcount_plt_init;
+#endif
+	return NULL;
+}
+
 /*
  * Find the address the callsite must branch to in order to reach '*addr'.
  *
@@ -127,7 +138,22 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
 	if (WARN_ON(!mod))
 		return false;
 
+
 	plt = get_ftrace_plt(mod, *addr);
+	if (plt) {
+		*addr = (unsigned long)plt;
+		return true;
+	}
+
+	/*
+	 * For the mcount-based implementation, we might call from
+	 * ftrace_init_nop(), and '*addr' should be MCOUNT_ADDR. We have saved
+	 * the mcount PLT entry address, see module_set_mcount_plt(). So here
+	 * we can still find the appropriate PLT based on whether the 'pc' is
+	 * in the init section or core section to make the 'old' instructions
+	 * that need to be replaced.
+	 */
+	plt = get_mcount_plt(mod, *addr, pc);
 	if (!plt) {
 		pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
 		return false;
@@ -209,7 +235,8 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
 #endif
 
 /*
- * Turn off the call to ftrace_caller() in instrumented function
+ * Turn off the call to ftrace_caller() in instrumented function, or initialize
+ * the _mcount call to nop.
  */
 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 		    unsigned long addr)
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c
index 5a0a8f552a61..5e553a1bf2a8 100644
--- a/arch/arm64/kernel/module-plts.c
+++ b/arch/arm64/kernel/module-plts.c
@@ -70,6 +70,22 @@ static bool in_init(const struct module *mod, void *loc)
 	return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size;
 }
 
+struct plt_entry *find_plt_entry(struct module *mod, const Elf_Shdr *sechdrs,
+				 u64 dest, bool init_sec)
+{
+	struct mod_plt_sec *pltsec = !init_sec ? &mod->arch.core :
+						 &mod->arch.init;
+	struct plt_entry *plts = (struct plt_entry *)sechdrs[pltsec->plt_shndx].sh_addr;
+	struct plt_entry plt = get_plt_entry(dest, &plt);
+	int i;
+
+	for (i = 0; i < pltsec->plt_num_entries; i++)
+		if (plt_entries_equal(&plt, &plts[i]))
+			return &plts[i];
+
+	return 0;
+}
+
 u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs,
 			  void *loc, const Elf64_Rela *rela,
 			  Elf64_Sym *sym)
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index f2d4bb14bfab..9ed0909e2729 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -520,6 +520,15 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
 	return 0;
 }
 
+static void module_set_mcount_plt(const Elf_Shdr *sechdrs, struct module *mod)
+{
+#if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE) && \
+	!defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS)
+	mod->arch.mcount_plt_init = find_plt_entry(mod, sechdrs, MCOUNT_ADDR, true);
+	mod->arch.mcount_plt = find_plt_entry(mod, sechdrs, MCOUNT_ADDR, false);
+#endif
+}
+
 int module_finalize(const Elf_Ehdr *hdr,
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
@@ -529,5 +538,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 	if (s)
 		apply_alternatives_module((void *)s->sh_addr, s->sh_size);
 
+	module_set_mcount_plt(sechdrs, me);
+
 	return module_init_ftrace_plt(hdr, sechdrs, me);
 }
