From 01e6fac4d61fdd7fff5433942ec93fc2ea1e4df1 Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Wed, 28 Jun 2023 18:24:25 -0400 Subject: Include nvgpu headers These are needed to build on NVIDIA's Jetson boards for the time being. Only a couple structs are required, so it should be fairly easy to remove this dependency at some point in the future. --- include/os/linux/timers.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 include/os/linux/timers.c (limited to 'include/os/linux/timers.c') diff --git a/include/os/linux/timers.c b/include/os/linux/timers.c new file mode 100644 index 0000000..018fd2d --- /dev/null +++ b/include/os/linux/timers.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2016-2018, 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 +#include +#include + +#include "platform_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 !nvgpu_platform_is_silicon(timeout->g); +} + +/** + * 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, + u32 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 = ktime_to_ns(ktime_add_ns(ktime_get(), + (s64)NSEC_PER_MSEC * duration)); + + return 0; +} + +static int __nvgpu_timeout_expired_msg_cpu(struct nvgpu_timeout *timeout, + void *caller, + const char *fmt, va_list args) +{ + struct gk20a *g = timeout->g; + ktime_t now = ktime_get(); + + if (nvgpu_timeout_is_pre_silicon(timeout)) + return 0; + + if (ktime_after(now, ns_to_ktime(timeout->time))) { + if (!(timeout->flags & NVGPU_TIMER_SILENT_TIMEOUT)) { + char buf[128]; + + vsnprintf(buf, sizeof(buf), fmt, args); + + nvgpu_err(g, "Timeout detected @ %pF %s", caller, buf); + } + + return -ETIMEDOUT; + } + + return 0; +} + +static int __nvgpu_timeout_expired_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); + + nvgpu_err(g, "No more retries @ %pF %s", caller, buf); + } + + return -ETIMEDOUT; + } + + timeout->retries.attempted++; + + return 0; +} + +/** + * __nvgpu_timeout_expired_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_expired_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_expired_msg_retry(timeout, caller, fmt, + args); + else + ret = __nvgpu_timeout_expired_msg_cpu(timeout, caller, fmt, + args); + va_end(args); + + return ret; +} + +/** + * nvgpu_timeout_peek_expired - 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_expired(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 ktime_after(ktime_get(), ns_to_ktime(timeout->time)); +} + +/** + * nvgpu_udelay - Delay for some number of microseconds. + * + * @usecs - Microseconds to wait for. + * + * Wait for at least @usecs microseconds. This is not guaranteed to be perfectly + * accurate. This is normally backed by a busy-loop so this means waits should + * be kept short, below 100us. If longer delays are necessary then + * nvgpu_msleep() should be preferred. + * + * Alternatively, on some platforms, nvgpu_usleep_range() is usable. This + * function will attempt to not use a busy-loop. + */ +void nvgpu_udelay(unsigned int usecs) +{ + udelay(usecs); +} + +/** + * nvgpu_usleep_range - Sleep for a range of microseconds. + * + * @min_us - Minimum wait time. + * @max_us - Maximum wait time. + * + * Wait for some number of microseconds between @min_us and @max_us. This, + * unlike nvgpu_udelay(), will attempt to sleep for the passed number of + * microseconds instead of busy looping. Not all platforms support this, + * and in that case this reduces to nvgpu_udelay(min_us). + * + * Linux note: this is not safe to use in atomic context. If you are in + * atomic context you must use nvgpu_udelay(). + */ +void nvgpu_usleep_range(unsigned int min_us, unsigned int max_us) +{ + usleep_range(min_us, max_us); +} + +/** + * nvgpu_msleep - Sleep for some milliseconds. + * + * @msecs - Sleep for at least this many milliseconds. + * + * Sleep for at least @msecs of milliseconds. For small @msecs (less than 20 ms + * or so) the sleep will be significantly longer due to scheduling overhead and + * mechanics. + */ +void nvgpu_msleep(unsigned int msecs) +{ + msleep(msecs); +} + +/** + * nvgpu_current_time_ms - Time in milliseconds from a monotonic clock. + * + * Return a clock in millisecond units. The start time of the clock is + * unspecified; the time returned can be compared with older ones to measure + * durations. The source clock does not jump when the system clock is adjusted. + */ +s64 nvgpu_current_time_ms(void) +{ + return ktime_to_ms(ktime_get()); +} + +/** + * nvgpu_current_time_ns - Time in nanoseconds from a monotonic clock. + * + * Return a clock in nanosecond units. The start time of the clock is + * unspecified; the time returned can be compared with older ones to measure + * durations. The source clock does not jump when the system clock is adjusted. + */ +s64 nvgpu_current_time_ns(void) +{ + return ktime_to_ns(ktime_get()); +} + +/** + * nvgpu_hr_timestamp - Opaque 'high resolution' time stamp. + * + * Return a "high resolution" time stamp. It does not really matter exactly what + * it is, so long as it generally returns unique values and monotonically + * increases - wrap around _is_ possible though in a system running for long + * enough. + * + * Note: what high resolution means is system dependent. + */ +u64 nvgpu_hr_timestamp(void) +{ + return get_cycles(); +} -- cgit v1.2.2