diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index a045f3086047..4de066fb530a 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -528,6 +528,18 @@ config ARC_DBG_TLB_PARANOIA
 	bool "Paranoia Checks in Low Level TLB Handlers"
 	default n
 
+config ARC_SMART_TRACE
+	bool "Enable SmaRT real time trace on-chip debug HW"
+	depends on ISA_ARCV2
+	help
+	  Enable SmaRT (small real time trace) on-chip debug hardware component
+	  that captures instruction-trace history if exists. This trace will be
+	  printed if any unexpected exception is occurred.
+	  In runtime the SmaRT can be disabled/enabled and the number of SmaRT
+	  buffer lines to record/display can be configured via
+	  '/proc/sys/arc_smart_trace/entries' procfs option. By default SmaRT
+	  is enabled and configured to use all available buffer entries.
+
 endif
 
 config ARC_UBOOT_SUPPORT
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index 49bfbd879caa..cd8228d82872 100644
--- a/arch/arc/include/asm/arcregs.h
+++ b/arch/arc/include/asm/arcregs.h
@@ -118,6 +118,20 @@
 #define ARC_AUX_DPFP_2H         0x304
 #define ARC_AUX_DPFP_STAT       0x305
 
+/* SmaRT registers */
+#define ARC_AUX_SMART_CONTROL	0x700
+#define SMART_CTL_EN		BIT(0)
+#define SMART_CTL_DATA_POS	8
+#define SMART_CTL_DATA_SRC	(0 << SMART_CTL_DATA_POS)
+#define SMART_CTL_DATA_DST	(1 << SMART_CTL_DATA_POS)
+#define SMART_CTL_DATA_FLAG	(2 << SMART_CTL_DATA_POS)
+#define SMART_CTL_IDX_POS	10
+#define ARC_AUX_SMART_DATA	0x701
+#define SMART_FLAG_U		BIT(8)
+#define SMART_FLAG_E		BIT(9)
+#define SMART_FLAG_R		BIT(10)
+#define SMART_FLAG_V		BIT(31)
+
 #ifndef __ASSEMBLY__
 
 #include <soc/arc/aux.h>
@@ -199,6 +213,15 @@ struct bcr_dccm_arcv2 {
 #endif
 };
 
+/* SmaRT BCR encoding starting from version 0x03 */
+struct bcr_smart_v3p {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+	unsigned int stack_size:22, pad:2, ver:8;
+#else
+	unsigned int ver:8, pad:2, stack_size:22;
+#endif
+};
+
 /* ARCompact: Both SP and DP FPU BCRs have same format */
 struct bcr_fp_arcompact {
 #ifdef CONFIG_CPU_BIG_ENDIAN
diff --git a/arch/arc/include/asm/smart.h b/arch/arc/include/asm/smart.h
new file mode 100644
index 000000000000..ceb14c58285a
--- /dev/null
+++ b/arch/arc/include/asm/smart.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Copyright (C) 2018 Synopsys
+ * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+ */
+
+#ifndef __ASM_SMART_H
+#define __ASM_SMART_H
+
+#include <asm/arcregs.h>
+
+/*
+ * SmaRT versions < 0x03 have different registers encoding and small
+ * buffer size. We don't support them.
+ */
+#define SMART_VERSION_SUPPORTED_P	0x03
+
+#ifdef CONFIG_ARC_SMART_TRACE
+void smart_populate(void);
+void smart_show(void);
+void smart_init(void);
+
+#define SMART_POPULATE()	smart_populate()
+
+#else
+#define SMART_POPULATE()
+static inline void smart_show(void) {}
+static inline void smart_init(void) {}
+
+#endif /* CONFIG_ARC_SMART_TRACE */
+
+/* smart_exist - do we have at least some version of SmaRT? */
+static inline bool smart_exist(void)
+{
+	struct bcr_smart_v3p bcr;
+
+	READ_BCR(ARC_REG_SMART_BCR, bcr);
+	return !!bcr.ver;
+}
+
+/* smart_supported - do we have an version of SmaRT which we can use? */
+static inline bool smart_supported(void)
+{
+	struct bcr_smart_v3p bcr;
+
+	READ_BCR(ARC_REG_SMART_BCR, bcr);
+	return bcr.ver >= SMART_VERSION_SUPPORTED_P;
+}
+
+static inline u32 smart_stack_size(void)
+{
+	struct bcr_smart_v3p bcr;
+
+	READ_BCR(ARC_REG_SMART_BCR, bcr);
+	if (bcr.ver >= SMART_VERSION_SUPPORTED_P)
+		return bcr.stack_size;
+	else
+		return 0;
+}
+
+#endif /* __ASM_SMART_H */
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index 2dc5f4296d44..4e58a5f90c78 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_ARC_EMUL_UNALIGNED) 	+= unaligned.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_ARC_METAWARE_HLINK)	+= arc_hostlink.o
 obj-$(CONFIG_PERF_EVENTS)		+= perf_event.o
+obj-$(CONFIG_ARC_SMART_TRACE)		+= smart.o
 
 obj-$(CONFIG_ARC_FPU_SAVE_RESTORE)	+= fpu.o
 CFLAGS_fpu.o   += -mdpfp
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index b2cae79a25d7..c5641e6ffc2a 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -28,6 +28,7 @@
 #include <asm/unwind.h>
 #include <asm/mach_desc.h>
 #include <asm/smp.h>
+#include <asm/smart.h>
 
 #define FIX_PTR(x)  __asm__ __volatile__(";" : "+r"(x))
 
@@ -447,6 +448,9 @@ void setup_processor(void)
 	pr_info("%s", arc_platform_smp_cpuinfo());
 
 	arc_chk_core_config();
+
+	if (IS_ENABLED(CONFIG_ARC_SMART_TRACE))
+		smart_init();
 }
 
 static inline int is_kernel(unsigned long addr)
diff --git a/arch/arc/kernel/smart.c b/arch/arc/kernel/smart.c
new file mode 100644
index 000000000000..70675ceb59d3
--- /dev/null
+++ b/arch/arc/kernel/smart.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Synopsys SmaRT (Small Real time Trace) handling code
+//
+// Copyright (C) 2018 Synopsys
+// Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/sysctl.h>
+#include <linux/percpu.h>
+#include <linux/percpu-defs.h>
+
+#include <asm/arcregs.h>
+#include <asm/smart.h>
+#include <asm/bug.h>
+
+#define SMART_BUFF_MAX	4096	/* HW limit */
+
+struct smart_buff {
+	u32 entries_collected;
+	u32 src[SMART_BUFF_MAX];
+	u32 dst[SMART_BUFF_MAX];
+	u32 flags[SMART_BUFF_MAX];
+};
+
+DEFINE_PER_CPU(struct smart_buff, smart_buff_log);
+
+struct smart_fvma_info {
+	bool vma_found;
+	struct faulting_vma_info fvma;
+};
+
+/* 0 value of 'smart_entries_use' will be treated as 'disable' */
+static unsigned int smart_entries_use = SMART_BUFF_MAX;
+
+/* limits for smart_trace/entries */
+static unsigned int smart_entries_min;
+static unsigned int smart_entries_max = SMART_BUFF_MAX;
+
+static struct ctl_table ctl_smart_vars[] = {
+	{
+		.procname	= "entries",
+		.data		= &smart_entries_use,
+		.maxlen		= sizeof(smart_entries_use),
+		.mode		= 0644,
+		.proc_handler	= proc_douintvec_minmax,
+		.extra1		= &smart_entries_min,
+		.extra2		= &smart_entries_max,
+	}, {}
+};
+
+static struct ctl_table ctl_smart[] = {
+	{
+		.procname	= "arc_smart_trace",
+		.mode		= 0555,
+		.child		= ctl_smart_vars,
+	}, {}
+};
+
+static inline void smart_enable(void)
+{
+	write_aux_reg(ARC_AUX_SMART_CONTROL, SMART_CTL_EN);
+}
+
+static inline void smart_disable(void)
+{
+	write_aux_reg(ARC_AUX_SMART_CONTROL, 0);
+}
+
+static bool smart_fvma_changed(struct smart_fvma_info *curr,
+			       struct smart_fvma_info *prev)
+{
+	if (!prev->vma_found)
+		return true;
+
+	return prev->fvma.vm_start != curr->fvma.vm_start ||
+	       prev->fvma.vm_end   != curr->fvma.vm_end;
+}
+
+static void smart_show_fault_vma(unsigned long address, char *buf, int buflen,
+				 struct smart_fvma_info *curr,
+				 struct smart_fvma_info *prev)
+{
+	int ret;
+
+	ret = get_faulting_vma_info(address, buf, buflen, &curr->fvma);
+	curr->vma_found = !ret;
+	if (ret) {
+		pr_cont(": No matching VMA found\n");
+		return;
+	}
+
+	if (smart_fvma_changed(curr, prev))
+		pr_cont(": off 0x%lx in %s (VMA: %08lx:%08lx)\n",
+			curr->fvma.offset, curr->fvma.file_path,
+			curr->fvma.vm_start, curr->fvma.vm_end);
+	else
+		pr_cont(": off 0x%lx in %s\n",
+			curr->fvma.offset, curr->fvma.file_path);
+}
+
+/* Show decoded userspace/kernelspace address */
+static void smart_show_address(u32 address, char *buf, int buflen,
+			       struct smart_fvma_info *curr,
+			       struct smart_fvma_info *prev)
+{
+	curr->vma_found = false;
+
+	if (address < 0x80000000)
+		smart_show_fault_vma(address, buf, buflen, curr, prev);
+	else
+		pr_cont(": %pS\n", (void *)address);
+}
+
+static void smart_show_dst(int i, u32 flags, u32 dst, char *buf, int buflen,
+			   struct smart_fvma_info *curr,
+			   struct smart_fvma_info *prev)
+{
+	pr_info(" dst[%4d]: %s%s%s%s %#010x", i,
+		flags & SMART_FLAG_U ? "U" : "_",
+		flags & SMART_FLAG_E ? "E" : "_",
+		flags & SMART_FLAG_R ? "R" : "_",
+		flags & SMART_FLAG_V ? "V" : "_",
+		dst);
+
+	smart_show_address(dst, buf, buflen, curr, prev);
+}
+
+static void smart_show_src(int i, u32 src, char *buf, int buflen,
+			   struct smart_fvma_info *curr,
+			   struct smart_fvma_info *prev)
+{
+	pr_info(" src[%4d]:      %#010x", i, src);
+
+	smart_show_address(src, buf, buflen, curr, prev);
+}
+
+static void smart_show_entries(struct smart_buff *smart_buff, u32 stack_use,
+			       char *buf, int buflen)
+{
+	struct smart_fvma_info fvma_0, fvma_1;
+	int i;
+
+	/*
+	 * fvma_1 will be treat as 'previous' vma while we process first entry.
+	 * We had to errase is to show first VMAs unconditionally.
+	 */
+	fvma_1.vma_found = false;
+
+	for (i = 0; i < stack_use; i++) {
+		smart_show_dst(i, smart_buff->flags[i], smart_buff->dst[i],
+			       buf, buflen, &fvma_0, &fvma_1);
+
+		smart_show_src(i, smart_buff->src[i], buf, buflen,
+			       &fvma_1, &fvma_0);
+	}
+}
+
+/* Should be called per cpu */
+void __init smart_init(void)
+{
+	struct smart_buff *smart_buff_cpu;
+
+	/*
+	 * We don't check 'smart_entries_use' value here as sysctl is not
+	 * available yet, so smart_entries_use' value is unchanged.
+	 */
+	if (!smart_supported())
+		return;
+
+	smart_buff_cpu = this_cpu_ptr(&smart_buff_log);
+	smart_buff_cpu->entries_collected = 0;
+
+	smart_enable();
+}
+
+void smart_show(void)
+{
+	struct smart_buff *smart_buff_cpu;
+	u32 stack_size, stack_use;
+	char *buf;
+
+	if (!smart_supported() || !smart_entries_use)
+		return;
+
+	smart_buff_cpu = this_cpu_ptr(&smart_buff_log);
+
+	stack_size = smart_stack_size();
+	stack_use = min_t(u32, stack_size, smart_buff_cpu->entries_collected);
+	pr_info("SmaRT [%d entries] (U=userspace, E=exception/interrupt, R=repeated, V=valid):\n",
+		stack_use);
+
+	buf = (char *)__get_free_page(GFP_NOWAIT);
+	if (!buf)
+		return;
+
+	smart_show_entries(smart_buff_cpu, stack_use, buf, PAGE_SIZE - 1);
+
+	free_page((unsigned long)buf);
+}
+
+#define SMART_CTL_IDX(i)	((i) << SMART_CTL_IDX_POS)
+#define SMART_CTL_GET_SRC(i)	(SMART_CTL_IDX(i) | SMART_CTL_DATA_SRC)
+#define SMART_CTL_GET_DST(i)	(SMART_CTL_IDX(i) | SMART_CTL_DATA_DST)
+#define SMART_CTL_GET_FLG(i)	(SMART_CTL_IDX(i) | SMART_CTL_DATA_FLAG)
+
+void smart_populate(void)
+{
+	struct smart_buff *smart_buff_cpu;
+	u32 stack_size, stack_use;
+	int i;
+
+	if (!smart_supported() || !smart_entries_use) {
+		smart_buff_cpu = this_cpu_ptr(&smart_buff_log);
+		smart_buff_cpu->entries_collected = 0;
+
+		return;
+	}
+
+	/*
+	 * The ARC_AUX_SMART_DATA register may be read safely only when the
+	 * processor is in the state in which SmaRT is not collecting data.
+	 */
+	smart_disable();
+
+	smart_buff_cpu = this_cpu_ptr(&smart_buff_log);
+
+	stack_size = smart_stack_size();
+	stack_use = min_t(u32, stack_size, smart_entries_use);
+	smart_buff_cpu->entries_collected = stack_use;
+
+	for (i = 0; i < stack_use; i++) {
+		write_aux_reg(ARC_AUX_SMART_CONTROL, SMART_CTL_GET_SRC(i));
+		smart_buff_cpu->src[i] = read_aux_reg(ARC_AUX_SMART_DATA);
+		write_aux_reg(ARC_AUX_SMART_CONTROL, SMART_CTL_GET_DST(i));
+		smart_buff_cpu->dst[i] = read_aux_reg(ARC_AUX_SMART_DATA);
+		write_aux_reg(ARC_AUX_SMART_CONTROL, SMART_CTL_GET_FLG(i));
+		smart_buff_cpu->flags[i] = read_aux_reg(ARC_AUX_SMART_DATA);
+	}
+
+	smart_enable();
+}
+
+static int __init smart_register_sysctl(void)
+{
+	if (!register_sysctl_table(ctl_smart))
+		pr_err("Unable to register SmaRT sysctl\n");
+
+	return 0;
+}
+
+arch_initcall(smart_register_sysctl);
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index e66fd40296b3..cdeae95c7af9 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -22,6 +22,7 @@
 #include <asm/setup.h>
 #include <asm/unaligned.h>
 #include <asm/kprobes.h>
+#include <asm/smart.h>
 
 void __init trap_init(void)
 {
@@ -70,6 +71,7 @@ int name(unsigned long address, struct pt_regs *regs) \
 {						\
 	siginfo_t info;				\
 						\
+	SMART_POPULATE();			\
 	clear_siginfo(&info);			\
 	info.si_signo = signr;			\
 	info.si_errno = 0;			\
@@ -96,6 +98,8 @@ DO_ERROR_INFO(SIGSEGV, "gcc generated __builtin_trap", do_trap5_error, 0)
 int do_misaligned_access(unsigned long address, struct pt_regs *regs,
 			 struct callee_regs *cregs)
 {
+	SMART_POPULATE();
+
 	/* If emulation not enabled, or failed, kill the task */
 	if (misaligned_fixup(address, regs, cregs) != 0)
 		return do_misaligned_error(address, regs);
@@ -128,6 +132,8 @@ void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
 {
 	unsigned int param = regs->ecr_param;
 
+	SMART_POPULATE();
+
 	switch (param) {
 	case 1:
 		trap_is_brkpt(address, regs);
@@ -159,6 +165,8 @@ void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
 {
 	int rc;
 
+	SMART_POPULATE();
+
 	/* Check if this exception is caused by kprobes */
 	rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
 	if (rc == NOTIFY_STOP)
diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 00efcdfde0ee..1410fdfcdfef 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -17,6 +17,7 @@
 
 #include <asm/arcregs.h>
 #include <asm/irqflags.h>
+#include <asm/smart.h>
 
 /*
  * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25)
@@ -218,6 +219,8 @@ void show_exception_mesg(struct pt_regs *regs)
 		show_exception_mesg_u(regs);
 	else
 		show_exception_mesg_k(regs);
+
+	smart_show();
 }
 
 void show_regs(struct pt_regs *regs)
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index 026d662a7668..17bb1be7037d 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -18,6 +18,7 @@
 #include <linux/mm_types.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
+#include <asm/smart.h>
 
 /*
  * kernel virtual address is required to implement vmalloc/pkmap/fixmap
@@ -72,6 +73,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
 	int write = regs->ecr_cause & ECR_C_PROTV_STORE;  /* ST/EX */
 	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
+	SMART_POPULATE();
 	clear_siginfo(&info);
 
 	/*
