diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu
index 96cdfb0aa..710773866 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu
@@ -1,10 +1,11 @@
GCOV_PROFILE := y
-ccflags-y += -Idrivers/gpu/nvgpu
+ccflags-y += -Idrivers/gpu/nvgpu/include
ccflags-y += -Idrivers/video/tegra/host
ccflags-y += -Idrivers/devfreq
ccflags-y += -I../nvgpu/include
ccflags-y += -I../nvgpu/include/uapi
+ccflags-y += -I../nvgpu/drivers/gpu/nvgpu/include
ccflags-y += -Wno-multichar
ccflags-y += -Werror
ccflags-y += -Wno-error=cpp
@@ -25,8 +26,9 @@ endif
obj-$(CONFIG_GK20A) := nvgpu.o
nvgpu-y := \
- gk20a/gk20a.o \
+ common/linux/timers.o \
nvgpu_common.o \
+ gk20a/gk20a.o \
gk20a/sched_gk20a.o \
gk20a/as_gk20a.o \
gk20a/ctrl_gk20a.o \
diff --git a/drivers/gpu/nvgpu/common/linux/timers.c b/drivers/gpu/nvgpu/common/linux/timers.c
new file mode 100644
index 000000000..e1e08f822
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/timers.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include
+
+#include "gk20a/gk20a.h"
+
+/*
+ * Returns 1 if the platform is pre-Si and should ignore the timeout checking.
+ * Setting %NVGPU_TIMER_NO_PRE_SI will make this always return 0 (i.e do the
+ * timeout check regardless of platform).
+ */
+static int nvgpu_timeout_is_pre_silicon(struct nvgpu_timeout *timeout)
+{
+ if (timeout->flags & NVGPU_TIMER_NO_PRE_SI)
+ return 0;
+
+ return !tegra_platform_is_silicon();
+}
+
+/**
+ * nvgpu_timeout_init - Init timer.
+ *
+ * @g - nvgpu device.
+ * @timeout - The timer.
+ * @duration - Timeout in milliseconds or number of retries.
+ * @flags - Flags for timer.
+ *
+ * This configures the timeout to start the timeout duration now, i.e: when this
+ * function is called. Available flags to pass to @flags:
+ *
+ * %NVGPU_TIMER_CPU_TIMER
+ * %NVGPU_TIMER_RETRY_TIMER
+ * %NVGPU_TIMER_NO_PRE_SI
+ * %NVGPU_TIMER_SILENT_TIMEOUT
+ *
+ * If neither %NVGPU_TIMER_CPU_TIMER or %NVGPU_TIMER_RETRY_TIMER is passed then
+ * a CPU timer is used by default.
+ */
+int nvgpu_timeout_init(struct gk20a *g, struct nvgpu_timeout *timeout,
+ int duration, unsigned long flags)
+{
+ if (flags & ~NVGPU_TIMER_FLAG_MASK)
+ return -EINVAL;
+
+ memset(timeout, 0, sizeof(*timeout));
+
+ timeout->g = g;
+ timeout->flags = flags;
+
+ if (flags & NVGPU_TIMER_RETRY_TIMER)
+ timeout->retries.max = duration;
+ else
+ timeout->time = jiffies + msecs_to_jiffies(duration);
+
+ return 0;
+}
+
+static int __nvgpu_timeout_check_msg_cpu(struct nvgpu_timeout *timeout,
+ void *caller,
+ const char *fmt, va_list args)
+{
+ struct gk20a *g = timeout->g;
+ unsigned long now = jiffies;
+
+ if (nvgpu_timeout_is_pre_silicon(timeout))
+ return 0;
+
+ if (time_after(now, (unsigned long)timeout->time)) {
+ if (!(timeout->flags & NVGPU_TIMER_SILENT_TIMEOUT)) {
+ char buf[128];
+
+ vsnprintf(buf, sizeof(buf), fmt, args);
+
+ dev_err(dev_from_gk20a(g),
+ "Timeout detected @ 0x%pF %s\n", caller, buf);
+ }
+
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int __nvgpu_timeout_check_msg_retry(struct nvgpu_timeout *timeout,
+ void *caller,
+ const char *fmt, va_list args)
+{
+ struct gk20a *g = timeout->g;
+
+ if (nvgpu_timeout_is_pre_silicon(timeout))
+ return 0;
+
+ if (timeout->retries.attempted >= timeout->retries.max) {
+ if (!(timeout->flags & NVGPU_TIMER_SILENT_TIMEOUT)) {
+ char buf[128];
+
+ vsnprintf(buf, sizeof(buf), fmt, args);
+
+ dev_err(dev_from_gk20a(g),
+ "No more retries @ 0x%pF %s\n", caller, buf);
+ }
+
+ return -ETIMEDOUT;
+ }
+
+ timeout->retries.attempted++;
+
+ return 0;
+}
+
+/**
+ * __nvgpu_timeout_check_msg - Check if a timeout has expired.
+ *
+ * @timeout - The timeout to check.
+ * @caller - Address of the caller of this function.
+ * @fmt - The fmt string.
+ *
+ * Returns -ETIMEDOUT if the timeout has expired, 0 otherwise.
+ *
+ * If a timeout occurs and %NVGPU_TIMER_SILENT_TIMEOUT is not set in the timeout
+ * then a message is printed based on %fmt.
+ */
+int __nvgpu_timeout_check_msg(struct nvgpu_timeout *timeout,
+ void *caller, const char *fmt, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, fmt);
+ if (timeout->flags & NVGPU_TIMER_RETRY_TIMER)
+ ret = __nvgpu_timeout_check_msg_retry(timeout, caller, fmt,
+ args);
+ else
+ ret = __nvgpu_timeout_check_msg_cpu(timeout, caller, fmt,
+ args);
+ va_end(args);
+
+ return ret;
+}
+
+/**
+ * nvgpu_timeout_peek - Check the status of a timeout.
+ *
+ * @timeout - The timeout to check.
+ *
+ * Returns non-zero if the timeout is expired, zero otherwise. In the case of
+ * retry timers this will not increment the underlying retry count. Also if the
+ * timer has expired no messages will be printed.
+ *
+ * This function honors the pre-Si check as well.
+ */
+int nvgpu_timeout_peek(struct nvgpu_timeout *timeout)
+{
+ if (nvgpu_timeout_is_pre_silicon(timeout))
+ return 0;
+
+ if (timeout->flags & NVGPU_TIMER_RETRY_TIMER)
+ return timeout->retries.attempted >= timeout->retries.max;
+ else
+ return time_after(jiffies, (unsigned long)timeout->time);
+}
diff --git a/drivers/gpu/nvgpu/include/nvgpu/timers.h b/drivers/gpu/nvgpu/include/nvgpu/timers.h
new file mode 100644
index 000000000..e46982c9c
--- /dev/null
+++ b/drivers/gpu/nvgpu/include/nvgpu/timers.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __NVGPU_TIMERS_H__
+#define __NVGPU_TIMERS_H__
+
+struct gk20a;
+
+/*
+ * struct nvgpu_timeout - define a timeout.
+ *
+ * There are two types of timer suported:
+ *
+ * o NVGPU_TIMER_CPU_TIMER
+ * Timer uses the CPU to measure the timeout.
+ *
+ * o NVGPU_TIMER_RETRY_TIMER
+ * Instead of measuring a time limit keep track of the number of times
+ * something has been attempted. After said limit, "expire" the timer.
+ *
+ * Available flags:
+ *
+ * o NVGPU_TIMER_NO_PRE_SI
+ * By default when the system is not running on silicon the timeout
+ * code will ignore the requested timeout. Specifying this flag will
+ * override that behavior and honor the timeout regardless of platform.
+ *
+ * o NVGPU_TIMER_SILENT_TIMEOUT
+ * Do not print any messages on timeout. Normally a simple message is
+ * printed that specifies where the timeout occurred.
+ */
+struct nvgpu_timeout {
+ struct gk20a *g;
+
+ unsigned int flags;
+
+ union {
+ unsigned long time;
+ struct {
+ int max;
+ int attempted;
+ } retries;
+ };
+};
+
+/*
+ * Bit 0 specifies the type of timer: CPU or retry.
+ */
+#define NVGPU_TIMER_CPU_TIMER (0x0)
+#define NVGPU_TIMER_RETRY_TIMER (0x1)
+
+/*
+ * Bits 1 through 7 are reserved; bits 8 and up are flags:
+ */
+#define NVGPU_TIMER_NO_PRE_SI (0x1 << 8)
+#define NVGPU_TIMER_SILENT_TIMEOUT (0x1 << 9)
+
+#define NVGPU_TIMER_FLAG_MASK (NVGPU_TIMER_RETRY_TIMER | \
+ NVGPU_TIMER_NO_PRE_SI | \
+ NVGPU_TIMER_SILENT_TIMEOUT)
+
+int nvgpu_timeout_init(struct gk20a *g, struct nvgpu_timeout *timeout,
+ int duration, unsigned long flags);
+int nvgpu_timeout_peek(struct nvgpu_timeout *timeout);
+
+#define nvgpu_timeout_check(__timeout) \
+ __nvgpu_timeout_check_msg(__timeout, \
+ __builtin_return_address(0), "")
+
+#define nvgpu_timeout_check_msg(__timeout, fmt, args...) \
+ __nvgpu_timeout_check_msg(__timeout, \
+ __builtin_return_address(0), \
+ fmt, ##args)
+
+/*
+ * Don't use this directly.
+ */
+int __nvgpu_timeout_check_msg(struct nvgpu_timeout *timeout,
+ void *caller, const char *fmt, ...);
+
+#endif