diff -ru usr/src/nv/nv.c usr/src/nv.7152258/nv.c --- usr/src/nv/nv.c 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/nv.c 2008-07-15 23:56:46.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; @@ -502,7 +498,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; @@ -754,17 +750,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) @@ -789,7 +786,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, @@ -798,24 +795,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; @@ -870,19 +872,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); @@ -892,31 +897,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 } @@ -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; } @@ -1157,7 +1162,7 @@ return retval; } -#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) { @@ -1190,7 +1195,7 @@ .priority = 0 }; -#endif /* defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) */ +#endif /*** @@ -1199,8 +1204,9 @@ static int __init nvidia_init_module(void) { - int rc; - U032 i, count; + int rc, disable_pat = 0; + U032 i, count, data; + nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device); #if defined(VM_CHECKER) nv_init_lock(vm_lock); @@ -1314,18 +1320,6 @@ nv_printf(NV_DBG_ERRORS, "NVRM: pte cache allocation failed\n"); 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); @@ -1404,15 +1398,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 @@ -1552,15 +1564,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) @@ -1677,7 +1687,8 @@ } } } - +#if !defined(NV_VM_INSERT_PAGE_PRESENT) +static struct page *nv_kern_vma_nopage( struct vm_area_struct *vma, unsigned long address, @@ -1688,22 +1699,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 * @@ -1982,12 +1992,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 @@ -2007,7 +2020,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 @@ -2024,8 +2036,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", @@ -3465,8 +3475,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 -ru usr/src/nv/nv-linux.h usr/src/nv.7152258/nv-linux.h --- usr/src/nv/nv-linux.h 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/nv-linux.h 2008-07-15 23:56:46.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) @@ -954,19 +963,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 @@ -1057,8 +1053,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 -ru usr/src/nv/nv-vm.c usr/src/nv.7152258/nv-vm.c --- usr/src/nv/nv-vm.c 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/nv-vm.c 2008-07-15 23:56:46.000000000 +0200 @@ -360,7 +360,6 @@ #if defined(NV_CPA_NEEDS_FLUSHING) nv_execute_on_all_cpus(cache_flush, NULL); #endif - global_flush_tlb(); #endif } diff -ru usr/src/nv/os-agp.c usr/src/nv.7152258/os-agp.c --- usr/src/nv/os-agp.c 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/os-agp.c 2008-07-15 23:56:46.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 -ru usr/src/nv/os-interface.c usr/src/nv.7152258/os-interface.c --- usr/src/nv/os-interface.c 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/os-interface.c 2008-07-15 23:56:46.000000000 +0200 @@ -1260,7 +1260,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 -ru usr/src/nv/os-registry.c usr/src/nv.7152258/os-registry.c --- usr/src/nv/os-registry.c 2008-01-23 05:12:23.000000000 +0100 +++ usr/src/nv.7152258/os-registry.c 2008-07-15 23:56:46.000000000 +0200 @@ -483,6 +483,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 @@ -517,6 +526,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 } };