mirror of
https://github.com/Frogging-Family/nvidia-all
synced 2024-10-30 15:20:10 +00:00
647 lines
20 KiB
Diff
647 lines
20 KiB
Diff
From 11adcf1e8d2fbebeb614390832de08388a46bcda Mon Sep 17 00:00:00 2001
|
|
From: Tk-Glitch <ti3nou@gmail.com>
|
|
Date: Mon, 28 Jan 2019 18:21:34 +0100
|
|
Subject: kernel 5.0 patch
|
|
|
|
|
|
diff --git a/kernel-dkms/common/inc/nv.h b/kernel-dkms/common/inc/nv.h
|
|
index d52c2a1ef..f6dc2dc32 100644
|
|
--- a/kernel-dkms/common/inc/nv.h
|
|
+++ b/kernel-dkms/common/inc/nv.h
|
|
@@ -603,6 +605,7 @@ typedef NV_STATUS (*nvPmaEvictRangeCallback)(void *, NvU64, NvU64);
|
|
#define NV_MAX_ISR_DELAY_US 20000
|
|
#define NV_MAX_ISR_DELAY_MS (NV_MAX_ISR_DELAY_US / 1000)
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
|
#define NV_TIMERCMP(a, b, CMP) \
|
|
(((a)->tv_sec == (b)->tv_sec) ? \
|
|
((a)->tv_usec CMP (b)->tv_usec) : ((a)->tv_sec CMP (b)->tv_sec))
|
|
@@ -630,6 +633,35 @@ typedef NV_STATUS (*nvPmaEvictRangeCallback)(void *, NvU64, NvU64);
|
|
}
|
|
|
|
#define NV_TIMEVAL_TO_US(tv) ((NvU64)(tv).tv_sec * 1000000 + (tv).tv_usec)
|
|
+#else
|
|
+#define NV_TIMERCMP(a, b, CMP) \
|
|
+ (((a)->tv_sec == (b)->tv_sec) ? \
|
|
+ ((a)->tv_nsec CMP (b)->tv_nsec) : ((a)->tv_sec CMP (b)->tv_sec))
|
|
+
|
|
+#define NV_TIMERADD(a, b, result) \
|
|
+ { \
|
|
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
|
+ (result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
|
|
+ if ((result)->tv_nsec >= NSEC_PER_SEC) \
|
|
+ { \
|
|
+ ++(result)->tv_sec; \
|
|
+ (result)->tv_nsec -= NSEC_PER_SEC; \
|
|
+ } \
|
|
+ }
|
|
+
|
|
+#define NV_TIMERSUB(a, b, result) \
|
|
+ { \
|
|
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
|
+ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
|
|
+ if ((result)->tv_nsec < 0) \
|
|
+ { \
|
|
+ --(result)->tv_sec; \
|
|
+ (result)->tv_nsec += NSEC_PER_SEC; \
|
|
+ } \
|
|
+ }
|
|
+
|
|
+#define NV_TIMEVAL_TO_US(tv) ((NvU64)(tv).tv_sec * USEC_PER_SEC + (tv).tv_nsec/NSEC_PER_USEC)
|
|
+#endif
|
|
|
|
#ifndef NV_ALIGN_UP
|
|
#define NV_ALIGN_UP(v,g) (((v) + ((g) - 1)) & ~((g) - 1))
|
|
diff --git a/kernel-dkms/conftest.sh b/kernel-dkms/conftest.sh
|
|
index 0ae7a2662..9a71ae7b3 100755
|
|
--- a/kernel-dkms/conftest.sh
|
|
+++ b/kernel-dkms/conftest.sh
|
|
@@ -1653,6 +1653,24 @@ compile_test() {
|
|
compile_check_conftest "$CODE" "NV_DRM_AVAILABLE" "" "generic"
|
|
;;
|
|
|
|
+ drm_dev_put)
|
|
+ #
|
|
+ # Determine if drm_dev_put() is present.
|
|
+ #
|
|
+ CODE="
|
|
+ #include <linux/version.h>
|
|
+ #if defined(NV_DRM_DRMP_H_PRESENT)
|
|
+ #include <drm/drmP.h>
|
|
+ #endif
|
|
+#if LINUX_VERSION_CODE => KERNEL_VERSION(5,0,0)
|
|
+ void conftest_drm_dev_put(void) {
|
|
+ drm_dev_put();
|
|
+ }
|
|
+#endif"
|
|
+
|
|
+ compile_check_conftest "$CODE" "NV_DRM_DEV_PUT_PRESENT" "" "functions"
|
|
+ ;;
|
|
+
|
|
drm_dev_unref)
|
|
#
|
|
# Determine if drm_dev_unref() is present.
|
|
diff --git a/kernel-dkms/nvidia-drm/nvidia-drm-gem.h b/kernel-dkms/nvidia-drm/nvidia-drm-gem.h
|
|
index f276588db..7cbdbe632 100644
|
|
--- a/kernel-dkms/nvidia-drm/nvidia-drm-gem.h
|
|
+++ b/kernel-dkms/nvidia-drm/nvidia-drm-gem.h
|
|
@@ -79,7 +81,11 @@ static inline int nv_drm_gem_handle_create_drop_reference(
|
|
|
|
/* drop reference from allocate - handle holds it now */
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
drm_gem_object_unreference_unlocked(&nv_gem->base);
|
|
+#else
|
|
+ drm_gem_object_put_unlocked(&nv_gem->base);
|
|
+#endif
|
|
|
|
return ret;
|
|
}
|
|
@@ -148,13 +154,21 @@ static inline struct nv_drm_gem_object *nv_drm_gem_object_lookup(
|
|
static inline void
|
|
nv_drm_gem_object_unreference_unlocked(struct nv_drm_gem_object *nv_gem)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
drm_gem_object_unreference_unlocked(&nv_gem->base);
|
|
+#else
|
|
+ drm_gem_object_put_unlocked(&nv_gem->base);
|
|
+#endif
|
|
}
|
|
|
|
static inline void
|
|
nv_drm_gem_object_unreference(struct nv_drm_gem_object *nv_gem)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
drm_gem_object_unreference(&nv_gem->base);
|
|
+#else
|
|
+ drm_gem_object_put(&nv_gem->base);
|
|
+#endif
|
|
}
|
|
|
|
static inline int nv_drm_gem_handle_create(struct drm_file *filp,
|
|
diff --git a/kernel-dkms/nvidia-drm/nvidia-drm-helper.c b/kernel-dkms/nvidia-drm/nvidia-drm-helper.c
|
|
index 4ccf81929..7fb59bbb3 100644
|
|
--- a/kernel-dkms/nvidia-drm/nvidia-drm-helper.c
|
|
+++ b/kernel-dkms/nvidia-drm/nvidia-drm-helper.c
|
|
@@ -149,12 +151,20 @@ void nv_drm_atomic_clean_old_fb(struct drm_device *dev,
|
|
if (ret == 0) {
|
|
struct drm_framebuffer *new_fb = plane->state->fb;
|
|
if (new_fb)
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
drm_framebuffer_reference(new_fb);
|
|
+#else
|
|
+ drm_framebuffer_get(new_fb);
|
|
+#endif
|
|
plane->fb = new_fb;
|
|
plane->crtc = plane->state->crtc;
|
|
|
|
if (plane->old_fb)
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
drm_framebuffer_unreference(plane->old_fb);
|
|
+#else
|
|
+ drm_framebuffer_put(plane->old_fb);
|
|
+#endif
|
|
}
|
|
plane->old_fb = NULL;
|
|
}
|
|
diff --git a/kernel-dkms/nvidia-drm/nvidia-drm-helper.h b/kernel-dkms/nvidia-drm/nvidia-drm-helper.h
|
|
index efecc4ad7..2a0c3bbca 100644
|
|
--- a/kernel-dkms/nvidia-drm/nvidia-drm-helper.h
|
|
+++ b/kernel-dkms/nvidia-drm/nvidia-drm-helper.h
|
|
@@ -36,7 +36,9 @@
|
|
*/
|
|
static inline void nv_drm_dev_free(struct drm_device *dev)
|
|
{
|
|
-#if defined(NV_DRM_DEV_UNREF_PRESENT)
|
|
+#if defined(NV_DRM_DEV_PUT_PRESENT)
|
|
+ drm_dev_put(dev);
|
|
+#elif defined(NV_DRM_DEV_UNREF_PRESENT)
|
|
drm_dev_unref(dev);
|
|
#else
|
|
drm_dev_free(dev);
|
|
diff --git a/kernel-dkms/nvidia-drm/nvidia-drm-linux.c b/kernel-dkms/nvidia-drm/nvidia-drm-linux.c
|
|
index 5a2bbc18c..133d8fe64 100644
|
|
--- a/kernel-dkms/nvidia-drm/nvidia-drm-linux.c
|
|
+++ b/kernel-dkms/nvidia-drm/nvidia-drm-linux.c
|
|
@@ -151,11 +153,19 @@ void nv_drm_vunmap(void *address)
|
|
|
|
uint64_t nv_drm_get_time_usec(void)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
struct timeval tv;
|
|
|
|
do_gettimeofday(&tv);
|
|
|
|
return (((uint64_t)tv.tv_sec) * 1000000) + tv.tv_usec;
|
|
+#else
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ ktime_get_real_ts64(&ts);
|
|
+
|
|
+ return (((uint64_t)ts.tv_sec) * USEC_PER_SEC) + (((uint64_t)ts.tv_nsec) / NSEC_PER_USEC);
|
|
+#endif
|
|
}
|
|
|
|
#endif /* NV_DRM_AVAILABLE */
|
|
diff --git a/kernel-dkms/nvidia-drm/nvidia-drm.Kbuild b/kernel-dkms/nvidia-drm/nvidia-drm.Kbuild
|
|
index 466b51528..bcf8aff10 100644
|
|
--- a/kernel-dkms/nvidia-drm/nvidia-drm.Kbuild
|
|
+++ b/kernel-dkms/nvidia-drm/nvidia-drm.Kbuild
|
|
@@ -53,6 +53,7 @@ NV_CONFTEST_GENERIC_COMPILE_TESTS += drm_atomic_modeset_nonblocking_commit_avail
|
|
NV_CONFTEST_GENERIC_COMPILE_TESTS += is_export_symbol_gpl_refcount_inc
|
|
NV_CONFTEST_GENERIC_COMPILE_TESTS += is_export_symbol_gpl_refcount_dec_and_test
|
|
|
|
+NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_dev_put
|
|
NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_dev_unref
|
|
NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_reinit_primary_mode_group
|
|
NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_atomic_set_mode_for_crtc
|
|
diff --git a/kernel-dkms/nvidia-modeset/nvidia-modeset-linux.c b/kernel-dkms/nvidia-modeset/nvidia-modeset-linux.c
|
|
index 1b9148ee7..4c1bd3617 100644
|
|
--- a/kernel-dkms/nvidia-modeset/nvidia-modeset-linux.c
|
|
+++ b/kernel-dkms/nvidia-modeset/nvidia-modeset-linux.c
|
|
@@ -210,11 +212,19 @@ void NVKMS_API_CALL nvkms_usleep(NvU64 usec)
|
|
|
|
NvU64 NVKMS_API_CALL nvkms_get_usec(void)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
struct timeval tv;
|
|
|
|
do_gettimeofday(&tv);
|
|
|
|
return (((NvU64)tv.tv_sec) * 1000000) + tv.tv_usec;
|
|
+#else
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ ktime_get_real_ts64(&ts);
|
|
+
|
|
+ return (((NvU64)ts.tv_sec) * 1000000) + ts.tv_nsec/NSEC_PER_USEC;
|
|
+#endif
|
|
}
|
|
|
|
int NVKMS_API_CALL nvkms_copyin(void *kptr, NvU64 uaddr, size_t n)
|
|
diff --git a/kernel-dkms/nvidia-uvm/uvm_linux.h b/kernel-dkms/nvidia-uvm/uvm_linux.h
|
|
index 8707ac070..990cefbd4 100644
|
|
--- a/kernel-dkms/nvidia-uvm/uvm_linux.h
|
|
+++ b/kernel-dkms/nvidia-uvm/uvm_linux.h
|
|
@@ -320,12 +322,21 @@ static inline uint64_t NV_DIV64(uint64_t dividend, uint64_t divisor, uint64_t *r
|
|
/* Return a nanosecond-precise value */
|
|
static inline NvU64 NV_GETTIME(void)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
struct timespec ts = {0};
|
|
|
|
getrawmonotonic(&ts);
|
|
|
|
/* Wraps around every 583 years */
|
|
return (ts.tv_sec * 1000000000ULL + ts.tv_nsec);
|
|
+#else
|
|
+ struct timespec64 ts = {0};
|
|
+
|
|
+ ktime_get_raw_ts64(&ts);
|
|
+
|
|
+ /* Wraps around every 583 years */
|
|
+ return (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec);
|
|
+#endif
|
|
}
|
|
#else
|
|
/* We can only return a microsecond-precise value with the
|
|
@@ -334,9 +345,15 @@ static inline NvU64 NV_GETTIME(void)
|
|
{
|
|
struct timeval tv = {0};
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
do_gettimeofday(&tv);
|
|
|
|
return (tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ULL);
|
|
+#else
|
|
+ ktime_get_real_ts64(&tv);
|
|
+
|
|
+ return (tv.tv_sec * 1000000000ULL + (tv.tv_nsec/NSEC_PER_USEC) * 1000ULL);
|
|
+#endif
|
|
}
|
|
#endif
|
|
|
|
diff --git a/kernel-dkms/nvidia/nvlink_linux.c b/kernel-dkms/nvidia/nvlink_linux.c
|
|
index c13b72515..db691679c 100644
|
|
--- a/kernel-dkms/nvidia/nvlink_linux.c
|
|
+++ b/kernel-dkms/nvidia/nvlink_linux.c
|
|
@@ -500,6 +502,7 @@ void * NVLINK_API_CALL nvlink_memcpy(void *dest, void *src, NvLength size)
|
|
return memcpy(dest, src, size);
|
|
}
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
|
static NvBool nv_timer_less_than
|
|
(
|
|
const struct timeval *a,
|
|
@@ -610,6 +613,118 @@ void NVLINK_API_CALL nvlink_sleep(unsigned int ms)
|
|
udelay(us);
|
|
}
|
|
}
|
|
+#else
|
|
+static NvBool nv_timer_less_than
|
|
+(
|
|
+ const struct timespec64 *a,
|
|
+ const struct timespec64 *b
|
|
+)
|
|
+{
|
|
+ return (a->tv_sec == b->tv_sec) ? (a->tv_nsec < b->tv_nsec)
|
|
+ : (a->tv_sec < b->tv_sec);
|
|
+}
|
|
+
|
|
+static void nv_timeradd
|
|
+(
|
|
+ const struct timespec64 *a,
|
|
+ const struct timespec64 *b,
|
|
+ struct timespec64 *result
|
|
+)
|
|
+{
|
|
+ result->tv_sec = a->tv_sec + b->tv_sec;
|
|
+ result->tv_nsec = a->tv_nsec + b->tv_nsec;
|
|
+ while (result->tv_nsec >= NSEC_PER_SEC)
|
|
+ {
|
|
+ ++result->tv_sec;
|
|
+ result->tv_nsec -= NSEC_PER_SEC;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void nv_timersub
|
|
+(
|
|
+ const struct timespec64 *a,
|
|
+ const struct timespec64 *b,
|
|
+ struct timespec64 *result
|
|
+)
|
|
+{
|
|
+ result->tv_sec = a->tv_sec - b->tv_sec;
|
|
+ result->tv_nsec = a->tv_nsec - b->tv_nsec;
|
|
+ while (result->tv_nsec < 0)
|
|
+ {
|
|
+ --(result->tv_sec);
|
|
+ result->tv_nsec += NSEC_PER_SEC;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Sleep for specified milliseconds. Yields the CPU to scheduler.
|
|
+ */
|
|
+void NVLINK_API_CALL nvlink_sleep(unsigned int ms)
|
|
+{
|
|
+ unsigned long us;
|
|
+ unsigned long jiffies;
|
|
+ unsigned long mdelay_safe_msec;
|
|
+ struct timespec64 ts_end, ts_aux;
|
|
+
|
|
+ ktime_get_real_ts64(&ts_aux);
|
|
+
|
|
+ if (in_irq() && (ms > NV_MAX_ISR_DELAY_MS))
|
|
+ {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (irqs_disabled() || in_interrupt() || in_atomic())
|
|
+ {
|
|
+ mdelay(ms);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ us = ms * 1000;
|
|
+ ts_end.tv_nsec = us*NSEC_PER_USEC;
|
|
+ ts_end.tv_sec = 0;
|
|
+ nv_timeradd(&ts_aux, &ts_end, &ts_end);
|
|
+
|
|
+ /* do we have a full jiffie to wait? */
|
|
+ jiffies = NV_USECS_TO_JIFFIES(us);
|
|
+
|
|
+ if (jiffies)
|
|
+ {
|
|
+ //
|
|
+ // If we have at least one full jiffy to wait, give up
|
|
+ // up the CPU; since we may be rescheduled before
|
|
+ // the requested timeout has expired, loop until less
|
|
+ // than a jiffie of the desired delay remains.
|
|
+ //
|
|
+ current->state = TASK_INTERRUPTIBLE;
|
|
+ do
|
|
+ {
|
|
+ schedule_timeout(jiffies);
|
|
+ ktime_get_real_ts64(&ts_aux);
|
|
+ if (nv_timer_less_than(&ts_aux, &ts_end))
|
|
+ {
|
|
+ nv_timersub(&ts_end, &ts_aux, &ts_aux);
|
|
+ us = ts_aux.tv_nsec/NSEC_PER_USEC + ts_aux.tv_sec * USEC_PER_SEC;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ us = 0;
|
|
+ }
|
|
+ }
|
|
+ while ((jiffies = NV_USECS_TO_JIFFIES(us)) != 0);
|
|
+ }
|
|
+
|
|
+ if (us > 1000)
|
|
+ {
|
|
+ mdelay_safe_msec = us / USEC_PER_MSEC;
|
|
+ mdelay(mdelay_safe_msec);
|
|
+ us %= 1000;
|
|
+ }
|
|
+ if (us)
|
|
+ {
|
|
+ udelay(us);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
|
|
void NVLINK_API_CALL nvlink_assert(int cond)
|
|
{
|
|
diff --git a/kernel-dkms/nvidia/os-interface.c b/kernel-dkms/nvidia/os-interface.c
|
|
index d1c889f69..88c57b2da 100644
|
|
--- a/kernel-dkms/nvidia/os-interface.c
|
|
+++ b/kernel-dkms/nvidia/os-interface.c
|
|
@@ -426,6 +428,7 @@ NV_STATUS NV_API_CALL os_get_current_time(
|
|
NvU32 *seconds,
|
|
NvU32 *useconds
|
|
)
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
{
|
|
struct timeval tm;
|
|
|
|
@@ -608,6 +611,190 @@ NV_STATUS NV_API_CALL os_delay(NvU32 MilliSeconds)
|
|
|
|
return NV_OK;
|
|
}
|
|
+#else
|
|
+{
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ ktime_get_real_ts64(&ts);
|
|
+
|
|
+ *seconds = ts.tv_sec;
|
|
+ *useconds = ((uint64_t)(ts.tv_nsec / NSEC_PER_USEC));
|
|
+
|
|
+ return NV_OK;
|
|
+}
|
|
+
|
|
+#if BITS_PER_LONG >= 64
|
|
+
|
|
+void NV_API_CALL os_get_current_tick(NvU64 *nseconds)
|
|
+{
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ jiffies_to_timespec64(jiffies, &ts);
|
|
+
|
|
+ *nseconds = ((NvU64)ts.tv_sec * NSEC_PER_SEC + (NvU64)ts.tv_nsec);
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+void NV_API_CALL os_get_current_tick(NvU64 *nseconds)
|
|
+{
|
|
+ /*
|
|
+ * 'jiffies' overflows regularly on 32-bit builds (unsigned long is 4 bytes
|
|
+ * instead of 8 bytes), so it's unwise to build a tick counter on it, since
|
|
+ * the rest of the Resman assumes the 'tick' returned from this function is
|
|
+ * monotonically increasing and never overflows.
|
|
+ *
|
|
+ * Instead, use the previous implementation that we've lived with since the
|
|
+ * beginning, which uses system clock time to calculate the tick. This is
|
|
+ * subject to problems if the system clock time changes dramatically
|
|
+ * (more than a second or so) while the Resman is actively tracking a
|
|
+ * timeout.
|
|
+ */
|
|
+ NvU32 seconds, useconds;
|
|
+
|
|
+ (void) os_get_current_time(&seconds, &useconds);
|
|
+
|
|
+ *nseconds = ((NvU64)seconds * NSEC_PER_SEC +
|
|
+ (NvU64)useconds * NSEC_PER_USEC);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+//---------------------------------------------------------------------------
|
|
+//
|
|
+// Misc services.
|
|
+//
|
|
+//---------------------------------------------------------------------------
|
|
+
|
|
+#define NV_MSECS_PER_JIFFIE (1000 / HZ)
|
|
+#define NV_MSECS_TO_JIFFIES(msec) ((msec) * HZ / 1000)
|
|
+#define NV_USECS_PER_JIFFIE (1000000 / HZ)
|
|
+#define NV_USECS_TO_JIFFIES(usec) ((usec) * HZ / 1000000)
|
|
+
|
|
+// #define NV_CHECK_DELAY_ACCURACY 1
|
|
+
|
|
+/*
|
|
+ * It is generally a bad idea to use udelay() to wait for more than
|
|
+ * a few milliseconds. Since the caller is most likely not aware of
|
|
+ * this, we use mdelay() for any full millisecond to be safe.
|
|
+ */
|
|
+
|
|
+NV_STATUS NV_API_CALL os_delay_us(NvU32 MicroSeconds)
|
|
+{
|
|
+ unsigned long mdelay_safe_msec;
|
|
+ unsigned long usec;
|
|
+
|
|
+#ifdef NV_CHECK_DELAY_ACCURACY
|
|
+ struct timespec64 ts1, ts2;
|
|
+
|
|
+ ktime_get_real_ts64(&ts1);
|
|
+#endif
|
|
+
|
|
+ if (in_irq() && (MicroSeconds > NV_MAX_ISR_DELAY_US))
|
|
+ return NV_ERR_GENERIC;
|
|
+
|
|
+ mdelay_safe_msec = MicroSeconds / 1000;
|
|
+ if (mdelay_safe_msec)
|
|
+ mdelay(mdelay_safe_msec);
|
|
+
|
|
+ usec = MicroSeconds % 1000;
|
|
+ if (usec)
|
|
+ udelay(usec);
|
|
+
|
|
+#ifdef NV_CHECK_DELAY_ACCURACY
|
|
+ ktime_get_real_ts64(&ts2);
|
|
+ nv_printf(NV_DBG_ERRORS, "NVRM: osDelayUs %d: 0x%x 0x%x\n",
|
|
+ MicroSeconds, ts2.tv_sec - ts1.tv_sec, (ts2.tv_nsec - ts1.tv_nsec) / NSEC_PER_USEC);
|
|
+#endif
|
|
+
|
|
+ return NV_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * On Linux, a jiffie represents the time passed in between two timer
|
|
+ * interrupts. The number of jiffies per second (HZ) varies across the
|
|
+ * supported platforms. On i386, where HZ is 100, a timer interrupt is
|
|
+ * generated every 10ms; the resolution is a lot better on ia64, where
|
|
+ * HZ is 1024. NV_MSECS_TO_JIFFIES should be accurate independent of
|
|
+ * the actual value of HZ; any partial jiffies will be 'floor'ed, the
|
|
+ * remainder will be accounted for with mdelay().
|
|
+ */
|
|
+
|
|
+NV_STATUS NV_API_CALL os_delay(NvU32 MilliSeconds)
|
|
+{
|
|
+ unsigned long MicroSeconds;
|
|
+ unsigned long jiffies;
|
|
+ unsigned long mdelay_safe_msec;
|
|
+ struct timespec64 ts_end, ts_aux;
|
|
+#ifdef NV_CHECK_DELAY_ACCURACY
|
|
+ struct timespec64 ts_start;
|
|
+#endif
|
|
+
|
|
+ ktime_get_real_ts64(&ts_aux);
|
|
+#ifdef NV_CHECK_DELAY_ACCURACY
|
|
+ ts_start = ts_aux;
|
|
+#endif
|
|
+
|
|
+ if (in_irq() && (MilliSeconds > NV_MAX_ISR_DELAY_MS))
|
|
+ return NV_ERR_GENERIC;
|
|
+
|
|
+ if (!NV_MAY_SLEEP())
|
|
+ {
|
|
+ mdelay(MilliSeconds);
|
|
+ return NV_OK;
|
|
+ }
|
|
+
|
|
+ MicroSeconds = MilliSeconds * USEC_PER_MSEC;
|
|
+ ts_end.tv_nsec = MicroSeconds * NSEC_PER_USEC;
|
|
+ ts_end.tv_sec = 0;
|
|
+ NV_TIMERADD(&ts_aux, &ts_end, &ts_end);
|
|
+
|
|
+ /* do we have a full jiffie to wait? */
|
|
+ jiffies = NV_USECS_TO_JIFFIES(MicroSeconds);
|
|
+
|
|
+ if (jiffies)
|
|
+ {
|
|
+ //
|
|
+ // If we have at least one full jiffy to wait, give up
|
|
+ // up the CPU; since we may be rescheduled before
|
|
+ // the requested timeout has expired, loop until less
|
|
+ // than a jiffie of the desired delay remains.
|
|
+ //
|
|
+ current->state = TASK_INTERRUPTIBLE;
|
|
+ do
|
|
+ {
|
|
+ schedule_timeout(jiffies);
|
|
+ ktime_get_real_ts64(&ts_aux);
|
|
+ if (NV_TIMERCMP(&ts_aux, &ts_end, <))
|
|
+ {
|
|
+ NV_TIMERSUB(&ts_end, &ts_aux, &ts_aux);
|
|
+ MicroSeconds = ts_aux.tv_nsec/NSEC_PER_USEC + ts_aux.tv_sec * USEC_PER_SEC;
|
|
+ }
|
|
+ else
|
|
+ MicroSeconds = 0;
|
|
+ } while ((jiffies = NV_USECS_TO_JIFFIES(MicroSeconds)) != 0);
|
|
+ }
|
|
+
|
|
+ if (MicroSeconds > 1000)
|
|
+ {
|
|
+ mdelay_safe_msec = MicroSeconds / 1000;
|
|
+ mdelay(mdelay_safe_msec);
|
|
+ MicroSeconds %= 1000;
|
|
+ }
|
|
+ if (MicroSeconds)
|
|
+ {
|
|
+ udelay(MicroSeconds);
|
|
+ }
|
|
+#ifdef NV_CHECK_DELAY_ACCURACY
|
|
+ ktime_get_real_ts64(&ts_aux);
|
|
+ timersub(&ts_aux, &ts_start, &ts_aux);
|
|
+ nv_printf(NV_DBG_ERRORS, "NVRM: osDelay %dmsec: %d.%06dsec\n",
|
|
+ MilliSeconds, ts_aux.tv_sec, ts_aux.tv_nsec/NSEC_PER_USEC);
|
|
+#endif
|
|
+
|
|
+ return NV_OK;
|
|
+}
|
|
+#endif
|
|
|
|
NvU64 NV_API_CALL os_get_cpu_frequency(void)
|
|
{
|
|
@@ -1896,6 +2083,7 @@ static NV_STATUS NV_API_CALL _os_ipmi_receive_resp
|
|
nvipmi_resp_t *p_resp
|
|
)
|
|
{
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
struct ipmi_recv_msg *rx_msg;
|
|
int err_no;
|
|
struct timeval tv;
|
|
@@ -1928,6 +2116,40 @@ static NV_STATUS NV_API_CALL _os_ipmi_receive_resp
|
|
os_delay(NV_IPMI_SLEEP_MS);
|
|
do_gettimeofday(&tv);
|
|
} while (NV_TIMEVAL_TO_US(tv) < (start_time + NV_IPMI_READ_TIMEOUT_US));
|
|
+#else
|
|
+ struct ipmi_recv_msg *rx_msg;
|
|
+ int err_no;
|
|
+ struct timespec64 ts;
|
|
+ NvU64 start_time;
|
|
+
|
|
+ ktime_get_real_ts64(&ts);
|
|
+ start_time = NV_TIMEVAL_TO_US(ts);
|
|
+
|
|
+ err_no = -EAGAIN;
|
|
+ do
|
|
+ {
|
|
+ unsigned long flags;
|
|
+ struct list_head *ent;
|
|
+
|
|
+ rx_msg = NULL;
|
|
+
|
|
+ spin_lock_irqsave(&p_priv->msg_lock, flags);
|
|
+ if (!list_empty(&p_priv->msgs))
|
|
+ {
|
|
+ ent = p_priv->msgs.next;
|
|
+ rx_msg = list_entry(ent, struct ipmi_recv_msg, link);
|
|
+ list_del(ent);
|
|
+ spin_unlock_irqrestore(&p_priv->msg_lock, flags);
|
|
+
|
|
+ err_no = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ spin_unlock_irqrestore(&p_priv->msg_lock, flags);
|
|
+ os_delay(NV_IPMI_SLEEP_MS);
|
|
+ ktime_get_real_ts64(&ts);
|
|
+ } while (NV_TIMEVAL_TO_US(ts) < (start_time + NV_IPMI_READ_TIMEOUT_US));
|
|
+#endif
|
|
|
|
if (rx_msg != NULL)
|
|
{
|