From 2a292037e97991dbfc2c291d87119c7bf0cd50be Mon Sep 17 00:00:00 2001
From: Alberto Milone <alberto.milone@canonical.com>
Date: Thu, 12 Mar 2020 16:03:30 +0100
Subject: [PATCH 1/1] Add support for Linux 5.6

---
 common/inc/nv-procfs.h               | 54 ++++++++++++++++++-
 common/inc/nv-time.h                 | 80 ++++++++++++++++++++++++++++
 conftest.sh                          | 50 +++++++++++++++++
 nvidia-modeset/nvidia-modeset.Kbuild |  4 +-
 nvidia-uvm/nvidia-uvm.Kbuild         |  2 +
 nvidia/linux_nvswitch.c              |  1 +
 nvidia/nv-procfs.c                   | 65 ++++++++++++++++++++++
 nvidia/nvidia.Kbuild                 |  2 +
 nvidia/nvlink_linux.c                |  1 -
 9 files changed, 256 insertions(+), 3 deletions(-)

diff --git a/common/inc/nv-procfs.h b/common/inc/nv-procfs.h
index 8b53f86..7e1bfed 100644
--- a/common/inc/nv-procfs.h
+++ b/common/inc/nv-procfs.h
@@ -28,6 +28,18 @@
 
 #define IS_EXERCISE_ERROR_FORWARDING_ENABLED() (EXERCISE_ERROR_FORWARDING)
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+#define NV_CREATE_PROC_FILE(filename,parent,__name,__data)               \
+   ({                                                                    \
+        struct proc_dir_entry *__entry;                                  \
+        int mode = (S_IFREG | S_IRUGO);                                  \
+        const struct proc_ops *fops = &nv_procfs_##__name##_fops;		 \
+        if (fops->proc_write != 0)                                            \
+            mode |= S_IWUSR;                                             \
+        __entry = proc_create_data(filename, mode, parent, fops, __data);\
+        __entry;                                                         \
+    })
+#else
 #define NV_CREATE_PROC_FILE(filename,parent,__name,__data)               \
    ({                                                                    \
         struct proc_dir_entry *__entry;                                  \
@@ -38,6 +50,7 @@
         __entry = proc_create_data(filename, mode, parent, fops, __data);\
         __entry;                                                         \
     })
+#endif
 
 /*
  * proc_mkdir_mode exists in Linux 2.6.9, but isn't exported until Linux 3.0.
@@ -77,6 +90,45 @@
     remove_proc_entry(entry->name, entry->parent);
 #endif
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+#define NV_DEFINE_SINGLE_PROCFS_FILE(name, open_callback, close_callback)     \
+    static int nv_procfs_open_##name(                                         \
+        struct inode *inode,                                                  \
+        struct file *filep                                                    \
+    )                                                                         \
+    {                                                                         \
+        int ret;                                                              \
+        ret = single_open(filep, nv_procfs_read_##name,                       \
+                          NV_PDE_DATA(inode));                                \
+        if (ret < 0)                                                          \
+        {                                                                     \
+            return ret;                                                       \
+        }                                                                     \
+        ret = open_callback();                                                \
+        if (ret < 0)                                                          \
+        {                                                                     \
+            single_release(inode, filep);                                     \
+        }                                                                     \
+        return ret;                                                           \
+    }                                                                         \
+                                                                              \
+    static int nv_procfs_release_##name(                                      \
+        struct inode *inode,                                                  \
+        struct file *filep                                                    \
+    )                                                                         \
+    {                                                                         \
+        close_callback();                                                     \
+        return single_release(inode, filep);                                  \
+    }                                                                         \
+                                                                              \
+    static const struct proc_ops nv_procfs_##name##_fops = {           \
+        .proc_open       = nv_procfs_open_##name,                                  \
+        .proc_read       = seq_read,                                               \
+        .proc_lseek     = seq_lseek,                                              \
+        .proc_release    = nv_procfs_release_##name,                               \
+    };
+
+#else
 #define NV_DEFINE_SINGLE_PROCFS_FILE(name, open_callback, close_callback)     \
     static int nv_procfs_open_##name(                                         \
         struct inode *inode,                                                  \
@@ -114,7 +166,7 @@
         .llseek     = seq_lseek,                                              \
         .release    = nv_procfs_release_##name,                               \
     };
-
+#endif
 #endif  /* CONFIG_PROC_FS */
 
 #endif /* _NV_PROCFS_H */
diff --git a/common/inc/nv-time.h b/common/inc/nv-time.h
index 968b873..5714e41 100644
--- a/common/inc/nv-time.h
+++ b/common/inc/nv-time.h
@@ -27,6 +27,86 @@
 
 #include <linux/ktime.h>
 
+#ifndef NV_TIME_STRUCTS_PRESENT
+struct timespec {
+    __kernel_old_time_t tv_sec;     /* seconds */
+    long            tv_nsec;    /* nanoseconds */
+};
+
+struct timeval {
+    __kernel_old_time_t tv_sec;     /* seconds */
+    __kernel_suseconds_t    tv_usec;    /* microseconds */
+};
+
+struct itimerspec {
+    struct timespec it_interval;/* timer period */
+    struct timespec it_value;   /* timer expiration */
+};
+
+struct itimerval {
+    struct timeval it_interval;/* timer interval */
+    struct timeval it_value;    /* current value */
+};
+
+
+/* timespec64 is defined as timespec here */
+static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
+{
+       return *(const struct timespec *)&ts64;
+}
+
+static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
+{
+       return *(const struct timespec64 *)&ts;
+}
+
+static inline s64 timespec_to_ns(const struct timespec *ts)
+{
+       return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
+}
+
+static inline unsigned long timespec_to_jiffies(const struct timespec *value)
+{
+       struct timespec64 ts = timespec_to_timespec64(*value);
+
+       return timespec64_to_jiffies(&ts);
+}
+
+static inline void jiffies_to_timespec(const unsigned long jiffies,
+                                      struct timespec *value)
+{
+       struct timespec64 ts;
+
+       jiffies_to_timespec64(jiffies, &ts);
+       *value = timespec64_to_timespec(ts);
+}
+
+static inline void getnstimeofday(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       ktime_get_real_ts64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+static inline void getrawmonotonic(struct timespec *ts)
+{
+       struct timespec64 ts64;
+
+       ktime_get_raw_ts64(&ts64);
+       *ts = timespec64_to_timespec(ts64);
+}
+
+extern struct timespec timespec64_to_timespec(const struct timespec64 ts64);
+extern struct timespec64 timespec_to_timespec64(const struct timespec ts);
+extern unsigned long timespec_to_jiffies(const struct timespec *value);
+extern void jiffies_to_timespec(const unsigned long jiffies,
+                                struct timespec *value);
+extern void getnstimeofday(struct timespec *ts);
+extern s64 timespec_to_ns(const struct timespec *ts);
+extern void getrawmonotonic(struct timespec *ts);
+#endif
+
 static inline void nv_gettimeofday(struct timeval *tv)
 {
 #ifdef NV_DO_GETTIMEOFDAY_PRESENT
diff --git a/conftest.sh b/conftest.sh
index e44e5c3..7bb1811 100755
--- a/conftest.sh
+++ b/conftest.sh
@@ -1270,6 +1270,40 @@ compile_test() {
             compile_check_conftest "$CODE" "NV_PROC_REMOVE_PRESENT" "" "functions"
         ;;
 
+        proc_create)
+            #
+            # Determine if the proc_*() function rely on file_operations.
+            #
+            # Added by commit a8ca16ea7b0a ("proc: Supply a function to
+            # Replaced by commit 97a32539b956 ("proc: convert everything
+            # to "struct proc_ops"
+            #
+            CODE="
+            #include <linux/proc_fs.h>
+            #include <linux/seq_file.h>
+
+            static int conftest_proc_show(struct seq_file *m, void *v) {
+                return 0;
+            }
+
+            static int conftest_proc_open(struct inode *inode, struct  file *file) {
+              return single_open(file, conftest_proc_show, NULL);
+            }
+
+            static const struct proc_ops conftest_proc_ops = {
+                .proc_open = conftest_proc_open,
+                .proc_read = seq_read,
+                .proc_lseek = seq_lseek,
+                .proc_release = single_release,
+            };
+
+            void conftest_proc_create(void) {
+                proc_create(\"conftest_proc\", 0, NULL, &conftest_proc_ops);
+            }"
+
+            compile_check_conftest "$CODE" "NV_PROCFS_PROC_OPS_PRESENT" "" "types"
+        ;;
+
         backing_dev_info)
             #
             # Determine if the 'address_space' structure has
@@ -2905,6 +2939,22 @@ compile_test() {
             compile_check_conftest "$CODE" "NV_TIMER_SETUP_PRESENT" "" "functions"
         ;;
 
+        timeval_structs)
+            #
+            # Determine if timespec and timeval structs are present.
+            #
+            # Hidden by commit c766d1472c70 ("y2038: hide timeval/timespec/itimerval/
+            # itimerspec types") (2020-02-20)
+            #
+            CODE="
+            #include <linux/time.h>
+            void conftest_timeval_structs(void) {
+                struct timeval tmp;
+            }"
+            compile_check_conftest "$CODE" "NV_TIME_STRUCTS_PRESENT" "" "types"
+        ;;
+
+
         radix_tree_replace_slot)
             #
             # Determine if the radix_tree_replace_slot() function is
diff --git a/nvidia-modeset/nvidia-modeset.Kbuild b/nvidia-modeset/nvidia-modeset.Kbuild
index 349b337..bb45fa5 100644
--- a/nvidia-modeset/nvidia-modeset.Kbuild
+++ b/nvidia-modeset/nvidia-modeset.Kbuild
@@ -83,9 +83,11 @@ NV_OBJECTS_DEPEND_ON_CONFTEST += $(NVIDIA_MODESET_OBJECTS)
 NV_CONFTEST_TYPE_COMPILE_TESTS += file_inode
 NV_CONFTEST_TYPE_COMPILE_TESTS += file_operations
 NV_CONFTEST_TYPE_COMPILE_TESTS += node_states_n_memory
+NV_CONFTEST_TYPE_COMPILE_TESTS += timeval_structs
+NV_CONFTEST_TYPE_COMPILE_TESTS += proc_create
 NV_CONFTEST_FUNCTION_COMPILE_TESTS += pde_data
 NV_CONFTEST_FUNCTION_COMPILE_TESTS += proc_remove
 NV_CONFTEST_FUNCTION_COMPILE_TESTS += timer_setup
 NV_CONFTEST_FUNCTION_COMPILE_TESTS += do_gettimeofday
 NV_CONFTEST_FUNCTION_COMPILE_TESTS += kthread_create_on_node
-NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_kthread_create_on_node
\ No newline at end of file
+NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_kthread_create_on_node
diff --git a/nvidia-uvm/nvidia-uvm.Kbuild b/nvidia-uvm/nvidia-uvm.Kbuild
index 64cdc26..11f4963 100644
--- a/nvidia-uvm/nvidia-uvm.Kbuild
+++ b/nvidia-uvm/nvidia-uvm.Kbuild
@@ -113,3 +113,5 @@ NV_CONFTEST_TYPE_COMPILE_TESTS += node_states_n_memory
 NV_CONFTEST_TYPE_COMPILE_TESTS += kmem_cache_has_kobj_remove_work
 NV_CONFTEST_TYPE_COMPILE_TESTS += sysfs_slab_unlink
 NV_CONFTEST_TYPE_COMPILE_TESTS += vm_fault_t
+NV_CONFTEST_TYPE_COMPILE_TESTS += timeval_structs
+NV_CONFTEST_TYPE_COMPILE_TESTS += proc_create
diff --git a/nvidia/linux_nvswitch.c b/nvidia/linux_nvswitch.c
index 1d2c1bc..e3560c9 100644
--- a/nvidia/linux_nvswitch.c
+++ b/nvidia/linux_nvswitch.c
@@ -26,6 +26,7 @@
 #include "conftest.h"
 #include "nvmisc.h"
 #include "nv-linux.h"
+#include "nv-time.h"
 #include "nv-procfs.h"
 #include "nvlink_common.h"
 #include "nvlink_errors.h"
diff --git a/nvidia/nv-procfs.c b/nvidia/nv-procfs.c
index 064d727..fc4eefe 100644
--- a/nvidia/nv-procfs.c
+++ b/nvidia/nv-procfs.c
@@ -452,6 +452,15 @@ done:
     return ((status < 0) ? status : (int)count);
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static struct proc_ops nv_procfs_registry_fops = {
+    .proc_open    = nv_procfs_open_registry,
+    .proc_read    = seq_read,
+    .proc_write   = nv_procfs_write_file,
+    .proc_lseek  = seq_lseek,
+    .proc_release = nv_procfs_close_registry,
+};
+#else
 static struct file_operations nv_procfs_registry_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_registry,
@@ -460,6 +469,7 @@ static struct file_operations nv_procfs_registry_fops = {
     .llseek  = seq_lseek,
     .release = nv_procfs_close_registry,
 };
+#endif
 
 #if defined(CONFIG_PM)
 static int
@@ -531,6 +541,15 @@ nv_procfs_open_suspend_depth(
     return single_open(file, nv_procfs_show_suspend_depth, NULL);
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static struct proc_ops nv_procfs_suspend_depth_fops = {
+    .proc_open    = nv_procfs_open_suspend_depth,
+    .proc_read    = seq_read,
+    .proc_write   = nv_procfs_write_suspend_depth,
+    .proc_lseek  = seq_lseek,
+    .proc_release = single_release
+};
+#else
 static struct file_operations nv_procfs_suspend_depth_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_suspend_depth,
@@ -539,6 +558,7 @@ static struct file_operations nv_procfs_suspend_depth_fops = {
     .llseek  = seq_lseek,
     .release = single_release
 };
+#endif
 
 static int
 nv_procfs_show_suspend(
@@ -613,6 +633,15 @@ nv_procfs_open_suspend(
     return single_open(file, nv_procfs_show_suspend, NULL);
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static struct proc_ops nv_procfs_suspend_fops = {
+    .proc_open    = nv_procfs_open_suspend,
+    .proc_read    = seq_read,
+    .proc_write   = nv_procfs_write_suspend,
+    .proc_lseek  = seq_lseek,
+    .proc_release = single_release
+};
+#else
 static struct file_operations nv_procfs_suspend_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_suspend,
@@ -622,6 +651,7 @@ static struct file_operations nv_procfs_suspend_fops = {
     .release = single_release
 };
 #endif
+#endif
 
 /*
  * Forwards error to nv_log_error which exposes data to vendor callback
@@ -724,12 +754,20 @@ done:
     return status;
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static struct proc_ops nv_procfs_exercise_error_forwarding_fops = {
+    .proc_open    = nv_procfs_open_exercise_error_forwarding,
+    .proc_write   = nv_procfs_write_file,
+    .proc_release = nv_procfs_close_exercise_error_forwarding,
+};
+#else
 static struct file_operations nv_procfs_exercise_error_forwarding_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_exercise_error_forwarding,
     .write   = nv_procfs_write_file,
     .release = nv_procfs_close_exercise_error_forwarding,
 };
+#endif
 
 static int
 nv_procfs_read_unbind_lock(
@@ -851,6 +889,15 @@ done:
     return rc;
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static struct proc_ops nv_procfs_unbind_lock_fops = {
+    .proc_open    = nv_procfs_open_unbind_lock,
+    .proc_read    = seq_read,
+    .proc_write   = nv_procfs_write_file,
+    .proc_lseek  = seq_lseek,
+    .proc_release = nv_procfs_close_unbind_lock,
+};
+#else
 static struct file_operations nv_procfs_unbind_lock_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_unbind_lock,
@@ -859,6 +906,7 @@ static struct file_operations nv_procfs_unbind_lock_fops = {
     .llseek  = seq_lseek,
     .release = nv_procfs_close_unbind_lock,
 };
+#endif
 
 static const char*
 numa_status_describe(nv_numa_status_t state)
@@ -1187,6 +1235,22 @@ done:
     return retval;
 }
 
+#if defined(NV_PROCFS_PROC_OPS_PRESENT)
+static const struct proc_ops nv_procfs_numa_status_fops = {
+    .proc_open    = nv_procfs_open_numa_status,
+    .proc_read    = seq_read,
+    .proc_write   = nv_procfs_write_file,
+    .proc_lseek  = seq_lseek,
+    .proc_release = nv_procfs_close_numa_status,
+};
+
+static const struct proc_ops nv_procfs_offline_pages_fops = {
+    .proc_open    = nv_procfs_open_offline_pages,
+    .proc_read    = seq_read,
+    .proc_lseek  = seq_lseek,
+    .proc_release = nv_procfs_close_offline_pages,
+};
+#else
 static const struct file_operations nv_procfs_numa_status_fops = {
     .owner   = THIS_MODULE,
     .open    = nv_procfs_open_numa_status,
@@ -1203,6 +1267,7 @@ static const struct file_operations nv_procfs_offline_pages_fops = {
     .llseek  = seq_lseek,
     .release = nv_procfs_close_offline_pages,
 };
+#endif
 
 static int
 nv_procfs_read_text_file(
diff --git a/nvidia/nvidia.Kbuild b/nvidia/nvidia.Kbuild
index 5ec3e65..e1db498 100644
--- a/nvidia/nvidia.Kbuild
+++ b/nvidia/nvidia.Kbuild
@@ -167,6 +167,8 @@ NV_CONFTEST_TYPE_COMPILE_TESTS += device_of_node
 NV_CONFTEST_TYPE_COMPILE_TESTS += node_states_n_memory
 NV_CONFTEST_TYPE_COMPILE_TESTS += kmem_cache_has_kobj_remove_work
 NV_CONFTEST_TYPE_COMPILE_TESTS += sysfs_slab_unlink
+NV_CONFTEST_TYPE_COMPILE_TESTS += timeval_structs
+NV_CONFTEST_TYPE_COMPILE_TESTS += proc_create
 
 NV_CONFTEST_GENERIC_COMPILE_TESTS += dom0_kernel_present
 NV_CONFTEST_GENERIC_COMPILE_TESTS += nvidia_vgpu_hyperv_available
diff --git a/nvidia/nvlink_linux.c b/nvidia/nvlink_linux.c
index c84b36a..284b30d 100644
--- a/nvidia/nvlink_linux.c
+++ b/nvidia/nvlink_linux.c
@@ -276,7 +276,6 @@ static long nvlink_fops_unlocked_ioctl(struct file *file,
     return nvlink_fops_ioctl(NV_FILE_INODE(file), file, cmd, arg);
 }
 
-
 static const struct file_operations nvlink_fops = {
     .owner           = THIS_MODULE,
     .open            = nvlink_fops_open,
-- 
2.20.1

