diff --git a/kernel/Makefile b/kernel/Makefile
index 125a690..a36cc63 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -108,12 +108,14 @@ COMPILE_TESTS = \
 	acquire_console_sem \
 	console_lock \
 	kmem_cache_create \
+	kmem_cache_create_usercopy \
 	outer_flush_all \
 	on_each_cpu \
 	smp_call_function \
 	nvmap_support \
 	acpi_evaluate_integer \
 	ioremap_cache \
+	ioremap_nocache \
 	ioremap_wc \
 	proc_dir_entry \
 	INIT_WORK \
@@ -122,6 +124,7 @@ COMPILE_TESTS = \
 	pci_domain_nr \
 	pci_dma_mapping_error \
 	file_operations \
+	proc_ops \
 	sg_alloc_table \
 	sg_init_table \
 	pci_get_domain_bus_and_slot \
diff --git a/kernel/conftest.sh b/kernel/conftest.sh
index b7a85f0..83700ad 100755
--- a/kernel/conftest.sh
+++ b/kernel/conftest.sh
@@ -914,6 +914,21 @@ compile_test() {
             fi
         ;;
 
+        kmem_cache_create_usercopy)
+            #
+            # Determine if the kmem_cache_create_usercopy function exists.
+            #
+            # This function was added by:
+            #   2017-06-10  8eb8284b412906181357c2b0110d879d5af95e52
+            CODE="
+            #include <linux/slab.h>
+            void kmem_cache_create_usercopy(void) {
+                kmem_cache_create_usercopy();
+            }"
+
+            compile_check_conftest "$CODE" "NV_KMEM_CACHE_CREATE_USERCOPY_PRESENT" "" "functions"
+        ;;
+
         smp_call_function)
             #
             # Determine if the smp_call_function() function is
@@ -1188,6 +1203,22 @@ compile_test() {
             compile_check_conftest "$CODE" "NV_IOREMAP_CACHE_PRESENT" "" "functions"
         ;;
 
+        ioremap_nocache)
+            #
+            # Determine if the ioremap_nocache() function is present.
+            #
+            # Removed by commit 4bdc0d676a64 ("remove ioremap_nocache and
+            # devm_ioremap_nocache") in v5.6 (2020-01-06)
+            #
+            CODE="
+            #include <asm/io.h>
+            void conftest_ioremap_nocache(void) {
+                ioremap_nocache();
+            }"
+
+            compile_check_conftest "$CODE" "NV_IOREMAP_NOCACHE_PRESENT" "" "functions"
+        ;;
+
         ioremap_wc)
             #
             # Determine if the ioremap_wc() function is present.
@@ -1371,6 +1402,16 @@ compile_test() {
             compile_check_conftest "$CODE" "NV_FILE_OPERATIONS_HAS_COMPAT_IOCTL" "" "types"
         ;;
 
+        proc_ops)
+            CODE="
+            #include <linux/proc_fs.h>
+            int conftest_proc_ops(void) {
+                return offsetof(struct proc_ops, proc_open);
+            }"
+
+            compile_check_conftest "$CODE" "NV_HAVE_PROC_OPS" "" "types"
+        ;;
+
         sg_init_table)
             #
             # Determine if the sg_init_table() function is present.
diff --git a/kernel/dkms.conf b/kernel/dkms.conf
index 79a02ae..3140f03 100644
--- a/kernel/dkms.conf
+++ b/kernel/dkms.conf
@@ -1,7 +1,13 @@
+if [ -x /usr/bin/nproc ]; then
+  num_cpu_cores=$(nproc)
+else
+  num_cpu_cores=1
+fi
+
 PACKAGE_NAME="nvidia"
 PACKAGE_VERSION="340.108"
 BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
 DEST_MODULE_LOCATION[0]="/kernel/drivers/video"
-MAKE[0]="make module KERNEL_UNAME=${kernelver}"
+MAKE[0]="make -j$num_cpu_cores module KERNEL_UNAME=${kernelver}"
 CLEAN="make clean"
 AUTOINSTALL="yes"
diff --git a/kernel/nv-drm.c b/kernel/nv-drm.c
index 0d1cdbf..2e4b867 100644
--- a/kernel/nv-drm.c
+++ b/kernel/nv-drm.c
@@ -50,6 +50,60 @@
 #if defined(NV_DRM_LEGACY_PCI_INIT_PRESENT)
 #define nv_drm_pci_init drm_legacy_pci_init
 #define nv_drm_pci_exit drm_legacy_pci_exit
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+int nv_drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
+{
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *pid;
+	int i;
+
+	DRM_DEBUG("\n");
+
+	if (WARN_ON(!(driver->driver_features & DRIVER_LEGACY)))
+		return -EINVAL;
+
+	/* If not using KMS, fall back to stealth mode manual scanning. */
+	INIT_LIST_HEAD(&driver->legacy_dev_list);
+	for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
+		pid = &pdriver->id_table[i];
+
+		/* Loop around setting up a DRM device for each PCI device
+		 * matching our ID and device class.  If we had the internal
+		 * function that pci_get_subsys and pci_get_class used, we'd
+		 * be able to just pass pid in instead of doing a two-stage
+		 * thing.
+		 */
+		pdev = NULL;
+		while ((pdev =
+			pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
+				       pid->subdevice, pdev)) != NULL) {
+			if ((pdev->class & pid->class_mask) != pid->class)
+				continue;
+
+			/* stealth mode requires a manual probe */
+			pci_dev_get(pdev);
+			drm_get_pci_dev(pdev, pid, driver);
+		}
+	}
+	return 0;
+}
+
+void nv_drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
+{
+	struct drm_device *dev, *tmp;
+	DRM_DEBUG("\n");
+
+	if (!(driver->driver_features & DRIVER_LEGACY)) {
+		WARN_ON(1);
+	} else {
+		list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
+					 legacy_dev_list) {
+			list_del(&dev->legacy_dev_list);
+			drm_put_dev(dev);
+		}
+	}
+	DRM_INFO("Module unloaded\n");
+}
 #else
 #define nv_drm_pci_init drm_pci_init
 #define nv_drm_pci_exit drm_pci_exit
diff --git a/kernel/nv-linux.h b/kernel/nv-linux.h
index a1d2c68..83e6433 100644
--- a/kernel/nv-linux.h
+++ b/kernel/nv-linux.h
@@ -688,11 +688,16 @@ extern nv_spinlock_t km_lock;
         VM_ALLOC_RECORD(ptr, size, "vm_ioremap"); \
     }
 
+#if defined(NV_IOREMAP_NOCACHE_PRESENT)
 #define NV_IOREMAP_NOCACHE(ptr, physaddr, size) \
     { \
         (ptr) = ioremap_nocache(physaddr, size); \
         VM_ALLOC_RECORD(ptr, size, "vm_ioremap_nocache"); \
     }
+#else
+#define NV_IOREMAP_NOCACHE(ptr, physaddr, size) \
+    NV_IOREMAP(ptr, physaddr, size)
+#endif
 
 #if defined(NV_IOREMAP_CACHE_PRESENT)
 #define NV_IOREMAP_CACHE(ptr, physaddr, size)            \
@@ -774,6 +779,17 @@ extern nv_spinlock_t km_lock;
 #error "NV_KMEM_CACHE_CREATE() undefined (kmem_cache_create() unavailable)!"
 #endif
 
+#if defined(NV_KMEM_CACHE_CREATE_USERCOPY_PRESENT)
+#define NV_KMEM_CACHE_CREATE_USERCOPY(kmem_cache, name, type)       \
+    {                                                               \
+        kmem_cache = kmem_cache_create_usercopy(name, sizeof(type), \
+                        0, 0, 0, sizeof(type), NULL);               \
+    }
+#else
+#define NV_KMEM_CACHE_CREATE_USERCOPY(kmem_cache, name, type)       \
+        NV_KMEM_CACHE_CREATE(kmem_cache, name, type)
+#endif
+
 #define NV_KMEM_CACHE_ALLOC(ptr, kmem_cache, type)              \
     {                                                           \
         (ptr) = kmem_cache_alloc(kmem_cache, GFP_KERNEL);       \
@@ -1971,6 +1987,19 @@ extern NvU32 nv_assign_gpu_count;
     })
 #endif
 
+#if defined(NV_HAVE_PROC_OPS)
+#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 = NV_CREATE_PROC_ENTRY(filename, mode, parent, fops,     \
+            __data);                                                     \
+        __entry;                                                         \
+    })
+#else
 #define NV_CREATE_PROC_FILE(filename,parent,__name,__data)               \
    ({                                                                    \
         struct proc_dir_entry *__entry;                                  \
@@ -1982,6 +2011,7 @@ extern NvU32 nv_assign_gpu_count;
             __data);                                                     \
         __entry;                                                         \
     })
+#endif
 
 /*
  * proc_mkdir_mode exists in Linux 2.6.9, but isn't exported until Linux 3.0.
@@ -2023,6 +2053,24 @@ extern NvU32 nv_assign_gpu_count;
     remove_proc_entry(entry->name, entry->parent);
 #endif
 
+#if defined(NV_HAVE_PROC_OPS)
+#define NV_DEFINE_PROCFS_SINGLE_FILE(__name)                                  \
+    static int nv_procfs_open_##__name(                                       \
+        struct inode *inode,                                                  \
+        struct file *filep                                                    \
+    )                                                                         \
+    {                                                                         \
+        return single_open(filep, nv_procfs_read_##__name,                    \
+            NV_PDE_DATA(inode));                                              \
+    }                                                                         \
+                                                                              \
+    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    = single_release,                                    \
+    };
+#else
 #define NV_DEFINE_PROCFS_SINGLE_FILE(__name)                                  \
     static int nv_procfs_open_##__name(                                       \
         struct inode *inode,                                                  \
@@ -2040,6 +2088,7 @@ extern NvU32 nv_assign_gpu_count;
         .llseek     = seq_lseek,                                              \
         .release    = single_release,                                         \
     };
+#endif
 
 #endif  /* CONFIG_PROC_FS */
 
diff --git a/kernel/nv-procfs.c b/kernel/nv-procfs.c
index ebca3e8..9365c3c 100644
--- a/kernel/nv-procfs.c
+++ b/kernel/nv-procfs.c
@@ -409,6 +409,15 @@ done:
     return ((status < 0) ? status : (int)count);
 }
 
+#if defined(NV_HAVE_PROC_OPS)
+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,
@@ -417,6 +426,7 @@ static struct file_operations nv_procfs_registry_fops = {
     .llseek  = seq_lseek,
     .release = nv_procfs_close_registry,
 };
+#endif
 
 static int
 nv_procfs_read_unbind_lock(
@@ -538,6 +548,15 @@ done:
     return rc;
 }
 
+#if defined(NV_HAVE_PROC_OPS)
+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,
@@ -546,6 +565,7 @@ static struct file_operations nv_procfs_unbind_lock_fops = {
     .llseek  = seq_lseek,
     .release = nv_procfs_close_unbind_lock,
 };
+#endif
 
 static int
 nv_procfs_read_text_file(
diff --git a/kernel/nv-time.h b/kernel/nv-time.h
index a34ceb2..780f8bc 100644
--- a/kernel/nv-time.h
+++ b/kernel/nv-time.h
@@ -28,7 +28,12 @@
 #include <linux/ktime.h>
 #endif
 
-static inline void nv_gettimeofday(struct timeval *tv)
+struct nv_timeval {
+    __kernel_long_t      tv_sec;
+    __kernel_suseconds_t tv_usec;
+};
+
+static inline void nv_gettimeofday(struct nv_timeval *tv)
 {
 #ifdef NV_DO_GETTIMEOFDAY_PRESENT
     do_gettimeofday(tv);
@@ -37,7 +42,7 @@ static inline void nv_gettimeofday(struct timeval *tv)
 
     ktime_get_real_ts64(&now);
 
-    *tv = (struct timeval) {
+    *tv = (struct nv_timeval) {
         .tv_sec = now.tv_sec,
         .tv_usec = now.tv_nsec/1000,
     };
diff --git a/kernel/nv.c b/kernel/nv.c
index a167be9..a218f83 100644
--- a/kernel/nv.c
+++ b/kernel/nv.c
@@ -752,7 +752,7 @@ int __init nvidia_init_module(void)
     NV_SPIN_LOCK_INIT(&km_lock);
 #endif
 
-    NV_KMEM_CACHE_CREATE(nv_stack_t_cache, NV_STACK_CACHE_STR, nv_stack_t);
+    NV_KMEM_CACHE_CREATE_USERCOPY(nv_stack_t_cache, NV_STACK_CACHE_STR, nv_stack_t);
     if (nv_stack_t_cache == NULL)
     {
         nv_printf(NV_DBG_ERRORS, "NVRM: stack cache allocation failed!\n");
diff --git a/kernel/os-interface.c b/kernel/os-interface.c
index 7190b26..0c0dc05 100644
--- a/kernel/os-interface.c
+++ b/kernel/os-interface.c
@@ -439,7 +439,7 @@ RM_STATUS NV_API_CALL os_get_current_time(
     NvU32 *useconds
 )
 {
-    struct timeval tm;
+    struct nv_timeval tm;
 
     nv_gettimeofday(&tm);
 
@@ -474,7 +474,7 @@ RM_STATUS NV_API_CALL os_delay_us(NvU32 MicroSeconds)
     unsigned long usec;
 
 #ifdef NV_CHECK_DELAY_ACCURACY
-    struct timeval tm1, tm2;
+    struct nv_timeval tm1, tm2;
 
     nv_gettimeofday(&tm1);
 #endif
@@ -514,9 +514,9 @@ RM_STATUS NV_API_CALL os_delay(NvU32 MilliSeconds)
     unsigned long MicroSeconds;
     unsigned long jiffies;
     unsigned long mdelay_safe_msec;
-    struct timeval tm_end, tm_aux;
+    struct nv_timeval tm_end, tm_aux;
 #ifdef NV_CHECK_DELAY_ACCURACY
-    struct timeval tm_start;
+    struct nv_timeval tm_start;
 #endif
 
     nv_gettimeofday(&tm_aux);
diff --git a/kernel/uvm/Makefile b/kernel/uvm/Makefile
index 0cad8ff..043a08d 100644
--- a/kernel/uvm/Makefile
+++ b/kernel/uvm/Makefile
@@ -207,6 +207,7 @@ ccflags-y += $(EXTRA_CFLAGS)
 
 RM_MODULE_SYMVERS:= $(RM_OUT_DIR)/Module.symvers
 UVM_MODULE_SYMVERS:= $(obj)/Module.symvers
+KBUILD_EXTRA_SYMBOLS:= $(UVM_MODULE_SYMVERS)
 
 module $(MODULE_NAME).ko: $(UVM_MODULE_SYMVERS) debug_diagnostics_printing
 
diff --git a/kernel/uvm/nvidia_uvm_lite.c b/kernel/uvm/nvidia_uvm_lite.c
index 6943e7c..9a7e3b6 100644
--- a/kernel/uvm/nvidia_uvm_lite.c
+++ b/kernel/uvm/nvidia_uvm_lite.c
@@ -131,8 +131,8 @@ static
 RM_STATUS _preexisting_error_on_channel(UvmGpuMigrationTracking *pMigTracker,
                                          UvmCommitRecord *pRecord);
 
-static void _set_timeout_in_usec(struct timeval *src,
-                                 struct timeval *result,
+static void _set_timeout_in_usec(struct nv_timeval *src,
+                                 struct nv_timeval *result,
                                  unsigned long timeoutInUsec)
 {
     if (!src || !result)
@@ -820,7 +820,13 @@ done:
 }
 
 #if defined(NV_VM_OPERATIONS_STRUCT_HAS_FAULT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+vm_fault_t _fault(struct vm_fault *vmf)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+int _fault(struct vm_fault *vmf)
+#else
 int _fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+#endif
 {
 #if defined(NV_VM_FAULT_HAS_ADDRESS)
     unsigned long vaddr = vmf->address;
@@ -828,8 +834,15 @@ int _fault(struct vm_area_struct *vma, struct vm_fault *vmf)
     unsigned long vaddr = (unsigned long)vmf->virtual_address;
 #endif
     struct page *page = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+    vm_fault_t retval;
+#else
     int retval;
 
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+   struct vm_area_struct *vma = vmf->vma;
+#endif
     retval = _fault_common(vma, vaddr, &page, vmf->flags);
 
     vmf->page = page;
@@ -868,7 +881,13 @@ static struct vm_operations_struct uvmlite_vma_ops =
 // it's dealing with anonymous mapping (see handle_pte_fault).
 //
 #if defined(NV_VM_OPERATIONS_STRUCT_HAS_FAULT)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
+vm_fault_t _sigbus_fault(struct vm_fault *vmf)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+int _sigbus_fault(struct vm_fault *vmf)
+#else
 int _sigbus_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+#endif
 {
     vmf->page = NULL;
     return VM_FAULT_SIGBUS;
@@ -1992,9 +2011,9 @@ void umvlite_destroy_per_process_gpu_resources(UvmGpuUuid *gpuUuidStruct)
 static RM_STATUS _check_ecc_errors(UvmGpuMigrationTracking *pMigTracker,
                                     NvBool *pIsEccErrorSet)
 {
-    struct timeval eccErrorStartTime = {0};
-    struct timeval eccErrorCurrentTime = {0};
-    struct timeval eccTimeout = {0};
+    struct nv_timeval eccErrorStartTime = {0};
+    struct nv_timeval eccErrorCurrentTime = {0};
+    struct nv_timeval eccTimeout = {0};
     NvBool bEccErrorTimeout = NV_FALSE;
     NvBool bEccIncomingError = NV_FALSE;
     unsigned rmInterruptSet = 0;
