diff -ru usr/src/nv/Makefile.kbuild usr/src/nv.2305230/Makefile.kbuild
--- usr/src/nv/Makefile.kbuild	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/Makefile.kbuild	2008-03-18 12:55:25.461856977 -0700
@@ -176,6 +176,7 @@
 	vmap \
 	signal_struct \
 	agp_backend_acquire \
+	set_pages_uc \
 	change_page_attr \
 	pci_get_class \
 	sysctl_max_map_count \
diff -ru usr/src/nv/conftest.sh usr/src/nv.2305230/conftest.sh
--- usr/src/nv/conftest.sh	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/conftest.sh	2008-03-18 12:55:28.782046180 -0700
@@ -100,6 +100,32 @@
             fi
         ;;
 
+        set_pages_uc)
+            #
+            # Determine if the set_pages_uc() function is present.
+            #
+            echo "#include <linux/autoconf.h>
+            #include <asm/cacheflush.h>
+            void conftest_set_pages_uc(void) {
+                set_pages_uc();
+            }" > conftest$$.c
+
+            $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1
+            rm -f conftest$$.c
+
+            if [ -f conftest$$.o ]; then
+                rm -f conftest$$.o
+                echo "#undef NV_SET_PAGES_UC_PRESENT" >> conftest.h
+                return
+            else
+                echo "#ifdef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
+                echo "#undef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
+                echo "#endif"                             >> conftest.h
+                echo "#define NV_SET_PAGES_UC_PRESENT"    >> conftest.h
+                return
+            fi
+        ;;
+
         change_page_attr)
             #
             # Determine if the change_page_attr() function is
@@ -124,7 +150,9 @@
                 rm -f conftest$$.o
                 return
             else
+                echo "#ifndef NV_SET_PAGES_UC_PRESENT"     >> conftest.h
                 echo "#define NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
+                echo "#endif"                              >> conftest.h
                 return
             fi
         ;;
@@ -501,6 +529,8 @@
                 return
             fi
 
+            rm -f conftest$$.o
+
             echo "#include <linux/autoconf.h>
             #include <linux/interrupt.h>
             irq_handler_t conftest_isr;
diff -ru usr/src/nv/nv-linux.h usr/src/nv.2305230/nv-linux.h
--- usr/src/nv/nv-linux.h	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/nv-linux.h	2008-03-18 12:57:26.340745475 -0700
@@ -19,8 +19,8 @@
 #include <linux/utsname.h>
 
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
-#  error This driver does not support pre-2.4 kernels!
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 7)
+#  error This driver does not support 2.4 kernels older than 2.4.7!
 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
 #  define KERNEL_2_4
 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
@@ -51,6 +51,10 @@
 #include <linux/modversions.h>
 #endif
 
+#if defined(KERNEL_2_4) && !defined(EXPORT_SYMTAB)
+#define EXPORT_SYMTAB
+#endif
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 
@@ -98,6 +102,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/semaphore.h>
+#include <linux/completion.h>
 #include <linux/highmem.h>
 
 #ifdef CONFIG_PROC_FS
@@ -118,8 +123,12 @@
 #endif
 
 #if defined(CONFIG_KGDB)
+#if defined(NV_OLD_MM_KGDB_BREAKPOINT_PRESENT)
+#include <asm/kgdb.h>
+#else
 #include <linux/kgdb.h>
 #endif
+#endif
 
 #if defined (CONFIG_AGP) || defined (CONFIG_AGP_MODULE)
 #define AGPGART
@@ -516,19 +525,16 @@
 #define NV_KMEM_CACHE_ALLOC(ptr, kmem_cache, type)              \
     {                                                           \
         (ptr) = kmem_cache_alloc(kmem_cache, GFP_KERNEL);       \
-        KM_ALLOC_RECORD(ptr, sizeof(type), "km_cache_alloc");   \
     }
 
 #define NV_KMEM_CACHE_FREE(ptr, type, kmem_cache)               \
     {                                                           \
-        KM_FREE_RECORD(ptr, sizeof(type), "km_cache_free");     \
         kmem_cache_free(kmem_cache, ptr);                       \
     }
 
-#if defined(NV_SG_MAP_BUFFERS) /* Linux/x86-64, only */
 #if defined(NV_VMAP_PRESENT)
 #if (NV_VMAP_ARGUMENT_COUNT == 2)
-#define NV_VMAP(ptr, pages, count, cached)                              \
+#define NV_VMAP_KERNEL(ptr, pages, count, prot)                         \
     {                                                                   \
         (ptr) = (unsigned long)vmap(pages, count);                      \
         VM_ALLOC_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");   \
@@ -537,26 +543,35 @@
 #ifndef VM_MAP
 #define VM_MAP  0
 #endif
-#define NV_VMAP(ptr, pages, count, cached)                              \
+#define NV_VMAP_KERNEL(ptr, pages, count, prot)                         \
     {                                                                   \
-        pgprot_t __prot = (cached) ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE; \
-        (ptr) = (unsigned long)vmap(pages, count, VM_MAP, __prot);      \
+        (ptr) = (unsigned long)vmap(pages, count, VM_MAP, prot);        \
         VM_ALLOC_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");   \
     }
 #else
 #error "NV_VMAP_ARGUMENT_COUNT value unrecognized!"
 #endif
 #else
+#if defined(NV_SG_MAP_BUFFERS)
 #error "NV_VMAP() undefined (vmap() unavailable)!"
+#endif
 #endif /* NV_VMAP_PRESENT */
 
-#define NV_VUNMAP(ptr, count)                                           \
+#define NV_VUNMAP_KERNEL(ptr, count)                                    \
     {                                                                   \
-        VM_FREE_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");    \
+        VM_FREE_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vunmap");  \
         vunmap((void *)(ptr));                                          \
     }
 
-#endif /* NV_SG_MAP_BUFFERS */
+#define NV_VMAP(addr, pages, count, cached)                             \
+    {                                                                   \
+        pgprot_t __prot = (cached) ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE; \
+        void *__ptr = nv_vmap(pages, count, __prot);                    \
+        (addr) = (unsigned long)__ptr;                                  \
+    }
+
+#define NV_VUNMAP(addr, count) nv_vunmap((void *)addr, count)
+
 
 #endif /* !defined NVWATCH */
 
@@ -764,9 +779,10 @@
 
 #define NV_PGD_OFFSET(address, kernel, mm)              \
    ({                                                   \
+        struct mm_struct *__mm = (mm);                  \
         pgd_t *__pgd;                                   \
         if (!kernel)                                    \
-            __pgd = pgd_offset(mm, address);            \
+            __pgd = pgd_offset(__mm, address);          \
         else                                            \
             __pgd = pgd_offset_k(address);              \
         __pgd;                                          \
@@ -968,9 +984,7 @@
 #define NV_ALLOC_TYPE_PCI      (1<<0)
 #define NV_ALLOC_TYPE_AGP      (1<<1)
 #define NV_ALLOC_TYPE_CONTIG   (1<<2)
-#define NV_ALLOC_TYPE_KERNEL   (1<<3)
-#define NV_ALLOC_TYPE_VMALLOC  (1<<4)
-#define NV_ALLOC_TYPE_VMAP     (1<<5)
+#define NV_ALLOC_TYPE_VMAP     (1<<3)
 
 #define NV_ALLOC_MAPPING_SHIFT      16
 #define NV_ALLOC_MAPPING(flags)     (((flags)>>NV_ALLOC_MAPPING_SHIFT)&0xff)
@@ -980,7 +994,6 @@
 
 #define NV_ALLOC_MAPPING_AGP(flags)     ((flags) & NV_ALLOC_TYPE_AGP)
 #define NV_ALLOC_MAPPING_CONTIG(flags)  ((flags) & NV_ALLOC_TYPE_CONTIG)
-#define NV_ALLOC_MAPPING_VMALLOC(flags) ((flags) & NV_ALLOC_TYPE_VMALLOC)
 #define NV_ALLOC_MAPPING_VMAP(flags)    ((flags) & NV_ALLOC_TYPE_VMAP)
 
 static inline U032 nv_alloc_init_flags(int cached, int agp, int contig, int kernel)
@@ -988,12 +1001,7 @@
     U032 flags = NV_ALLOC_ENC_MAPPING(cached);
     if (agp)    flags |= NV_ALLOC_TYPE_AGP;
     else        flags |= NV_ALLOC_TYPE_PCI;
-    if (kernel) flags |= NV_ALLOC_TYPE_KERNEL; 
-#if defined(NV_SG_MAP_BUFFERS)
     if (kernel && !contig) flags |= NV_ALLOC_TYPE_VMAP;
-#else
-    if (kernel && !contig) flags |= NV_ALLOC_TYPE_VMALLOC;
-#endif
     if (contig && !agp) flags |= NV_ALLOC_TYPE_CONTIG;
     return flags;
 }
@@ -1067,21 +1075,24 @@
 #define NV_ATOMIC_DEC_AND_TEST(data)    atomic_dec_and_test(&(data))
 #define NV_ATOMIC_READ(data)            atomic_read(&(data))
 
+extern int nv_update_memory_types;
+
 /*
- * a BUG() is triggered on early 2.6 x86_64 kernels. the underlying
- * problem actually exists on many architectures and kernels, but
- * these are the only kernels that check the condition and trigger
- * a BUG(). note that this is a problem of the core kernel, not an
- * nvidia bug (and can still be triggered by agpgart). let's avoid
- * change_page_attr on those kernels.
+ * Using change_page_attr() on early Linux/x86-64 2.6 kernels may
+ * result in a BUG() being triggered. The underlying problem
+ * actually exists on multiple architectures and kernels, but only
+ * the above check for the condition and trigger a BUG().
+ *
+ * Note that this is a due to a bug in the Linux kernel, not an
+ * NVIDIA driver bug (it can also be triggered by AGPGART).
+ *
+ * We therefore need to determine at runtime if change_page_attr()
+ * can be used safely on these kernels.
  */
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-extern int nv_use_cpa;
-
-#if defined(NVCPU_X86_64) && !defined(KERNEL_2_4) && \
-         (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
-#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT 1
-#endif
+#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) && defined(NVCPU_X86_64) && \
+  !defined(KERNEL_2_4) && \
+  (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
+#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT
 #endif
 
 #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
@@ -1093,7 +1104,7 @@
  *
  * We need to be careful to mask out _PAGE_NX when the host system
  * doesn't support this feature or when it's disabled: the kernel
- * may not do this in its implementation of the  change_page_attr()
+ * may not do this in its implementation of the change_page_attr()
  * interface.
  */
 #ifndef X86_FEATURE_NX
diff -ru usr/src/nv/nv-vm.c usr/src/nv.2305230/nv-vm.c
--- usr/src/nv/nv-vm.c	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/nv-vm.c	2008-03-18 12:55:58.755754293 -0700
@@ -43,42 +43,40 @@
 }
 #endif
 
-/*
- * AMD Athlon processors expose a subtle bug in the Linux
- * kernel, that may lead to AGP memory corruption. Recent
- * kernel versions had a workaround for this problem, but
- * 2.4.20 is the first kernel to address it properly. The
- * page_attr API provides the means to solve the problem. 
- */
-
 static inline void nv_set_page_attrib_uncached(nv_pte_t *page_ptr)
 {
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-    if (nv_use_cpa)
+    if (nv_update_memory_types)
     {
-        struct page *page = virt_to_page(__va(page_ptr->phys_addr));
+#if defined(NV_SET_PAGES_UC_PRESENT)
+        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
+        set_pages_uc(page, 1);
+#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT)
+        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
         pgprot_t prot = PAGE_KERNEL_NOCACHE;
 #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
         pgprot_val(prot) &= __nv_supported_pte_mask;
 #endif
         change_page_attr(page, 1, prot);
-    }
 #endif
+    }
 }
 
 static inline void nv_set_page_attrib_cached(nv_pte_t *page_ptr)
 {
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-    if (nv_use_cpa)
+    if (nv_update_memory_types)
     {
-        struct page *page = virt_to_page(__va(page_ptr->phys_addr));
+#if defined(NV_SET_PAGES_UC_PRESENT)
+        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
+        set_pages_wb(page, 1);
+#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT)
+        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
         pgprot_t prot = PAGE_KERNEL;
 #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
         pgprot_val(prot) &= __nv_supported_pte_mask;
 #endif
         change_page_attr(page, 1, prot);
+#endif
     }
-#endif /* NV_CHANGE_PAGE_ATTR_PRESENT */
 }
 
 static inline void nv_lock_page(nv_pte_t *page_ptr)
@@ -360,8 +358,11 @@
 #if defined(NV_CPA_NEEDS_FLUSHING)
     nv_execute_on_all_cpus(cache_flush, NULL);
 #endif
+#if (defined(NVCPU_X86) || defined(NVCPU_X86_64)) && \
+  defined(NV_CHANGE_PAGE_ATTR_PRESENT)
     global_flush_tlb();
 #endif
+#endif
 }
 
 /*
@@ -409,11 +410,11 @@
     nv_pte_t *page_ptr = *at->page_table;
     unsigned int i, j, gfp_mask;
     unsigned long virt_addr = 0, phys_addr;
+    struct page **pages = 0;
 #if defined(NV_SG_MAP_BUFFERS)
     int ret = -1;
     nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
     struct pci_dev *dev = nvl->dev;
-    struct page **pages = 0;
 #endif
 
     nv_printf(NV_DBG_MEMINFO, "NVRM: VM: nv_vm_malloc_pages: %d pages\n",
@@ -462,22 +463,7 @@
         }
 #endif
     }
-    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
-    {
-        void *virt_kptr = NULL;
-        at->size = at->num_pages * PAGE_SIZE;
-        nv_printf(NV_DBG_MEMINFO, "NVRM: VM:    vmalloc, size 0x%x\n", at->size);
-        NV_VMALLOC(virt_kptr, at->size, NV_ALLOC_MAPPING_CACHED(at->flags));
-        virt_addr = (unsigned long) virt_kptr;
-        if (virt_addr == 0)
-        {
-            nv_printf(NV_DBG_ERRORS,
-                "NVRM: nv_vm_malloc failed to allocate vmalloc memory\n");
-            return -1;
-        }
-    }
 
-#if defined(NV_SG_MAP_BUFFERS)
     if (NV_ALLOC_MAPPING_VMAP(at->flags))
     {
         NV_KMALLOC(pages, sizeof(struct page *) * at->num_pages);
@@ -488,11 +474,10 @@
             return -1;
         }
     }
-#endif
 
     for (i = 0; i < at->num_pages; i++) 
     {
-        if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
+        if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
         { 
             NV_GET_FREE_PAGES(virt_addr, 0, gfp_mask); 
             if (virt_addr == 0)
@@ -553,10 +538,10 @@
             }
         }
         nv_sg_load(&page_ptr->sg_list, page_ptr);
+#endif
 
         if (NV_ALLOC_MAPPING_VMAP(at->flags))
             pages[i] = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
-#endif
 
         if (!NV_ALLOC_MAPPING_CACHED(at->flags))
             nv_set_page_attrib_uncached(page_ptr);
@@ -565,41 +550,21 @@
         virt_addr += PAGE_SIZE;
     }
 
-#if defined(NV_SG_MAP_BUFFERS)
     if (NV_ALLOC_MAPPING_VMAP(at->flags))
     {
         NV_VMAP(virt_addr, pages, at->num_pages, NV_ALLOC_MAPPING_CACHED(at->flags));
-#if defined(KERNEL_2_4)
-        if (virt_addr != 0)
-        {
-            unsigned int i;
-            /*
-             * XXX Linux 2.4's vmap() increments the pages' reference counts
-             * in preparation for vfree(); the latter skips the calls to
-             * __free_page() if the pages are marked reserved, however, so
-             * that the underlying memory is effectively leaked when we free
-             * it later. Decrement the count here to avoid this leak.
-             */
-            for (i = 0; i < at->num_pages; i++)
-            {
-                if (PageReserved(pages[i]))
-                    atomic_dec(&pages[i]->count);
-            }
-        }
-#endif
-        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
         if (virt_addr == 0)
         {
             nv_printf(NV_DBG_ERRORS,
                 "NVRM: VM: nv_vm_malloc_pages: failed to vmap pages\n");
             goto failed;
         }
+        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
         for (i = 0; i < at->num_pages; i++)
         {
             at->page_table[i]->virt_addr = virt_addr + i * PAGE_SIZE;
         }
     }
-#endif /* NV_SG_MAP_BUFFERS */
 
     nv_vm_list_page_count(at->page_table, at->num_pages);
 
@@ -624,7 +589,7 @@
                 nv_sg_unmap_buffer(dev, &page_ptr->sg_list, page_ptr);
 #endif
             nv_unlock_page(page_ptr);
-            if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
+            if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
                 NV_FREE_PAGES(page_ptr->virt_addr, 0);
         }
     }
@@ -638,16 +603,9 @@
 #endif
         NV_FREE_PAGES(page_ptr->virt_addr, at->order);
     }
-    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
-    {
-        page_ptr = *at->page_table;
-        NV_VFREE((void *) page_ptr->virt_addr, at->size);
-    }
 
-#if defined(NV_SG_MAP_BUFFERS)
     if (NV_ALLOC_MAPPING_VMAP(at->flags) && pages != 0)
-        NV_VFREE((void *)pages, sizeof(struct page *) * at->num_pages);
-#endif
+        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
 
     return -1;
 }
@@ -674,19 +632,17 @@
     }
     nv_vm_list_page_count(at->page_table, at->num_pages);
 
-#if defined(NV_SG_MAP_BUFFERS)
     if (NV_ALLOC_MAPPING_VMAP(at->flags))
         NV_VUNMAP((void *)at->page_table[0]->virt_addr, at->num_pages);    // undo vmap()
-#endif
 
     for (i = 0; i < at->num_pages; i++)
     {
         page_ptr = at->page_table[i];
         if (!NV_ALLOC_MAPPING_CACHED(at->flags))
             nv_set_page_attrib_cached(page_ptr);
-#if defined(NV_SG_MAP_BUFFERS)
         if (NV_ALLOC_MAPPING_VMAP(at->flags))
             page_ptr->virt_addr = (unsigned long) __va(page_ptr->phys_addr);
+#if defined(NV_SG_MAP_BUFFERS)
         if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
             nv_sg_unmap_buffer(dev, &page_ptr->sg_list, page_ptr);
 #endif
@@ -701,7 +657,7 @@
             }
         }
         nv_unlock_page(page_ptr);
-        if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
+        if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
             NV_FREE_PAGES(page_ptr->virt_addr, 0);
     }
     nv_flush_caches();
@@ -714,9 +670,136 @@
 #endif
         NV_FREE_PAGES(page_ptr->virt_addr, at->order);
     }
-    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
+}
+
+#if defined(NV_VMAP_PRESENT) && defined(KERNEL_2_4) && defined(NVCPU_X86)
+static unsigned long
+nv_vmap_vmalloc(
+    int count,
+    struct page **pages,
+    pgprot_t prot
+)
+{
+    void *virt_addr = NULL;
+    unsigned int i, size = count * PAGE_SIZE;
+
+    NV_VMALLOC(virt_addr, size, TRUE);
+    if (virt_addr == NULL)
+    {
+        nv_printf(NV_DBG_ERRORS,
+            "NVRM: vmalloc() failed to allocate vmap() scratch pages!\n");
+        return 0;
+    }
+
+    for (i = 0; i < (unsigned int)count; i++)
     {
-        page_ptr = *at->page_table;
-        NV_VFREE((void *) page_ptr->virt_addr, at->size);
+        pgd_t *pgd = NULL;
+        pmd_t *pmd = NULL;
+        pte_t *pte = NULL;
+        unsigned long address;
+        struct page *page;
+
+        address = (unsigned long)virt_addr + i * PAGE_SIZE; 
+
+        pgd = NV_PGD_OFFSET(address, 1, NULL);
+        if (!NV_PGD_PRESENT(pgd))
+            goto failed;
+
+        pmd = NV_PMD_OFFSET(address, pgd);
+        if (!NV_PMD_PRESENT(pmd))
+            goto failed;
+
+        pte = NV_PTE_OFFSET(address, pmd);
+        if (!NV_PTE_PRESENT(pte))
+            goto failed;
+
+        page = NV_GET_PAGE_STRUCT(pte_val(*pte) & PAGE_MASK);
+        get_page(pages[i]);
+        set_pte(pte, mk_pte(pages[i], prot));
+        put_page(page);
+        NV_PTE_UNMAP(pte);
+    }
+    nv_flush_caches();
+
+    return (unsigned long)virt_addr;
+
+failed:
+    NV_VFREE(virt_addr, size);
+
+    return 0;
+}
+
+static void
+nv_vunmap_vmalloc(
+    void *address,
+    int count
+)
+{
+    NV_VFREE(address, count * PAGE_SIZE);
+}
+#endif /* NV_VMAP_PRESENT && KERNEL_2_4 && NVCPU_X86 */
+
+void *nv_vmap(
+    struct page **pages,
+    int count,
+    pgprot_t prot
+)
+{
+    unsigned long virt_addr = 0;
+#if defined(NV_VMAP_PRESENT)
+#if defined(KERNEL_2_4) && defined(NVCPU_X86)
+    /*
+     * XXX Linux 2.4's vmap() checks the requested mapping's size against
+     * the value of (max_mapnr << PAGESHIFT); since 'map_nr' is a 32-bit
+     * symbol, the checks fails given enough physical memory. We can't solve
+     * this problem by adjusting the value of 'map_nr', but we can avoid
+     * vmap() by going through vmalloc().
+     */
+    if (max_mapnr >= 0x100000)
+        virt_addr = nv_vmap_vmalloc(count, pages, prot);
+    else
+#endif
+        NV_VMAP_KERNEL(virt_addr, pages, count, prot);
+#if defined(KERNEL_2_4)
+    if (virt_addr)
+    {
+        int i;
+        /*
+         * XXX Linux 2.4's vmap() increments the pages' reference counts
+         * in preparation for vfree(); the latter skips the calls to
+         * __free_page() if the pages are marked reserved, however, so
+         * that the underlying memory is effectively leaked when we free
+         * it later. Decrement the count here to avoid this leak.
+         */
+        for (i = 0; i < count; i++)
+        {
+            if (PageReserved(pages[i]))
+                atomic_dec(&pages[i]->count);
+        }
     }
+#endif
+#endif /* NV_VMAP_PRESENT */
+    return (void *)virt_addr;
+}
+
+void nv_vunmap(
+    void *address,
+    int count
+)
+{
+#if defined(NV_VMAP_PRESENT)
+#if defined(KERNEL_2_4) && defined(NVCPU_X86)
+    /*
+     * XXX Linux 2.4's vmap() checks the requested mapping's size against
+     * the value of (max_mapnr << PAGESHIFT); since 'map_nr' is a 32-bit
+     * symbol, the checks fails given enough physical memory. We can't solve
+     * this problem by adjusting the value of 'map_nr', but we can avoid
+     * vmap() by going through vmalloc().
+     */
+    if (max_mapnr >= 0x100000)
+        nv_vunmap_vmalloc(address, count);
+    else
+#endif
+        NV_VUNMAP_KERNEL(address, count);
+#endif /* NV_VMAP_PRESENT */
 }
diff -ru usr/src/nv/nv-vm.h usr/src/nv.2305230/nv-vm.h
--- usr/src/nv/nv-vm.h	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/nv-vm.h	2008-03-18 12:55:54.643519951 -0700
@@ -11,6 +11,9 @@
 #ifndef _NV_VM_H_
 #define _NV_VM_H_
 
+void *   nv_vmap(struct page **, int, pgprot_t);
+void     nv_vunmap(void *, int);
+
 int      nv_vm_malloc_pages(nv_state_t *, nv_alloc_t *);
 void     nv_vm_free_pages(nv_state_t *, nv_alloc_t *);
 
diff -ru usr/src/nv/nv.c usr/src/nv.2305230/nv.c
--- usr/src/nv/nv.c	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/nv.c	2008-03-18 12:56:01.123889244 -0700
@@ -97,9 +97,7 @@
 unsigned int nv_remap_limit;
 #endif
 
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-int nv_use_cpa = 1;
-#endif
+int nv_update_memory_types = 1;
 
 static void *nv_pte_t_cache = NULL;
 
@@ -850,16 +848,13 @@
 
     for (i = 0; i < 4; i++)
     {
-         if (NV_PAT_ENTRY(pat1, i) == 1)
+         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;
          }
-    }
 
-    for (i = 0; i < 4; i++)
-    {
          if (NV_PAT_ENTRY(pat2, i) == 1)
          {
              nv_printf(NV_DBG_ERRORS, "NVRM: PAT index %d already configured for Write-Combining!\n", i + 4);
@@ -969,30 +964,26 @@
 #endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */
 }
 
-
 #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT)
-
-/* nv_verify_cpa_interface - determine if the change_page_attr bug is fixed
- * in this kernel.
+/*
+ * nv_verify_cpa_interface() - determine if the change_page_attr() large page
+ * management accounting bug known to exist in early Linux/x86-64 kernels
+ * is present in this kernel.
  *
- * there's really not a good way to determine if change_page_attr is fixed.
- * we can't really use cpa on 2.6 x86_64 kernels < 2.6.11, as if we run into
- * the accounting bug, the kernel will throw a BUG. this isn't 100% accurate,
- * as it doesn't throw a bug until we try to restore the caching attributes
- * of the page. so if we can track down a 4M allocation, we can mark it
- * uncached and see if the accounting was done correctly.
- * 
- * this is a little ugly, but the most accurate approach to determining if
- * this kernel is good.
+ * There's really no good way to determine if change_page_attr() is working
+ * correctly. We can't reliably use change_page_attr() on Linux/x86-64 2.6
+ * kernels < 2.6.11: if we run into the accounting bug, the Linux kernel will
+ * trigger a BUG() if we attempt to restore the WB memory type of a page
+ * originally part of a large page.
  *
- * why do we even bother? some distributions have back-ported the cpa fix to
- * kernels < 2.6.11. we want to use change_page_attr to avoid random corruption
- * and hangs, but need to make sure it's safe to do so.
+ * So if we can successfully allocate such a page, change its memory type to
+ * UC and check if the accounting was done correctly, we can determine if
+ * the change_page_attr() interface can be used safely.
  *
- * return values:
- *    0 - test passed, interface works
- *    1 - test failed, status unclear
- *   -1 - test failed, interface broken
+ * Return values:
+ *    0 - test passed, the change_page_attr() interface works
+ *    1 - test failed, the status is unclear
+ *   -1 - test failed, the change_page_attr() interface is broken
  */
 
 static inline pte_t *check_large_page(unsigned long vaddr)
@@ -1000,7 +991,7 @@
     pgd_t *pgd = NULL;
     pmd_t *pmd = NULL;
 
-    pgd = NV_PGD_OFFSET(vaddr, 1, &init_mm);
+    pgd = NV_PGD_OFFSET(vaddr, 1, NULL);
     if (!NV_PGD_PRESENT(pgd))
         return NULL;
 
@@ -1110,35 +1101,42 @@
 
     return 1;
 }
-
 #endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */
 
-
-// verify that the kernel's mapping matches the requested type 
-// this is to protect against accidental cache aliasing problems
+/*
+ * nv_verify_page_mappings() - verify that the kernel mapping of the specified
+ * page matches the specified type. This is to help detect bugs in the Linux
+ * kernel's change_page_attr() interface, early.
+ *
+ * This function relies on the ability to perform kernel virtul address to PFN
+ * translations and therefore on 'init_mm'. Unfortunately, the latter is no
+ * longer exported in recent Linux/x86 2.6 kernels. The export was removed at
+ * roughtly the same time as the set_pages_{uc,wb}() change_page_attr()
+ * replacement interfaces were introduced; hopefully, it will be sufficient to
+ * check for their presence.
+ */
 int nv_verify_page_mappings(
     nv_pte_t *page_ptr,
     unsigned int cachetype
 )
 {
-    struct mm_struct *mm;
+#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || \
+    (defined(NV_SET_PAGES_UC_PRESENT) && !defined(NVCPU_X86))
+    unsigned long retval = -1;
+#if defined(NVCPU_X86) || defined(NVCPU_X86_64)
     pgd_t *pgd = NULL;
     pmd_t *pmd = NULL;
     pte_t *pte = NULL;
-    unsigned long retval = -1;
     unsigned int flags, expected;
     unsigned long address;
     static int count = 0;
 
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-    if (!nv_use_cpa)
+    if (!nv_update_memory_types)
         return 0;
-#endif
 
     address = (unsigned long)__va(page_ptr->phys_addr);
-    mm = &init_mm; // always a kernel page
 
-    pgd = NV_PGD_OFFSET(address, 1, mm);
+    pgd = NV_PGD_OFFSET(address, 1, NULL);
     if (!NV_PGD_PRESENT(pgd))
     {
         nv_printf(NV_DBG_ERRORS, "NVRM: pgd not present for addr 0x%lx\n", address);
@@ -1204,7 +1202,11 @@
     }
 
 failed:
+#endif /* defined(NVCPU_X86) || defined(NVCPU_X86_64) */
     return retval;
+#else
+    return 0;
+#endif
 }
 
 #if defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU)
@@ -1250,7 +1252,8 @@
 static int __init nvidia_init_module(void)
 {
     int rc;
-    U032 i, count;
+    U032 i, count, data;
+    nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device);
 
 #if defined(VM_CHECKER)
     nv_init_lock(vm_lock);
@@ -1266,11 +1269,18 @@
         return -ENODEV;
     }
 
+    if (!rm_init_rm())
+    {
+        nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_rm() failed!\n");
+        return -EIO;
+    }
+
     memset(nv_linux_devices, 0, sizeof(nv_linux_devices));
 
     if (pci_register_driver(&nv_pci_driver) < 0)
     {
         pci_unregister_driver(&nv_pci_driver); // XXX ???
+        rm_shutdown_rm();
         nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter found!\n");
         return -ENODEV;
     }
@@ -1293,6 +1303,7 @@
     if (num_probed_nv_devices == 0)
     {
         pci_unregister_driver(&nv_pci_driver);
+        rm_shutdown_rm();
         nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter probed!\n");
         return -ENODEV;
     }
@@ -1307,6 +1318,7 @@
     if (num_nv_devices == 0)
     {
         pci_unregister_driver(&nv_pci_driver);
+        rm_shutdown_rm();
         nv_printf(NV_DBG_ERRORS,
             "NVRM: None of the NVIDIA graphics adapters were initialized!\n");
         return -ENODEV;
@@ -1317,8 +1329,9 @@
     rc = register_chrdev(nv_major, "nvidia", &nv_fops);
     if (rc < 0)
     {
-        nv_printf(NV_DBG_ERRORS, "NVRM: register chrdev failed\n");
         pci_unregister_driver(&nv_pci_driver);
+        rm_shutdown_rm();
+        nv_printf(NV_DBG_ERRORS, "NVRM: register_chrdev() failed!\n");
         return rc;
     }
 
@@ -1367,14 +1380,6 @@
     }
 #endif
 
-    // Init the resource manager
-    if (!rm_init_rm())
-    {
-        nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_rm() failed\n");
-        rc = -EIO;
-        goto failed;
-    }
-
 #if defined(NV_SG_MAP_BUFFERS)
     rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "RemapLimit",  &nv_remap_limit);
 
@@ -1407,48 +1412,41 @@
     /* create /proc/driver/nvidia */
     nvos_proc_create();
 
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
+    /*
+     * Give users an opportunity to disable the driver's use of
+     * the change_page_attr() and set_pages_{uc,wb}() kernel
+     * interfaces.
+     */
+    rc = rm_read_registry_dword(nv, "NVreg", "UpdateMemoryTypes", &data);
+    if ((rc == 0) && ((int)data != ~0))
     {
-        int data;
-
-        // allow the user to override us with a registry key
-        rc = rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "UseCPA",  &data);
-        if ((rc == 0) && (data != -1))
-        {
-            nv_use_cpa = data;
-        }
+        nv_update_memory_types = data;
+    }
 #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT)
-        else
+    /*
+     * Unless we explicitely detect that the change_page_attr()
+     * inteface is fixed, disable usage of the interface on
+     * this kernel. Notify the user of this problem using the
+     * driver's /proc warnings interface (read by the installer
+     * and the bug report script).
+     */
+    else
+    {
+        rc = nv_verify_cpa_interface();
+        if (rc < 0)
         {
-            /*
-             * Unless we explicitely detect that the change_page_attr()
-             * inteface is fixed, disable usage of the interface on
-             * this kernel. Notify the user of this problem using the
-             * driver's /proc warnings interface (read by the installer
-             * and the bug report script).
-             */
-            rc = nv_verify_cpa_interface();
-            if (rc < 0)
-            {
-                nv_prints(NV_DBG_ERRORS, __cpgattr_warning);
-                nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning);
-                nv_use_cpa = 0;
-            }
-            else if (rc != 0)
-            {
-                nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2);
-                nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2);
-                nv_use_cpa = 0;
-            }
+            nv_prints(NV_DBG_ERRORS, __cpgattr_warning);
+            nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning);
+            nv_update_memory_types = 0;
+        }
+        else if (rc != 0)
+        {
+            nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2);
+            nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2);
+            nv_update_memory_types = 0;
         }
-#endif
     }
-#endif
-
-
-#if defined(DEBUG)
-    inter_module_register("nv_linux_devices", THIS_MODULE, nv_linux_devices);
-#endif
+#endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */
 
 #if defined(NVCPU_X86_64) && defined(CONFIG_IA32_EMULATION) && !defined(HAVE_COMPAT_IOCTL)
     /* Register ioctl conversions for 32 bit clients */
@@ -1501,6 +1499,8 @@
     }
 
     pci_unregister_driver(&nv_pci_driver);
+    rm_shutdown_rm();
+
     return rc;
 }
 
@@ -1532,10 +1532,6 @@
     /* remove /proc/driver/nvidia */
     nvos_proc_remove();
 
-#if defined(DEBUG)
-    inter_module_unregister("nv_linux_devices");
-#endif
-
 #if defined(NV_PM_SUPPORT_OLD_STYLE_APM)
     for (i = 0; i < num_nv_devices; i++)
     {
@@ -2112,6 +2108,8 @@
         if (rm_validate_pfn_range(file, NV_VMA_PGOFF(vma),
                 NV_VMA_SIZE(vma)) == RM_OK)
         {
+            if (vma->vm_flags & VM_WRITE)
+                return -EACCES;
             vma->vm_flags |= (VM_IO | VM_LOCKED);
 #if defined(NV_VM_INSERT_PAGE_PRESENT)
             if (NV_VM_INSERT_PAGE(vma, vma->vm_start, pfn_to_page(NV_VMA_PGOFF(vma))))
@@ -2240,6 +2238,8 @@
             if (rm_validate_pfn_range(file, NV_VMA_PGOFF(vma),
                     NV_VMA_SIZE(vma)) == RM_OK)
             {
+                if (vma->vm_flags & VM_WRITE)
+                    return -EACCES;
                 vma->vm_flags |= (VM_IO | VM_LOCKED);
 #if defined(NV_VM_INSERT_PAGE_PRESENT)
                 if (NV_VM_INSERT_PAGE(vma, vma->vm_start, pfn_to_page(NV_VMA_PGOFF(vma))))
@@ -3266,8 +3266,21 @@
     pte_t *pte = NULL;
     unsigned long retval;
 
-    mm = (kern) ? &init_mm : current->mm;
-    if (!kern) down_read(&current->mm->mmap_sem);
+    if (!kern)
+    {
+        mm = current->mm;
+        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))
@@ -3288,11 +3301,13 @@
     retval &= ~_PAGE_NX;
 #endif
 
-    if (!kern) up_read(&current->mm->mmap_sem);
+    if (!kern)
+        up_read(&mm->mmap_sem);
     return retval;
 
 failed:
-    if (!kern) up_read(&current->mm->mmap_sem);
+    if (!kern)
+        up_read(&mm->mmap_sem);
     return 0;
 }
 
@@ -3300,12 +3315,19 @@
     unsigned long address
 )
 {
-    // make sure this address is a kernel pointer
+#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86)
+    nv_linux_state_t *nvl;
+    nv_alloc_t *at;
+    unsigned long virt_addr;
+    U032 i, j;
+#endif
+
+    /* make sure this address is a kernel virtual address */
 #if defined(DEBUG) && !defined(CONFIG_X86_4G)
     if (address < PAGE_OFFSET)
     {
         nv_printf(NV_DBG_WARNINGS,
-            "NVRM: user address passed to get_kern_phys_address: 0x%lx\n",
+            "NVRM: user address passed to get_kern_phys_address: 0x%llx!\n",
             address);
         return 0;
     }
@@ -3315,6 +3337,30 @@
     if ((address > PAGE_OFFSET) && (address < VMALLOC_START))
         return __pa(address);
 
+#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86)
+    for (i = 0; i < num_nv_devices; i++)
+    {
+        nvl = &nv_linux_devices[i];
+
+        for (at = nvl->alloc_queue; (at != NULL); at = at->next)
+        {
+            if (!NV_ALLOC_MAPPING_VMAP(at->flags))
+                continue;
+
+            for (j = 0; j < at->num_pages; j++)
+            {
+                virt_addr = at->page_table[j]->virt_addr;
+                if ((address >= virt_addr) &&
+                        (address < (virt_addr + PAGE_SIZE)))
+                {
+                    return (at->page_table[j]->phys_addr +
+                            (address & ~PAGE_MASK));
+                }
+            }
+        }
+    }
+#endif
+
     return _get_phys_address(address, 1);
 }
 
@@ -3322,12 +3368,12 @@
     unsigned long address
 )
 {
-    // make sure this address is not a kernel pointer
+    /* make sure this address is not a kernel virtual address */
 #if defined(DEBUG) && !defined(CONFIG_X86_4G)
     if (address >= PAGE_OFFSET)
     {
         nv_printf(NV_DBG_WARNINGS,
-            "NVRM: kernel address passed to get_user_phys_address: 0x%lx\n",
+            "NVRM: kernel address passed to get_user_phys_address: 0x%llx!\n",
             address);
         return 0;
     }
@@ -3396,8 +3442,6 @@
             if (nv_vm_malloc_pages(nv, at))
                 goto failed;
 
-            at->class = class;
-
             // set our 'key' to the page_table. rm_alloc_agp_pages will call
             // nv_translate_address below, which will look up pages using
             // the value of *pAddress as a key, then index into the page_table
@@ -3952,7 +3996,8 @@
 
     if (num_nv_devices == NV_MAX_DEVICES)
     {
-        nv_printf(NV_DBG_ERRORS, "NVRM: maximum device number (%d) reached!\n", num_nv_devices);
+        nv_printf(NV_DBG_ERRORS, "NVRM: maximum device number (%d) exceeded!\n",
+                  (NV_MAX_DEVICES - 1));
         return -1;
     }
 
@@ -4085,13 +4130,10 @@
     return -1;
 }
 
-int NV_API_CALL nv_no_incoherent_mappings
-(
-    void
-)
+int NV_API_CALL nv_no_incoherent_mappings(void)
 {
-#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
-    return 1;
+#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || defined(NV_SET_PAGES_UC_PRESENT)
+    return (nv_update_memory_types);
 #else
     return 0;
 #endif
diff -ru usr/src/nv/nv.h usr/src/nv.2305230/nv.h
--- usr/src/nv/nv.h	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/nv.h	2008-03-18 12:55:56.919649651 -0700
@@ -335,15 +332,39 @@
 
 #define NV_DEVICE_NAME_LENGTH 40
 
+#define NV_MAX_ISR_DELAY_US           20000
+#define NV_MAX_ISR_DELAY_MS           (NV_MAX_ISR_DELAY_US / 1000)
+
+#define NV_TIMERCMP(a, b, CMP)                                              \
+    (((a)->tv_sec == (b)->tv_sec) ?                                         \
+        ((a)->tv_usec CMP (b)->tv_usec) : ((a)->tv_sec CMP (b)->tv_sec))
+
+#define NV_TIMERADD(a, b, result)                                           \
+    {                                                                       \
+        (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                       \
+        (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                    \
+        if ((result)->tv_usec >= 1000000)                                   \
+        {                                                                   \
+            ++(result)->tv_sec;                                             \
+            (result)->tv_usec -= 1000000;                                   \
+        }                                                                   \
+    }
+
+#define NV_TIMERSUB(a, b, result)                                           \
+    {                                                                       \
+        (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                       \
+        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                    \
+        if ((result)->tv_usec < 0)                                          \
+        {                                                                   \
+          --(result)->tv_sec;                                               \
+          (result)->tv_usec += 1000000;                                     \
+        }                                                                   \
+    }
 
 /*
  * driver internal interfaces
  */
 
-/* need a fake device number for control device; just to flag it for msgs */
-#define NV_CONTROL_DEVICE_NUMBER     100
-
-
 #ifndef NVWATCH
 
 /*
diff -ru usr/src/nv/os-interface.c usr/src/nv.2305230/os-interface.c
--- usr/src/nv/os-interface.c	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/os-interface.c	2008-03-18 12:56:04.288069559 -0700
@@ -25,7 +25,6 @@
 #include "os-interface.h"
 #include "nv-linux.h"
 
-
 static volatile int os_block_on_smp_barrier;
 
 #ifdef CONFIG_SMP
@@ -63,7 +62,7 @@
 //
 typedef struct os_sema_s
 {
-    struct semaphore wait;
+    struct completion  completion;
     spinlock_t       lock;
     S032             count;
 } os_sema_t;
@@ -86,7 +85,7 @@
         return rmStatus;
 
     os_sema = (os_sema_t *)*ppSema;
-    sema_init(&os_sema->wait, 0);
+    init_completion(&os_sema->completion);
     spin_lock_init(&os_sema->lock);
     os_sema->count = 1;
 
@@ -131,7 +130,7 @@
     {
         os_sema->count--;
         spin_unlock_irqrestore(&os_sema->lock, old_irq);
-        down(&os_sema->wait);
+        wait_for_completion(&os_sema->completion);
     }
     else
     {
@@ -208,7 +207,7 @@
     spin_unlock_irqrestore(&os_sema->lock, old_irq);
 
     if (doWakeup)
-        up(&os_sema->wait);
+        complete(&os_sema->completion);
 
     return RM_OK;
 }
@@ -448,8 +447,6 @@
 //
 //---------------------------------------------------------------------------
 
-#define NV_MAX_ISR_UDELAY           20000
-#define NV_MAX_ISR_MDELAY           (NV_MAX_ISR_UDELAY / 1000)
 #define NV_MSECS_PER_JIFFIE         (1000 / HZ)
 #define NV_MSECS_TO_JIFFIES(msec)   ((msec) * HZ / 1000)
 #define NV_USECS_PER_JIFFIE         (1000000 / HZ)
@@ -474,7 +471,7 @@
     do_gettimeofday(&tm1);
 #endif
 
-    if (in_irq() && MicroSeconds > NV_MAX_ISR_UDELAY)
+    if (in_irq() && (MicroSeconds > NV_MAX_ISR_DELAY_US))
         return RM_ERROR;
     
     mdelay_safe_msec = MicroSeconds / 1000;
@@ -494,36 +491,6 @@
     return RM_OK;
 }
 
-#ifndef timercmp
-# define timercmp(a, b, CMP)                                                  \
-  (((a)->tv_sec == (b)->tv_sec) ?                                             \
-   ((a)->tv_usec CMP (b)->tv_usec) :                                          \
-   ((a)->tv_sec CMP (b)->tv_sec))
-#endif
-#ifndef timeradd
-# define timeradd(a, b, result)                                               \
-  do {                                                                        \
-    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                             \
-    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                          \
-    if ((result)->tv_usec >= 1000000)                                         \
-      {                                                                       \
-        ++(result)->tv_sec;                                                   \
-        (result)->tv_usec -= 1000000;                                         \
-      }                                                                       \
-  } while (0)
-#endif
-#ifndef timersub
-# define timersub(a, b, result)                                               \
-  do {                                                                        \
-    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
-    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
-    if ((result)->tv_usec < 0) {                                              \
-      --(result)->tv_sec;                                                     \
-      (result)->tv_usec += 1000000;                                           \
-    }                                                                         \
-  } while (0)
-#endif
-
 /* 
  * On Linux, a jiffie represents the time passed in between two timer
  * interrupts. The number of jiffies per second (HZ) varies across the
@@ -549,7 +516,7 @@
     tm_start = tm_aux;
 #endif
 
-    if (in_irq() && MilliSeconds > NV_MAX_ISR_MDELAY)
+    if (in_irq() && (MilliSeconds > NV_MAX_ISR_DELAY_MS))
         return RM_ERROR;
 
     if (!NV_MAY_SLEEP()) 
@@ -561,7 +528,7 @@
     MicroSeconds = MilliSeconds * 1000;
     tm_end.tv_usec = MicroSeconds;
     tm_end.tv_sec = 0;
-    timeradd(&tm_aux, &tm_end, &tm_end);
+    NV_TIMERADD(&tm_aux, &tm_end, &tm_end);
 
     /* do we have a full jiffie to wait? */
     jiffies = NV_USECS_TO_JIFFIES(MicroSeconds);
@@ -590,9 +557,9 @@
             schedule_timeout(jiffies);
             /* catch the remainder, if any */
             do_gettimeofday(&tm_aux);
-            if (timercmp(&tm_aux, &tm_end, <))
+            if (NV_TIMERCMP(&tm_aux, &tm_end, <))
             {
-                timersub(&tm_end, &tm_aux, &tm_aux);    //  tm_aux = tm_end - tm_aux
+                NV_TIMERSUB(&tm_end, &tm_aux, &tm_aux); // tm_aux = tm_end - tm_aux
                 MicroSeconds = tm_aux.tv_usec + tm_aux.tv_sec * 1000000;
             } else
                 MicroSeconds = 0;
@@ -1109,6 +1076,18 @@
 {
     void *vaddr;
 
+    if (start == 0)
+    {
+        if (mode != NV_MEMORY_CACHED)
+        {
+            nv_printf(NV_DBG_ERRORS,
+                "NVRM: os_map_kernel_space: won't map address 0x%0llx UC!\n", start);
+            return NULL;
+        }
+        else
+            return (void *)PAGE_OFFSET;
+    }
+
     if (!NV_MAY_SLEEP())
     {
         nv_printf(NV_DBG_ERRORS,
@@ -1131,6 +1110,9 @@
     U032 size_bytes
 )
 {
+    if (addr == (void *)PAGE_OFFSET)
+        return;
+
     NV_IOUNMAP(addr, size_bytes);
 }
 
@@ -1176,7 +1158,11 @@
 #if defined(CONFIG_X86_REMOTE_DEBUG)
         __asm__ __volatile__ ("int $3");
 #elif defined(CONFIG_KGDB)
+#if defined(NV_OLD_MM_KGDB_BREAKPOINT_PRESENT)
+        BREAKPOINT;
+#else
         BREAKPOINT();
+#endif
 #elif defined(CONFIG_KDB)
     KDB_ENTER();
 #else
diff -ru usr/src/nv/os-registry.c usr/src/nv.2305230/os-registry.c
--- usr/src/nv/os-registry.c	2008-01-21 11:48:11.000000000 -0800
+++ usr/src/nv.2305230/os-registry.c	2008-03-18 12:56:07.492252151 -0700
@@ -48,24 +48,6 @@
  *   This could be changed to work on a per-device basis.
  */
 
-/*
- * The 2nd argument to MODULE_PARM is used to verify parameters passed
- * to the module at load time. It should be a string in the following 
- * format:
- *
- *      [min[-max]]{b,h,i,l,s}
- *
- * The MIN and MAX specifiers delimit the length of the array. If MAX
- * is omitted, it defaults to MIN; if both are omitted, the default is
- * 1. The final character is a type specifier.
- *
- *  b   byte
- *  h   short
- *  i   int
- *  l   long
- *  s   string
- */
-
 /* 
  * Option: VideoMemoryTypeOverride
  * 
@@ -360,9 +342,6 @@
 static int NVreg_DevicesConnected = 0;
 NV_MODULE_PARAMETER(NVreg_DevicesConnected);
 
-static int NVreg_VideoEnhancement = 0;
-NV_MODULE_PARAMETER(NVreg_VideoEnhancement);
-
 static int NVreg_RmLogonRC = 1;
 NV_MODULE_PARAMETER(NVreg_RmLogonRC);
 
@@ -402,34 +381,36 @@
 NV_MODULE_PARAMETER(NVreg_RemapLimit);
 
 /*
- * Option: UseCPA
+ * Option: UpdateMemoryTypes
  *
  * Description:
  *
- * Many kernels have a broken implementation of change_page_attr that leads
- * to cache aliasing problems. x86_64 kernels between 2.6.0 and 2.6.10 will
- * force a kernel BUG_ON() when this condition is encountered. For this
- * reason, the NVIDIA driver is very careful about not using the CPA kernel
- * interface on these kernels.
+ * Many kernels have broken implementations of the change_page_attr()
+ * kernel interface that may cause cache aliasing problems. Linux/x86-64
+ * kernels between 2.6.0 and 2.6.10 may prompt kernel BUG()s due to
+ * improper accounting in the interface's large page management code, for
+ * example. For this reason, the NVIDIA Linux driver is very careful about
+ * not using the change_page_attr() kernel interface on these kernels.
+ *
+ * Due to the serious nature of the problems that can arise from bugs in
+ * the change_page_attr(), set_pages_{uc,wb}() and other kernel interfaces
+ * used to modify memory types, the NVIDIA driver implements a manual
+ * registry key override to allow forcibly enabling or disabling use of
+ * these APIs.
  *
- * Some distributions have backported this fix to kernel versions that fall
- * within this version range. The NVIDIA driver attempts to automatically
- * detect these fixes and reenable usage of the change_page_attr interface.
+ * Possible values:
  *
- * Due to the serious nature of the problems that can arise from this, the
- * NVIDIA driver implements a manual registry key to force usage of this API
- * to be enabled or disabled. This registry key can be used to force usage
- * of the API on a known fixed kernel if the NVIDIA driver fails to detect
- * the kernel as fixed. This registry key can also be used to disable usage
- * of the API on a bad kernel that is misdetected as a fixed kernel.
+ * ~0 = use the NVIDIA driver's default logic (default)
+ *  0 = enable use of change_page_attr(), etc.
+ *  1 = disable use of change_page_attr(), etc.
  *
- * The default value is '-1' (use NVIDIA driver default logic)
- * A value of '0' will forcibly disable change_page_attr calls.
- * A value of '1' will forcibly enable change_page_attr calls.
+ * By default, the NVIDIA driver will attempt to auto-detect if it can
+ * safely use the change_page_attr() and other kernel interfaces to modify
+ * the memory types of kernel mappings.
  */
 
-static int NVreg_UseCPA = -1;
-NV_MODULE_PARAMETER(NVreg_UseCPA);
+static int NVreg_UpdateMemoryTypes = ~0;
+NV_MODULE_PARAMETER(NVreg_UpdateMemoryTypes);
 
 // 1 - Force sourcing vbios from ROM
 // 0 - business as usual
@@ -477,15 +458,14 @@
     { "NVreg",  "ResmanDebugLevel",         &NVreg_ResmanDebugLevel,         1 },
     { "NVreg",  "FlatPanelMode",            &NVreg_FlatPanelMode,            1 },
     { "NVreg",  "DevicesConnected",         &NVreg_DevicesConnected,         1 },
-    { "NVreg",  "VideoEnhancement",         &NVreg_VideoEnhancement,         1 },
     { "NVreg",  "RmLogonRC",                &NVreg_RmLogonRC,                1 },
+    { "NVreg",  "VbiosFromROM",             &NVreg_VbiosFromROM,             1 },
     { "NVreg",  "ModifyDeviceFiles",        &NVreg_ModifyDeviceFiles,        1 },
     { "NVreg",  "DeviceFileUID",            &NVreg_DeviceFileUID,            1 },
     { "NVreg",  "DeviceFileGID",            &NVreg_DeviceFileGID,            1 },
     { "NVreg",  "DeviceFileMode",           &NVreg_DeviceFileMode,           1 },
-    { "NVreg",  "VbiosFromROM",             &NVreg_VbiosFromROM,             1 },
     { "NVreg",  "RemapLimit",               &NVreg_RemapLimit,               1 },
-    { "NVreg",  "UseCPA",                   &NVreg_UseCPA,                   1 },
+    { "NVreg",  "UpdateMemoryTypes",        &NVreg_UpdateMemoryTypes,        1 },
     { "NVreg",  "RMEdgeIntrCheck",          &NVreg_RMEdgeIntrCheck,          1 },
     {  NULL,     NULL,                      NULL,                            0 }
 };