diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index e3931e515906..074afd05aaa8 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -43,6 +43,8 @@
 #include <linux/atomic.h>
 #include <linux/dma-resv.h>
 
+#include "ttm_trace.h"
+
 static void ttm_bo_global_kobj_release(struct kobject *kobj);
 
 /**
@@ -143,6 +145,8 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo,
 	if (mem->placement & TTM_PL_FLAG_NO_EVICT)
 		return;
 
+	trace_ttm_bo_add_mem_to_lru(bo, mem);
+
 	man = ttm_manager_type(bdev, mem->mem_type);
 	list_add_tail(&bo->lru, &man->lru[bo->priority]);
 
@@ -167,6 +171,8 @@ static void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
 		notify = true;
 	}
 
+	trace_ttm_bo_del_from_lru(bo, notify);
+
 	if (notify && bdev->driver->del_from_lru_notify)
 		bdev->driver->del_from_lru_notify(bo);
 }
@@ -299,6 +305,8 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 		}
 	}
 
+	trace_ttm_bo_move_mem(bo, mem, evict);
+
 	if (bdev->driver->move_notify)
 		bdev->driver->move_notify(bo, evict, mem);
 
@@ -542,6 +550,8 @@ static void ttm_bo_release(struct kref *kref)
 	size_t acc_size = bo->acc_size;
 	int ret;
 
+	trace_ttm_bo_release(bo);
+
 	if (!bo->deleted) {
 		ret = ttm_bo_individualize_resv(bo);
 		if (ret) {
@@ -668,6 +678,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
 		ttm_resource_free(bo, &evict_mem);
 		goto out;
 	}
+
+	trace_ttm_bo_evict(bo, &evict_mem);
 	bo->evicted = true;
 out:
 	return ret;
@@ -1151,6 +1163,8 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
 
 	dma_resv_assert_held(bo->base.resv);
 
+	trace_ttm_bo_validate(bo);
+
 	/*
 	 * Remove the backing store if no placement is given.
 	 */
@@ -1263,6 +1277,8 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev,
 	}
 	atomic_inc(&ttm_bo_glob.bo_count);
 
+	trace_ttm_bo_init_reserved(bo, size);
+
 	/*
 	 * For ttm_bo_type_device buffers, allocate
 	 * address space from the device.
@@ -1487,6 +1503,8 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
 	if (!ret)
 		ttm_bo_global_release();
 
+	trace_ttm_bo_device_release(bdev);
+
 	return ret;
 }
 EXPORT_SYMBOL(ttm_bo_device_release);
@@ -1537,6 +1555,8 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
 	list_add_tail(&bdev->device_list, &glob->device_list);
 	mutex_unlock(&ttm_global_mutex);
 
+	trace_ttm_bo_device_init(bdev);
+
 	return 0;
 }
 EXPORT_SYMBOL(ttm_bo_device_init);
@@ -1580,6 +1600,8 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
 
 	timeout = dma_resv_wait_timeout_rcu(bo->base.resv, true,
 						      interruptible, timeout);
+
+	trace_ttm_bo_wait(bo, interruptible, timeout);
 	if (timeout < 0)
 		return timeout;
 
@@ -1670,6 +1692,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx)
 	 * anyone tries to access a ttm page.
 	 */
 
+	trace_ttm_bo_swapout(bo, i);
 	if (bo->bdev->driver->swap_notify)
 		bo->bdev->driver->swap_notify(bo);
 
diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c
index 6ff40c041d79..8b70e8aebecb 100644
--- a/drivers/gpu/drm/ttm/ttm_module.c
+++ b/drivers/gpu/drm/ttm/ttm_module.c
@@ -35,6 +35,9 @@
 #include <drm/ttm/ttm_module.h>
 #include <drm/drm_sysfs.h>
 
+#define CREATE_TRACE_POINTS
+#include "ttm_trace.h"
+
 static DECLARE_WAIT_QUEUE_HEAD(exit_q);
 static atomic_t device_released;
 
diff --git a/drivers/gpu/drm/ttm/ttm_trace.h b/drivers/gpu/drm/ttm/ttm_trace.h
new file mode 100644
index 000000000000..7c5e55725e8e
--- /dev/null
+++ b/drivers/gpu/drm/ttm/ttm_trace.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Kevin Wang
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ttm
+
+#if !defined(_TRACE_TTM_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TTM_H_
+
+#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_module.h>
+#include <drm/ttm/ttm_page_alloc.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#define TTM_PLACEMENT_FLAGS_TRACE \
+	{ TTM_PL_FLAG_SYSTEM,		"SYSTEM"	},\
+	{ TTM_PL_FLAG_TT,		"TT"		},\
+	{ TTM_PL_FLAG_VRAM,		"VRAM"		},\
+	{ TTM_PL_FLAG_PRIV,		"PRIV"		},\
+	{ TTM_PL_FLAG_CACHED,		"CACHED"	},\
+	{ TTM_PL_FLAG_UNCACHED,		"UNCACHED"	},\
+	{ TTM_PL_FLAG_WC,		"WC"		},\
+	{ TTM_PL_FLAG_CONTIGUOUS,	"CONTIGUOUS"	},\
+	{ TTM_PL_FLAG_NO_EVICT,		"NO_EVICT"	},\
+	{ TTM_PL_FLAG_TOPDOWN,		"TOPDOWN"	}
+
+#define __show_ttm_pl_flags(flags, mask)		\
+	(flags & mask) ? __print_flags(flags, "|",	\
+	TTM_PLACEMENT_FLAGS_TRACE			\
+	) : "none"
+
+#define show_ttm_pl_flags(flags)		\
+	__show_ttm_pl_flags(flags, ~0UL)
+
+#define show_ttm_pl_mem_flags(flags)		\
+	__show_ttm_pl_flags(flags, TTM_PL_MASK_MEM)
+
+
+TRACE_EVENT(ttm_bo_add_mem_to_lru,
+	    TP_PROTO(struct ttm_buffer_object *bo, struct ttm_resource *res),
+	    TP_ARGS(bo, res),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(unsigned long, size)
+			     __field(uint32_t, placement)
+			     __field(enum ttm_bo_type, bo_type)
+			     __field(uint32_t, mem_type)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->bo_type = bo->type;
+			   __entry->size = bo->mem.size;
+			   __entry->placement = res->placement;
+			   __entry->mem_type = res->mem_type;
+			   ),
+
+	    TP_printk("bo:%p, size=%lx, bo_type=%d, mtype=%d, placement=%s(%x)",
+		      __entry->bo, __entry->size, __entry->bo_type, __entry->mem_type,
+		      show_ttm_pl_flags(__entry->placement), __entry->placement)
+);
+
+TRACE_EVENT(ttm_bo_del_from_lru,
+	    TP_PROTO(struct ttm_buffer_object *bo, bool notify),
+	    TP_ARGS(bo, notify),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(unsigned long, size)
+			     __field(uint32_t, placement)
+			     __field(enum ttm_bo_type, bo_type)
+			     __field(uint32_t, mem_type)
+			     __field(bool, notify)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->bo_type = bo->type;
+			   __entry->size = bo->mem.size;
+			   __entry->placement = bo->mem.placement;
+			   __entry->mem_type = bo->mem.mem_type;
+			   __entry->notify = notify;
+			   ),
+
+	    TP_printk("bo:%p, size=%lx, bo_type=%d, mtype=%d, placement=%s(%x), notify=%s",
+		      __entry->bo, __entry->size, __entry->bo_type, __entry->mem_type,
+		      show_ttm_pl_flags(__entry->placement), __entry->placement,
+		      __entry->notify ? "true" : "false")
+);
+
+TRACE_EVENT(ttm_bo_move_mem,
+	    TP_PROTO(struct ttm_buffer_object *bo, struct ttm_resource *res, bool evict),
+	    TP_ARGS(bo, res, evict),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(unsigned long, start)
+			     __field(unsigned long, size)
+			     __field(uint32_t, old_placement)
+			     __field(uint32_t, new_placement)
+			     __field(uint32_t, old_mem_type)
+			     __field(uint32_t, new_mem_type)
+			     __field(bool, evict)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->start = res->start;
+			   __entry->size = res->size;
+			   __entry->old_placement = bo->mem.placement;
+			   __entry->new_placement = res->placement;
+			   __entry->old_mem_type = bo->mem.mem_type;
+			   __entry->new_mem_type = res->mem_type;
+			   __entry->evict = evict;
+			   ),
+
+	    TP_printk("bo:%p, start=%lx, size=%lx, mtype: %d -> %d, placement: %s(%x) -> %s(%x), evict=%s",
+		      __entry->bo, __entry->start, __entry->size,
+		      __entry->old_mem_type, __entry->new_mem_type,
+		      show_ttm_pl_flags(__entry->old_placement), __entry->old_placement,
+		      show_ttm_pl_flags(__entry->new_placement), __entry->new_placement,
+		      __entry->evict ? "true" : "false")
+);
+
+TRACE_EVENT(ttm_bo_wait,
+	    TP_PROTO(struct ttm_buffer_object *bo, bool interruptible, long timeout),
+	    TP_ARGS(bo, interruptible, timeout),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(bool, interruptible)
+			     __field(long, timeout)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->interruptible = interruptible;
+			   __entry->timeout = timeout;
+			   ),
+
+	    TP_printk("bo:%p, interruptible=%s, timeout=%ld", __entry->bo,
+		      __entry->interruptible ? "true" : "false", __entry->timeout)
+);
+
+TRACE_EVENT(ttm_bo_evict,
+	    TP_PROTO(struct ttm_buffer_object *bo, struct ttm_resource *res),
+	    TP_ARGS(bo, res),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(enum ttm_bo_type, bo_type)
+			     __field(unsigned long, size)
+			     __field(uint32_t, old_placement)
+			     __field(uint32_t, new_placement)
+			     __field(uint32_t, old_mem_type)
+			     __field(uint32_t, new_mem_type)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->bo_type = bo->type;
+			   __entry->size = res->size;
+			   __entry->old_placement = bo->mem.placement;
+			   __entry->new_placement = res->placement;
+			   __entry->old_mem_type = bo->mem.mem_type;
+			   __entry->new_mem_type = res->mem_type;
+			   ),
+
+	    TP_printk("bo:%p, size=%lx, bo_type=%d, mtype: %d -> %d, placement: %s(%x) -> %s(%x)",
+		      __entry->bo, __entry->size, __entry->bo_type,
+		      __entry->old_mem_type, __entry->new_mem_type,
+		      show_ttm_pl_flags(__entry->old_placement), __entry->old_placement,
+		      show_ttm_pl_flags(__entry->new_placement), __entry->new_placement)
+
+);
+
+TRACE_EVENT(ttm_bo_swapout,
+	    TP_PROTO(struct ttm_buffer_object *bo, int priority),
+	    TP_ARGS(bo, priority),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(enum ttm_bo_type, bo_type)
+			     __field(unsigned long, size)
+			     __field(uint32_t, placement)
+			     __field(uint32_t, mem_type)
+			     __field(int, priority)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->priority = priority;
+			   __entry->bo_type = bo->type;
+			   __entry->size = bo->mem.size;
+			   __entry->placement = bo->mem.placement;
+			   __entry->mem_type = bo->mem.mem_type;
+			   ),
+
+	    TP_printk("bo:%p, size=%lx, bo_type=%d, mtype=%d, placement=%s(%x), prio=%d",
+		      __entry->bo, __entry->size, __entry->bo_type, __entry->mem_type,
+		      show_ttm_pl_flags(__entry->placement), __entry->placement,
+		      __entry->priority)
+);
+
+TRACE_EVENT(ttm_bo_device_init,
+	    TP_PROTO(struct ttm_bo_device *bdev),
+	    TP_ARGS(bdev),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_bo_device *, bdev)
+			     __field(struct ttm_bo_driver *, driver)
+			     __field(bool, need_dma32)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bdev = bdev;
+			   __entry->driver = bdev->driver;
+			   __entry->need_dma32 = bdev->need_dma32;
+			   ),
+
+	    TP_printk("bdev:%p, driver=%p, need_dma32=%s", __entry->bdev, __entry->driver,
+		      __entry->need_dma32 ? "true" : "false")
+);
+
+TRACE_EVENT(ttm_bo_device_release,
+	    TP_PROTO(struct ttm_bo_device *bdev),
+	    TP_ARGS(bdev),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_bo_device *, bdev)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bdev = bdev;
+			   ),
+
+	    TP_printk("bdev:%p", __entry->bdev)
+);
+
+TRACE_EVENT(ttm_bo_init_reserved,
+	    TP_PROTO(struct ttm_buffer_object *bo, unsigned long size),
+	    TP_ARGS(bo, size),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_bo_device *, bdev)
+			     __field(struct ttm_buffer_object *, bo)
+			     __field(enum ttm_bo_type, bo_type)
+			     __field(uint32_t, page_alignment)
+			     __field(uint32_t, placement)
+			     __field(unsigned long, size)
+			     __field(size_t, acc_size)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   __entry->bdev = bo->bdev;
+			   __entry->bo_type = bo->type;
+			   __entry->placement = bo->mem.placement;
+			   __entry->page_alignment = bo->mem.page_alignment;
+			   __entry->size = size;
+			   __entry->acc_size = bo->acc_size;
+			   ),
+
+	    TP_printk("bo:%p, bdev=%p, bo_type=%d, %s(%x) size=%lx, accsize=%lx, alignment=%d",
+		      __entry->bo, __entry->bdev, __entry->bo_type,
+		      show_ttm_pl_flags(__entry->placement), __entry->placement,
+		      __entry->size, __entry->acc_size, __entry->page_alignment)
+);
+
+TRACE_EVENT(ttm_bo_validate,
+	    TP_PROTO(struct ttm_buffer_object *bo),
+	    TP_ARGS(bo),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   ),
+
+	    TP_printk("bo:%p", __entry->bo)
+);
+
+TRACE_EVENT(ttm_bo_release,
+	    TP_PROTO(struct ttm_buffer_object *bo),
+	    TP_ARGS(bo),
+	    TP_STRUCT__entry(
+			     __field(struct ttm_buffer_object *, bo)
+			     ),
+
+	    TP_fast_assign(
+			   __entry->bo = bo;
+			   ),
+
+	    TP_printk("bo:%p", __entry->bo)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/ttm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE ttm_trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
