diff -ur ./usr/src/nv/nv-linux.h /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/nv-linux.h --- ./usr/src/nv/nv-linux.h 2008-05-26 14:41:35.000000000 +0200 +++ /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/nv-linux.h 2008-05-26 12:18:16.000000000 +0200 @@ -139,16 +139,18 @@ #endif #if defined(NVCPU_X86) || defined(NVCPU_X86_64) -#define NV_BUILD_NV_PAT_SUPPORT 1 +#define NV_ENABLE_PAT_SUPPORT 1 #endif +#define NV_PAT_MODE_DISABLED 0 +#define NV_PAT_MODE_KERNEL 1 +#define NV_PAT_MODE_BUILTIN 2 + +extern int nv_pat_mode; -#if defined(NV_BUILD_NV_PAT_SUPPORT) -#include "pat.h" #if defined(CONFIG_HOTPLUG_CPU) #include /* CPU hotplug support */ #include /* struct notifier_block, etc */ #endif -#endif #if (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) #include @@ -630,6 +632,13 @@ #define nv_down(lock) down(&lock) #define nv_up(lock) up(&lock) +#define NV_INIT_MUTEX(mutex) \ + { \ + struct semaphore __mutex = \ + __SEMAPHORE_INITIALIZER(*(mutex), 1); \ + *(mutex) = __mutex; \ + } + #if defined (KERNEL_2_4) # define NV_IS_SUSER() suser() # define NV_PCI_DEVICE_NAME(dev) ((dev)->name) @@ -955,19 +964,6 @@ } #endif -#if defined(NV_BUILD_NV_PAT_SUPPORT) && !defined (pgprot_writecombined) -static inline pgprot_t pgprot_writecombined(pgprot_t old_prot) - { - pgprot_t new_prot = old_prot; - if (boot_cpu_data.x86 > 3) - { - pgprot_val(old_prot) &= ~(_PAGE_PCD | _PAGE_PWT); - new_prot = __pgprot(pgprot_val(old_prot) | _PAGE_WRTCOMB); - } - return new_prot; - } -#endif - #if defined(KERNEL_2_4) && defined(NVCPU_X86) && !defined(pfn_to_page) #define pfn_to_page(pfn) (mem_map + (pfn)) #endif @@ -1058,8 +1054,6 @@ struct semaphore at_lock; } nv_linux_state_t; -extern int nv_pat_enabled; - /* * file-private data * hide a pointer to our data structures in a file-private ptr diff -ur ./usr/src/nv/nv.c /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/nv.c --- ./usr/src/nv/nv.c 2008-05-26 14:41:35.000000000 +0200 +++ /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/nv.c 2008-05-26 15:02:52.000000000 +0200 @@ -21,10 +21,9 @@ #endif #if defined(KERNEL_2_4) && (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) -// weak linking? extern int i2c_add_adapter (struct i2c_adapter *) __attribute__ ((weak)); extern int i2c_del_adapter (struct i2c_adapter *) __attribute__ ((weak)); -#endif // defined(KERNEL_2_4) && (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) +#endif /* * our global state; one per device @@ -40,10 +39,7 @@ static struct pm_dev *apm_nv_dev[NV_MAX_DEVICES] = { 0 }; #endif -int nv_pat_enabled = 0; - -static int nv_disable_pat = 0; -NV_MODULE_PARAMETER(nv_disable_pat); +int nv_pat_mode = NV_PAT_MODE_DISABLED; #if defined(NVCPU_X86) || defined(NVCPU_X86_64) NvU64 __nv_supported_pte_mask = ~_PAGE_NX; @@ -499,7 +495,7 @@ nv_state_t *nv; nv_linux_state_t *nvl; - proc_nvidia = create_proc_entry("nvidia", d_flags, proc_root_driver); + proc_nvidia = create_proc_entry("driver/nvidia", d_flags, NULL); if (!proc_nvidia) goto failed; @@ -751,17 +747,18 @@ static int __nv_enable_pat_support (void); static void __nv_disable_pat_support (void); -#if defined(NV_BUILD_NV_PAT_SUPPORT) +#if defined(NV_ENABLE_PAT_SUPPORT) /* - * Private PAT support for use by the NVIDIA driver. This is an - * interim solution until the kernel offers PAT support. + * Private PAT support for use by the NVIDIA driver. This is used + * on kernels that do not modify the PAT to include a write-combining + * entry. */ static int __check_pat_support (void); static void __nv_setup_pat_entries (void *); static void __nv_restore_pat_entries (void *); -#define NV_READ_PAT_ENTRIES(pat1, pat2) rdmsr(IA32_CR_PAT, (pat1), (pat2)) -#define NV_WRITE_PAT_ENTRIES(pat1, pat2) wrmsr(IA32_CR_PAT, (pat1), (pat2)) +#define NV_READ_PAT_ENTRIES(pat1, pat2) rdmsr(0x277, (pat1), (pat2)) +#define NV_WRITE_PAT_ENTRIES(pat1, pat2) wrmsr(0x277, (pat1), (pat2)) #define NV_PAT_ENTRY(pat, index) (((pat) & (0xff<<((index)*8)))>>((index)*8)) static inline void __nv_disable_caches(unsigned long *cr4) @@ -786,7 +783,7 @@ static int __check_pat_support() { unsigned int pat1, pat2, i; - + U008 PAT_WC_index; if (!test_bit(X86_FEATURE_PAT, (volatile unsigned long *)&boot_cpu_data.x86_capability)) { nv_printf(NV_DBG_ERRORS, @@ -795,24 +792,29 @@ } NV_READ_PAT_ENTRIES(pat1, pat2); + PAT_WC_index = 0xf; for (i = 0; i < 4; i++) { - // we plan to mark PAT entry 1 as WC. if it's already marked such, - // that's fine, since it would be no different than us setting it. - if ((i != 1) && NV_PAT_ENTRY(pat1, i) == 1) - { - nv_printf(NV_DBG_ERRORS, "NVRM: PAT index %d already configured for Write-Combining!\n", i); - nv_printf(NV_DBG_ERRORS, "NVRM: Aborting, due to PAT already being configured\n"); - return 0; - } - - if (NV_PAT_ENTRY(pat2, i) == 1) - { - nv_printf(NV_DBG_ERRORS, "NVRM: PAT index %d already configured for Write-Combining!\n", i + 4); - nv_printf(NV_DBG_ERRORS, "NVRM: Aborting, due to PAT already being configured\n"); - return 0; - } + if (NV_PAT_ENTRY(pat1, i) == 0x01) + { + PAT_WC_index = i; + break; + } + if (NV_PAT_ENTRY(pat2, i) == 0x01) + { + PAT_WC_index = i + 4; + break; + } + } + + if (PAT_WC_index == 1) + nv_pat_mode = NV_PAT_MODE_KERNEL; + else if (PAT_WC_index != 0xf) + { + nv_printf(NV_DBG_ERRORS, + "NVRM: PAT configuration unsupported, falling back to MTRRs.\n"); + return 0; } return 1; @@ -867,19 +869,22 @@ NV_RESTORE_FLAGS(eflags); } -#endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */ +#endif static int __nv_enable_pat_support() { -#if defined(NV_BUILD_NV_PAT_SUPPORT) +#if defined(NV_ENABLE_PAT_SUPPORT) unsigned long pat1, pat2; - if (nv_pat_enabled) + if (nv_pat_mode != NV_PAT_MODE_DISABLED) return 1; if (!__check_pat_support()) return 0; + if (nv_pat_mode != NV_PAT_MODE_DISABLED) + return 1; + NV_READ_PAT_ENTRIES(orig_pat1, orig_pat2); nv_printf(NV_DBG_SETUP, "saved orig pats as 0x%lx 0x%lx\n", orig_pat1, orig_pat2); @@ -889,31 +894,31 @@ return 0; } - nv_pat_enabled = 1; + nv_pat_mode = NV_PAT_MODE_BUILTIN; NV_READ_PAT_ENTRIES(pat1, pat2); nv_printf(NV_DBG_SETUP, "changed pats to 0x%lx 0x%lx\n", pat1, pat2); -#endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */ +#endif return 1; } static void __nv_disable_pat_support() { -#if defined(NV_BUILD_NV_PAT_SUPPORT) +#if defined(NV_ENABLE_PAT_SUPPORT) unsigned long pat1, pat2; - if (!nv_pat_enabled) + if (!nv_pat_mode != NV_PAT_MODE_BUILTIN) return; if (nv_execute_on_all_cpus(__nv_restore_pat_entries, NULL) != 0) return; - nv_pat_enabled = 0; + nv_pat_mode = NV_PAT_MODE_DISABLED; NV_READ_PAT_ENTRIES(pat1, pat2); nv_printf(NV_DBG_SETUP, "restored orig pats as 0x%lx 0x%lx\n", pat1, pat2); -#endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */ +#endif } #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) @@ -1130,7 +1135,7 @@ break; default: expected = pgprot_val(PAGE_KERNEL_NOCACHE); - if ((flags & ~_PAGE_NX) == (expected & ~_PAGE_NX)) + if ((flags & ~(_PAGE_NX | _PAGE_PWT)) == (expected & ~(_PAGE_NX | _PAGE_PWT))) retval = 0; break; } @@ -1161,7 +1166,7 @@ #endif } -#if defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) +#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) static int nv_kern_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -1194,7 +1199,7 @@ .priority = 0 }; -#endif /* defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) */ +#endif /*** @@ -1203,7 +1208,7 @@ static int __init nvidia_init_module(void) { - int rc; + int rc, disable_pat = 0; U032 i, count, data; nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device); @@ -1320,18 +1325,6 @@ goto failed; } -#if defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) - if (!nv_disable_pat) - { - if (register_hotcpu_notifier(&nv_hotcpu_nfb) != 0) - { - rc = -EIO; - nv_printf(NV_DBG_ERRORS, "NVRM: CPU hotplug notifier registration failed!\n"); - goto failed; - } - } -#endif - #if defined(NV_SG_MAP_BUFFERS) rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "RemapLimit", &nv_remap_limit); @@ -1407,15 +1400,33 @@ nvos_proc_add_warning_file("README", __README_warning); -#if defined(NV_BUILD_NV_PAT_SUPPORT) - if (!nv_disable_pat) + rc = rm_read_registry_dword(nv, "NVreg", "UsePageAttributeTable", &data); + if ((rc == 0) && ((int)data != ~0)) + { + disable_pat = (data == 0); + } + if (!disable_pat) + { __nv_enable_pat_support(); +#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) + if (nv_pat_mode == NV_PAT_MODE_BUILTIN) + { + if (register_hotcpu_notifier(&nv_hotcpu_nfb) != 0) + { + __nv_disable_pat_support(); + rc = -EIO; + nv_printf(NV_DBG_ERRORS, + "NVRM: CPU hotplug notifier registration failed!\n"); + goto failed; + } + } +#endif + } else { nv_printf(NV_DBG_ERRORS, "NVRM: builtin PAT support disabled, falling back to MTRRs.\n"); } -#endif #if (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)) && defined(KERNEL_2_4) // attempt to load the i2c modules for linux kernel @@ -1555,15 +1566,13 @@ rm_unregister_ioctl_conversions(); #endif -#if defined(NV_BUILD_NV_PAT_SUPPORT) - if (nv_pat_enabled) + if (nv_pat_mode == NV_PAT_MODE_BUILTIN) { __nv_disable_pat_support(); -#if defined(CONFIG_HOTPLUG_CPU) +#if defined(NV_ENABLE_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) unregister_hotcpu_notifier(&nv_hotcpu_nfb); #endif } -#endif #if defined(NV_ENABLE_MEM_TRACKING) #if defined(VM_CHECKER) @@ -1680,7 +1689,8 @@ } } } - +#if !defined(NV_VM_INSERT_PAGE_PRESENT) +static struct page *nv_kern_vma_nopage( struct vm_area_struct *vma, unsigned long address, @@ -1691,22 +1701,21 @@ #endif ) { -#if !defined(NV_VM_INSERT_PAGE_PRESENT) struct page *page; page = pfn_to_page(vma->vm_pgoff); get_page(page); return page; -#else - return NOPAGE_SIGBUS; -#endif } +#endif struct vm_operations_struct nv_vm_ops = { .open = nv_kern_vma_open, .close = nv_kern_vma_release, /* "close" */ +#if !defined(NV_VM_INSERT_PAGE_PRESENT) .nopage = nv_kern_vma_nopage, +#endif }; static nv_file_private_t * @@ -1985,12 +1994,15 @@ *prot = pgprot_noncached(*prot); break; case NV_MEMORY_WRITECOMBINED: - if (nv_pat_enabled && +#if defined(NV_ENABLE_PAT_SUPPORT) + if ((nv_pat_mode != NV_PAT_MODE_DISABLED) && (memory_type != NV_MEMORY_TYPE_REGISTERS)) { - *prot = pgprot_writecombined(*prot); + pgprot_val(*prot) &= ~(_PAGE_PSE | _PAGE_PCD | _PAGE_PWT); + *prot = __pgprot(pgprot_val(*prot) | _PAGE_PWT); break; } +#endif /* * If PAT support is unavailable and the memory space isn't * NV_MEMORY_TYPE_AGP, we need to return an error code to @@ -2010,7 +2022,6 @@ break; return 1; case NV_MEMORY_CACHED: - //case NV_MEMORY_WRITEBACK: /* * RAM is cached on Linux by default, we can assume there's * nothing to be done here. This is not the case for the @@ -2027,8 +2038,6 @@ */ if (memory_type == NV_MEMORY_TYPE_SYSTEM) break; - //case NV_MEMORY_WRITETHRU: - //case NV_MEMORY_WRITEPROTECT: default: nv_printf(NV_DBG_ERRORS, "NVRM: VM: memory type %d not supported for memory space %d!\n", @@ -3239,15 +3248,7 @@ down_read(&mm->mmap_sem); } else - { -#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86) - /* nv_printf(NV_DBG_ERRORS, - "NVRM: can't translate KVA in nv_get_phys_address()!\n"); */ - return 0; -#else mm = NULL; -#endif - } pgd = NV_PGD_OFFSET(address, kern, mm); if (!NV_PGD_PRESENT(pgd)) @@ -3483,8 +3484,9 @@ nv_init_lock(nvl->rm_lock); - sema_init(&nvl->ldata_lock, 1); - sema_init(&nvl->at_lock, 1); + NV_INIT_MUTEX(&nvl->ldata_lock); + NV_INIT_MUTEX(&nvl->at_lock); + NV_ATOMIC_SET(nvl->usage_count, 0); nvl->rm_lock_cpu = -1; diff -ur ./usr/src/nv/os-agp.c /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-agp.c --- ./usr/src/nv/os-agp.c 2008-01-23 03:19:52.000000000 +0100 +++ /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-agp.c 2008-05-26 14:17:07.000000000 +0200 @@ -112,7 +112,7 @@ goto release; } - if (!nv_pat_enabled) + if (nv_pat_mode == NV_PAT_MODE_DISABLED) { #ifdef CONFIG_MTRR /* @@ -171,7 +171,7 @@ failed: #ifdef CONFIG_MTRR - if (!nv_pat_enabled) + if (nv_pat_mode == NV_PAT_MODE_DISABLED) mtrr_del(-1, agp_info.aper_base, agp_info.aper_size << 20); #endif release: @@ -199,7 +199,7 @@ nvl = NV_GET_NVL_FROM_NV_STATE(nv); #ifdef CONFIG_MTRR - if (!nv_pat_enabled) + if (nv_pat_mode == NV_PAT_MODE_DISABLED) mtrr_del(-1, nv->agp.address, nv->agp.size); #endif diff -ur ./usr/src/nv/os-interface.c /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-interface.c --- ./usr/src/nv/os-interface.c 2008-05-26 14:41:35.000000000 +0200 +++ /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-interface.c 2008-05-26 14:17:40.000000000 +0200 @@ -1275,7 +1275,7 @@ BOOL NV_API_CALL os_pat_supported(void) { - return nv_pat_enabled; + return nv_pat_mode != NV_PAT_MODE_DISABLED; } void NV_API_CALL os_dump_stack() diff -ur ./usr/src/nv/os-registry.c /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-registry.c --- ./usr/src/nv/os-registry.c 2008-05-26 14:41:35.000000000 +0200 +++ /home/jon/NVIDIA-Linux-x86_64-96.43.05-pkg2/usr/src/nv/os-registry.c 2008-05-26 15:10:46.000000000 +0200 @@ -485,6 +485,15 @@ static int NVreg_RMEdgeIntrCheck = 1; NV_MODULE_PARAMETER(NVreg_RMEdgeIntrCheck); + +// Option: UsePageAttributeTable +// Possible values: +// ~0 = use the NVIDIA driver's default logic (default) +// 1 = enable use of PAT for WC mappings. +// 2 = disable use of the PAT for WC mappings. +static int NVreg_UsePageAttributeTable = 0; +NV_MODULE_PARAMETER(NVreg_UsePageAttributeTable); + /* * You can enable any of the registry options disabled by default by * editing their respective entries in the table below. The last field @@ -519,6 +528,7 @@ { "NVreg", "PanelPWMFrequency", &NVreg_PanelPWMFrequency, 1 }, { "NVreg", "PanelBrightnessLimits", &NVreg_PanelBrightnessLimits, 1 }, { "NVreg", "RMEdgeIntrCheck", &NVreg_RMEdgeIntrCheck, 1 }, + { "NVreg", "UsePageAttributeTable", &NVreg_UsePageAttributeTable, 1 }, { NULL, NULL, NULL, 0 } };