From d8fd0e64678997b535c3208ce8cc081b1cac7fa9 Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Fri, 11 Nov 2016 14:35:54 -0800 Subject: gpu: nvgpu: Add timeout API Add a timeout API to nvgpu since this is a common operation done all across the nvgpu driver. Also add two new directories for this common code: drivers/gpu/nvgpu/common drivers/gpu/nvgpu/include/nvgpu The common directory is for common C code. The include directory is for common include files. Bug 1799159 Change-Id: I8b710eecaa75c0707df83f859fb28484525185a6 Signed-off-by: Alex Waterman Reviewed-on: http://git-master/r/1255864 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom --- drivers/gpu/nvgpu/Makefile.nvgpu | 6 +- drivers/gpu/nvgpu/common/linux/timers.c | 177 +++++++++++++++++++++++++++++++ drivers/gpu/nvgpu/include/nvgpu/timers.h | 94 ++++++++++++++++ 3 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/linux/timers.c create mode 100644 drivers/gpu/nvgpu/include/nvgpu/timers.h diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu index 96cdfb0a..71077386 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 00000000..e1e08f82 --- /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 00000000..e46982c9 --- /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 -- cgit v1.2.2