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 + 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 + 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 + 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 #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;